New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

duoyun-ui

Package Overview
Dependencies
Maintainers
1
Versions
86
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

duoyun-ui - npm Package Compare versions

Comparing version 1.1.17 to 1.1.18

lib/timer.d.ts

2

elements/base/resize.js

@@ -9,3 +9,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { GemElement } from '@mantou/gem/lib/element';
import { throttle } from '../../lib/utils';
import { throttle } from '../../lib/timer';
export function resizeObserver(ele, options = {}) {

@@ -12,0 +12,0 @@ const { throttle: needThrottle = true } = options;

@@ -37,2 +37,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
:host(:not([borderless], [disabled])) {
box-shadow: ${theme.controlShadow};
}
:host([round]) {

@@ -39,0 +42,0 @@ border-radius: 10em;

@@ -24,3 +24,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { icons } from '../lib/icons';
import { structuredClone, getCascaderDeep, readProp } from '../lib/utils';
import { getCascaderDeep, readProp } from '../lib/utils';
import { theme } from '../lib/theme';

@@ -27,0 +27,0 @@ import { isNotNullish } from '../lib/types';

@@ -54,2 +54,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
:host(:not([disabled])) .checkbox {
box-shadow: ${theme.controlShadow};
}
.checkbox::part(icon) {

@@ -56,0 +59,0 @@ stroke-width: 1px;

@@ -114,2 +114,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

border-inline: none;
box-shadow: none;
}

@@ -116,0 +117,0 @@ :where(.value, .alpha)::part(input) {

@@ -33,2 +33,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
:host(:not([disabled])) {
box-shadow: ${theme.controlShadow};
}
:host([disabled]) {

@@ -35,0 +38,0 @@ cursor: not-allowed;

@@ -19,6 +19,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { locale } from '../lib/locale';
import { setBodyInert } from '../lib/utils';
import { setBodyInert, toggleActiveState } from '../lib/element';
import { hotkeys } from '../lib/hotkeys';
import { theme } from '../lib/theme';
import { toggleActiveState } from '../lib/element';
import './compartment';

@@ -151,5 +150,3 @@ import './button';

else {
update({
menuStack: menuStack.slice(0, menuStackIndex + 1),
});
update({ menuStack: menuStack.slice(0, menuStackIndex + 1) });
}

@@ -165,13 +162,6 @@ });

evt.stopPropagation();
const focusPrevMenu = () => {
var _a;
update({
menuStack: contextmenuStore.menuStack.slice(0, menuStackIndex),
});
(_a = __classPrivateFieldGet(this, _DuoyunContextmenuElement_instances, "a", _DuoyunContextmenuElement_menuElements_get)[menuStackIndex - 1]) === null || _a === void 0 ? void 0 : _a.focus();
};
hotkeys({
esc: menuStackIndex === 0 ? ContextMenu.close : focusPrevMenu,
left: focusPrevMenu,
right: () => { var _a; return (_a = __classPrivateFieldGet(this, _DuoyunContextmenuElement_instances, "a", _DuoyunContextmenuElement_menuElements_get)[menuStackIndex + 1]) === null || _a === void 0 ? void 0 : _a.focus(); },
esc: menuStackIndex === 0
? ContextMenu.close
: () => update({ menuStack: contextmenuStore.menuStack.slice(0, menuStackIndex) }),
})(evt);

@@ -211,4 +201,3 @@ });

