@bpmn-io/form-js-viewer
Advanced tools
Comparing version 0.7.2 to 0.8.0-alpha.0
@@ -5,6 +5,7 @@ import Ids from 'ids'; | ||
import { jsx, jsxs } from 'preact/jsx-runtime'; | ||
import { useContext, useState, useCallback } from 'preact/hooks'; | ||
import { useContext, useState, useEffect, useRef, useMemo, useCallback } from 'preact/hooks'; | ||
import { createContext, createElement, Fragment, render } from 'preact'; | ||
import React, { createPortal } from 'preact/compat'; | ||
import classNames from 'classnames'; | ||
import Markup from 'preact-markup'; | ||
import { createPortal } from 'preact/compat'; | ||
import { Injector } from 'didi'; | ||
@@ -811,15 +812,22 @@ | ||
_path, | ||
type | ||
} = formField; | ||
type, | ||
valuesKey | ||
} = formField; // get values defined via valuesKey | ||
if (!_path) { | ||
return importedData; | ||
} // (1) try to get value from data | ||
// (2) try to get default value from form field | ||
// (3) get empty value from form field | ||
if (valuesKey) { | ||
importedData = { ...importedData, | ||
[valuesKey]: get(data, [valuesKey]) | ||
}; | ||
} // try to get value from data | ||
// if unavailable - try to get default value from form field | ||
// if unavailable - get empty value from form field | ||
return { ...importedData, | ||
[_path[0]]: get(data, _path, isUndefined(defaultValue) ? this._formFields.get(type).emptyValue : defaultValue) | ||
}; | ||
if (_path) { | ||
importedData = { ...importedData, | ||
[_path[0]]: get(data, _path, isUndefined(defaultValue) ? this._formFields.get(type).emptyValue : defaultValue) | ||
}; | ||
} | ||
return importedData; | ||
}, {}); | ||
@@ -985,3 +993,3 @@ } | ||
const type$6 = 'button'; | ||
const type$8 = 'button'; | ||
function Button(props) { | ||
@@ -996,3 +1004,3 @@ const { | ||
return jsx("div", { | ||
class: formFieldClasses(type$6), | ||
class: formFieldClasses(type$8), | ||
children: jsx("button", { | ||
@@ -1014,3 +1022,3 @@ class: "fjs-button", | ||
Button.type = type$6; | ||
Button.type = type$8; | ||
Button.label = 'Button'; | ||
@@ -1097,3 +1105,3 @@ Button.keyed = true; | ||
const type$5 = 'checkbox'; | ||
const type$7 = 'checkbox'; | ||
function Checkbox(props) { | ||
@@ -1125,3 +1133,3 @@ const { | ||
return jsxs("div", { | ||
class: formFieldClasses(type$5, errors), | ||
class: formFieldClasses(type$7, errors), | ||
children: [jsx(Label, { | ||
@@ -1152,3 +1160,3 @@ id: prefixId(id, formId), | ||
Checkbox.type = type$5; | ||
Checkbox.type = type$7; | ||
Checkbox.label = 'Checkbox'; | ||
@@ -1165,2 +1173,148 @@ Checkbox.keyed = true; | ||
/** | ||
* @enum { String } | ||
*/ | ||
const LOAD_STATES = { | ||
LOADING: 'loading', | ||
LOADED: 'loaded', | ||
ERROR: 'error' | ||
}; | ||
/** | ||
* @typedef {Object} ValuesGetter | ||
* @property {Object[]} values - The values data | ||
* @property {(LOAD_STATES)} state - The values data's loading state, to use for conditional rendering | ||
*/ | ||
/** | ||
* A hook to load values for single and multiselect components. | ||
* | ||
* @param {Object} field - The form field to handle values for | ||
* @return {ValuesGetter} valuesGetter - A values getter object providing loading state and values | ||
*/ | ||
function useValuesAsync (field) { | ||
const { | ||
valuesKey, | ||
values: staticValues | ||
} = field; | ||
const [valuesGetter, setValuesGetter] = useState({ | ||
values: [], | ||
error: undefined, | ||
state: LOAD_STATES.LOADING | ||
}); | ||
const initialData = useService('form')._getState().initialData; | ||
useEffect(() => { | ||
let values = []; | ||
if (valuesKey !== undefined) { | ||
const keyedValues = (initialData || {})[valuesKey]; | ||
if (keyedValues && Array.isArray(keyedValues)) { | ||
values = keyedValues; | ||
} | ||
} else if (staticValues !== undefined) { | ||
values = Array.isArray(staticValues) ? staticValues : []; | ||
} else { | ||
setValuesGetter(getErrorState('No values source defined in the form definition')); | ||
return; | ||
} | ||
setValuesGetter(buildLoadedState(values)); | ||
}, [valuesKey, staticValues, initialData]); | ||
return valuesGetter; | ||
} | ||
const getErrorState = error => ({ | ||
values: [], | ||
error, | ||
state: LOAD_STATES.ERROR | ||
}); | ||
const buildLoadedState = values => ({ | ||
values, | ||
error: undefined, | ||
state: LOAD_STATES.LOADED | ||
}); | ||
const type$6 = 'checklist'; | ||
function Checklist(props) { | ||
const { | ||
disabled, | ||
errors = [], | ||
field, | ||
value = [] | ||
} = props; | ||
const { | ||
description, | ||
id, | ||
label | ||
} = field; | ||
const toggleCheckbox = v => { | ||
let newValue = [...value]; | ||
if (!newValue.includes(v)) { | ||
newValue.push(v); | ||
} else { | ||
newValue = newValue.filter(x => x != v); | ||
} | ||
props.onChange({ | ||
field, | ||
value: newValue | ||
}); | ||
}; | ||
const { | ||
state: loadState, | ||
values: options | ||
} = useValuesAsync(field); | ||
const { | ||
formId | ||
} = useContext(FormContext); | ||
return jsxs("div", { | ||
class: formFieldClasses(type$6, errors), | ||
children: [jsx(Label, { | ||
label: label | ||
}), loadState == LOAD_STATES.LOADED && options.map((v, index) => { | ||
return jsx(Label, { | ||
id: prefixId(`${id}-${index}`, formId), | ||
label: v.label, | ||
required: false, | ||
children: jsx("input", { | ||
checked: value.includes(v.value), | ||
class: "fjs-input", | ||
disabled: disabled, | ||
id: prefixId(`${id}-${index}`, formId), | ||
type: "checkbox", | ||
onClick: () => toggleCheckbox(v.value) | ||
}) | ||
}, `${id}-${index}`); | ||
}), jsx(Description, { | ||
description: description | ||
}), jsx(Errors, { | ||
errors: errors | ||
})] | ||
}); | ||
} | ||
Checklist.create = function (options = {}) { | ||
if (options.valuesKey) return options; | ||
return { | ||
values: [{ | ||
label: 'Value', | ||
value: 'value' | ||
}], | ||
...options | ||
}; | ||
}; | ||
Checklist.type = type$6; | ||
Checklist.label = 'Checklist'; | ||
Checklist.keyed = true; | ||
Checklist.emptyValue = []; | ||
const noop$1 = () => false; | ||
@@ -1374,3 +1528,3 @@ | ||
const type$4 = 'number'; | ||
const type$5 = 'number'; | ||
function Number(props) { | ||
@@ -1407,3 +1561,3 @@ const { | ||
return jsxs("div", { | ||
class: formFieldClasses(type$4, errors), | ||
class: formFieldClasses(type$5, errors), | ||
children: [jsx(Label, { | ||
@@ -1433,3 +1587,3 @@ id: prefixId(id, formId), | ||
Number.type = type$4; | ||
Number.type = type$5; | ||
Number.keyed = true; | ||
@@ -1439,3 +1593,3 @@ Number.label = 'Number'; | ||
const type$3 = 'radio'; | ||
const type$4 = 'radio'; | ||
function Radio(props) { | ||
@@ -1452,4 +1606,3 @@ const { | ||
label, | ||
validate = {}, | ||
values | ||
validate = {} | ||
} = field; | ||
@@ -1468,16 +1621,20 @@ const { | ||
const { | ||
state: loadState, | ||
values: options | ||
} = useValuesAsync(field); | ||
const { | ||
formId | ||
} = useContext(FormContext); | ||
return jsxs("div", { | ||
class: formFieldClasses(type$3, errors), | ||
class: formFieldClasses(type$4, errors), | ||
children: [jsx(Label, { | ||
label: label, | ||
required: required | ||
}), values.map((v, index) => { | ||
}), loadState == LOAD_STATES.LOADED && options.map((option, index) => { | ||
return jsx(Label, { | ||
id: prefixId(`${id}-${index}`, formId), | ||
label: v.label, | ||
label: option.label, | ||
required: false, | ||
children: jsx("input", { | ||
checked: v.value === value, | ||
checked: option.value === value, | ||
class: "fjs-input", | ||
@@ -1487,3 +1644,3 @@ disabled: disabled, | ||
type: "radio", | ||
onClick: () => onChange(v.value) | ||
onClick: () => onChange(option.value) | ||
}) | ||
@@ -1500,2 +1657,3 @@ }, `${id}-${index}`); | ||
Radio.create = function (options = {}) { | ||
if (options.valuesKey) return options; | ||
return { | ||
@@ -1510,3 +1668,3 @@ values: [{ | ||
Radio.type = type$3; | ||
Radio.type = type$4; | ||
Radio.label = 'Radio'; | ||
@@ -1516,3 +1674,3 @@ Radio.keyed = true; | ||
const type$2 = 'select'; | ||
const type$3 = 'select'; | ||
function Select(props) { | ||
@@ -1529,4 +1687,3 @@ const { | ||
label, | ||
validate = {}, | ||
values | ||
validate = {} | ||
} = field; | ||
@@ -1547,6 +1704,10 @@ const { | ||
const { | ||
state: loadState, | ||
values: options | ||
} = useValuesAsync(field); | ||
const { | ||
formId | ||
} = useContext(FormContext); | ||
return jsxs("div", { | ||
class: formFieldClasses(type$2, errors), | ||
class: formFieldClasses(type$3, errors), | ||
children: [jsx(Label, { | ||
@@ -1564,6 +1725,6 @@ id: prefixId(id, formId), | ||
value: "" | ||
}), values.map((v, index) => { | ||
}), loadState == LOAD_STATES.LOADED && options.map((option, index) => { | ||
return jsx("option", { | ||
value: v.value, | ||
children: v.label | ||
value: option.value, | ||
children: option.label | ||
}, `${id}-${index}`); | ||
@@ -1580,2 +1741,3 @@ })] | ||
Select.create = function (options = {}) { | ||
if (options.valuesKey) return options; | ||
return { | ||
@@ -1590,3 +1752,3 @@ values: [{ | ||
Select.type = type$2; | ||
Select.type = type$3; | ||
Select.label = 'Select'; | ||
@@ -1596,2 +1758,304 @@ Select.keyed = true; | ||
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); } | ||
var CloseIcon = (({ | ||
styles = {}, | ||
...props | ||
}) => /*#__PURE__*/React.createElement("svg", _extends({ | ||
width: "16", | ||
height: "16", | ||
fill: "none", | ||
xmlns: "http://www.w3.org/2000/svg" | ||
}, props), /*#__PURE__*/React.createElement("path", { | ||
fillRule: "evenodd", | ||
clipRule: "evenodd", | ||
d: "M12 4.7l-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7z", | ||
fill: "#000" | ||
}))); | ||
function useKeyDownAction(targetKey, action, listenerElement = window) { | ||
function downHandler({ | ||
key | ||
}) { | ||
if (key === targetKey) { | ||
action(); | ||
} | ||
} | ||
useEffect(() => { | ||
listenerElement.addEventListener('keydown', downHandler); | ||
return () => { | ||
listenerElement.removeEventListener('keydown', downHandler); | ||
}; | ||
}); | ||
} | ||
const DEFAULT_LABEL_GETTER = value => value; | ||
const NOOP = () => {}; | ||
function DropdownList(props) { | ||
const { | ||
keyEventsListener = window, | ||
values = [], | ||
getLabel = DEFAULT_LABEL_GETTER, | ||
onValueSelected = NOOP, | ||
height = 235, | ||
emptyListMessage = 'No results' | ||
} = props; | ||
const [mouseControl, setMouseControl] = useState(true); | ||
const [focusedValueIndex, setFocusedValueIndex] = useState(0); | ||
const dropdownContainer = useRef(); | ||
const mouseScreenPos = useRef(); | ||
const focusedItem = useMemo(() => values.length ? values[focusedValueIndex] : null, [focusedValueIndex, values]); | ||
const changeFocusedValueIndex = useCallback(delta => { | ||
setFocusedValueIndex(x => Math.min(Math.max(0, x + delta), values.length - 1)); | ||
}, [values.length]); | ||
useEffect(() => { | ||
if (focusedValueIndex === 0) return; | ||
if (!focusedValueIndex || !values.length) { | ||
setFocusedValueIndex(0); | ||
} else if (focusedValueIndex >= values.length) { | ||
setFocusedValueIndex(values.length - 1); | ||
} | ||
}, [focusedValueIndex, values.length]); | ||
useKeyDownAction('ArrowUp', () => { | ||
if (values.length) { | ||
changeFocusedValueIndex(-1); | ||
setMouseControl(false); | ||
} | ||
}, keyEventsListener); | ||
useKeyDownAction('ArrowDown', () => { | ||
if (values.length) { | ||
changeFocusedValueIndex(1); | ||
setMouseControl(false); | ||
} | ||
}, keyEventsListener); | ||
useKeyDownAction('Enter', () => { | ||
if (focusedItem) { | ||
onValueSelected(focusedItem); | ||
} | ||
}, keyEventsListener); | ||
useEffect(() => { | ||
const individualEntries = dropdownContainer.current.children; | ||
if (individualEntries.length && !mouseControl) { | ||
individualEntries[focusedValueIndex].scrollIntoView({ | ||
block: 'nearest', | ||
inline: 'nearest' | ||
}); | ||
} | ||
}, [focusedValueIndex, mouseControl]); | ||
const mouseMove = (e, i) => { | ||
const userMoved = !mouseScreenPos.current || mouseScreenPos.current.x !== e.screenX && mouseScreenPos.current.y !== e.screenY; | ||
if (userMoved) { | ||
mouseScreenPos.current = { | ||
x: e.screenX, | ||
y: e.screenY | ||
}; | ||
if (!mouseControl) { | ||
setMouseControl(true); | ||
setFocusedValueIndex(i); | ||
} | ||
} | ||
}; | ||
return jsxs("div", { | ||
ref: dropdownContainer, | ||
tabIndex: -1, | ||
class: "fjs-dropdownlist", | ||
style: { | ||
maxHeight: height | ||
}, | ||
children: [!!values.length && values.map((v, i) => { | ||
return jsx("div", { | ||
class: 'fjs-dropdownlist-item' + (focusedValueIndex === i ? ' focused' : ''), | ||
onMouseMove: e => mouseMove(e, i), | ||
onMouseEnter: mouseControl ? () => setFocusedValueIndex(i) : undefined, | ||
onMouseDown: e => { | ||
e.preventDefault(); | ||
onValueSelected(v); | ||
}, | ||
children: getLabel(v) | ||
}); | ||
}), !values.length && jsx("div", { | ||
class: "fjs-dropdownlist-empty", | ||
children: emptyListMessage | ||
})] | ||
}); | ||
} | ||
const type$2 = 'taglist'; | ||
function Taglist(props) { | ||
const { | ||
disabled, | ||
errors = [], | ||
field, | ||
value: values = [] | ||
} = props; | ||
const { | ||
description, | ||
id, | ||
label | ||
} = field; | ||
const { | ||
formId | ||
} = useContext(FormContext); | ||
const [filter, setFilter] = useState(''); | ||
const [selectedValues, setSelectedValues] = useState([]); | ||
const [filteredValues, setFilteredValues] = useState([]); | ||
const [isDropdownExpanded, setIsDropdownExpanded] = useState(false); | ||
const [hasValuesLeft, setHasValuesLeft] = useState(true); | ||
const [isEscapeClosed, setIsEscapeClose] = useState(false); | ||
const searchbarRef = useRef(); | ||
const { | ||
state: loadState, | ||
values: options | ||
} = useValuesAsync(field); // Usage of stringify is necessary here because we want this effect to only trigger when there is a value change to the array | ||
useEffect(() => { | ||
if (loadState === LOAD_STATES.LOADED) { | ||
const selectedValues = values.map(v => options.find(o => o.value === v)).filter(v => v !== undefined); | ||
setSelectedValues(selectedValues); | ||
} else { | ||
setSelectedValues([]); | ||
} | ||
}, [JSON.stringify(values), options, loadState]); | ||
useEffect(() => { | ||
if (loadState === LOAD_STATES.LOADED) { | ||
setFilteredValues(options.filter(o => o.label && o.label.toLowerCase().includes(filter.toLowerCase()) && !values.includes(o.value))); | ||
} else { | ||
setFilteredValues([]); | ||
} | ||
}, [filter, JSON.stringify(values), options]); | ||
useEffect(() => { | ||
setHasValuesLeft(selectedValues.length < options.length); | ||
}, [selectedValues.length, options.length]); | ||
const onFilterChange = ({ | ||
target | ||
}) => { | ||
setIsEscapeClose(false); | ||
setFilter(target.value); | ||
}; | ||
const selectValue = option => { | ||
setFilter(''); | ||
props.onChange({ | ||
value: [...values, option.value], | ||
field | ||
}); | ||
}; | ||
const deselectValue = option => { | ||
props.onChange({ | ||
value: values.filter(v => v != option.value), | ||
field | ||
}); | ||
}; | ||
const onInputKeyDown = e => { | ||
switch (e.key) { | ||
case 'ArrowUp': | ||
case 'ArrowDown': | ||
// We do not want the cursor to seek in the search field when we press up and down | ||
e.preventDefault(); | ||
break; | ||
case 'Backspace': | ||
if (!filter && selectedValues.length) { | ||
deselectValue(selectedValues[selectedValues.length - 1]); | ||
} | ||
break; | ||
case 'Escape': | ||
setIsEscapeClose(true); | ||
break; | ||
case 'Enter': | ||
if (isEscapeClosed) { | ||
setIsEscapeClose(false); | ||
} | ||
break; | ||
} | ||
}; | ||
return jsxs("div", { | ||
class: formFieldClasses(type$2, errors), | ||
children: [jsx(Label, { | ||
label: label, | ||
id: prefixId(id, formId) | ||
}), jsxs("div", { | ||
class: classNames('fjs-taglist', { | ||
'disabled': disabled | ||
}), | ||
children: [!disabled && loadState === LOAD_STATES.LOADED && selectedValues.map(sv => { | ||
return jsxs("div", { | ||
class: "fjs-taglist-tag", | ||
onMouseDown: e => e.preventDefault(), | ||
children: [jsx("span", { | ||
class: "fjs-taglist-tag-label", | ||
children: sv.label | ||
}), jsx("span", { | ||
class: "fjs-taglist-tag-remove", | ||
onMouseDown: () => deselectValue(sv), | ||
children: jsx(CloseIcon, {}) | ||
})] | ||
}); | ||
}), jsx("input", { | ||
disabled: disabled, | ||
class: "fjs-taglist-input", | ||
ref: searchbarRef, | ||
id: prefixId(`${id}-search`, formId), | ||
onChange: onFilterChange, | ||
type: "text", | ||
value: filter, | ||
placeholder: 'Search', | ||
autoComplete: "off", | ||
onKeyDown: e => onInputKeyDown(e), | ||
onMouseDown: () => setIsEscapeClose(false), | ||
onFocus: () => setIsDropdownExpanded(true), | ||
onBlur: () => { | ||
setIsDropdownExpanded(false); | ||
setFilter(''); | ||
} | ||
})] | ||
}), jsx("div", { | ||
class: "fjs-taglist-anchor", | ||
children: !disabled && loadState === LOAD_STATES.LOADED && isDropdownExpanded && !isEscapeClosed && jsx(DropdownList, { | ||
values: filteredValues, | ||
getLabel: v => v.label, | ||
onValueSelected: v => selectValue(v), | ||
emptyListMessage: hasValuesLeft ? 'No results' : 'All values selected', | ||
listenerElement: searchbarRef.current | ||
}) | ||
}), jsx(Description, { | ||
description: description | ||
}), jsx(Errors, { | ||
errors: errors | ||
})] | ||
}); | ||
} | ||
Taglist.create = function (options = {}) { | ||
if (options.valuesKey) return options; | ||
return { | ||
values: [{ | ||
label: 'Value', | ||
value: 'value' | ||
}], | ||
...options | ||
}; | ||
}; | ||
Taglist.type = type$2; | ||
Taglist.label = 'Taglist'; | ||
Taglist.keyed = true; | ||
Taglist.emptyValue = []; | ||
const type$1 = 'text'; | ||
@@ -1685,3 +2149,3 @@ function Text(props) { | ||
const formFields = [Button, Checkbox, Default, Number, Radio, Select, Text, Textfield]; | ||
const formFields = [Button, Checkbox, Checklist, Default, Number, Radio, Select, Taglist, Text, Textfield]; | ||
@@ -2173,3 +2637,3 @@ class FormFields { | ||
const schemaVersion = 4; | ||
const schemaVersion = 5; | ||
/** | ||
@@ -2199,3 +2663,3 @@ * @typedef { import('./types').CreateFormOptions } CreateFormOptions | ||
export { Button, Checkbox, Default, Form, FormComponent, FormContext, FormFieldRegistry, FormFields, FormRenderContext, Number, Radio, Select, Text, Textfield, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion }; | ||
export { Button, Checkbox, Checklist, Default, Form, FormComponent, FormContext, FormFieldRegistry, FormFields, FormRenderContext, Number, Radio, Select, Taglist, Text, Textfield, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion }; | ||
//# sourceMappingURL=index.es.js.map |
@@ -17,3 +17,3 @@ /** | ||
import Form from "./Form"; | ||
export const schemaVersion: 4; | ||
export const schemaVersion: 5; | ||
export { Form }; |
declare function Radio(props: any): import("preact").JSX.Element; | ||
declare namespace Radio { | ||
export function create(options?: {}): { | ||
values: { | ||
label: string; | ||
value: string; | ||
}[]; | ||
}; | ||
export function create(options?: {}): {}; | ||
export { type }; | ||
@@ -10,0 +5,0 @@ export const label: string; |
declare function Select(props: any): import("preact").JSX.Element; | ||
declare namespace Select { | ||
export function create(options?: {}): { | ||
values: { | ||
label: string; | ||
value: string; | ||
}[]; | ||
}; | ||
export function create(options?: {}): {}; | ||
export { type }; | ||
@@ -10,0 +5,0 @@ export const label: string; |
export const formFields: (typeof Button | typeof Default | typeof Number | typeof Text)[]; | ||
import Button from "./form-fields/Button"; | ||
import Checkbox from "./form-fields/Checkbox"; | ||
import Checklist from "./form-fields/Checklist"; | ||
import Default from "./form-fields/Default"; | ||
@@ -9,4 +10,5 @@ import FormComponent from "./FormComponent"; | ||
import Select from "./form-fields/Select"; | ||
import Taglist from "./form-fields/Taglist"; | ||
import Text from "./form-fields/Text"; | ||
import Textfield from "./form-fields/Textfield"; | ||
export { Button, Checkbox, Default, FormComponent, Number, Radio, Select, Text, Textfield }; | ||
export { Button, Checkbox, Checklist, Default, FormComponent, Number, Radio, Select, Taglist, Text, Textfield }; |
{ | ||
"name": "@bpmn-io/form-js-viewer", | ||
"version": "0.7.2", | ||
"version": "0.8.0-alpha.0", | ||
"description": "View forms - powered by bpmn.io", | ||
@@ -23,3 +23,3 @@ "exports": { | ||
"start": "SINGLE_START=basic npm run dev", | ||
"bundle": "rollup -c", | ||
"bundle": "rollup -c --failAfterWarnings", | ||
"bundle:watch": "rollup -c -w", | ||
@@ -43,2 +43,3 @@ "dev": "npm test -- --auto-watch --no-single-run", | ||
"@bpmn-io/snarkdown": "^2.1.0", | ||
"classnames": "^2.3.1", | ||
"didi": "^5.2.1", | ||
@@ -56,3 +57,3 @@ "ids": "^1.0.0", | ||
], | ||
"gitHead": "46631f707eea5537cbeb81aa05423fd9be71a3c0" | ||
"gitHead": "ffc5f0cedcf0b9a923b34ff56e7f63a34c362cf9" | ||
} |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
416238
49
5361
7
1
+ Addedclassnames@^2.3.1
+ Addedclassnames@2.5.1(transitive)