Socket
Socket
Sign inDemoInstall

@visx/text

Package Overview
Dependencies
Maintainers
4
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@visx/text - npm Package Compare versions

Comparing version 1.1.0 to 1.3.0-alpha.0

esm/hooks/useText.js

3

esm/index.js
export { default as Text } from './Text';
export { default as getStringWidth } from './util/getStringWidth';
export { default as getStringWidth } from './util/getStringWidth';
export { default as useText } from './hooks/useText';

@@ -1,3 +0,1 @@

import _pt from "prop-types";
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

@@ -7,234 +5,53 @@

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import React from 'react';
import reduceCSSCalc from 'reduce-css-calc';
import getStringWidth from './util/getStringWidth';
import useText from './hooks/useText';
import { TextProps } from './types';
export { TextProps } from './types';
var SVG_STYLE = {
overflow: 'visible'
};
export default function Text(props) {
var _props$dx = props.dx,
dx = _props$dx === void 0 ? 0 : _props$dx,
_props$dy = props.dy,
dy = _props$dy === void 0 ? 0 : _props$dy,
_props$textAnchor = props.textAnchor,
textAnchor = _props$textAnchor === void 0 ? 'start' : _props$textAnchor,
innerRef = props.innerRef,
verticalAnchor = props.verticalAnchor,
angle = props.angle,
_props$lineHeight = props.lineHeight,
lineHeight = _props$lineHeight === void 0 ? '1em' : _props$lineHeight,
_props$scaleToFit = props.scaleToFit,
scaleToFit = _props$scaleToFit === void 0 ? false : _props$scaleToFit,
capHeight = props.capHeight,
width = props.width,
textProps = _objectWithoutPropertiesLoose(props, ["dx", "dy", "textAnchor", "innerRef", "verticalAnchor", "angle", "lineHeight", "scaleToFit", "capHeight", "width"]);
function isNumber(val) {
return typeof val === 'number';
}
var _textProps$x = textProps.x,
x = _textProps$x === void 0 ? 0 : _textProps$x,
fontSize = textProps.fontSize;
function isValidXOrY(xOrY) {
return (// number that is not NaN or Infinity
typeof xOrY === 'number' && Number.isFinite(xOrY) || // for percentage
typeof xOrY === 'string'
);
}
var _useText = useText(props),
wordsByLines = _useText.wordsByLines,
startDy = _useText.startDy,
transform = _useText.transform;
var Text = /*#__PURE__*/function (_React$Component) {
_inheritsLoose(Text, _React$Component);
function Text() {
var _this;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
_defineProperty(_assertThisInitialized(_this), "state", {
wordsByLines: []
});
_defineProperty(_assertThisInitialized(_this), "wordsWithWidth", []);
_defineProperty(_assertThisInitialized(_this), "spaceWidth", 0);
return _this;
}
var _proto = Text.prototype;
_proto.componentDidMount = function componentDidMount() {
this.updateWordsByLines(this.props, true);
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
// We calculated a new state, break out of the loop.
if (prevState.wordsByLines !== this.state.wordsByLines) {
return;
}
var needCalculate = prevProps.children !== this.props.children || prevProps.style !== this.props.style;
this.updateWordsByLines(this.props, needCalculate);
};
_proto.updateWordsByLines = function updateWordsByLines(props, needCalculate) {
if (needCalculate === void 0) {
needCalculate = false;
}
// Only perform calculations if using features that require them (multiline, scaleToFit)
if (props.width || props.scaleToFit) {
if (needCalculate) {
var words = props.children == null ? [] : props.children.toString().split(/(?:(?!\u00A0+)\s+)/);
this.wordsWithWidth = words.map(function (word) {
return {
word: word,
width: getStringWidth(word, props.style) || 0
};
});
this.spaceWidth = getStringWidth("\xA0", props.style) || 0;
}
var wordsByLines = this.calculateWordsByLines(this.wordsWithWidth, this.spaceWidth, props.width);
this.setState({
wordsByLines: wordsByLines
});
} else {
this.updateWordsWithoutCalculate(props);
}
};
_proto.updateWordsWithoutCalculate = function updateWordsWithoutCalculate(props) {
var words = props.children == null ? [] : props.children.toString().split(/(?:(?!\u00A0+)\s+)/);
this.setState({
wordsByLines: [{
words: words
}]
});
};
_proto.calculateWordsByLines = function calculateWordsByLines(wordsWithWidth, spaceWidth, lineWidth) {
var scaleToFit = this.props.scaleToFit;
return wordsWithWidth.reduce(function (result, _ref) {
var word = _ref.word,
width = _ref.width;
var currentLine = result[result.length - 1];
if (currentLine && (lineWidth == null || scaleToFit || (currentLine.width || 0) + width + spaceWidth < lineWidth)) {
// Word can be added to an existing line
currentLine.words.push(word);
currentLine.width = currentLine.width || 0;
currentLine.width += width + spaceWidth;
} else {
// Add first word to line or word is too long to scaleToFit on existing line
var newLine = {
words: [word],
width: width
};
result.push(newLine);
}
return result;
}, []);
};
_proto.render = function render() {
var _this$props = this.props,
dx = _this$props.dx,
dy = _this$props.dy,
textAnchor = _this$props.textAnchor,
verticalAnchor = _this$props.verticalAnchor,
scaleToFit = _this$props.scaleToFit,
angle = _this$props.angle,
lineHeight = _this$props.lineHeight,
capHeight = _this$props.capHeight,
innerRef = _this$props.innerRef,
width = _this$props.width,
textProps = _objectWithoutPropertiesLoose(_this$props, ["dx", "dy", "textAnchor", "verticalAnchor", "scaleToFit", "angle", "lineHeight", "capHeight", "innerRef", "width"]);
var wordsByLines = this.state.wordsByLines;
var x = textProps.x,
y = textProps.y; // Cannot render <text> if x or y is invalid
if (!isValidXOrY(x) || !isValidXOrY(y)) {
return /*#__PURE__*/React.createElement("svg", {
ref: innerRef,
x: dx,
y: dy,
fontSize: textProps.fontSize,
style: SVG_STYLE
});
}
var startDy;
if (verticalAnchor === 'start') {
startDy = reduceCSSCalc("calc(" + capHeight + ")");
} else if (verticalAnchor === 'middle') {
startDy = reduceCSSCalc("calc(" + (wordsByLines.length - 1) / 2 + " * -" + lineHeight + " + (" + capHeight + " / 2))");
} else {
startDy = reduceCSSCalc("calc(" + (wordsByLines.length - 1) + " * -" + lineHeight + ")");
}
var transforms = [];
if (isNumber(x) && isNumber(y) && isNumber(width) && scaleToFit && wordsByLines.length > 0) {
var lineWidth = wordsByLines[0].width || 1;
var sx = width / lineWidth;
var sy = sx;
var originX = x - sx * x;
var originY = y - sy * y;
transforms.push("matrix(" + sx + ", 0, 0, " + sy + ", " + originX + ", " + originY + ")");
}
if (angle) {
transforms.push("rotate(" + angle + ", " + x + ", " + y + ")");
}
var transform = transforms.length > 0 ? transforms.join(' ') : undefined;
return /*#__PURE__*/React.createElement("svg", {
ref: innerRef,
x: dx,
y: dy,
fontSize: textProps.fontSize,
style: SVG_STYLE
}, /*#__PURE__*/React.createElement("text", _extends({
transform: transform
}, textProps, {
textAnchor: textAnchor
}), wordsByLines.map(function (line, index) {
return /*#__PURE__*/React.createElement("tspan", {
key: index,
x: x,
dy: index === 0 ? startDy : lineHeight
}, line.words.join(' '));
})));
};
return Text;
}(React.Component);
_defineProperty(Text, "propTypes", {
className: _pt.string,
scaleToFit: _pt.bool,
angle: _pt.number,
textAnchor: _pt.oneOf(['start', 'middle', 'end', 'inherit']),
verticalAnchor: _pt.oneOf(['start', 'middle', 'end']),
innerRef: _pt.oneOfType([_pt.string, _pt.func, _pt.object]),
x: _pt.oneOfType([_pt.string, _pt.number]),
y: _pt.oneOfType([_pt.string, _pt.number]),
dx: _pt.oneOfType([_pt.string, _pt.number]),
dy: _pt.oneOfType([_pt.string, _pt.number]),
fontSize: _pt.oneOfType([_pt.string, _pt.number]),
fontFamily: _pt.string,
fill: _pt.string,
width: _pt.number,
children: _pt.oneOfType([_pt.string, _pt.number])
});
_defineProperty(Text, "defaultProps", {
x: 0,
y: 0,
dx: 0,
dy: 0,
lineHeight: '1em',
capHeight: '0.71em',
// Magic number from d3
scaleToFit: false,
textAnchor: 'start',
verticalAnchor: 'end' // default SVG behavior
});
export default Text;
return /*#__PURE__*/React.createElement("svg", {
ref: innerRef,
x: dx,
y: dy,
fontSize: fontSize,
style: SVG_STYLE
}, wordsByLines.length > 0 ? /*#__PURE__*/React.createElement("text", _extends({
transform: transform
}, textProps, {
textAnchor: textAnchor
}), wordsByLines.map(function (line, index) {
return /*#__PURE__*/React.createElement("tspan", {
key: index,
x: x,
dy: index === 0 ? startDy : lineHeight
}, line.words.join(' '));
})) : null);
}
export { default as Text } from './Text';
export { default as getStringWidth } from './util/getStringWidth';
export { default as useText } from './hooks/useText';
//# sourceMappingURL=index.d.ts.map
"use strict";
exports.__esModule = true;
exports.getStringWidth = exports.Text = void 0;
exports.useText = exports.getStringWidth = exports.Text = void 0;