this.mounted = () => {
var _a;
(_a = __classPrivateFieldGet(this, _DuoyunContextmenuElement_instances, "a", _DuoyunContextmenuElement_menuElements_get).shift()) === null || _a === void 0 ? void 0 : _a.focus();
this.effect(() => { var _a; return (_a = __classPrivateFieldGet(this, _DuoyunContextmenuElement_instances, "a", _DuoyunContextmenuElement_menuElements_get).at(-1)) === null || _a === void 0 ? void 0 : _a.focus(); }, () => [contextmenuStore.menuStack.length]);
const restoreInert = setBodyInert(this);

@@ -215,0 +204,0 @@ ContextMenu.instance = this;

@@ -71,3 +71,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
.calendar::part(no-highlight-cell):hover {
.calendar::part(no-highlight-cell) {
border-radius: ${theme.smallRound};

@@ -90,11 +90,13 @@ }

.item {
display: flex;
align-items: center;
justify-content: center;
outline: 1px solid transparent;
outline-offset: -0.5em;
position: relative;
display: grid;
place-items: center;
border-radius: ${theme.smallRound};
}
.item.highlight {
z-index: 1;
outline-color: ${theme.highlightColor};
.item.highlight::after {
content: '';
position: absolute;
border-radius: inherit;
inset: 0.5em;
border: 1px solid ${theme.highlightColor};
}

@@ -115,5 +117,4 @@ .item:hover {

.time {
display: flex;
align-items: center;
justify-content: center;
display: grid;
place-items: center;
height: 3em;

@@ -194,3 +195,3 @@ }

<dy-action-text @click=${() => this.setState({ mode: 'day' })}>
${__classPrivateFieldGet(this, _DuoyunDatePanelElement_instances, "a", _DuoyunDatePanelElement_currentPosition_get).format('YYYY-MM-DD')}
${__classPrivateFieldGet(this, _DuoyunDatePanelElement_instances, "a", _DuoyunDatePanelElement_currentPosition_get).format('YYYY')}
</dy-action-text>

@@ -207,2 +208,5 @@ `;

<span
tabindex="0"
role="button"
@keydown=${commonHandle}
class=${classMap({

@@ -229,2 +233,5 @@ item: true,

<span
tabindex="0"
role="button"
@keydown=${commonHandle}
class=${classMap({

@@ -231,0 +238,0 @@ item: true,

@@ -69,6 +69,6 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

border-radius: ${theme.normalRound};
border: 1px dashed ${theme.borderColor};
border: 1px solid ${theme.borderColor};
}
.button:hover {
border-color: ${theme.textColor};
:host(:not([disabled])) .button {
box-shadow: ${theme.controlShadow};
}

@@ -75,0 +75,0 @@ :host([type='image']:where(:not([hidden]))) {

@@ -33,2 +33,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
dy-form:not([inline]) dy-form-item {
margin-block-end: 1.8em;
}
:where(dy-form[inline]:not([hidden])) {

@@ -63,15 +66,14 @@ display: flex;

}
dy-form-item {
flex-grow: 1;
margin-block-end: 1.8em;
}
dy-form-item[type='checkbox'] {
flex-grow: 0;
}
dy-form-item:where([data-invalid], :state(invalid)) * {
border-color: ${theme.negativeColor};
}
dy-form-item-inline-group {
display: flex;
gap: 1em;
@media not ${mediaQuery.PHONE} {
dy-form-item-inline-group {
display: flex;
gap: 1em;
}
dy-form:not([inline]) dy-form-item-inline-group > dy-form-item {
width: 0;
flex-grow: 1;
}
}

@@ -159,2 +161,6 @@ @media ${mediaQuery.PHONE} {

}
:host([type='checkbox']) {
flex-direction: row;
align-items: center;
}
:host([required]) .label::after {

@@ -164,2 +170,3 @@ content: '*';

.label {
cursor: default;
font-size: 0.875em;

@@ -178,13 +185,7 @@ line-height: 1.2;

width: 100%;
flex-grow: 1;
flex-shrink: 1;
}
.input + .input,
.footer {
margin-top: 10px;
margin-top: 0.7em;
}
:host([type='checkbox']) {
flex-direction: row;
align-items: center;
}
`);

@@ -191,0 +192,0 @@ /**

@@ -19,3 +19,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { getDisplayKey } from '../lib/hotkeys';
import { throttle } from '../lib/utils';
import { throttle } from '../lib/timer';
import { contentsContainer } from '../lib/styles';

@@ -22,0 +22,0 @@ import './paragraph';

@@ -28,3 +28,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { clamp } from '../lib/number';
import { throttle } from '../lib/utils';
import { throttle } from '../lib/timer';
import './use';

@@ -73,2 +73,5 @@ class InputHistory {

}
:host(:not([disabled])) {
box-shadow: ${theme.controlShadow};
}
:host(:not([type='textarea'])) {

@@ -87,2 +90,3 @@ block-size: calc(2.2em + 2px);

outline: none;
cursor: inherit;
font: inherit;

@@ -89,0 +93,0 @@ text-align: inherit;

import { GemElement } from '@mantou/gem/lib/element';
import { Emitter } from '@mantou/gem/lib/decorators';
import { HotKeyHandles } from '../lib/hotkeys';

@@ -9,2 +10,3 @@ import 'deep-query-selector';

left: number;
element: Element;
};

@@ -17,2 +19,3 @@ type State = {

};
export type NavigationDirection = 'up' | 'down' | 'left' | 'right';
/**

@@ -27,2 +30,3 @@ * @customElement dy-keyboard-access

scrollContainer?: HTMLElement;
navigation: Emitter<NavigationDirection>;
state: State;

@@ -29,0 +33,0 @@ mounted: () => () => void;

@@ -12,6 +12,6 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

};
var _DuoyunKeyboardAccessElement_instances, _DuoyunKeyboardAccessElement_activeKey_get, _DuoyunKeyboardAccessElement_container_get, _DuoyunKeyboardAccessElement_isInputTarget, _DuoyunKeyboardAccessElement_onActive, _DuoyunKeyboardAccessElement_onInactive, _DuoyunKeyboardAccessElement_onCancel, _DuoyunKeyboardAccessElement_onKeydown;
var _DuoyunKeyboardAccessElement_instances, _DuoyunKeyboardAccessElement_activeKey_get, _DuoyunKeyboardAccessElement_container_get, _DuoyunKeyboardAccessElement_onActive, _DuoyunKeyboardAccessElement_onInactive, _DuoyunKeyboardAccessElement_onCancel, _DuoyunKeyboardAccessElement_onNavigation, _DuoyunKeyboardAccessElement_onKeydown;
var DuoyunKeyboardAccessElement_1;
import { GemElement, html } from '@mantou/gem/lib/element';
import { adoptedStyle, customElement, attribute, part, property } from '@mantou/gem/lib/decorators';
import { adoptedStyle, customElement, attribute, part, property, emitter } from '@mantou/gem/lib/decorators';
import { addListener, createCSSSheet, css, styleMap } from '@mantou/gem/lib/utils';

@@ -23,5 +23,35 @@ import { logger } from '@mantou/gem/helper/logger';

import { contentsContainer } from '../lib/styles';
import { closestElement, findActiveElement, isInputElement } from '../lib/element';
import { Toast } from './toast';
import { DuoyunLinkElement } from './link';
import 'deep-query-selector';
import './paragraph';
const getFocusableElements = () => {
const get = (root) => root
.deepQuerySelectorAll('>>> :is(input,textarea,button,select,area,summary,audio,video,[tabindex],a[href])')
.map((element) => {
var _a, _b;
// details 内容 Chrome 能检测到尺寸,Bug?
if (element.checkVisibility && !element.checkVisibility({ checkVisibilityCSS: true, checkOpacity: true })) {
return;
}
if (element.tabIndex < 0 ||
element.disabled ||
((_a = element.internals) === null || _a === void 0 ? void 0 : _a.ariaDisabled) === 'true' ||
((_b = element.internals) === null || _b === void 0 ? void 0 : _b.ariaHidden) === 'true' ||
closestElement(element, ':is([inert],[disabled],[aria-disabled=true],[aria-hidden=true])')) {
return;
}
const rect = element.getBoundingClientRect();
if (!rect.width || !rect.height) {
return;
}
return { rect, element };
})
.filter(isNotNullish);
const elements = get(document);
return elements.filter(({ element }) => {
return get(element).length === 0;
});
};
const style = createCSSSheet(css `

@@ -48,11 +78,2 @@ :host {

/**
* a,b,b...,y,za,zb...,zy
*/
function getChars(index) {
if (index > 50)
return;
const prefix = index >= 25 ? 'z' : '';
return prefix + String.fromCharCode(97 + (index % 25));
}
/**
* @customElement dy-keyboard-access

@@ -70,14 +91,35 @@ * Firefox cross origin open popup allow: about:config -> dom.popup_allowed_events add `keydown`

};
_DuoyunKeyboardAccessElement_onActive.set(this, (evt) => {
if (__classPrivateFieldGet(this, _DuoyunKeyboardAccessElement_instances, "m", _DuoyunKeyboardAccessElement_isInputTarget).call(this, evt))
return;
const { active } = this.state;
if (active)
return;
const elements = document.deepQuerySelectorAll('>>> :is([tabindex],input,textarea,button,select,area,a[href])');
if (!elements.length) {
_DuoyunKeyboardAccessElement_onActive.set(this, () => {
const focusableElements = getFocusableElements()
.map(({ rect, element }) => {
const { top, left, right, bottom, width, height } = rect;
if (right < 0 || bottom < 0 || left > innerWidth || top > innerHeight) {
return;
}
// https://bugzilla.mozilla.org/show_bug.cgi?id=1750907
// https://bugs.chromium.org/p/chromium/issues/detail?id=1188919&q=elementFromPoint&can=2
const root = element.getRootNode();
const elementsFromLeftTop = root.elementsFromPoint(left + 2, top + 2);
const elementsFromRightBottom = root.elementsFromPoint(left + width - 2, top + height - 2);
// `elementsFromPoint` 不包含 SVG a 元素,不知道原因
const elements = [...elementsFromLeftTop, ...elementsFromRightBottom].map((e) => e instanceof SVGElement ? e.closest('a') : e);
if (!elements.includes(element)) {
return;
}
return { key: '', top, left, element };
})
.filter(isNotNullish)
.map((e, index) => {
// a,b,c...,y,za,zb...,zy
if (index >= 50)
return;
const prefix = index >= 25 ? 'z' : '';
e.key = prefix + String.fromCharCode(97 + (index % 25));
return e;
})
.filter(isNotNullish);
if (!focusableElements.length) {
Toast.open('default', 'Not found focusable element');
return;
}
let index = 0;
const keydownHandles = {

@@ -89,2 +131,18 @@ esc: __classPrivateFieldGet(this, _DuoyunKeyboardAccessElement_onInactive, "f"),

};
focusableElements.forEach(({ key, element }) => {
// `a-b`
keydownHandles[[...key].join('-')] = () => {
this.setState({ active: false });
if (element instanceof HTMLElement) {
// BasePickerElement 的 `showPicker` 一样支持通过 `click` 触发
element.focus();
element.click();
}
else if (element instanceof SVGAElement) {
const link = new DuoyunLinkElement();
link.href = element.getAttribute('href');
link.click();
}
};
});
this.setState({

@@ -94,38 +152,3 @@ active: true,

keydownHandles,
focusableElements: elements
.map((element) => {
const { top, left, right, bottom, width, height } = element.getBoundingClientRect();
if (element.disabled ||
element.inert ||
element.tabIndex < 0 ||
!width ||
!height ||
right < 0 ||
bottom < 0 ||
left > innerWidth ||
top > innerHeight) {
return;
}
// https://bugzilla.mozilla.org/show_bug.cgi?id=1750907
// https://bugs.chromium.org/p/chromium/issues/detail?id=1188919&q=elementFromPoint&can=2
const root = element.getRootNode();
const elementsFromLeftTop = root.elementsFromPoint(left + 2, top + 2);
const elementsFromRightBottom = root.elementsFromPoint(left + width - 2, top + height - 2);
if (!elementsFromLeftTop.includes(element) && !elementsFromRightBottom.includes(element)) {
return;
}
const key = getChars(index);
if (!key)
return;
// `a-b`
keydownHandles[[...key].join('-')] = () => {
this.setState({ active: false });
// BasePickerElement 的 `showPicker` 一样支持通过 `click` 触发
element.focus();
element.click();
};
index++;
return { key, top, left };
})
.filter(isNotNullish),
focusableElements,
});

@@ -144,6 +167,51 @@ });

});
_DuoyunKeyboardAccessElement_onNavigation.set(this, (dir) => {
var _a, _b;
const activeElement = findActiveElement();
const focusableElements = getFocusableElements();
const current = focusableElements.find(({ element }) => activeElement === element);
const currentRect = (current === null || current === void 0 ? void 0 : current.rect) || {
left: 0,
right: 0,
top: 0,
bottom: 0,
};
const elements = focusableElements
.filter((ele) => {
return ele !== current;
})
.filter(({ rect }) => {
if (!current)
return true;
switch (dir) {
case 'down':
return rect.bottom > currentRect.bottom;
case 'up':
return rect.top < currentRect.top;
case 'right':
return rect.right > currentRect.right;
case 'left':
return rect.left < currentRect.left;
}
})
.sort((a, b) => {
const getPoint = (rect) => [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];
const originPoint = getPoint(currentRect);
const getDistance = (rect) => {
const point = getPoint(rect);
const isHorizontal = dir === 'left' || dir === 'right';
const weights = [isHorizontal ? 1 : 100, !isHorizontal ? 1 : 100];
return Math.sqrt((point[0] - originPoint[0]) ** 2 * weights[0] + (point[1] - originPoint[1]) ** 2 * weights[1]);
};
return getDistance(a.rect) - getDistance(b.rect);
});
if (elements.length) {
(_b = (_a = elements[0].element).focus) === null || _b === void 0 ? void 0 : _b.call(_a);
this.navigation(dir);
}
});
_DuoyunKeyboardAccessElement_onKeydown.set(this, (evt) => {
if (this.state.active)
return;
if (__classPrivateFieldGet(this, _DuoyunKeyboardAccessElement_instances, "m", _DuoyunKeyboardAccessElement_isInputTarget).call(this, evt))
if (isInputElement(evt.composedPath()[0]))
return;

@@ -156,2 +224,6 @@ hotkeys({

l: () => __classPrivateFieldGet(this, _DuoyunKeyboardAccessElement_instances, "a", _DuoyunKeyboardAccessElement_container_get).scrollBy(0, innerHeight),
down: () => __classPrivateFieldGet(this, _DuoyunKeyboardAccessElement_onNavigation, "f").call(this, 'down'),
up: () => __classPrivateFieldGet(this, _DuoyunKeyboardAccessElement_onNavigation, "f").call(this, 'up'),
left: () => __classPrivateFieldGet(this, _DuoyunKeyboardAccessElement_onNavigation, "f").call(this, 'left'),
right: () => __classPrivateFieldGet(this, _DuoyunKeyboardAccessElement_onNavigation, "f").call(this, 'right'),
}, { stopPropagation: true })(evt);

@@ -204,2 +276,3 @@ });

_DuoyunKeyboardAccessElement_onCancel = new WeakMap();
_DuoyunKeyboardAccessElement_onNavigation = new WeakMap();
_DuoyunKeyboardAccessElement_onKeydown = new WeakMap();

@@ -213,10 +286,2 @@ _DuoyunKeyboardAccessElement_instances = new WeakSet();

};
_DuoyunKeyboardAccessElement_isInputTarget = function _DuoyunKeyboardAccessElement_isInputTarget(evt) {
const originElement = evt.composedPath()[0];
if (originElement.isContentEditable ||
originElement instanceof HTMLInputElement ||
originElement instanceof HTMLTextAreaElement) {
return true;
}
};
__decorate([

@@ -229,2 +294,5 @@ attribute

__decorate([
emitter
], DuoyunKeyboardAccessElement.prototype, "navigation", void 0);
__decorate([
part

@@ -231,0 +299,0 @@ ], DuoyunKeyboardAccessElement, "kbd", void 0);

@@ -27,3 +27,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { findScrollContainer } from '../lib/element';
import { once, throttle } from '../lib/utils';
import { throttle, once } from '../lib/timer';
import { DuoyunVisibleBaseElement, visibilityObserver } from './base/visible';

@@ -30,0 +30,0 @@ import { DuoyunResizeBaseElement } from './base/resize';

import { Emitter, RefObject } from '@mantou/gem/lib/decorators';
import { GemElement, TemplateResult } from '@mantou/gem/lib/element';
import { DyPromise } from '../lib/utils';
import './button';

@@ -56,4 +57,12 @@ import './divider';

closing: boolean;
static open<T = Element>(options: ModalOptions & ModalOpenOptions<T>): Promise<T>;
static confirm(body: string | TemplateResult | Record<string, unknown>, options?: ModalOptions): Promise<Element>;
static open<T = Element>(options: ModalOptions & ModalOpenOptions<T>): DyPromise<T, {
modal: DuoyunModalElement;
}> & {
modal: DuoyunModalElement;
};
static confirm(body: string | TemplateResult | Record<string, unknown>, options?: ModalOptions): DyPromise<Element, {
modal: DuoyunModalElement;
}> & {
modal: DuoyunModalElement;
};
constructor(options?: ModalOptions);

@@ -60,0 +69,0 @@ willMount: () => void;

@@ -21,3 +21,4 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { hotkeys } from '../lib/hotkeys';
import { setBodyInert } from '../lib/utils';
import { DyPromise } from '../lib/utils';
import { setBodyInert } from '../lib/element';
import { commonAnimationOptions, fadeIn, fadeOut, slideInUp } from '../lib/animations';

@@ -126,3 +127,3 @@ import './button';

// 错误必须处理,不然会被默认通过 Toast 显示
static async open(options) {
static open(options) {
const modal = new this({ ...options, open: true });

@@ -132,3 +133,3 @@ const restoreInert = setBodyInert(modal);

// bubble close event close modal
return new Promise((res, rej) => {
return DyPromise.new((res, rej) => {
const getBodyEle = () => {

@@ -151,3 +152,3 @@ var _a;

});
}).finally(async () => {
}, { modal }).finally(async () => {
restoreInert();

@@ -154,0 +155,0 @@ await __classPrivateFieldGet(modal, _DuoyunModalElement_closeAnimate, "f").call(modal);

@@ -231,3 +231,2 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

@pointerenter=${onPointerEnter}
@focus=${onPointerEnter}
@pointerleave=${onPointerLeave}

@@ -234,0 +233,0 @@ @pointerdown=${onPointerDown}

@@ -11,3 +11,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { theme } from '../lib/theme';
import { sleep } from '../lib/utils';
import { sleep } from '../lib/timer';
const style = createCSSSheet(css `

@@ -14,0 +14,0 @@ :host(:where(:not([hidden]))) {

@@ -36,2 +36,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
:host(:not([borderless], [disabled])) {
box-shadow: ${theme.controlShadow};
}
:host(:where([data-active], :state(active))) {

@@ -38,0 +41,0 @@ background: ${theme.lightBackgroundColor};

@@ -23,4 +23,4 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { addListener, createCSSSheet, css, styleMap } from '@mantou/gem/lib/utils';
import { toggleActiveState, getBoundingClientRect } from '../lib/element';
import { sleep, setBodyInert } from '../lib/utils';
import { toggleActiveState, getBoundingClientRect, setBodyInert } from '../lib/element';
import { sleep } from '../lib/timer';
import { hotkeys } from '../lib/hotkeys';

@@ -27,0 +27,0 @@ import { theme } from '../lib/theme';

@@ -43,2 +43,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
:host(:not([disabled])) .radio {
box-shadow: ${theme.controlShadow};
}
:host(:where(:hover, [checked])) .radio {

@@ -45,0 +48,0 @@ color: ${theme.primaryColor};

@@ -64,2 +64,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
:host(:not([disabled])) .segment.current {
box-shadow: ${theme.controlShadow};
}
.icon {

@@ -80,3 +83,7 @@ flex-shrink: 0;

background: none;
box-shadow: none;
}
:host(:not([disabled])) .segment.current {
box-shadow: none;
}
.marker {

@@ -92,2 +99,5 @@ display: block;

}
:host(:not([disabled])) .marker {
box-shadow: ${theme.controlShadow};
}
}

@@ -94,0 +104,0 @@ `);

@@ -26,3 +26,4 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { locale } from '../lib/locale';
import { isIncludesString, setBodyInert } from '../lib/utils';
import { isIncludesString } from '../lib/utils';
import { setBodyInert } from '../lib/element';
import { hotkeys } from '../lib/hotkeys';

@@ -96,2 +97,3 @@ import { isNotNullish } from '../lib/types';

margin-block: -1em;
box-shadow: none;
}

@@ -98,0 +100,0 @@ .search::part(input) {

@@ -34,2 +34,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
:host(:not([disabled])) {
box-shadow: ${theme.controlShadow};
}
:host(:focus) {

@@ -36,0 +39,0 @@ border-color: ${theme.textColor};

@@ -59,2 +59,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
:host(:not([disabled])) .mark {
box-shadow: ${theme.controlShadow};
}
.mark:hover {

@@ -61,0 +64,0 @@ opacity: 1;

@@ -47,2 +47,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

}
:host(:not([disabled])) .switch {
box-shadow: ${theme.controlShadow};
}
.switch::before {

@@ -55,5 +58,9 @@ content: '';

border-radius: inherit;
border: 2px solid var(--color);
border: 2px solid transparent;
background: ${theme.lightBackgroundColor};
background-clip: content-box;
}
:host(:not([disabled])) .switch::before {
filter: drop-shadow(${theme.controlShadow});
}
:host([checked]) .switch::before {

@@ -60,0 +67,0 @@ margin-inline-start: calc(100% * 4 / 9);

@@ -23,2 +23,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

:host(:where(:not([hidden]))) {
cursor: default;
display: inline-flex;

@@ -25,0 +26,0 @@ align-items: center;

@@ -23,3 +23,4 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { createCSSSheet, css } from '@mantou/gem/lib/utils';
import { sleep, setBodyInert } from '../lib/utils';
import { sleep } from '../lib/timer';
import { setBodyInert } from '../lib/element';
import { theme } from '../lib/theme';

@@ -26,0 +27,0 @@ import { commonAnimationOptions, fadeIn, fadeOut } from '../lib/animations';

interface CacheOptions {
max?: number;
maxAge?: number;
renewal?: boolean;
}
export declare class Cache<T = any> {
#private;
constructor({ max, maxAge }?: CacheOptions);
set(key: string, value: T): void;
get(key: string, callback?: (result: T) => void): T | undefined;
constructor({ max, maxAge, renewal }?: CacheOptions);
set(key: string, value: T): T;
get(key: string): T | undefined;
get(key: string, init: (key: string) => T): T;
}
export {};
//# sourceMappingURL=cache.d.ts.map

@@ -12,9 +12,10 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {

};
var _Cache_instances, _Cache_max, _Cache_maxAge, _Cache_map, _Cache_reverseMap, _Cache_linkedList, _Cache_trim;
var _Cache_instances, _Cache_max, _Cache_maxAge, _Cache_renewal, _Cache_map, _Cache_reverseMap, _Cache_linkedList, _Cache_trim;
import { LinkedList } from '@mantou/gem/lib/utils';
export class Cache {
constructor({ max = Infinity, maxAge = Infinity } = {}) {
constructor({ max = Infinity, maxAge = Infinity, renewal = false } = {}) {
_Cache_instances.add(this);
_Cache_max.set(this, void 0);
_Cache_maxAge.set(this, void 0);
_Cache_renewal.set(this, void 0);
_Cache_map.set(this, new Map());

@@ -25,2 +26,3 @@ _Cache_reverseMap.set(this, new Map());

__classPrivateFieldSet(this, _Cache_maxAge, maxAge, "f");
__classPrivateFieldSet(this, _Cache_renewal, renewal, "f");
}

@@ -32,7 +34,9 @@ set(key, value) {

__classPrivateFieldGet(this, _Cache_instances, "m", _Cache_trim).call(this);
return value;
}
get(key, callback) {
get(key, init) {
const cache = __classPrivateFieldGet(this, _Cache_map, "f").get(key);
if (!cache)
return;
if (!cache) {
return init && this.set(key, init(key));
}
const { timestamp, value } = cache;

@@ -43,11 +47,13 @@ if (Date.now() - timestamp > __classPrivateFieldGet(this, _Cache_maxAge, "f")) {

__classPrivateFieldGet(this, _Cache_map, "f").delete(key);
return;
return init && this.set(key, init(key));
}
if (__classPrivateFieldGet(this, _Cache_renewal, "f")) {
cache.timestamp = Date.now();
}
__classPrivateFieldGet(this, _Cache_linkedList, "f").get();
__classPrivateFieldGet(this, _Cache_linkedList, "f").add(value);
callback === null || callback === void 0 ? void 0 : callback(value);
return value;
}
}
_Cache_max = new WeakMap(), _Cache_maxAge = new WeakMap(), _Cache_map = new WeakMap(), _Cache_reverseMap = new WeakMap(), _Cache_linkedList = new WeakMap(), _Cache_instances = new WeakSet(), _Cache_trim = function _Cache_trim() {
_Cache_max = new WeakMap(), _Cache_maxAge = new WeakMap(), _Cache_renewal = new WeakMap(), _Cache_map = new WeakMap(), _Cache_reverseMap = new WeakMap(), _Cache_linkedList = new WeakMap(), _Cache_instances = new WeakSet(), _Cache_trim = function _Cache_trim() {
for (let i = __classPrivateFieldGet(this, _Cache_linkedList, "f").size - __classPrivateFieldGet(this, _Cache_max, "f"); i > 0; i--) {

@@ -54,0 +60,0 @@ const value = __classPrivateFieldGet(this, _Cache_linkedList, "f").get();

@@ -11,2 +11,8 @@ export declare function getBoundingClientRect(eleList: Element[]): {

export declare function findRanges(root: Node, text: string): Range[];
export declare function findActiveElement(): Element | null;
export declare function isInputElement(originElement: HTMLElement): true | undefined;
export declare function closestElement(ele: Element, selector: string): Element | null;
export declare function containsElement(ele: Element, other: Element): boolean;
/**In addition to the parameter element, set the `inert` attribute for all element */
export declare function setBodyInert(modal: HTMLElement): () => void;
//# sourceMappingURL=element.d.ts.map

@@ -66,2 +66,55 @@ import { GemElement } from '@mantou/gem/lib/element';

}
export function findActiveElement() {
var _a;
let element = document.activeElement;
while (element) {
if (!((_a = element.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement))
break;
element = element.shadowRoot.activeElement;
}
return element;
}
export function isInputElement(originElement) {
if (originElement.isContentEditable ||
originElement instanceof HTMLInputElement ||
originElement instanceof HTMLTextAreaElement) {
return true;
}
}
export function closestElement(ele, selector) {
let node = ele;
while (node) {
const e = node.closest(selector);
if (e)
return e;
node = node.getRootNode().host;
}
return null;
}
export function containsElement(ele, other) {
let node = other;
while (node) {
if (ele.contains(node))
return true;
node = node.getRootNode().host;
}
return false;
}
/**In addition to the parameter element, set the `inert` attribute for all element */
export function setBodyInert(modal) {
const map = new Map();
[...document.body.children].forEach((e) => {
if (e instanceof HTMLElement) {
map.set(e, e.inert);
e.inert = true;
}
});
modal.inert = false;
return () => {
map.forEach((inert, ele) => {
ele.inert = inert;
});
modal.inert = true;
};
}
//# sourceMappingURL=element.js.map

@@ -9,4 +9,4 @@ export declare function b64ToUtf8(str: string): string;

export declare function hash(strOrAb: string | ArrayBuffer, output: 'arrayBuffer'): Promise<ArrayBuffer>;
/**output int */
/**Simple hash, output int */
export declare function fnv1a(str: string): number;
//# sourceMappingURL=encode.d.ts.map

@@ -37,3 +37,3 @@ import { pseudoRandom } from './number';

// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
/**output int */
/**Simple hash, output int */
export function fnv1a(str) {

@@ -40,0 +40,0 @@ const FNV_OFFSET_BASIS = 2166136261;

@@ -90,6 +90,7 @@ /**Use a comma to separate numbers */

export declare function adjustRange([min, max]: number[], stepCount: number, units?: number[]): number[];
/**Generate a pseudo -random function */
export declare function pseudoRandom(seed: number): () => number;
/**output 0-1 */
/**Random large integer normalization, output 0-1 */
export declare function normalizeNumber(n: number): number;
export {};
//# sourceMappingURL=number.d.ts.map

@@ -156,2 +156,3 @@ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat

}
/**Generate a pseudo -random function */
export function pseudoRandom(seed) {

@@ -166,3 +167,3 @@ const MULTIPLIER = 48271;

}
/**output 0-1 */
/**Random large integer normalization, output 0-1 */
export function normalizeNumber(n) {

@@ -169,0 +170,0 @@ return parseFloat(`0.${[...Math.abs(n).toString()].reverse().join('')}`);

@@ -14,2 +14,3 @@ export declare function getSemanticColor(semantic?: string): string | undefined;

maskAlpha: string;
controlShadow: string;
informativeColor: string;

@@ -42,2 +43,3 @@ neutralColor: string;

maskAlpha: string;
controlShadow: string;
informativeColor: string;

@@ -68,2 +70,3 @@ neutralColor: string;

maskAlpha: string;
controlShadow: string;
informativeColor: string;

@@ -95,2 +98,3 @@ neutralColor: string;

maskAlpha: string;
controlShadow: string;
informativeColor: string;

@@ -122,2 +126,3 @@ neutralColor: string;

maskAlpha: string;
controlShadow: string;
informativeColor: string;

@@ -124,0 +129,0 @@ neutralColor: string;

@@ -30,2 +30,3 @@ import { getThemeStore, useTheme } from '@mantou/gem/helper/theme';

maskAlpha: '0.2',
controlShadow: '0 1px 2px #0000000d',
// same of light/dark

@@ -32,0 +33,0 @@ // https://spectrum.adobe.com/page/color/#Semantic-colors

@@ -7,3 +7,2 @@ import { Store } from '@mantou/gem/lib/store';

export declare function convertToMap<T extends Record<string, any>, V = string>(list: (T | null)[], key: keyof T, value: keyof T, fallback?: any): Record<string, V>;
export declare const structuredClone: any;
/**Get Cascader/Tree max deep*/

@@ -20,17 +19,2 @@ export declare function getCascaderDeep<T>(list: T[], cascaderKey: keyof T): number;

export declare function readProp(obj: Record<string, any>, paths: string | number | symbol | string[]): any;
/**Until the callback function resolve */
export declare function forever<T>(callback: () => Promise<T>, interval?: number): Promise<T>;
/**Polling calls until cancel */
export declare function polling(fn: (args?: any[]) => any, delay: number): (haveNext?: boolean) => void;
export declare function sleep(ms?: number): Promise<unknown>;
export declare function throttle<T extends (...args: any) => any>(fn: T, wait?: number, { leading, maxWait }?: {
leading?: boolean;
maxWait?: number;
}): (...rest: Parameters<T>) => void;
export declare function debounce<T extends (...args: any) => any>(fn: T, wait?: number): (...rest: Parameters<T>) => any;
export declare function invokeByCount<T extends (...args: any) => any>(fn: T, condition: (tryCount: number, prevInvokeSuccessTimestamp: number) => boolean): (...rest: Parameters<T>) => ReturnType<T> | undefined;
/**Only invoke first */
export declare function once<T extends (...args: any) => any>(fn: T): T;
/**Ignore the first invoke */
export declare function omitOnce<T extends (...args: any) => any>(fn: T): (...rest: Parameters<T>) => ReturnType<T> | undefined;
/**Only let the last add Promise take effect, don’t care about the order of Resolve */

@@ -59,4 +43,2 @@ export declare class OrderlyPromisePool {

export declare function isIncludesString(origin: string | TemplateResult, search: string, caseSensitive?: boolean): boolean;
/**In addition to the parameter element, set the `inert` attribute for all element */
export declare function setBodyInert(modal: HTMLElement): () => void;
export type UseCacheStoreOptions<T> = {

@@ -72,2 +54,13 @@ cacheExcludeKeys?: (keyof T)[];

export declare function isRemoteIcon(icon: string | Element | DocumentFragment): icon is string;
/**
* Pass additional fields
*
* not support async function
*/
export declare class DyPromise<T, E extends Record<string, unknown>> extends Promise<T> {
static new<T, E extends Record<string, unknown>>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void, props: E): DyPromise<T, E> & E;
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): DyPromise<TResult1 | TResult2, E> & E;
catch<TResult>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): DyPromise<T | TResult, E> & E;
finally(onfinally?: (() => void) | null | undefined): DyPromise<T, E> & E;
}
//# sourceMappingURL=utils.d.ts.map
import { connect, updateStore, useStore } from '@mantou/gem/lib/store';
import { render, TemplateResult } from '@mantou/gem/lib/element';
import { cleanObject } from '@mantou/gem/lib/utils';
import { logger } from '@mantou/gem/helper/logger';
import { isNullish } from '../lib/types';

@@ -23,4 +22,2 @@ export function convertToMap(list, key, value, fallback) {

}
// https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
export const structuredClone = window.structuredClone || ((v) => JSON.parse(JSON.stringify(v)));
/**Get Cascader/Tree max deep*/

@@ -90,97 +87,2 @@ export function getCascaderDeep(list, cascaderKey) {

}
/**Until the callback function resolve */
export async function forever(callback, interval = 1000) {
try {
return await callback();
}
catch (err) {
logger.error(err);
await sleep(interval);
return forever(callback, interval);
}
}
/**Polling calls until cancel */
export function polling(fn, delay) {
let timer = 0;
let hasExit = false;
const poll = async () => {
try {
await fn();
}
catch (_a) {
}
finally {
if (!hasExit) {
timer = window.setTimeout(poll, delay);
}
}
};
poll();
return (haveNext = false) => {
hasExit = true;
haveNext ? setTimeout(() => clearTimeout(timer), delay) : clearTimeout(timer);
};
}
export function sleep(ms = 3000) {
return new Promise((res) => setTimeout(res, ms));
}
export function throttle(fn, wait = 500, { leading = false, maxWait = Infinity } = {}) {
let timer = 0;
let first = 0;
const exec = (...rest) => {
timer = window.setTimeout(() => (timer = 0), wait);
fn(...rest);
};
return (...rest) => {
const now = Date.now();
if (!timer)
first = now;
if (now - first > maxWait) {
first = now;
clearTimeout(timer);
exec(...rest);
}
else if (leading && !timer) {
exec(...rest);
}
else {
clearTimeout(timer);
timer = window.setTimeout(() => exec(...rest), wait);
}
};
}
export function debounce(fn, wait = 500) {
let timer = 0;
let result = undefined;
return (...rest) => {
if (!timer) {
timer = window.setTimeout(() => {
timer = 0;
}, wait);
result = fn(...rest);
}
return result;
};
}
export function invokeByCount(fn, condition) {
let count = 0;
let result;
let timestamp = 0;
return (...rest) => {
if (condition(count++, timestamp)) {
timestamp = performance.now();
result = fn(...rest);
return result;
}
return result;
};
}
/**Only invoke first */
export function once(fn) {
return invokeByCount(fn, (count) => count === 0);
}
/**Ignore the first invoke */
export function omitOnce(fn) {
return invokeByCount(fn, (count) => count !== 0);
}
/**Only let the last add Promise take effect, don’t care about the order of Resolve */

@@ -273,19 +175,2 @@ export class OrderlyPromisePool {

}
/**In addition to the parameter element, set the `inert` attribute for all element */
export function setBodyInert(modal) {
const map = new Map();
[...document.body.children].forEach((e) => {
if (e instanceof HTMLElement) {
map.set(e, e.inert);
e.inert = true;
}
});
modal.inert = false;
return () => {
map.forEach((inert, ele) => {
ele.inert = inert;
});
modal.inert = true;
};
}
/**Create auto cache(localStorage) Store */

@@ -334,2 +219,25 @@ export function useCacheStore(storageKey, initStore, options) {

}
/**
* Pass additional fields
*
* not support async function
*/
export class DyPromise extends Promise {
static new(executor, props) {
const instance = new DyPromise(executor);
return Object.assign(instance, props);
}
then(onfulfilled, onrejected) {
const result = super.then(onfulfilled, onrejected);
return Object.assign(result, this);
}
catch(onrejected) {
const result = super.catch(onrejected);
return Object.assign(result, this);
}
finally(onfinally) {
const result = super.finally(onfinally);
return Object.assign(result, this);
}
}
//# sourceMappingURL=utils.js.map
{
"name": "duoyun-ui",
"version": "1.1.17",
"version": "1.1.18",
"description": "A lightweight desktop UI component library, implemented using Gem",

@@ -5,0 +5,0 @@ "keywords": [

@@ -142,7 +142,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

::target-text {
color: white;
color: ${theme.backgroundColor};
background: ${theme.primaryColor};
}
::highlight(search) {
color: white;
color: ${theme.backgroundColor};
background: ${theme.informativeColor};

@@ -149,0 +149,0 @@ }

@@ -42,4 +42,8 @@ import { GemElement, TemplateResult } from '@mantou/gem/lib/element';

} & ModalOptions & ModalOpenOptions<T> & Pick<DyPatFormElement<T>, 'formItems' | 'data'>;
export declare function createForm<T = Record<string, unknown>>(options: CreateFormOptions<T>): Promise<T>;
export declare function createForm<T = Record<string, unknown>>(options: CreateFormOptions<T>): import("../lib/utils").DyPromise<T, {
modal: import("../elements/modal").DuoyunModalElement;
}> & {
modal: import("../elements/modal").DuoyunModalElement;
};
export {};
//# sourceMappingURL=form.d.ts.map

@@ -18,4 +18,5 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { icons } from '../lib/icons';
import { blockContainer } from '../lib/styles';
import { blockContainer, focusStyle } from '../lib/styles';
import { readProp } from '../lib/utils';
import { theme } from '../lib/theme';
import { Drawer } from '../elements/drawer';

@@ -33,6 +34,7 @@ import { Modal } from '../elements/modal';

summary {
cursor: default;
cursor: pointer;
display: flex;
align-items: center;
gap: 1px;
border-radius: ${theme.normalRound};
}

@@ -142,2 +144,3 @@ summary dy-use {

adoptedStyle(blockContainer),
adoptedStyle(focusStyle),
adoptedStyle(style)

@@ -144,0 +147,0 @@ ], DyPatFormElement);

@@ -26,3 +26,4 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { theme } from '../lib/theme';
import { comparer, readProp, isIncludesString, splitString, sleep, getStringFromTemplate, convertToMap, throttle, } from '../lib/utils';
import { comparer, readProp, isIncludesString, splitString, getStringFromTemplate, convertToMap, } from '../lib/utils';
import { sleep, throttle } from '../lib/timer';
import { blockContainer } from '../lib/styles';

@@ -29,0 +30,0 @@ import { findRanges, findScrollContainer } from '../lib/element';

@@ -8,2 +8,3 @@ import { HTMLAttributes, RefAttributes } from 'react';

scrollContainer?: DuoyunKeyboardAccessElement['scrollContainer'];
'onnavigation'?: (event: CustomEvent<Parameters<DuoyunKeyboardAccessElement['navigation']>[0]>) => void;
};

@@ -10,0 +11,0 @@ declare global {

@@ -7,2 +7,3 @@ import type { HTMLAttributes } from "svelte/elements";

scrollContainer?: DuoyunKeyboardAccessElement['scrollContainer'];
'on:navigation'?: (event: CustomEvent<Parameters<DuoyunKeyboardAccessElement['navigation']>[0]>) => void;
}

@@ -9,0 +10,0 @@ declare module "svelte/elements" {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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