@rathkit/rte-element 0.0.0 → 0.1.0-alpha.3
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 +29 -4
- package/dist/define.d.ts +1 -0
- package/dist/define.js +2 -0
- package/dist/editor-element.d.ts +51 -0
- package/dist/editor-element.js +139 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +11 -0
- package/dist/toolbar-element.d.ts +14 -0
- package/dist/toolbar-element.js +70 -0
- package/package.json +67 -3
package/README.md
CHANGED
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
# @rathkit/rte-element
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Alpha** (0.1.0-alpha.0). Not for production: the APIs will change between releases. Published to the `next` tag only.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The editor as custom elements, `<rk-editor>` and `<rk-toolbar>`, for any page or framework: form-associated (it submits its value, resets, restores), with properties, attributes and events.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
6
8
|
|
|
7
9
|
```sh
|
|
8
|
-
npm install @rathkit/rte-element@next
|
|
10
|
+
npm install @rathkit/rte-element@next @rathkit/rte-core@next @rathkit/rte-headless@next
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
This package has no dependencies of its own. It works with `@rathkit/rte-core`, `@rathkit/rte-headless` (peer dependencies, all optional so that npm installs nothing you did not ask for), so install the ones you use alongside it.
|
|
14
|
+
|
|
15
|
+
## Example
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<script type="module">
|
|
19
|
+
import "@rathkit/rte-element/define";
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<form>
|
|
23
|
+
<rk-editor name="body" label="Body"><p>Start here</p></rk-editor>
|
|
24
|
+
</form>
|
|
25
|
+
<script>
|
|
26
|
+
document.querySelector("rk-editor").addEventListener("rk-change", (e) => console.log(e.detail.html));
|
|
27
|
+
</script>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## More
|
|
31
|
+
|
|
32
|
+
Documentation: <https://rathkit.com>. Source and issues: <https://github.com/rathkit/rte>. What is checked: [SUPPORT.md](https://github.com/rathkit/rte/blob/main/docs/SUPPORT.md). Changes: [CHANGELOG.md](https://github.com/rathkit/rte/blob/main/CHANGELOG.md). How a release is verified: [VERIFY.md](https://github.com/rathkit/rte/blob/main/docs/VERIFY.md).
|
|
33
|
+
|
|
34
|
+
## License
|
|
35
|
+
|
|
36
|
+
[Apache-2.0](LICENSE)
|
package/dist/define.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/define.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Editor } from "@rathkit/rte-core/dom";
|
|
2
|
+
import { type StandardOptions } from "@rathkit/rte-core/standard";
|
|
3
|
+
/** Options an app can only pass as code (functions, plugin lists): everything in the standard editor's options except what attributes control. */
|
|
4
|
+
export type RkEditorOptions = Omit<StandardOptions, "element" | "html" | "readOnly">;
|
|
5
|
+
export declare class RkEditor extends HTMLElement {
|
|
6
|
+
static formAssociated: boolean;
|
|
7
|
+
static observedAttributes: string[];
|
|
8
|
+
private internals;
|
|
9
|
+
private surface;
|
|
10
|
+
private current;
|
|
11
|
+
private html;
|
|
12
|
+
private defaultHtml;
|
|
13
|
+
private opts;
|
|
14
|
+
private stop;
|
|
15
|
+
private atFocus;
|
|
16
|
+
private resolveReady;
|
|
17
|
+
private ready;
|
|
18
|
+
constructor();
|
|
19
|
+
connectedCallback(): void;
|
|
20
|
+
disconnectedCallback(): void;
|
|
21
|
+
attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
|
|
22
|
+
formResetCallback(): void;
|
|
23
|
+
formDisabledCallback(disabled: boolean): void;
|
|
24
|
+
formStateRestoreCallback(state: string | File | FormData | null): void;
|
|
25
|
+
get form(): HTMLFormElement | null;
|
|
26
|
+
get name(): string;
|
|
27
|
+
set name(value: string);
|
|
28
|
+
get validity(): ValidityState | undefined;
|
|
29
|
+
checkValidity(): boolean;
|
|
30
|
+
reportValidity(): boolean;
|
|
31
|
+
/** The document as HTML. Setting it replaces the document and clears the undo history. */
|
|
32
|
+
get value(): string;
|
|
33
|
+
set value(html: string);
|
|
34
|
+
get readOnly(): boolean;
|
|
35
|
+
set readOnly(value: boolean);
|
|
36
|
+
/** The editor inside, once it exists: for commands, plugins and subscriptions. */
|
|
37
|
+
get editor(): Editor | undefined;
|
|
38
|
+
/** Resolves with the editor once the element is connected and the editor is built. */
|
|
39
|
+
whenReady(): Promise<Editor>;
|
|
40
|
+
/** Options only code can give (an upload function, more plugins). Set them before the element is connected. */
|
|
41
|
+
get options(): RkEditorOptions;
|
|
42
|
+
set options(options: RkEditorOptions);
|
|
43
|
+
focus(): void;
|
|
44
|
+
private changed;
|
|
45
|
+
private lastSent;
|
|
46
|
+
/** Brings the form value and validity up to date. */
|
|
47
|
+
private sync;
|
|
48
|
+
private isEmpty;
|
|
49
|
+
private onFocusIn;
|
|
50
|
+
private onFocusOut;
|
|
51
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { createEditor } from "@rathkit/rte-core/standard";
|
|
2
|
+
export class RkEditor extends HTMLElement {
|
|
3
|
+
static formAssociated = true;
|
|
4
|
+
static observedAttributes = ["value", "readonly", "disabled", "label", "required", "placeholder"];
|
|
5
|
+
internals;
|
|
6
|
+
surface;
|
|
7
|
+
current;
|
|
8
|
+
html = "";
|
|
9
|
+
defaultHtml = "";
|
|
10
|
+
opts = {};
|
|
11
|
+
stop;
|
|
12
|
+
atFocus = "";
|
|
13
|
+
resolveReady;
|
|
14
|
+
ready = new Promise((resolve) => { this.resolveReady = resolve; });
|
|
15
|
+
constructor() {
|
|
16
|
+
super();
|
|
17
|
+
this.internals = typeof this.attachInternals === "function" ? this.attachInternals() : undefined;
|
|
18
|
+
}
|
|
19
|
+
connectedCallback() {
|
|
20
|
+
if (this.current)
|
|
21
|
+
return;
|
|
22
|
+
if (this.html === "" && !this.hasAttribute("value"))
|
|
23
|
+
this.html = this.innerHTML.trim();
|
|
24
|
+
else if (this.html === "")
|
|
25
|
+
this.html = this.getAttribute("value") ?? "";
|
|
26
|
+
if (this.defaultHtml === "")
|
|
27
|
+
this.defaultHtml = this.hasAttribute("value") ? (this.getAttribute("value") ?? "") : this.html;
|
|
28
|
+
this.replaceChildren();
|
|
29
|
+
const surface = document.createElement("div");
|
|
30
|
+
surface.setAttribute("data-rk-surface", "");
|
|
31
|
+
this.appendChild(surface);
|
|
32
|
+
this.surface = surface;
|
|
33
|
+
const label = this.getAttribute("label");
|
|
34
|
+
if (label)
|
|
35
|
+
surface.setAttribute("aria-label", label);
|
|
36
|
+
else if (!this.hasAttribute("aria-label") && !this.hasAttribute("aria-labelledby"))
|
|
37
|
+
console.warn("[rte] <rk-editor> has no name: give it a label attribute.");
|
|
38
|
+
const maxLength = Number.parseInt(this.getAttribute("maxlength") ?? "", 10);
|
|
39
|
+
const spellcheck = this.getAttribute("spellcheck");
|
|
40
|
+
const editor = createEditor({
|
|
41
|
+
...this.opts, element: surface, html: this.html, readOnly: this.hasAttribute("readonly") || this.hasAttribute("disabled"),
|
|
42
|
+
...(this.hasAttribute("placeholder") ? { placeholder: this.getAttribute("placeholder") ?? "" } : {}),
|
|
43
|
+
...(Number.isFinite(maxLength) && maxLength >= 0 ? { maxLength } : {}),
|
|
44
|
+
...(spellcheck === "true" || spellcheck === "false" ? { spellcheck: spellcheck === "true" } : {}),
|
|
45
|
+
...(this.hasAttribute("autofocus") ? { autofocus: true } : {}),
|
|
46
|
+
});
|
|
47
|
+
this.current = editor;
|
|
48
|
+
this.stop = editor.subscribe(() => this.changed());
|
|
49
|
+
surface.addEventListener("focusin", this.onFocusIn);
|
|
50
|
+
surface.addEventListener("focusout", this.onFocusOut);
|
|
51
|
+
this.sync();
|
|
52
|
+
this.resolveReady?.(editor);
|
|
53
|
+
this.dispatchEvent(new CustomEvent("rk-ready", { bubbles: true, composed: true, detail: { editor } }));
|
|
54
|
+
}
|
|
55
|
+
disconnectedCallback() {
|
|
56
|
+
const editor = this.current;
|
|
57
|
+
if (!editor)
|
|
58
|
+
return;
|
|
59
|
+
this.html = editor.getHtml();
|
|
60
|
+
this.stop?.();
|
|
61
|
+
editor.destroy();
|
|
62
|
+
this.surface?.removeEventListener("focusin", this.onFocusIn);
|
|
63
|
+
this.surface?.removeEventListener("focusout", this.onFocusOut);
|
|
64
|
+
this.current = undefined;
|
|
65
|
+
this.surface = undefined;
|
|
66
|
+
this.ready = new Promise((resolve) => { this.resolveReady = resolve; });
|
|
67
|
+
}
|
|
68
|
+
attributeChangedCallback(name, _old, value) {
|
|
69
|
+
if (name === "value") {
|
|
70
|
+
if (value !== null && value !== this.value)
|
|
71
|
+
this.value = value;
|
|
72
|
+
}
|
|
73
|
+
else if (name === "readonly" || name === "disabled") {
|
|
74
|
+
this.current?.setReadOnly(this.hasAttribute("readonly") || this.hasAttribute("disabled"));
|
|
75
|
+
}
|
|
76
|
+
else if (name === "placeholder") {
|
|
77
|
+
this.current?.setPlaceholder(value ?? "");
|
|
78
|
+
}
|
|
79
|
+
else if (name === "label") {
|
|
80
|
+
if (value)
|
|
81
|
+
this.surface?.setAttribute("aria-label", value);
|
|
82
|
+
}
|
|
83
|
+
else if (name === "required") {
|
|
84
|
+
this.sync();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
formResetCallback() { this.value = this.defaultHtml; }
|
|
88
|
+
formDisabledCallback(disabled) { this.current?.setReadOnly(disabled || this.hasAttribute("readonly")); }
|
|
89
|
+
formStateRestoreCallback(state) { if (typeof state === "string")
|
|
90
|
+
this.value = state; }
|
|
91
|
+
get form() { return this.internals?.form ?? null; }
|
|
92
|
+
get name() { return this.getAttribute("name") ?? ""; }
|
|
93
|
+
set name(value) { this.setAttribute("name", value); }
|
|
94
|
+
get validity() { return this.internals?.validity; }
|
|
95
|
+
checkValidity() { return this.internals?.checkValidity() ?? true; }
|
|
96
|
+
reportValidity() { return this.internals?.reportValidity() ?? true; }
|
|
97
|
+
get value() { return this.current ? this.current.getHtml() : this.html; }
|
|
98
|
+
set value(html) {
|
|
99
|
+
this.html = html;
|
|
100
|
+
if (this.current)
|
|
101
|
+
this.current.setHtml(html);
|
|
102
|
+
else
|
|
103
|
+
this.defaultHtml ||= html;
|
|
104
|
+
this.sync();
|
|
105
|
+
}
|
|
106
|
+
get readOnly() { return this.hasAttribute("readonly"); }
|
|
107
|
+
set readOnly(value) { this.toggleAttribute("readonly", value); }
|
|
108
|
+
get editor() { return this.current; }
|
|
109
|
+
whenReady() { return this.ready; }
|
|
110
|
+
get options() { return this.opts; }
|
|
111
|
+
set options(options) {
|
|
112
|
+
if (this.current)
|
|
113
|
+
console.warn("[rte] <rk-editor> options set after it was connected have no effect.");
|
|
114
|
+
this.opts = options;
|
|
115
|
+
}
|
|
116
|
+
focus() { this.current?.focus(); }
|
|
117
|
+
changed() {
|
|
118
|
+
const html = this.value;
|
|
119
|
+
if (html === this.lastSent)
|
|
120
|
+
return;
|
|
121
|
+
this.lastSent = html;
|
|
122
|
+
this.sync();
|
|
123
|
+
this.dispatchEvent(new CustomEvent("rk-change", { bubbles: true, composed: true, detail: { html } }));
|
|
124
|
+
this.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
|
|
125
|
+
}
|
|
126
|
+
lastSent = "";
|
|
127
|
+
sync() {
|
|
128
|
+
const html = this.value;
|
|
129
|
+
this.internals?.setFormValue(html);
|
|
130
|
+
if (this.hasAttribute("required") && this.isEmpty(html))
|
|
131
|
+
this.internals?.setValidity({ valueMissing: true }, "Please fill in this field.", this.surface);
|
|
132
|
+
else
|
|
133
|
+
this.internals?.setValidity({});
|
|
134
|
+
}
|
|
135
|
+
isEmpty(html) { return html.replace(/<[^>]*>/g, "").replace(/ /g, "").trim() === "" && !html.includes("<img"); }
|
|
136
|
+
onFocusIn = () => { this.atFocus = this.value; };
|
|
137
|
+
onFocusOut = () => { if (this.value !== this.atFocus)
|
|
138
|
+
this.dispatchEvent(new Event("change", { bubbles: true })); };
|
|
139
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { RkEditor, type RkEditorOptions } from "./editor-element.ts";
|
|
2
|
+
import { RkToolbar } from "./toolbar-element.ts";
|
|
3
|
+
export { RkEditor, RkToolbar, type RkEditorOptions };
|
|
4
|
+
/** Registers the elements. Safe to call more than once. */
|
|
5
|
+
export declare function define(names?: {
|
|
6
|
+
readonly editor?: string;
|
|
7
|
+
readonly toolbar?: string;
|
|
8
|
+
}): void;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RkEditor } from "./editor-element.js";
|
|
2
|
+
import { RkToolbar } from "./toolbar-element.js";
|
|
3
|
+
export { RkEditor, RkToolbar };
|
|
4
|
+
export function define(names = {}) {
|
|
5
|
+
const editor = names.editor ?? "rk-editor";
|
|
6
|
+
const toolbar = names.toolbar ?? "rk-toolbar";
|
|
7
|
+
if (!customElements.get(editor))
|
|
8
|
+
customElements.define(editor, RkEditor);
|
|
9
|
+
if (!customElements.get(toolbar))
|
|
10
|
+
customElements.define(toolbar, RkToolbar);
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class RkToolbar extends HTMLElement {
|
|
2
|
+
static observedAttributes: string[];
|
|
3
|
+
private toolbar;
|
|
4
|
+
private unbind;
|
|
5
|
+
private unwatch;
|
|
6
|
+
private building;
|
|
7
|
+
connectedCallback(): void;
|
|
8
|
+
disconnectedCallback(): void;
|
|
9
|
+
attributeChangedCallback(): void;
|
|
10
|
+
/** The editor this toolbar belongs to: the element named by `for`, else the nearest <rk-editor> beside or around it. */
|
|
11
|
+
private target;
|
|
12
|
+
private teardown;
|
|
13
|
+
private build;
|
|
14
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createToolbar } from "@rathkit/rte-headless";
|
|
2
|
+
export class RkToolbar extends HTMLElement {
|
|
3
|
+
static observedAttributes = ["for", "label", "slot-name"];
|
|
4
|
+
toolbar;
|
|
5
|
+
unbind;
|
|
6
|
+
unwatch;
|
|
7
|
+
building = 0;
|
|
8
|
+
connectedCallback() { void this.build(); }
|
|
9
|
+
disconnectedCallback() { this.teardown(); }
|
|
10
|
+
attributeChangedCallback() { if (this.isConnected)
|
|
11
|
+
void this.build(); }
|
|
12
|
+
target() {
|
|
13
|
+
const id = this.getAttribute("for");
|
|
14
|
+
if (id)
|
|
15
|
+
return this.ownerDocument.getElementById(id);
|
|
16
|
+
return (this.parentElement?.querySelector("rk-editor") ?? this.closest("rk-editor"));
|
|
17
|
+
}
|
|
18
|
+
teardown() {
|
|
19
|
+
this.unwatch?.();
|
|
20
|
+
this.unbind?.();
|
|
21
|
+
this.toolbar?.destroy();
|
|
22
|
+
this.toolbar = undefined;
|
|
23
|
+
}
|
|
24
|
+
async build() {
|
|
25
|
+
const ticket = ++this.building;
|
|
26
|
+
this.teardown();
|
|
27
|
+
const host = this.target();
|
|
28
|
+
if (!host)
|
|
29
|
+
return;
|
|
30
|
+
await customElements.whenDefined("rk-editor");
|
|
31
|
+
const editor = await host.whenReady();
|
|
32
|
+
if (ticket !== this.building || !this.isConnected)
|
|
33
|
+
return;
|
|
34
|
+
const toolbar = createToolbar(editor, { label: this.getAttribute("label") ?? "Formatting", slot: this.getAttribute("slot-name") ?? "toolbar.main" });
|
|
35
|
+
this.toolbar = toolbar;
|
|
36
|
+
const draw = () => {
|
|
37
|
+
this.unbind?.();
|
|
38
|
+
const controls = [];
|
|
39
|
+
for (const item of toolbar.items) {
|
|
40
|
+
if (item.kind === "separator") {
|
|
41
|
+
const s = document.createElement("span");
|
|
42
|
+
s.setAttribute("role", "separator");
|
|
43
|
+
controls.push(s);
|
|
44
|
+
}
|
|
45
|
+
else if (item.kind === "select") {
|
|
46
|
+
const select = document.createElement("select");
|
|
47
|
+
select.setAttribute("data-rk-item", item.id);
|
|
48
|
+
for (const o of item.options) {
|
|
49
|
+
const option = document.createElement("option");
|
|
50
|
+
option.value = String(o.value);
|
|
51
|
+
option.textContent = o.label;
|
|
52
|
+
select.appendChild(option);
|
|
53
|
+
}
|
|
54
|
+
controls.push(select);
|
|
55
|
+
}
|
|
56
|
+
else if (item.kind !== "menu") {
|
|
57
|
+
const button = document.createElement("button");
|
|
58
|
+
button.type = "button";
|
|
59
|
+
button.setAttribute("data-rk-item", item.id);
|
|
60
|
+
button.textContent = toolbar.state(item.id)?.label ?? item.id;
|
|
61
|
+
controls.push(button);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
this.replaceChildren(...controls);
|
|
65
|
+
this.unbind = toolbar.bind(this, { onOpen: (item, control) => this.dispatchEvent(new CustomEvent("rk-open", { bubbles: true, composed: true, detail: { item, control } })) });
|
|
66
|
+
};
|
|
67
|
+
draw();
|
|
68
|
+
this.unwatch = editor.ui.subscribe(this.getAttribute("slot-name") ?? "toolbar.main", draw);
|
|
69
|
+
}
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rathkit/rte-element",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
|
+
"description": "The editor as a custom element, <rk-editor>, for any page or framework: form-associated, with properties, attributes and events.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"rich-text",
|
|
7
|
+
"editor",
|
|
8
|
+
"wysiwyg",
|
|
9
|
+
"contenteditable",
|
|
10
|
+
"zero-dependencies",
|
|
11
|
+
"typescript",
|
|
12
|
+
"web-components",
|
|
13
|
+
"custom-element"
|
|
14
|
+
],
|
|
5
15
|
"license": "Apache-2.0",
|
|
6
16
|
"homepage": "https://rathkit.com",
|
|
7
17
|
"repository": {
|
|
@@ -12,7 +22,61 @@
|
|
|
12
22
|
"bugs": {
|
|
13
23
|
"url": "https://github.com/rathkit/rte/issues"
|
|
14
24
|
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"sideEffects": [
|
|
27
|
+
"./dist/define.js"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22.14.0"
|
|
31
|
+
},
|
|
15
32
|
"publishConfig": {
|
|
16
|
-
"access": "public"
|
|
33
|
+
"access": "public",
|
|
34
|
+
"provenance": true,
|
|
35
|
+
"tag": "next"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"NOTICE",
|
|
40
|
+
"!dist/**/*.map"
|
|
41
|
+
],
|
|
42
|
+
"exports": {
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./dist/index.d.ts",
|
|
45
|
+
"default": "./dist/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./define": {
|
|
48
|
+
"types": "./dist/define.d.ts",
|
|
49
|
+
"default": "./dist/define.js"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@rathkit/rte-core": ">=0.1.0-alpha.3 <0.2.0",
|
|
54
|
+
"@rathkit/rte-headless": ">=0.1.0-alpha.3 <0.2.0"
|
|
55
|
+
},
|
|
56
|
+
"peerDependenciesMeta": {
|
|
57
|
+
"@rathkit/rte-core": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"@rathkit/rte-headless": {
|
|
61
|
+
"optional": true
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@rathkit/rte-core": "workspace:*",
|
|
66
|
+
"@rathkit/rte-headless": "workspace:*"
|
|
67
|
+
},
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && tsc -p tsconfig.build.js.json",
|
|
70
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
71
|
+
"test": "node -e \"process.exit(0)\""
|
|
72
|
+
},
|
|
73
|
+
"rathkit": {
|
|
74
|
+
"budgets": [
|
|
75
|
+
{
|
|
76
|
+
"name": "element",
|
|
77
|
+
"entry": "dist/index.js",
|
|
78
|
+
"gzipKB": 4
|
|
79
|
+
}
|
|
80
|
+
]
|
|
17
81
|
}
|
|
18
82
|
}
|