tutuca 0.15.0 → 1.0.0-beta.2
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/CHANGELOG.md +132 -0
- package/LICENSE +1 -1
- package/README.md +64 -170
- package/{dist → deps}/immer.js +674 -249
- package/dist/tutuca.js +2342 -4057
- package/dist/tutuca.min.js +3 -3
- package/package.json +78 -96
- package/src/component.js +66 -0
- package/src/css/classes.js +77 -0
- package/src/dev/formatters.js +393 -0
- package/src/dev/jsonml.js +35 -0
- package/src/dev/panel.js +400 -0
- package/src/dev/summary.js +239 -0
- package/src/dev/vdom-formatters.js +102 -0
- package/src/drag.js +23 -0
- package/src/embed/element.js +111 -0
- package/src/env.js +30 -0
- package/src/events.js +85 -0
- package/src/history/bar.js +198 -0
- package/src/history/index.js +149 -0
- package/src/host.js +360 -0
- package/src/lint/index.js +470 -0
- package/src/meta.js +12 -0
- package/src/optimize.js +58 -0
- package/src/paths.js +205 -0
- package/src/playground/element.js +360 -0
- package/src/playground/index.js +5 -0
- package/src/playground/sources.js +107 -0
- package/src/playground/ui/playground.js +287 -0
- package/src/schema.js +460 -0
- package/src/scope.js +92 -0
- package/src/storybook/index.js +80 -0
- package/src/storybook/runner.js +452 -0
- package/src/storybook/stories.js +208 -0
- package/src/storybook/stress.js +76 -0
- package/src/storybook/ui/common.js +37 -0
- package/src/storybook/ui/link.js +80 -0
- package/src/storybook/ui/panels.js +32 -0
- package/src/storybook/ui/story-panel.js +432 -0
- package/src/storybook/ui/storybook.js +191 -0
- package/src/storybook/ui/stress-panel.js +231 -0
- package/src/sync/automerge.js +159 -0
- package/src/sync/codec.js +206 -0
- package/src/sync/diff.js +153 -0
- package/src/sync/index.js +97 -0
- package/src/sync/migrate.js +184 -0
- package/src/sync/ops.js +160 -0
- package/src/sync/remote.js +206 -0
- package/src/tag.js +24 -0
- package/src/tasks.js +244 -0
- package/src/test/driver.js +141 -0
- package/src/test/pbt.js +589 -0
- package/src/tutuca.js +66 -0
- package/src/vdom.js +349 -0
- package/src/view.js +354 -0
- package/src/walk.js +79 -0
- package/dist/chai.js +0 -4210
- package/dist/tutuca-cli.js +0 -16315
- package/dist/tutuca-components.js +0 -2232
- package/dist/tutuca-dev.ext.js +0 -8476
- package/dist/tutuca-dev.js +0 -13220
- package/dist/tutuca-dev.min.js +0 -5
- package/dist/tutuca-extra.ext.js +0 -4261
- package/dist/tutuca-extra.js +0 -4964
- package/dist/tutuca-extra.min.js +0 -3
- package/dist/tutuca-storybook.js +0 -970
- package/dist/tutuca.ext.js +0 -4183
- package/skill/margaui/SKILL.md +0 -105
- package/skill/margaui/components/accordion.md +0 -127
- package/skill/margaui/components/alert.md +0 -174
- package/skill/margaui/components/aura.md +0 -97
- package/skill/margaui/components/avatar.md +0 -220
- package/skill/margaui/components/badge.md +0 -193
- package/skill/margaui/components/breadcrumbs.md +0 -103
- package/skill/margaui/components/button.md +0 -322
- package/skill/margaui/components/calendar.md +0 -67
- package/skill/margaui/components/card.md +0 -373
- package/skill/margaui/components/carousel.md +0 -387
- package/skill/margaui/components/chat.md +0 -171
- package/skill/margaui/components/checkbox.md +0 -101
- package/skill/margaui/components/collapse.md +0 -172
- package/skill/margaui/components/countdown.md +0 -165
- package/skill/margaui/components/diff.md +0 -53
- package/skill/margaui/components/divider.md +0 -107
- package/skill/margaui/components/dock.md +0 -173
- package/skill/margaui/components/drawer.md +0 -184
- package/skill/margaui/components/dropdown.md +0 -388
- package/skill/margaui/components/fab.md +0 -346
- package/skill/margaui/components/fieldset.md +0 -88
- package/skill/margaui/components/file-input.md +0 -84
- package/skill/margaui/components/filter.md +0 -52
- package/skill/margaui/components/footer.md +0 -583
- package/skill/margaui/components/hero.md +0 -135
- package/skill/margaui/components/hover-3d.md +0 -129
- package/skill/margaui/components/hover-gallery.md +0 -49
- package/skill/margaui/components/indicator.md +0 -265
- package/skill/margaui/components/input.md +0 -389
- package/skill/margaui/components/join.md +0 -100
- package/skill/margaui/components/kbd.md +0 -127
- package/skill/margaui/components/label.md +0 -102
- package/skill/margaui/components/link.md +0 -96
- package/skill/margaui/components/list.md +0 -182
- package/skill/margaui/components/loading.md +0 -105
- package/skill/margaui/components/mask.md +0 -168
- package/skill/margaui/components/megamenu.md +0 -131
- package/skill/margaui/components/menu.md +0 -887
- package/skill/margaui/components/mockup-browser.md +0 -39
- package/skill/margaui/components/mockup-code.md +0 -81
- package/skill/margaui/components/mockup-phone.md +0 -39
- package/skill/margaui/components/mockup-window.md +0 -33
- package/skill/margaui/components/modal.md +0 -196
- package/skill/margaui/components/navbar.md +0 -282
- package/skill/margaui/components/otp.md +0 -171
- package/skill/margaui/components/pagination.md +0 -122
- package/skill/margaui/components/progress.md +0 -135
- package/skill/margaui/components/radial-progress.md +0 -67
- package/skill/margaui/components/radio.md +0 -133
- package/skill/margaui/components/range.md +0 -134
- package/skill/margaui/components/rating.md +0 -170
- package/skill/margaui/components/select.md +0 -225
- package/skill/margaui/components/skeleton.md +0 -64
- package/skill/margaui/components/stack.md +0 -142
- package/skill/margaui/components/stat.md +0 -254
- package/skill/margaui/components/status.md +0 -73
- package/skill/margaui/components/steps.md +0 -138
- package/skill/margaui/components/swap.md +0 -152
- package/skill/margaui/components/tab.md +0 -248
- package/skill/margaui/components/table.md +0 -1018
- package/skill/margaui/components/text-rotate.md +0 -91
- package/skill/margaui/components/textarea.md +0 -85
- package/skill/margaui/components/theme-controller.md +0 -266
- package/skill/margaui/components/timeline.md +0 -1356
- package/skill/margaui/components/toast.md +0 -165
- package/skill/margaui/components/toggle.md +0 -135
- package/skill/margaui/components/tooltip.md +0 -181
- package/skill/margaui/components/validator.md +0 -163
- package/skill/tutuca/SKILL.md +0 -56
- package/skill/tutuca/advanced.md +0 -292
- package/skill/tutuca/cli.md +0 -239
- package/skill/tutuca/component-design.md +0 -168
- package/skill/tutuca/core.md +0 -935
- package/skill/tutuca/iteration.md +0 -207
- package/skill/tutuca/macros.md +0 -86
- package/skill/tutuca/margaui.md +0 -175
- package/skill/tutuca/messages-and-intents.md +0 -414
- package/skill/tutuca/patterns/README.md +0 -48
- package/skill/tutuca/patterns/add-a-story.md +0 -26
- package/skill/tutuca/patterns/bind-text-and-attributes.md +0 -30
- package/skill/tutuca/patterns/conditional-attribute-value.md +0 -29
- package/skill/tutuca/patterns/coordinate-components.md +0 -54
- package/skill/tutuca/patterns/edit-through-a-dynamic-target.md +0 -32
- package/skill/tutuca/patterns/enrich-each-item.md +0 -25
- package/skill/tutuca/patterns/file-input.md +0 -39
- package/skill/tutuca/patterns/filter-a-list.md +0 -25
- package/skill/tutuca/patterns/filter-and-paginate.md +0 -60
- package/skill/tutuca/patterns/handle-events.md +0 -45
- package/skill/tutuca/patterns/iterate-a-list.md +0 -18
- package/skill/tutuca/patterns/paginate-a-list.md +0 -29
- package/skill/tutuca/patterns/render-a-child-component.md +0 -21
- package/skill/tutuca/patterns/reuse-markup-with-macros.md +0 -36
- package/skill/tutuca/patterns/share-state-across-the-tree.md +0 -53
- package/skill/tutuca/patterns/show-or-hide-content.md +0 -23
- package/skill/tutuca/patterns/switch-between-views.md +0 -30
- package/skill/tutuca/patterns/tabbed-interface.md +0 -43
- package/skill/tutuca/semantics.md +0 -219
- package/skill/tutuca/storybook.md +0 -270
- package/skill/tutuca/styles.md +0 -48
- package/skill/tutuca/testing.md +0 -345
- package/skill/tutuca-source/SKILL.md +0 -33
- package/skill/tutuca-source/tutuca.ext.js +0 -4183
package/package.json
CHANGED
|
@@ -1,98 +1,80 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
},
|
|
81
|
-
"engines": {
|
|
82
|
-
"node": ">=18"
|
|
83
|
-
},
|
|
84
|
-
"author": "Mariano Guerra",
|
|
85
|
-
"license": "MIT",
|
|
86
|
-
"bugs": {
|
|
87
|
-
"url": "https://github.com/marianoguerra/tutuca/issues"
|
|
88
|
-
},
|
|
89
|
-
"homepage": "https://github.com/marianoguerra/tutuca#readme",
|
|
90
|
-
"devDependencies": {
|
|
91
|
-
"@biomejs/biome": "^2.5.1",
|
|
92
|
-
"chai": "^6.2.2",
|
|
93
|
-
"esbuild": "^0.28.1",
|
|
94
|
-
"fast-check": "^4.8.0",
|
|
95
|
-
"htmlparser2": "^12.0.0",
|
|
96
|
-
"vitest": "^4.1.10"
|
|
97
|
-
}
|
|
2
|
+
"name": "tutuca",
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
|
+
"description": "A small framework for web apps in the browser, with typed state, tests, a storybook and pluggable sync",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Mariano Guerra",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/marianoguerra/tutuca.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://marianoguerra.github.io/tutuca/",
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"exports": {
|
|
18
|
+
".": "./src/tutuca.js",
|
|
19
|
+
"./vdom": "./src/vdom.js",
|
|
20
|
+
"./dev": "./src/dev/formatters.js",
|
|
21
|
+
"./lint": "./src/lint/index.js",
|
|
22
|
+
"./classes": "./src/css/classes.js",
|
|
23
|
+
"./pbt": "./src/test/pbt.js",
|
|
24
|
+
"./storybook": "./src/storybook/index.js",
|
|
25
|
+
"./element": "./src/embed/element.js",
|
|
26
|
+
"./playground": "./src/playground/index.js",
|
|
27
|
+
"./history": "./src/history/index.js",
|
|
28
|
+
"./history/bar": "./src/history/bar.js",
|
|
29
|
+
"./sync": "./src/sync/index.js",
|
|
30
|
+
"./sync/remote": "./src/sync/remote.js",
|
|
31
|
+
"./automerge": "./src/sync/automerge.js",
|
|
32
|
+
"./package.json": "./package.json"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"src/",
|
|
36
|
+
"deps/",
|
|
37
|
+
"dist/",
|
|
38
|
+
"README.md",
|
|
39
|
+
"CHANGELOG.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"test": "node --test test/*/*.test.js",
|
|
44
|
+
"lint": "biome check .",
|
|
45
|
+
"fmt": "biome check --write .",
|
|
46
|
+
"dist": "node scripts/dist.js",
|
|
47
|
+
"smoke": "node scripts/smoke.js",
|
|
48
|
+
"prepublishOnly": "npm run lint && npm test && npm run dist && npm run smoke"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"@automerge/automerge": "^3",
|
|
52
|
+
"fast-check": "^4"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"fast-check": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"@automerge/automerge": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@automerge/automerge": "^3.5.0",
|
|
64
|
+
"@automerge/automerge-repo": "^2.6.0-alpha.3",
|
|
65
|
+
"@automerge/automerge-repo-network-broadcastchannel": "^2.6.0-alpha.3",
|
|
66
|
+
"@automerge/automerge-repo-network-websocket": "^2.6.0-alpha.3",
|
|
67
|
+
"@automerge/automerge-repo-storage-indexeddb": "^2.6.0-alpha.3",
|
|
68
|
+
"@biomejs/biome": "^2.5.15",
|
|
69
|
+
"@codemirror/lang-javascript": "^6.2.5",
|
|
70
|
+
"@codemirror/theme-one-dark": "^6.1.3",
|
|
71
|
+
"acorn": "^8.19.0",
|
|
72
|
+
"acorn-walk": "^8.3.5",
|
|
73
|
+
"codemirror": "^6.0.2",
|
|
74
|
+
"esbuild": "^0.28.2",
|
|
75
|
+
"fast-check": "^4.10.2",
|
|
76
|
+
"immer": "11.1.21",
|
|
77
|
+
"jsdom": "^30.1.3",
|
|
78
|
+
"margaui": "^0.5750.1"
|
|
79
|
+
}
|
|
98
80
|
}
|
package/src/component.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Component specs: component() turns options into a ComponentSpec that makes instances.
|
|
2
|
+
import { immerable } from "../deps/immer.js";
|
|
3
|
+
import { DRAG_EVENTS } from "./drag.js";
|
|
4
|
+
import { idSym, NoDefaultError, scopeSym, specSym, toAnswers, toMessages } from "./schema.js";
|
|
5
|
+
import { toExpr } from "./view.js";
|
|
6
|
+
import { Collect } from "./walk.js";
|
|
7
|
+
|
|
8
|
+
let nextId = 1;
|
|
9
|
+
export class ComponentSpec {
|
|
10
|
+
constructor({ name, fields, methods, views, on, answers, loops, scopes, provides, invariants }) {
|
|
11
|
+
this.name = name;
|
|
12
|
+
this.fields = fields;
|
|
13
|
+
this.methods = methods;
|
|
14
|
+
// Copy descriptors, not values, so getters in methods stay getters.
|
|
15
|
+
this.proto = Object.create(null, Object.getOwnPropertyDescriptors(methods));
|
|
16
|
+
Object.assign(this.proto, { [immerable]: true, [specSym]: this });
|
|
17
|
+
this.views = views;
|
|
18
|
+
this.on = on;
|
|
19
|
+
this.answers = answers; // ask name -> outcome (ok, error, unhandled) -> its handler.
|
|
20
|
+
this.loops = loops;
|
|
21
|
+
this.scopes = scopes;
|
|
22
|
+
this.provides = provides;
|
|
23
|
+
this.invariants = invariants; // name → predicate on the instance, checked in dev and tests.
|
|
24
|
+
const collect = new Collect();
|
|
25
|
+
for (const key in views) collect.visit(views[key]);
|
|
26
|
+
this.eventHandlers = collect.eventHandlers;
|
|
27
|
+
this.eventNames = new Set([...this.eventHandlers.values()].flat().map((h) => h.name));
|
|
28
|
+
// A drop target needs the drag from its start: the host tracks it.
|
|
29
|
+
if (this.eventNames.has("drop")) for (const name of DRAG_EVENTS) this.eventNames.add(name);
|
|
30
|
+
}
|
|
31
|
+
make(args = {}, scope = null) {
|
|
32
|
+
const state = Object.create(this.proto);
|
|
33
|
+
state[idSym] = nextId++;
|
|
34
|
+
if (scope !== null) state[scopeSym] = scope;
|
|
35
|
+
for (const key in this.fields) {
|
|
36
|
+
try {
|
|
37
|
+
state[key] = this.fields[key].make(args[key], scope, state);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// Prefix the field, so nested failures read as a path: Root.child: Child.item: ...
|
|
40
|
+
const Wrapped = error instanceof NoDefaultError ? NoDefaultError : Error;
|
|
41
|
+
throw new Wrapped(`${this.name}.${key}: ${error.message}`, { cause: error });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return state;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const ownEntries = (record) => Object.assign(Object.create(null), record); // no toString &c in entries
|
|
48
|
+
export const component = (opts) => {
|
|
49
|
+
const { name, fields = {}, methods = {}, view, views = {} } = opts;
|
|
50
|
+
const sources = view === undefined ? views : { ...views, main: view };
|
|
51
|
+
const exprs = ownEntries({});
|
|
52
|
+
for (const key in sources) exprs[key] = toExpr(sources[key]);
|
|
53
|
+
if (!("main" in exprs)) throw new Error(`Component ${name} has no main view`);
|
|
54
|
+
return new ComponentSpec({
|
|
55
|
+
name,
|
|
56
|
+
fields,
|
|
57
|
+
methods,
|
|
58
|
+
views: exprs,
|
|
59
|
+
on: toMessages(opts.on),
|
|
60
|
+
answers: toAnswers(opts.answers),
|
|
61
|
+
loops: ownEntries(opts.loops),
|
|
62
|
+
scopes: ownEntries(opts.scopes),
|
|
63
|
+
provides: ownEntries(opts.provides),
|
|
64
|
+
invariants: ownEntries(opts.invariants),
|
|
65
|
+
});
|
|
66
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Class names for CSS compilers that need them listed: the constant ones a view tree holds, and
|
|
2
|
+
// the computed ones as they show up in the DOM.
|
|
3
|
+
import { Walker } from "../tutuca.js";
|
|
4
|
+
|
|
5
|
+
// Constants are class names only while inside a class attribute.
|
|
6
|
+
class ClassNames extends Walker {
|
|
7
|
+
inClass = false;
|
|
8
|
+
constructor(classes) {
|
|
9
|
+
super();
|
|
10
|
+
this.classes = classes;
|
|
11
|
+
}
|
|
12
|
+
attr(node, name, value) {
|
|
13
|
+
const outer = this.inClass;
|
|
14
|
+
this.inClass = name === "class";
|
|
15
|
+
super.attr(node, name, value);
|
|
16
|
+
this.inClass = outer;
|
|
17
|
+
}
|
|
18
|
+
constant(node) {
|
|
19
|
+
if (!this.inClass || typeof node.value !== "string") return;
|
|
20
|
+
for (const c of node.value.split(/\s+/)) if (c) this.classes.add(c);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// The constant class names in a tree, including every $if branch; classes
|
|
25
|
+
// read from the state are only known at render time.
|
|
26
|
+
export const collectClasses = (tree, classes = new Set()) => {
|
|
27
|
+
new ClassNames(classes).visit(tree);
|
|
28
|
+
return classes;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// The class names the components use: the constant ones in views and those loops bind.
|
|
32
|
+
export const classNamesOf = (specs, extra = []) => {
|
|
33
|
+
const classes = new Set(extra.flatMap((c) => c.split(/\s+/)));
|
|
34
|
+
for (const spec of specs)
|
|
35
|
+
for (const name in spec.views) collectClasses(spec.views[name], classes);
|
|
36
|
+
return [...classes].filter(Boolean);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Compiles the class names stories render that the static css lacks: views can compute
|
|
40
|
+
// classes in methods and loops, which collectClasses can't see. compile(classes) → css.
|
|
41
|
+
export class ClassCompiler {
|
|
42
|
+
constructor(compile, known = []) {
|
|
43
|
+
this.compile = compile;
|
|
44
|
+
this.seen = new Set(known);
|
|
45
|
+
this.styles = new Set();
|
|
46
|
+
this.css = "";
|
|
47
|
+
this.queued = false;
|
|
48
|
+
}
|
|
49
|
+
watch(rootNode, style) {
|
|
50
|
+
this.styles.add(style);
|
|
51
|
+
style.textContent = this.css;
|
|
52
|
+
this.scan(rootNode);
|
|
53
|
+
}
|
|
54
|
+
scan(rootNode) {
|
|
55
|
+
let added = false;
|
|
56
|
+
for (const el of rootNode.querySelectorAll("[class]")) {
|
|
57
|
+
for (const c of el.getAttribute("class").split(/\s+/)) {
|
|
58
|
+
if (c !== "" && !this.seen.has(c)) {
|
|
59
|
+
this.seen.add(c);
|
|
60
|
+
added = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (added && !this.queued) {
|
|
65
|
+
this.queued = true;
|
|
66
|
+
queueMicrotask(() => this.update());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async update() {
|
|
70
|
+
this.queued = false;
|
|
71
|
+
this.css = await this.compile([...this.seen]);
|
|
72
|
+
for (const style of this.styles) {
|
|
73
|
+
if (style.isConnected) style.textContent = this.css;
|
|
74
|
+
else this.styles.delete(style);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|