@@ -14,2 +14,6 @@ var _Text = _interopRequireDefault(require("./Text"));

var _useText = _interopRequireDefault(require("./hooks/useText"));
exports.useText = _useText.default;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -1,77 +0,5 @@

import React from 'react';
interface WordWithWidth {
word: string;
width: number;
}
interface WordsWithWidth {
words: string[];
width?: number;
}
declare type SVGTSpanProps = React.SVGAttributes<SVGTSpanElement>;
declare type SVGTextProps = React.SVGAttributes<SVGTextElement>;
declare type OwnProps = {
/** className to apply to the SVGText element. */
className?: string;
/** Whether to scale the fontSize to accommodate the specified width. */
scaleToFit?: boolean;
/** Rotational angle of the text. */
angle?: number;
/** Horizontal text anchor. */
textAnchor?: 'start' | 'middle' | 'end' | 'inherit';
/** Vertical text anchor. */
verticalAnchor?: 'start' | 'middle' | 'end';
/** Styles to be applied to the text (and used in computation of its size). */
style?: React.CSSProperties;
/** Ref passed to the Text SVG element. */
innerRef?: React.Ref<SVGSVGElement>;
/** x position of the text. */
x?: string | number;
/** y position of the text. */
y?: string | number;
/** dx offset of the text. */
dx?: string | number;
/** dy offset of the text. */
dy?: string | number;
/** Desired "line height" of the text, implemented as y offsets. */
lineHeight?: SVGTSpanProps['dy'];
/** Cap height of the text. */
capHeight?: SVGTSpanProps['capHeight'];
/** Font size of text. */
fontSize?: string | number;
/** Font family of text. */
fontFamily?: string;
/** Fill color of text. */
fill?: string;
/** Maximum width to occupy (approximate as words are not split). */
width?: number;
/** String (or number coercible to one) to be styled and positioned. */
children?: string | number;
};
export declare type TextProps = OwnProps & Omit<SVGTextProps, keyof OwnProps>;
declare type TextState = {
wordsByLines: WordsWithWidth[];
};
declare class Text extends React.Component<TextProps, TextState> {
static defaultProps: {
x: number;
y: number;
dx: number;
dy: number;
lineHeight: string;
capHeight: string;
scaleToFit: boolean;
textAnchor: string;
verticalAnchor: string;
};
state: TextState;
private wordsWithWidth;
private spaceWidth;
componentDidMount(): void;
componentDidUpdate(prevProps: TextProps, prevState: TextState): void;
updateWordsByLines(props: TextProps, needCalculate?: boolean): void;
updateWordsWithoutCalculate(props: TextProps): void;
calculateWordsByLines(wordsWithWidth: WordWithWidth[], spaceWidth: number, lineWidth?: number): WordsWithWidth[];
render(): JSX.Element;
}
export default Text;
/// <reference types="react" />
import { TextProps } from './types';
export { TextProps } from './types';
export default function Text(props: TextProps): JSX.Element;
//# sourceMappingURL=Text.d.ts.map
"use strict";
exports.__esModule = true;
exports.default = void 0;
exports.default = Text;
var _propTypes = _interopRequireDefault(require("prop-types"));
var _react = _interopRequireDefault(require("react"));
var _reduceCssCalc = _interopRequireDefault(require("reduce-css-calc"));
var _useText2 = _interopRequireDefault(require("./hooks/useText"));
var _getStringWidth = _interopRequireDefault(require("./util/getStringWidth"));
var _types = require("./types");
exports.TextProps = _types.TextProps;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -20,8 +20,2 @@

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var SVG_STYLE = {

@@ -31,222 +25,46 @@ overflow: 'visible'

function isNumber(val) {
return typeof val === 'number';
}
function Text(props) {
var _props$dx = props.dx,
dx = _props$dx === void 0 ? 0 : _props$dx,
_props$dy = props.dy,
dy = _props$dy === void 0 ? 0 : _props$dy,
_props$textAnchor = props.textAnchor,
textAnchor = _props$textAnchor === void 0 ? 'start' : _props$textAnchor,
innerRef = props.innerRef,
verticalAnchor = props.verticalAnchor,
angle = props.angle,
_props$lineHeight = props.lineHeight,
lineHeight = _props$lineHeight === void 0 ? '1em' : _props$lineHeight,
_props$scaleToFit = props.scaleToFit,
scaleToFit = _props$scaleToFit === void 0 ? false : _props$scaleToFit,
capHeight = props.capHeight,
width = props.width,
textProps = _objectWithoutPropertiesLoose(props, ["dx", "dy", "textAnchor", "innerRef", "verticalAnchor", "angle", "lineHeight", "scaleToFit", "capHeight", "width"]);
function isValidXOrY(xOrY) {
return (// number that is not NaN or Infinity
typeof xOrY === 'number' && Number.isFinite(xOrY) || // for percentage
typeof xOrY === 'string'
);
}
var _textProps$x = textProps.x,
x = _textProps$x === void 0 ? 0 : _textProps$x,
fontSize = textProps.fontSize;
var Text = /*#__PURE__*/function (_React$Component) {
_inheritsLoose(Text, _React$Component);
var _useText = (0, _useText2.default)(props),
wordsByLines = _useText.wordsByLines,
startDy = _useText.startDy,
transform = _useText.transform;
function Text() {
var _this;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
_defineProperty(_assertThisInitialized(_this), "state", {
wordsByLines: []
});
_defineProperty(_assertThisInitialized(_this), "wordsWithWidth", []);
_defineProperty(_assertThisInitialized(_this), "spaceWidth", 0);
return _this;
}
var _proto = Text.prototype;
_proto.componentDidMount = function componentDidMount() {
this.updateWordsByLines(this.props, true);
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
// We calculated a new state, break out of the loop.
if (prevState.wordsByLines !== this.state.wordsByLines) {
return;
}
var needCalculate = prevProps.children !== this.props.children || prevProps.style !== this.props.style;
this.updateWordsByLines(this.props, needCalculate);
};
_proto.updateWordsByLines = function updateWordsByLines(props, needCalculate) {
if (needCalculate === void 0) {
needCalculate = false;
}
// Only perform calculations if using features that require them (multiline, scaleToFit)
if (props.width || props.scaleToFit) {
if (needCalculate) {
var words = props.children == null ? [] : props.children.toString().split(/(?:(?!\u00A0+)\s+)/);
this.wordsWithWidth = words.map(function (word) {
return {
word: word,
width: (0, _getStringWidth.default)(word, props.style) || 0
};
});
this.spaceWidth = (0, _getStringWidth.default)("\xA0", props.style) || 0;
}
var wordsByLines = this.calculateWordsByLines(this.wordsWithWidth, this.spaceWidth, props.width);
this.setState({
wordsByLines: wordsByLines
});
} else {
this.updateWordsWithoutCalculate(props);
}
};
_proto.updateWordsWithoutCalculate = function updateWordsWithoutCalculate(props) {
var words = props.children == null ? [] : props.children.toString().split(/(?:(?!\u00A0+)\s+)/);
this.setState({
wordsByLines: [{
words: words
}]
});
};
_proto.calculateWordsByLines = function calculateWordsByLines(wordsWithWidth, spaceWidth, lineWidth) {
var scaleToFit = this.props.scaleToFit;
return wordsWithWidth.reduce(function (result, _ref) {
var word = _ref.word,
width = _ref.width;
var currentLine = result[result.length - 1];
if (currentLine && (lineWidth == null || scaleToFit || (currentLine.width || 0) + width + spaceWidth < lineWidth)) {
// Word can be added to an existing line
currentLine.words.push(word);
currentLine.width = currentLine.width || 0;
currentLine.width += width + spaceWidth;
} else {
// Add first word to line or word is too long to scaleToFit on existing line
var newLine = {
words: [word],
width: width
};
result.push(newLine);
}
return result;
}, []);
};
_proto.render = function render() {
var _this$props = this.props,
dx = _this$props.dx,
dy = _this$props.dy,
textAnchor = _this$props.textAnchor,
verticalAnchor = _this$props.verticalAnchor,
scaleToFit = _this$props.scaleToFit,
angle = _this$props.angle,
lineHeight = _this$props.lineHeight,
capHeight = _this$props.capHeight,
innerRef = _this$props.innerRef,
width = _this$props.width,
textProps = _objectWithoutPropertiesLoose(_this$props, ["dx", "dy", "textAnchor", "verticalAnchor", "scaleToFit", "angle", "lineHeight", "capHeight", "innerRef", "width"]);
var wordsByLines = this.state.wordsByLines;
var x = textProps.x,
y = textProps.y; // Cannot render <text> if x or y is invalid
if (!isValidXOrY(x) || !isValidXOrY(y)) {
return /*#__PURE__*/_react.default.createElement("svg", {
ref: innerRef,
x: dx,
y: dy,
fontSize: textProps.fontSize,
style: SVG_STYLE
});
}
var startDy;
if (verticalAnchor === 'start') {
startDy = (0, _reduceCssCalc.default)("calc(" + capHeight + ")");
} else if (verticalAnchor === 'middle') {
startDy = (0, _reduceCssCalc.default)("calc(" + (wordsByLines.length - 1) / 2 + " * -" + lineHeight + " + (" + capHeight + " / 2))");
} else {
startDy = (0, _reduceCssCalc.default)("calc(" + (wordsByLines.length - 1) + " * -" + lineHeight + ")");
}
var transforms = [];
if (isNumber(x) && isNumber(y) && isNumber(width) && scaleToFit && wordsByLines.length > 0) {
var lineWidth = wordsByLines[0].width || 1;
var sx = width / lineWidth;
var sy = sx;
var originX = x - sx * x;
var originY = y - sy * y;
transforms.push("matrix(" + sx + ", 0, 0, " + sy + ", " + originX + ", " + originY + ")");
}
if (angle) {
transforms.push("rotate(" + angle + ", " + x + ", " + y + ")");
}
var transform = transforms.length > 0 ? transforms.join(' ') : undefined;
return /*#__PURE__*/_react.default.createElement("svg", {
ref: innerRef,
x: dx,
y: dy,
fontSize: textProps.fontSize,
style: SVG_STYLE
}, /*#__PURE__*/_react.default.createElement("text", _extends({
transform: transform
}, textProps, {
textAnchor: textAnchor
}), wordsByLines.map(function (line, index) {
return /*#__PURE__*/_react.default.createElement("tspan", {
key: index,
x: x,
dy: index === 0 ? startDy : lineHeight
}, line.words.join(' '));
})));
};
return Text;
}(_react.default.Component);
_defineProperty(Text, "propTypes", {
className: _propTypes.default.string,
scaleToFit: _propTypes.default.bool,
angle: _propTypes.default.number,
textAnchor: _propTypes.default.oneOf(['start', 'middle', 'end', 'inherit']),
verticalAnchor: _propTypes.default.oneOf(['start', 'middle', 'end']),
innerRef: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.object]),
x: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
y: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
dx: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
dy: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
fontSize: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
fontFamily: _propTypes.default.string,
fill: _propTypes.default.string,
width: _propTypes.default.number,
children: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number])
});
_defineProperty(Text, "defaultProps", {
x: 0,
y: 0,
dx: 0,
dy: 0,
lineHeight: '1em',
capHeight: '0.71em',
// Magic number from d3
scaleToFit: false,
textAnchor: 'start',
verticalAnchor: 'end' // default SVG behavior
});
var _default = Text;
exports.default = _default;
return /*#__PURE__*/_react.default.createElement("svg", {
ref: innerRef,
x: dx,
y: dy,
fontSize: fontSize,
style: SVG_STYLE
}, wordsByLines.length > 0 ? /*#__PURE__*/_react.default.createElement("text", _extends({
transform: transform
}, textProps, {
textAnchor: textAnchor
}), wordsByLines.map(function (line, index) {
return /*#__PURE__*/_react.default.createElement("tspan", {
key: index,
x: x,
dy: index === 0 ? startDy : lineHeight
}, line.words.join(' '));
})) : null);
}
{
"name": "@visx/text",
"version": "1.1.0",
"version": "1.3.0-alpha.0",
"description": "visx text",

@@ -45,3 +45,6 @@ "sideEffects": false,

},
"gitHead": "2370dc7ace913ffbcf729f64059fee50498d66a4"
"devDependencies": {
"@testing-library/react-hooks": "^3.4.2"
},
"gitHead": "d11b08238456bf5031df5da238d2bafa0d062316"
}

Sorry, the diff of this file is not supported yet

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