@y14e/disclosure 2.0.10 → 2.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.bundle.cjs +57 -18
- package/dist/index.bundle.js +57 -18
- package/dist/index.cjs +13 -12
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +13 -12
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,11 +13,11 @@ npm i @y14e/disclosure
|
|
|
13
13
|
import { Disclosure } from "@y14e/disclosure";
|
|
14
14
|
|
|
15
15
|
// CDNs
|
|
16
|
-
import { Disclosure } from "https://esm.sh/@y14e/disclosure@2.0.
|
|
16
|
+
import { Disclosure } from "https://esm.sh/@y14e/disclosure@2.0.12";
|
|
17
17
|
// or
|
|
18
|
-
import { Disclosure } from "https://cdn.jsdelivr.net/npm/@y14e/disclosure@2.0.
|
|
18
|
+
import { Disclosure } from "https://cdn.jsdelivr.net/npm/@y14e/disclosure@2.0.12/+esm";
|
|
19
19
|
// or
|
|
20
|
-
import { Disclosure } from "https://esm.unpkg.com/@y14e/disclosure@2.0.
|
|
20
|
+
import { Disclosure } from "https://esm.unpkg.com/@y14e/disclosure@2.0.12";
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## Usage
|
package/dist/index.bundle.cjs
CHANGED
|
@@ -4,12 +4,11 @@
|
|
|
4
4
|
var DEFAULT_PARSER = (value) => value.split(/\s+/);
|
|
5
5
|
var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
|
|
6
6
|
function addAttributeToken(element, name, token, options = {}) {
|
|
7
|
+
if (!isValid(element, name, token)) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
7
10
|
const value = element.getAttribute(name)?.trim();
|
|
8
|
-
const {
|
|
9
|
-
caseInsensitive = false,
|
|
10
|
-
parse = DEFAULT_PARSER,
|
|
11
|
-
serialize = DEFAULT_SERIALIZER
|
|
12
|
-
} = options;
|
|
11
|
+
const { caseInsensitive, parse, serialize } = resolveOptions(options);
|
|
13
12
|
const tokens = value ? parse(value).filter(Boolean) : [];
|
|
14
13
|
if (caseInsensitive) {
|
|
15
14
|
const lower = token.toLowerCase();
|
|
@@ -49,6 +48,45 @@ function saveAttributes(element_or_elements, name_or_names) {
|
|
|
49
48
|
});
|
|
50
49
|
});
|
|
51
50
|
}
|
|
51
|
+
function isValid(element, name, token) {
|
|
52
|
+
if (!(element instanceof Element)) {
|
|
53
|
+
console.warn("Invalid element");
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (!element.hasAttribute(name)) {
|
|
57
|
+
console.warn("Invalid attribute name");
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
if (typeof token !== "string" || !token.trim()) {
|
|
61
|
+
console.warn("Invalid token");
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
function resolveOptions(options) {
|
|
67
|
+
let {
|
|
68
|
+
caseInsensitive = false,
|
|
69
|
+
parse = DEFAULT_PARSER,
|
|
70
|
+
serialize = DEFAULT_SERIALIZER
|
|
71
|
+
} = options;
|
|
72
|
+
if (typeof caseInsensitive !== "boolean") {
|
|
73
|
+
console.warn("Invalid caseInsensitive option. Fallback: false.");
|
|
74
|
+
caseInsensitive = false;
|
|
75
|
+
}
|
|
76
|
+
if (typeof parse !== "function") {
|
|
77
|
+
console.warn(
|
|
78
|
+
"Invalid parser. Fallback: default parser (splits by whitespace)."
|
|
79
|
+
);
|
|
80
|
+
parse = DEFAULT_PARSER;
|
|
81
|
+
}
|
|
82
|
+
if (typeof serialize !== "function") {
|
|
83
|
+
console.warn(
|
|
84
|
+
"Invalid serializer. Fallback: default serializer (joins by whitespace)."
|
|
85
|
+
);
|
|
86
|
+
serialize = DEFAULT_SERIALIZER;
|
|
87
|
+
}
|
|
88
|
+
return { caseInsensitive, parse, serialize };
|
|
89
|
+
}
|
|
52
90
|
|
|
53
91
|
// node_modules/power-focusable/dist/index.js
|
|
54
92
|
var FOCUSABLE_SELECTOR = `:is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])`;
|
|
@@ -609,8 +647,8 @@ var Disclosure = class _Disclosure {
|
|
|
609
647
|
return;
|
|
610
648
|
}
|
|
611
649
|
this.#rootElement = root;
|
|
612
|
-
this.#defaults = this.#
|
|
613
|
-
this.#settings = this.#
|
|
650
|
+
this.#defaults = this.#resolveOptions(this.#defaults, _Disclosure.defaults);
|
|
651
|
+
this.#settings = this.#resolveOptions(this.#defaults, options);
|
|
614
652
|
matchMedia("(prefers-reduced-motion: reduce)").matches && Object.assign(this.#settings.animation, { duration: 0 });
|
|
615
653
|
const NOT_NESTED = ":not(:scope summary + * *)";
|
|
616
654
|
this.#detailsElements = [
|
|
@@ -833,27 +871,28 @@ var Disclosure = class _Disclosure {
|
|
|
833
871
|
#isFocusable(element) {
|
|
834
872
|
return element.tabIndex >= 0;
|
|
835
873
|
}
|
|
836
|
-
#
|
|
874
|
+
#resolveOptions(target, source) {
|
|
837
875
|
const merged = {
|
|
838
876
|
...target,
|
|
839
877
|
...source,
|
|
840
878
|
animation: { ...target.animation, ...source.animation ?? {} }
|
|
841
879
|
};
|
|
842
|
-
const
|
|
843
|
-
const duration =
|
|
880
|
+
const mergedAnimation = merged.animation;
|
|
881
|
+
const duration = mergedAnimation.duration;
|
|
882
|
+
const defaultAnimation = this.#defaults.animation;
|
|
844
883
|
if (typeof duration !== "number" || Number.isNaN(duration)) {
|
|
845
|
-
const duration2 =
|
|
884
|
+
const duration2 = defaultAnimation.duration;
|
|
846
885
|
console.warn(`Invalid animation duration. Fallback: ${duration2} (ms).`);
|
|
847
|
-
|
|
886
|
+
mergedAnimation.duration = duration2;
|
|
848
887
|
}
|
|
849
888
|
if (duration < 0) {
|
|
850
889
|
console.warn("Invalid animation duration. Fallback: 0 (ms).");
|
|
851
|
-
|
|
890
|
+
mergedAnimation.duration = 0;
|
|
852
891
|
}
|
|
853
|
-
if (!CSS.supports("animation-timing-function",
|
|
854
|
-
const easing =
|
|
892
|
+
if (!CSS.supports("animation-timing-function", mergedAnimation.easing)) {
|
|
893
|
+
const easing = defaultAnimation.easing;
|
|
855
894
|
console.warn(`Invalid animation easing. Fallback: '${easing}'.`);
|
|
856
|
-
|
|
895
|
+
mergedAnimation.easing = easing;
|
|
857
896
|
}
|
|
858
897
|
if (typeof merged.collapsible !== "boolean") {
|
|
859
898
|
const collapsible = this.#defaults.collapsible;
|
|
@@ -881,7 +920,7 @@ function waitAnimationFinish(animation) {
|
|
|
881
920
|
* WAI-ARIA compliant disclosure pattern implementation in TypeScript.
|
|
882
921
|
* Using the <details> and <summary> element.
|
|
883
922
|
*
|
|
884
|
-
* @version 2.0.
|
|
923
|
+
* @version 2.0.12
|
|
885
924
|
* @author Yusuke Kamiyamane
|
|
886
925
|
* @license MIT
|
|
887
926
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -893,7 +932,7 @@ function waitAnimationFinish(animation) {
|
|
|
893
932
|
(**
|
|
894
933
|
* Attribute Utils
|
|
895
934
|
*
|
|
896
|
-
* @version 2.0.
|
|
935
|
+
* @version 2.0.6
|
|
897
936
|
* @author Yusuke Kamiyamane
|
|
898
937
|
* @license MIT
|
|
899
938
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.bundle.js
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
var DEFAULT_PARSER = (value) => value.split(/\s+/);
|
|
3
3
|
var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
|
|
4
4
|
function addAttributeToken(element, name, token, options = {}) {
|
|
5
|
+
if (!isValid(element, name, token)) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
5
8
|
const value = element.getAttribute(name)?.trim();
|
|
6
|
-
const {
|
|
7
|
-
caseInsensitive = false,
|
|
8
|
-
parse = DEFAULT_PARSER,
|
|
9
|
-
serialize = DEFAULT_SERIALIZER
|
|
10
|
-
} = options;
|
|
9
|
+
const { caseInsensitive, parse, serialize } = resolveOptions(options);
|
|
11
10
|
const tokens = value ? parse(value).filter(Boolean) : [];
|
|
12
11
|
if (caseInsensitive) {
|
|
13
12
|
const lower = token.toLowerCase();
|
|
@@ -47,6 +46,45 @@ function saveAttributes(element_or_elements, name_or_names) {
|
|
|
47
46
|
});
|
|
48
47
|
});
|
|
49
48
|
}
|
|
49
|
+
function isValid(element, name, token) {
|
|
50
|
+
if (!(element instanceof Element)) {
|
|
51
|
+
console.warn("Invalid element");
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (!element.hasAttribute(name)) {
|
|
55
|
+
console.warn("Invalid attribute name");
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
if (typeof token !== "string" || !token.trim()) {
|
|
59
|
+
console.warn("Invalid token");
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
function resolveOptions(options) {
|
|
65
|
+
let {
|
|
66
|
+
caseInsensitive = false,
|
|
67
|
+
parse = DEFAULT_PARSER,
|
|
68
|
+
serialize = DEFAULT_SERIALIZER
|
|
69
|
+
} = options;
|
|
70
|
+
if (typeof caseInsensitive !== "boolean") {
|
|
71
|
+
console.warn("Invalid caseInsensitive option. Fallback: false.");
|
|
72
|
+
caseInsensitive = false;
|
|
73
|
+
}
|
|
74
|
+
if (typeof parse !== "function") {
|
|
75
|
+
console.warn(
|
|
76
|
+
"Invalid parser. Fallback: default parser (splits by whitespace)."
|
|
77
|
+
);
|
|
78
|
+
parse = DEFAULT_PARSER;
|
|
79
|
+
}
|
|
80
|
+
if (typeof serialize !== "function") {
|
|
81
|
+
console.warn(
|
|
82
|
+
"Invalid serializer. Fallback: default serializer (joins by whitespace)."
|
|
83
|
+
);
|
|
84
|
+
serialize = DEFAULT_SERIALIZER;
|
|
85
|
+
}
|
|
86
|
+
return { caseInsensitive, parse, serialize };
|
|
87
|
+
}
|
|
50
88
|
|
|
51
89
|
// node_modules/power-focusable/dist/index.js
|
|
52
90
|
var FOCUSABLE_SELECTOR = `:is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])`;
|
|
@@ -607,8 +645,8 @@ var Disclosure = class _Disclosure {
|
|
|
607
645
|
return;
|
|
608
646
|
}
|
|
609
647
|
this.#rootElement = root;
|
|
610
|
-
this.#defaults = this.#
|
|
611
|
-
this.#settings = this.#
|
|
648
|
+
this.#defaults = this.#resolveOptions(this.#defaults, _Disclosure.defaults);
|
|
649
|
+
this.#settings = this.#resolveOptions(this.#defaults, options);
|
|
612
650
|
matchMedia("(prefers-reduced-motion: reduce)").matches && Object.assign(this.#settings.animation, { duration: 0 });
|
|
613
651
|
const NOT_NESTED = ":not(:scope summary + * *)";
|
|
614
652
|
this.#detailsElements = [
|
|
@@ -831,27 +869,28 @@ var Disclosure = class _Disclosure {
|
|
|
831
869
|
#isFocusable(element) {
|
|
832
870
|
return element.tabIndex >= 0;
|
|
833
871
|
}
|
|
834
|
-
#
|
|
872
|
+
#resolveOptions(target, source) {
|
|
835
873
|
const merged = {
|
|
836
874
|
...target,
|
|
837
875
|
...source,
|
|
838
876
|
animation: { ...target.animation, ...source.animation ?? {} }
|
|
839
877
|
};
|
|
840
|
-
const
|
|
841
|
-
const duration =
|
|
878
|
+
const mergedAnimation = merged.animation;
|
|
879
|
+
const duration = mergedAnimation.duration;
|
|
880
|
+
const defaultAnimation = this.#defaults.animation;
|
|
842
881
|
if (typeof duration !== "number" || Number.isNaN(duration)) {
|
|
843
|
-
const duration2 =
|
|
882
|
+
const duration2 = defaultAnimation.duration;
|
|
844
883
|
console.warn(`Invalid animation duration. Fallback: ${duration2} (ms).`);
|
|
845
|
-
|
|
884
|
+
mergedAnimation.duration = duration2;
|
|
846
885
|
}
|
|
847
886
|
if (duration < 0) {
|
|
848
887
|
console.warn("Invalid animation duration. Fallback: 0 (ms).");
|
|
849
|
-
|
|
888
|
+
mergedAnimation.duration = 0;
|
|
850
889
|
}
|
|
851
|
-
if (!CSS.supports("animation-timing-function",
|
|
852
|
-
const easing =
|
|
890
|
+
if (!CSS.supports("animation-timing-function", mergedAnimation.easing)) {
|
|
891
|
+
const easing = defaultAnimation.easing;
|
|
853
892
|
console.warn(`Invalid animation easing. Fallback: '${easing}'.`);
|
|
854
|
-
|
|
893
|
+
mergedAnimation.easing = easing;
|
|
855
894
|
}
|
|
856
895
|
if (typeof merged.collapsible !== "boolean") {
|
|
857
896
|
const collapsible = this.#defaults.collapsible;
|
|
@@ -879,7 +918,7 @@ function waitAnimationFinish(animation) {
|
|
|
879
918
|
* WAI-ARIA compliant disclosure pattern implementation in TypeScript.
|
|
880
919
|
* Using the <details> and <summary> element.
|
|
881
920
|
*
|
|
882
|
-
* @version 2.0.
|
|
921
|
+
* @version 2.0.12
|
|
883
922
|
* @author Yusuke Kamiyamane
|
|
884
923
|
* @license MIT
|
|
885
924
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -891,7 +930,7 @@ function waitAnimationFinish(animation) {
|
|
|
891
930
|
(**
|
|
892
931
|
* Attribute Utils
|
|
893
932
|
*
|
|
894
|
-
* @version 2.0.
|
|
933
|
+
* @version 2.0.6
|
|
895
934
|
* @author Yusuke Kamiyamane
|
|
896
935
|
* @license MIT
|
|
897
936
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.cjs
CHANGED
|
@@ -53,8 +53,8 @@ var Disclosure = class _Disclosure {
|
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
55
|
this.#rootElement = root;
|
|
56
|
-
this.#defaults = this.#
|
|
57
|
-
this.#settings = this.#
|
|
56
|
+
this.#defaults = this.#resolveOptions(this.#defaults, _Disclosure.defaults);
|
|
57
|
+
this.#settings = this.#resolveOptions(this.#defaults, options);
|
|
58
58
|
matchMedia("(prefers-reduced-motion: reduce)").matches && Object.assign(this.#settings.animation, { duration: 0 });
|
|
59
59
|
const NOT_NESTED = ":not(:scope summary + * *)";
|
|
60
60
|
this.#detailsElements = [
|
|
@@ -277,27 +277,28 @@ var Disclosure = class _Disclosure {
|
|
|
277
277
|
#isFocusable(element) {
|
|
278
278
|
return element.tabIndex >= 0;
|
|
279
279
|
}
|
|
280
|
-
#
|
|
280
|
+
#resolveOptions(target, source) {
|
|
281
281
|
const merged = {
|
|
282
282
|
...target,
|
|
283
283
|
...source,
|
|
284
284
|
animation: { ...target.animation, ...source.animation ?? {} }
|
|
285
285
|
};
|
|
286
|
-
const
|
|
287
|
-
const duration =
|
|
286
|
+
const mergedAnimation = merged.animation;
|
|
287
|
+
const duration = mergedAnimation.duration;
|
|
288
|
+
const defaultAnimation = this.#defaults.animation;
|
|
288
289
|
if (typeof duration !== "number" || Number.isNaN(duration)) {
|
|
289
|
-
const duration2 =
|
|
290
|
+
const duration2 = defaultAnimation.duration;
|
|
290
291
|
console.warn(`Invalid animation duration. Fallback: ${duration2} (ms).`);
|
|
291
|
-
|
|
292
|
+
mergedAnimation.duration = duration2;
|
|
292
293
|
}
|
|
293
294
|
if (duration < 0) {
|
|
294
295
|
console.warn("Invalid animation duration. Fallback: 0 (ms).");
|
|
295
|
-
|
|
296
|
+
mergedAnimation.duration = 0;
|
|
296
297
|
}
|
|
297
|
-
if (!CSS.supports("animation-timing-function",
|
|
298
|
-
const easing =
|
|
298
|
+
if (!CSS.supports("animation-timing-function", mergedAnimation.easing)) {
|
|
299
|
+
const easing = defaultAnimation.easing;
|
|
299
300
|
console.warn(`Invalid animation easing. Fallback: '${easing}'.`);
|
|
300
|
-
|
|
301
|
+
mergedAnimation.easing = easing;
|
|
301
302
|
}
|
|
302
303
|
if (typeof merged.collapsible !== "boolean") {
|
|
303
304
|
const collapsible = this.#defaults.collapsible;
|
|
@@ -325,7 +326,7 @@ function waitAnimationFinish(animation) {
|
|
|
325
326
|
* WAI-ARIA compliant disclosure pattern implementation in TypeScript.
|
|
326
327
|
* Using the <details> and <summary> element.
|
|
327
328
|
*
|
|
328
|
-
* @version 2.0.
|
|
329
|
+
* @version 2.0.12
|
|
329
330
|
* @author Yusuke Kamiyamane
|
|
330
331
|
* @license MIT
|
|
331
332
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -31,8 +31,8 @@ var Disclosure = class _Disclosure {
|
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
this.#rootElement = root;
|
|
34
|
-
this.#defaults = this.#
|
|
35
|
-
this.#settings = this.#
|
|
34
|
+
this.#defaults = this.#resolveOptions(this.#defaults, _Disclosure.defaults);
|
|
35
|
+
this.#settings = this.#resolveOptions(this.#defaults, options);
|
|
36
36
|
matchMedia("(prefers-reduced-motion: reduce)").matches && Object.assign(this.#settings.animation, { duration: 0 });
|
|
37
37
|
const NOT_NESTED = ":not(:scope summary + * *)";
|
|
38
38
|
this.#detailsElements = [
|
|
@@ -255,27 +255,28 @@ var Disclosure = class _Disclosure {
|
|
|
255
255
|
#isFocusable(element) {
|
|
256
256
|
return element.tabIndex >= 0;
|
|
257
257
|
}
|
|
258
|
-
#
|
|
258
|
+
#resolveOptions(target, source) {
|
|
259
259
|
const merged = {
|
|
260
260
|
...target,
|
|
261
261
|
...source,
|
|
262
262
|
animation: { ...target.animation, ...source.animation ?? {} }
|
|
263
263
|
};
|
|
264
|
-
const
|
|
265
|
-
const duration =
|
|
264
|
+
const mergedAnimation = merged.animation;
|
|
265
|
+
const duration = mergedAnimation.duration;
|
|
266
|
+
const defaultAnimation = this.#defaults.animation;
|
|
266
267
|
if (typeof duration !== "number" || Number.isNaN(duration)) {
|
|
267
|
-
const duration2 =
|
|
268
|
+
const duration2 = defaultAnimation.duration;
|
|
268
269
|
console.warn(`Invalid animation duration. Fallback: ${duration2} (ms).`);
|
|
269
|
-
|
|
270
|
+
mergedAnimation.duration = duration2;
|
|
270
271
|
}
|
|
271
272
|
if (duration < 0) {
|
|
272
273
|
console.warn("Invalid animation duration. Fallback: 0 (ms).");
|
|
273
|
-
|
|
274
|
+
mergedAnimation.duration = 0;
|
|
274
275
|
}
|
|
275
|
-
if (!CSS.supports("animation-timing-function",
|
|
276
|
-
const easing =
|
|
276
|
+
if (!CSS.supports("animation-timing-function", mergedAnimation.easing)) {
|
|
277
|
+
const easing = defaultAnimation.easing;
|
|
277
278
|
console.warn(`Invalid animation easing. Fallback: '${easing}'.`);
|
|
278
|
-
|
|
279
|
+
mergedAnimation.easing = easing;
|
|
279
280
|
}
|
|
280
281
|
if (typeof merged.collapsible !== "boolean") {
|
|
281
282
|
const collapsible = this.#defaults.collapsible;
|
|
@@ -303,7 +304,7 @@ function waitAnimationFinish(animation) {
|
|
|
303
304
|
* WAI-ARIA compliant disclosure pattern implementation in TypeScript.
|
|
304
305
|
* Using the <details> and <summary> element.
|
|
305
306
|
*
|
|
306
|
-
* @version 2.0.
|
|
307
|
+
* @version 2.0.12
|
|
307
308
|
* @author Yusuke Kamiyamane
|
|
308
309
|
* @license MIT
|
|
309
310
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y14e/disclosure",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.12",
|
|
4
4
|
"description": "WAI-ARIA compliant disclosure pattern implementation in TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"esbuild": true
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@y14e/attribute-utils": "^2.0.
|
|
57
|
+
"@y14e/attribute-utils": "^2.0.6",
|
|
58
58
|
"@y14e/roving-tabindex": "^3.1.25"
|
|
59
59
|
}
|
|
60
60
|
}
|