@spearwolf/shadow-objects 0.33.0 → 0.35.0
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 +350 -61
- package/README.md +66 -13
- package/bundle.js +6 -53
- package/package.json +15 -3
- package/src/ChangeTrailRefusedError.d.ts +27 -0
- package/src/ChangeTrailRefusedError.d.ts.map +1 -0
- package/src/ChangeTrailRefusedError.js +12 -0
- package/src/ChangeTrailRefusedError.js.map +7 -0
- package/src/EntityUuidInUseError.d.ts +19 -0
- package/src/EntityUuidInUseError.d.ts.map +1 -0
- package/src/EntityUuidInUseError.js +11 -0
- package/src/EntityUuidInUseError.js.map +7 -0
- package/src/WorkerTimeoutError.d.ts +26 -0
- package/src/WorkerTimeoutError.d.ts.map +1 -0
- package/src/WorkerTimeoutError.js +12 -0
- package/src/WorkerTimeoutError.js.map +7 -0
- package/src/bundle.d.ts +1 -1
- package/src/bundle.d.ts.map +1 -1
- package/src/bundle.js +1 -1
- package/src/bundle.js.map +2 -2
- package/src/constants.d.ts +13 -2
- package/src/constants.d.ts.map +1 -1
- package/src/constants.js +7 -1
- package/src/constants.js.map +2 -2
- package/src/create-worker.bundle.d.ts +1 -1
- package/src/create-worker.bundle.d.ts.map +1 -1
- package/src/create-worker.bundle.js.map +1 -1
- package/src/create-worker.d.ts +1 -1
- package/src/create-worker.d.ts.map +1 -1
- package/src/create-worker.js.map +1 -1
- package/src/elements/ShaeElement.d.ts +70 -2
- package/src/elements/ShaeElement.d.ts.map +1 -1
- package/src/elements/ShaeElement.js +129 -25
- package/src/elements/ShaeElement.js.map +3 -3
- package/src/elements/ShaeEntElement.d.ts +39 -1
- package/src/elements/ShaeEntElement.d.ts.map +1 -1
- package/src/elements/ShaeEntElement.js +397 -167
- package/src/elements/ShaeEntElement.js.map +2 -2
- package/src/elements/ShaeLifecycleElement.d.ts +71 -0
- package/src/elements/ShaeLifecycleElement.d.ts.map +1 -0
- package/src/elements/ShaeLifecycleElement.js +83 -0
- package/src/elements/ShaeLifecycleElement.js.map +7 -0
- package/src/elements/ShaePropElement.d.ts +61 -2
- package/src/elements/ShaePropElement.d.ts.map +1 -1
- package/src/elements/ShaePropElement.js +264 -219
- package/src/elements/ShaePropElement.js.map +2 -2
- package/src/elements/ShaeWorkerElement.d.ts +59 -5
- package/src/elements/ShaeWorkerElement.d.ts.map +1 -1
- package/src/elements/ShaeWorkerElement.js +271 -73
- package/src/elements/ShaeWorkerElement.js.map +2 -2
- package/src/elements/constants.d.ts +9 -0
- package/src/elements/constants.d.ts.map +1 -1
- package/src/elements/constants.js +18 -0
- package/src/elements/constants.js.map +2 -2
- package/src/elements/deferredTeardown.d.ts +24 -0
- package/src/elements/deferredTeardown.d.ts.map +1 -0
- package/src/elements/deferredTeardown.js +30 -0
- package/src/elements/deferredTeardown.js.map +7 -0
- package/src/elements/displayContentsRule.d.ts +25 -0
- package/src/elements/displayContentsRule.d.ts.map +1 -0
- package/src/elements/displayContentsRule.js +37 -0
- package/src/elements/displayContentsRule.js.map +7 -0
- package/src/elements/events.d.ts +10 -7
- package/src/elements/events.d.ts.map +1 -1
- package/src/elements/forwardCustomEvents.d.ts +19 -0
- package/src/elements/forwardCustomEvents.d.ts.map +1 -0
- package/src/elements/forwardCustomEvents.js +47 -0
- package/src/elements/forwardCustomEvents.js.map +7 -0
- package/src/elements/hostedSlots.d.ts +36 -0
- package/src/elements/hostedSlots.d.ts.map +1 -0
- package/src/elements/hostedSlots.js +118 -0
- package/src/elements/hostedSlots.js.map +7 -0
- package/src/elements/parentRemoval.d.ts +18 -0
- package/src/elements/parentRemoval.d.ts.map +1 -0
- package/src/elements/parentRemoval.js +60 -0
- package/src/elements/parentRemoval.js.map +7 -0
- package/src/elements/propValueConverters.d.ts +3 -0
- package/src/elements/propValueConverters.d.ts.map +1 -0
- package/src/elements/propValueConverters.js +54 -0
- package/src/elements/propValueConverters.js.map +7 -0
- package/src/elements/requestEntAncestor.d.ts +32 -0
- package/src/elements/requestEntAncestor.d.ts.map +1 -0
- package/src/elements/requestEntAncestor.js +16 -0
- package/src/elements/requestEntAncestor.js.map +7 -0
- package/src/elements.js.map +1 -1
- package/src/in-the-dark/Entity.d.ts +143 -3
- package/src/in-the-dark/Entity.d.ts.map +1 -1
- package/src/in-the-dark/Entity.js +330 -63
- package/src/in-the-dark/Entity.js.map +3 -3
- package/src/in-the-dark/Kernel.d.ts +98 -16
- package/src/in-the-dark/Kernel.d.ts.map +1 -1
- package/src/in-the-dark/Kernel.js +466 -379
- package/src/in-the-dark/Kernel.js.map +3 -3
- package/src/in-the-dark/Registry.d.ts +7 -1
- package/src/in-the-dark/Registry.d.ts.map +1 -1
- package/src/in-the-dark/Registry.js +112 -14
- package/src/in-the-dark/Registry.js.map +2 -2
- package/src/in-the-dark/ShadowObject.d.ts.map +1 -1
- package/src/in-the-dark/ShadowObject.js +1 -0
- package/src/in-the-dark/ShadowObject.js.map +2 -2
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts +133 -0
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts.map +1 -0
- package/src/in-the-dark/ShadowObjectCreationScope.js +603 -0
- package/src/in-the-dark/ShadowObjectCreationScope.js.map +7 -0
- package/src/in-the-dark/SignalsPath.d.ts +2 -0
- package/src/in-the-dark/SignalsPath.d.ts.map +1 -1
- package/src/in-the-dark/SignalsPath.js +6 -2
- package/src/in-the-dark/SignalsPath.js.map +2 -2
- package/src/in-the-dark/displayName.d.ts +4 -0
- package/src/in-the-dark/displayName.d.ts.map +1 -0
- package/src/in-the-dark/displayName.js +5 -0
- package/src/in-the-dark/displayName.js.map +7 -0
- package/src/in-the-dark/events.js.map +1 -1
- package/src/in-the-dark/importModule.d.ts +7 -0
- package/src/in-the-dark/importModule.d.ts.map +1 -1
- package/src/in-the-dark/importModule.js +5 -2
- package/src/in-the-dark/importModule.js.map +2 -2
- package/src/index.d.ts +9 -1
- package/src/index.d.ts.map +1 -1
- package/src/index.js +9 -1
- package/src/index.js.map +2 -2
- package/src/inspect/createKernelSnapshot.d.ts +17 -0
- package/src/inspect/createKernelSnapshot.d.ts.map +1 -0
- package/src/inspect/createKernelSnapshot.js +247 -0
- package/src/inspect/createKernelSnapshot.js.map +7 -0
- package/src/inspect/createViewSnapshot.d.ts +10 -0
- package/src/inspect/createViewSnapshot.d.ts.map +1 -0
- package/src/inspect/createViewSnapshot.js +143 -0
- package/src/inspect/createViewSnapshot.js.map +7 -0
- package/src/inspect/normalizeInspectRequest.d.ts +32 -0
- package/src/inspect/normalizeInspectRequest.d.ts.map +1 -0
- package/src/inspect/normalizeInspectRequest.js +55 -0
- package/src/inspect/normalizeInspectRequest.js.map +7 -0
- package/src/inspect/serializeValue.d.ts +13 -0
- package/src/inspect/serializeValue.d.ts.map +1 -0
- package/src/inspect/serializeValue.js +149 -0
- package/src/inspect/serializeValue.js.map +7 -0
- package/src/inspect/types.d.ts +260 -0
- package/src/inspect/types.d.ts.map +1 -0
- package/src/inspect/types.js +1 -0
- package/src/inspect/types.js.map +7 -0
- package/src/model-context/ModelContextLike.d.ts +59 -0
- package/src/model-context/ModelContextLike.d.ts.map +1 -0
- package/src/model-context/ModelContextLike.js +15 -0
- package/src/model-context/ModelContextLike.js.map +7 -0
- package/src/model-context/exposeShadowEnvsToModelContext.d.ts +48 -0
- package/src/model-context/exposeShadowEnvsToModelContext.d.ts.map +1 -0
- package/src/model-context/exposeShadowEnvsToModelContext.js +39 -0
- package/src/model-context/exposeShadowEnvsToModelContext.js.map +7 -0
- package/src/model-context/redactProps.d.ts +14 -0
- package/src/model-context/redactProps.d.ts.map +1 -0
- package/src/model-context/redactProps.js +22 -0
- package/src/model-context/redactProps.js.map +7 -0
- package/src/model-context/sharedExposure.d.ts +32 -0
- package/src/model-context/sharedExposure.d.ts.map +1 -0
- package/src/model-context/sharedExposure.js +108 -0
- package/src/model-context/sharedExposure.js.map +7 -0
- package/src/model-context/toolSupport.d.ts +72 -0
- package/src/model-context/toolSupport.d.ts.map +1 -0
- package/src/model-context/toolSupport.js +145 -0
- package/src/model-context/toolSupport.js.map +7 -0
- package/src/model-context/tools/findEntities.d.ts +15 -0
- package/src/model-context/tools/findEntities.d.ts.map +1 -0
- package/src/model-context/tools/findEntities.js +71 -0
- package/src/model-context/tools/findEntities.js.map +7 -0
- package/src/model-context/tools/getEntity.d.ts +16 -0
- package/src/model-context/tools/getEntity.d.ts.map +1 -0
- package/src/model-context/tools/getEntity.js +65 -0
- package/src/model-context/tools/getEntity.js.map +7 -0
- package/src/model-context/tools/getEntityTree.d.ts +4 -0
- package/src/model-context/tools/getEntityTree.d.ts.map +1 -0
- package/src/model-context/tools/getEntityTree.js +58 -0
- package/src/model-context/tools/getEntityTree.js.map +7 -0
- package/src/model-context/tools/getRegistry.d.ts +14 -0
- package/src/model-context/tools/getRegistry.d.ts.map +1 -0
- package/src/model-context/tools/getRegistry.js +39 -0
- package/src/model-context/tools/getRegistry.js.map +7 -0
- package/src/model-context/tools/index.d.ts +9 -0
- package/src/model-context/tools/index.d.ts.map +1 -0
- package/src/model-context/tools/index.js +16 -0
- package/src/model-context/tools/index.js.map +7 -0
- package/src/model-context/tools/listEnvs.d.ts +33 -0
- package/src/model-context/tools/listEnvs.d.ts.map +1 -0
- package/src/model-context/tools/listEnvs.js +37 -0
- package/src/model-context/tools/listEnvs.js.map +7 -0
- package/src/model-context.d.ts +13 -0
- package/src/model-context.d.ts.map +1 -0
- package/src/model-context.js +15 -0
- package/src/model-context.js.map +7 -0
- package/src/shadow-objects.d.ts +4 -0
- package/src/shadow-objects.d.ts.map +1 -1
- package/src/shadow-objects.js +6 -0
- package/src/shadow-objects.js.map +2 -2
- package/src/shadow-objects.worker.js +0 -1
- package/src/shadow-objects.worker.js.map +2 -2
- package/src/shae-ent.js.map +1 -1
- package/src/shae-prop.js +2 -2
- package/src/shae-prop.js.map +2 -2
- package/src/shae-worker.js.map +1 -1
- package/src/testing/TestEntity.d.ts +79 -0
- package/src/testing/TestEntity.d.ts.map +1 -0
- package/src/testing/TestEntity.js +135 -0
- package/src/testing/TestEntity.js.map +7 -0
- package/src/testing/createTestKernel.d.ts +11 -0
- package/src/testing/createTestKernel.d.ts.map +1 -0
- package/src/testing/createTestKernel.js +132 -0
- package/src/testing/createTestKernel.js.map +7 -0
- package/src/testing/mountShadowObject.d.ts +21 -0
- package/src/testing/mountShadowObject.d.ts.map +1 -0
- package/src/testing/mountShadowObject.js +72 -0
- package/src/testing/mountShadowObject.js.map +7 -0
- package/src/testing/recordKernelErrors.d.ts +21 -0
- package/src/testing/recordKernelErrors.d.ts.map +1 -0
- package/src/testing/recordKernelErrors.js +39 -0
- package/src/testing/recordKernelErrors.js.map +7 -0
- package/src/testing/settle.d.ts +15 -0
- package/src/testing/settle.d.ts.map +1 -0
- package/src/testing/settle.js +19 -0
- package/src/testing/settle.js.map +7 -0
- package/src/testing/types.d.ts +119 -0
- package/src/testing/types.d.ts.map +1 -0
- package/src/testing/types.js +1 -0
- package/src/testing/types.js.map +7 -0
- package/src/testing.d.ts +14 -0
- package/src/testing.d.ts.map +1 -0
- package/src/testing.js +11 -0
- package/src/testing.js.map +7 -0
- package/src/types.d.ts +185 -14
- package/src/types.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.d.ts +45 -10
- package/src/utils/ConsoleLogger.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.js +51 -26
- package/src/utils/ConsoleLogger.js.map +2 -2
- package/src/utils/FrameLoop.d.ts +42 -3
- package/src/utils/FrameLoop.d.ts.map +1 -1
- package/src/utils/FrameLoop.js +71 -10
- package/src/utils/FrameLoop.js.map +2 -2
- package/src/utils/MicrotaskCollector.d.ts +45 -0
- package/src/utils/MicrotaskCollector.d.ts.map +1 -0
- package/src/utils/MicrotaskCollector.js +33 -0
- package/src/utils/MicrotaskCollector.js.map +7 -0
- package/src/utils/MicrotaskGate.d.ts +17 -0
- package/src/utils/MicrotaskGate.d.ts.map +1 -0
- package/src/utils/MicrotaskGate.js +20 -0
- package/src/utils/MicrotaskGate.js.map +7 -0
- package/src/utils/array-utils.js.map +1 -1
- package/src/utils/attr-utils.d.ts +11 -0
- package/src/utils/attr-utils.d.ts.map +1 -1
- package/src/utils/attr-utils.js +5 -1
- package/src/utils/attr-utils.js.map +2 -2
- package/src/utils/constants.js.map +1 -1
- package/src/utils/generateUUID.d.ts +11 -0
- package/src/utils/generateUUID.d.ts.map +1 -1
- package/src/utils/generateUUID.js +31 -266
- package/src/utils/generateUUID.js.map +2 -2
- package/src/utils/props-utils.d.ts +3 -2
- package/src/utils/props-utils.d.ts.map +1 -1
- package/src/utils/props-utils.js +13 -24
- package/src/utils/props-utils.js.map +2 -2
- package/src/utils/runGuarded.d.ts +27 -0
- package/src/utils/runGuarded.d.ts.map +1 -0
- package/src/utils/runGuarded.js +11 -0
- package/src/utils/runGuarded.js.map +7 -0
- package/src/utils/toMaybe.d.ts.map +1 -1
- package/src/utils/toMaybe.js.map +1 -1
- package/src/utils/toNamespace.d.ts.map +1 -1
- package/src/utils/toNamespace.js.map +1 -1
- package/src/utils/toUrlString.d.ts +12 -0
- package/src/utils/toUrlString.d.ts.map +1 -1
- package/src/utils/toUrlString.js.map +2 -2
- package/src/utils/waitForMessageOfType.d.ts +12 -1
- package/src/utils/waitForMessageOfType.d.ts.map +1 -1
- package/src/utils/waitForMessageOfType.js +16 -1
- package/src/utils/waitForMessageOfType.js.map +2 -2
- package/src/view/ComponentChanges.d.ts +88 -1
- package/src/view/ComponentChanges.d.ts.map +1 -1
- package/src/view/ComponentChanges.js +243 -73
- package/src/view/ComponentChanges.js.map +2 -2
- package/src/view/ComponentContext.d.ts +206 -16
- package/src/view/ComponentContext.d.ts.map +1 -1
- package/src/view/ComponentContext.js +548 -91
- package/src/view/ComponentContext.js.map +2 -2
- package/src/view/ComponentMemory.d.ts +3 -3
- package/src/view/ComponentMemory.d.ts.map +1 -1
- package/src/view/ComponentMemory.js.map +1 -1
- package/src/view/IShadowObjectEnvProxy.d.ts +38 -3
- package/src/view/IShadowObjectEnvProxy.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.d.ts +8 -1
- package/src/view/LocalShadowObjectEnv.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.js +23 -7
- package/src/view/LocalShadowObjectEnv.js.map +2 -2
- package/src/view/RemoteWorkerEnv.d.ts +108 -5
- package/src/view/RemoteWorkerEnv.d.ts.map +1 -1
- package/src/view/RemoteWorkerEnv.js +244 -77
- package/src/view/RemoteWorkerEnv.js.map +2 -2
- package/src/view/ShadowEnv.d.ts +79 -2
- package/src/view/ShadowEnv.d.ts.map +1 -1
- package/src/view/ShadowEnv.js +323 -59
- package/src/view/ShadowEnv.js.map +3 -3
- package/src/view/ViewComponent.d.ts +78 -14
- package/src/view/ViewComponent.d.ts.map +1 -1
- package/src/view/ViewComponent.js +90 -14
- package/src/view/ViewComponent.js.map +2 -2
- package/src/view/cloneChangeTrail.js.map +2 -2
- package/src/worker/MessageRouter.d.ts +14 -0
- package/src/worker/MessageRouter.d.ts.map +1 -1
- package/src/worker/MessageRouter.js +98 -15
- package/src/worker/MessageRouter.js.map +2 -2
- package/src/worker/WorkerRuntime.d.ts +22 -1
- package/src/worker/WorkerRuntime.d.ts.map +1 -1
- package/src/worker/WorkerRuntime.js +60 -8
- package/src/worker/WorkerRuntime.js.map +2 -2
|
@@ -1,63 +1,35 @@
|
|
|
1
|
-
import { batch, createEffect, createSignal, link } from "@spearwolf/signalize";
|
|
1
|
+
import { batch, createEffect, createSignal, Effect, hibernate, link } from "@spearwolf/signalize";
|
|
2
2
|
import { readBooleanAttribute } from "../utils/attr-utils.js";
|
|
3
3
|
import { ConsoleLogger } from "../utils/ConsoleLogger.js";
|
|
4
|
-
import {
|
|
5
|
-
import { ATTR_NAME, ATTR_NO_TRIM, ATTR_TYPE, ATTR_VALUE } from "./constants.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
import { MicrotaskGate } from "../utils/MicrotaskGate.js";
|
|
5
|
+
import { ATTR_NAME, ATTR_NO_TRIM, ATTR_TYPE, ATTR_VALUE, ReRequestEntHostEventName } from "./constants.js";
|
|
6
|
+
import { propValueConverters } from "./propValueConverters.js";
|
|
7
|
+
import { requestEntAncestor } from "./requestEntAncestor.js";
|
|
8
|
+
import { ShaeLifecycleElement } from "./ShaeLifecycleElement.js";
|
|
9
|
+
const declarantsPerComponent = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
const addDeclarant = (vc, name) => {
|
|
11
|
+
let names = declarantsPerComponent.get(vc);
|
|
12
|
+
if (names == null) {
|
|
13
|
+
names = /* @__PURE__ */ new Map();
|
|
14
|
+
declarantsPerComponent.set(vc, names);
|
|
15
|
+
}
|
|
16
|
+
names.set(name, (names.get(name) ?? 0) + 1);
|
|
17
|
+
};
|
|
18
|
+
const removeDeclarant = (vc, name) => {
|
|
19
|
+
const names = declarantsPerComponent.get(vc);
|
|
20
|
+
if (names == null) return true;
|
|
21
|
+
const remaining = (names.get(name) ?? 1) - 1;
|
|
22
|
+
if (remaining > 0) {
|
|
23
|
+
names.set(name, remaining);
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
names.delete(name);
|
|
27
|
+
if (names.size === 0) {
|
|
28
|
+
declarantsPerComponent.delete(vc);
|
|
13
29
|
}
|
|
14
|
-
return
|
|
30
|
+
return true;
|
|
15
31
|
};
|
|
16
|
-
|
|
17
|
-
"string",
|
|
18
|
-
"text",
|
|
19
|
-
"number",
|
|
20
|
-
"bigint",
|
|
21
|
-
"float",
|
|
22
|
-
"int",
|
|
23
|
-
"integer",
|
|
24
|
-
"hex",
|
|
25
|
-
"hexadecimal",
|
|
26
|
-
"oct",
|
|
27
|
-
"octal",
|
|
28
|
-
"bin",
|
|
29
|
-
"binary",
|
|
30
|
-
"bool",
|
|
31
|
-
"boolean",
|
|
32
|
-
"[]",
|
|
33
|
-
"text[]",
|
|
34
|
-
"string[]",
|
|
35
|
-
"number[]",
|
|
36
|
-
"float[]",
|
|
37
|
-
"int[]",
|
|
38
|
-
"integer[]",
|
|
39
|
-
"hex[]",
|
|
40
|
-
"hexadecimal[]",
|
|
41
|
-
"oct[]",
|
|
42
|
-
"octal[]",
|
|
43
|
-
"bin[]",
|
|
44
|
-
"binary[]",
|
|
45
|
-
"bool[]",
|
|
46
|
-
"boolean[]",
|
|
47
|
-
"int8array",
|
|
48
|
-
"uint8array",
|
|
49
|
-
"uint8clampedarray",
|
|
50
|
-
"int16array",
|
|
51
|
-
"uint16array",
|
|
52
|
-
"int32array",
|
|
53
|
-
"uint32array",
|
|
54
|
-
"float32array",
|
|
55
|
-
"float64array",
|
|
56
|
-
"bigint64array",
|
|
57
|
-
"biguint64array",
|
|
58
|
-
"json"
|
|
59
|
-
]);
|
|
60
|
-
class ShaePropElement extends HTMLElement {
|
|
32
|
+
class ShaePropElement extends ShaeLifecycleElement {
|
|
61
33
|
constructor() {
|
|
62
34
|
super();
|
|
63
35
|
this.isShaePropElement = true;
|
|
@@ -68,9 +40,78 @@ class ShaePropElement extends HTMLElement {
|
|
|
68
40
|
this.valueOut$ = createSignal();
|
|
69
41
|
this.type$ = createSignal();
|
|
70
42
|
this.shouldTrim$ = createSignal(true);
|
|
71
|
-
this
|
|
43
|
+
this.#logger = new ConsoleLogger("ShaePropElement");
|
|
44
|
+
/** Whether the missing-host warning has already gone out for this element. */
|
|
45
|
+
this.#reportedMissingHost = false;
|
|
46
|
+
// Two terms, and they answer two different questions. `isConnected` separates an element in
|
|
47
|
+
// the tree from one on its way out: a round booked before the departure has nothing left to
|
|
48
|
+
// say about a position the element no longer holds. `isDestroyed` separates one that is
|
|
49
|
+
// listening from one that was ended by hand and is still standing where it was — a lookup
|
|
50
|
+
// running there would write `entNode$` and register the re-request listener again that the
|
|
51
|
+
// teardown just took off, and the element would be listening after it let go of everything.
|
|
52
|
+
// The flag is up before `teardown()` runs, so a round that comes due afterwards reads the
|
|
53
|
+
// state the element is actually in.
|
|
54
|
+
//
|
|
55
|
+
// The test stands here and not in the gate: a `MicrotaskGate` has no way to call a booking
|
|
56
|
+
// off, and that is the whole of what tells it apart from `DeferredTeardown`.
|
|
57
|
+
this.#hostLookup = new MicrotaskGate(() => {
|
|
58
|
+
if (this.isConnected && !this.isDestroyed) {
|
|
59
|
+
this.#findEntNode();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
// Determines the host from where the element stands right now. The request runs *without* a
|
|
63
|
+
// namespace: a property belongs to the closest entity above it, whatever namespace that entity
|
|
64
|
+
// is in.
|
|
65
|
+
//
|
|
66
|
+
// Nobody answering means there is no entity above this position, and the element says so. A
|
|
67
|
+
// binding without an answer belongs to a place that is no longer there — whether the element
|
|
68
|
+
// moved or the entity above it did. The cleanup on `entNode$` then takes the property off the
|
|
69
|
+
// entity that no longer holds it, instead of leaving the element writing into an entity it does
|
|
70
|
+
// not sit under any more.
|
|
72
71
|
this.#findEntNode = () => {
|
|
73
|
-
|
|
72
|
+
let found;
|
|
73
|
+
requestEntAncestor(this, { answer: (entNode) => found = entNode });
|
|
74
|
+
this.entNode$.set(found);
|
|
75
|
+
if (found == null && this.isConnected && !this.#reportedMissingHost) {
|
|
76
|
+
this.#reportedMissingHost = true;
|
|
77
|
+
this.logger.warn(`[${this.name}] no entity above this element, the property is set nowhere`, {
|
|
78
|
+
shaeProp: this
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
this.#listenForHostChanges();
|
|
82
|
+
};
|
|
83
|
+
// Someone above started or stopped answering. Two things separate this from a lookup the
|
|
84
|
+
// element makes on arrival, and both belong here, to the trigger — what an unanswered
|
|
85
|
+
// request means is the same on either path.
|
|
86
|
+
//
|
|
87
|
+
// It waits a microtask: the message arrives while the tree is still moving. An entity that
|
|
88
|
+
// announces its departure has left, but everything below it can be back in place before the
|
|
89
|
+
// tick ends, and an ancestor answering *right now* can be one this element is about to
|
|
90
|
+
// leave behind. Asking after the dust settles is asking once, about the tree that is
|
|
91
|
+
// actually there.
|
|
92
|
+
//
|
|
93
|
+
// And it drops the question if this element has left in the meantime, for the same reason
|
|
94
|
+
// `#reRequestParent` does in `ShaeEntElement`: an element that is out of the tree answers
|
|
95
|
+
// nothing about its position any more. Whether its departure is a move or an end is
|
|
96
|
+
// `#disconnectFromEntNode`'s to answer, one microtask later, and it is answered in one place.
|
|
97
|
+
// Nothing observable turns on the test — a departing entity takes its properties with it
|
|
98
|
+
// either way — so it stands as a rule, not as a measurement.
|
|
99
|
+
//
|
|
100
|
+
// `#hostLookup` bounds the cost: a page filling up with entities sends many messages through the
|
|
101
|
+
// same ancestor chain, and the gate turns them into one lookup per microtask and per element.
|
|
102
|
+
this.#onReRequestHost = () => {
|
|
103
|
+
this.#hostLookup.schedule();
|
|
104
|
+
};
|
|
105
|
+
this.#listenForHostChanges = () => {
|
|
106
|
+
const target = this.entNode$.value ?? this.ownerDocument;
|
|
107
|
+
if (target === this.#reRequestHostTarget) return;
|
|
108
|
+
this.#stopListeningForHostChanges();
|
|
109
|
+
target.addEventListener(ReRequestEntHostEventName, this.#onReRequestHost);
|
|
110
|
+
this.#reRequestHostTarget = target;
|
|
111
|
+
};
|
|
112
|
+
this.#stopListeningForHostChanges = () => {
|
|
113
|
+
this.#reRequestHostTarget?.removeEventListener(ReRequestEntHostEventName, this.#onReRequestHost);
|
|
114
|
+
this.#reRequestHostTarget = void 0;
|
|
74
115
|
};
|
|
75
116
|
this.#disconnectFromEntNode = () => {
|
|
76
117
|
queueMicrotask(() => {
|
|
@@ -83,16 +124,20 @@ class ShaePropElement extends HTMLElement {
|
|
|
83
124
|
this.name$.set(this.getAttribute(ATTR_NAME)?.trim() ?? void 0);
|
|
84
125
|
};
|
|
85
126
|
this.#readValueAttribute = () => {
|
|
86
|
-
this.
|
|
127
|
+
const value = this.getAttribute(ATTR_VALUE);
|
|
128
|
+
this.valueIn$.set(value === null || value === "" ? void 0 : value);
|
|
129
|
+
};
|
|
130
|
+
/** Whether the `value` attribute says something — absent and empty are the same "nothing" here. */
|
|
131
|
+
this.#valueAttributeCarriesValue = () => {
|
|
132
|
+
const value = this.getAttribute(ATTR_VALUE);
|
|
133
|
+
return value !== null && value !== "";
|
|
87
134
|
};
|
|
88
135
|
this.#readTypeAttribute = () => {
|
|
89
136
|
let type = this.getAttribute(ATTR_TYPE)?.trim().toLowerCase();
|
|
90
|
-
if (type && !
|
|
91
|
-
|
|
92
|
-
this
|
|
93
|
-
|
|
94
|
-
});
|
|
95
|
-
}
|
|
137
|
+
if (type && !propValueConverters.has(type)) {
|
|
138
|
+
this.logger.warn(`[${this.name}] unknown type "${type}"`, {
|
|
139
|
+
shaeProp: this
|
|
140
|
+
});
|
|
96
141
|
type = void 0;
|
|
97
142
|
}
|
|
98
143
|
this.type$.set(type);
|
|
@@ -100,7 +145,77 @@ class ShaePropElement extends HTMLElement {
|
|
|
100
145
|
this.#readNoTrimAttribute = () => {
|
|
101
146
|
this.shouldTrim$.set(!readBooleanAttribute(this, ATTR_NO_TRIM));
|
|
102
147
|
};
|
|
103
|
-
|
|
148
|
+
batch(() => {
|
|
149
|
+
this.#readNameAttribute();
|
|
150
|
+
this.#readValueAttribute();
|
|
151
|
+
this.#readTypeAttribute();
|
|
152
|
+
this.#readNoTrimAttribute();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
static {
|
|
156
|
+
this.observedAttributes = [ATTR_NAME, ATTR_VALUE, ATTR_TYPE, ATTR_NO_TRIM];
|
|
157
|
+
}
|
|
158
|
+
#logger;
|
|
159
|
+
/** The logger this element reports through: a subclass reads it and does not replace it. */
|
|
160
|
+
get logger() {
|
|
161
|
+
return this.#logger;
|
|
162
|
+
}
|
|
163
|
+
/** Binds this element to the entity above it, and carries that entity's component through. */
|
|
164
|
+
#hostBinding;
|
|
165
|
+
/** Holds the property on the entity for as long as this element declares it. */
|
|
166
|
+
#declareProperty;
|
|
167
|
+
/** Writes the value through to the entity. */
|
|
168
|
+
#writePropertyValue;
|
|
169
|
+
/** Turns what the attribute spells into the value the property carries. */
|
|
170
|
+
#convertValue;
|
|
171
|
+
#reportedMissingHost;
|
|
172
|
+
/** The node this element listens on for a re-request of the host, so the listener can come off the same one. */
|
|
173
|
+
#reRequestHostTarget;
|
|
174
|
+
#hostLookup;
|
|
175
|
+
get name() {
|
|
176
|
+
return this.name$.value;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Writes the `name` attribute, and `attributeChangedCallback` takes it from there: the attribute
|
|
180
|
+
* is the one source the name is read from, so a write through the property and a write through
|
|
181
|
+
* `setAttribute` end up in the same place and are trimmed by the same rule. A framework renderer
|
|
182
|
+
* assigns every prop it finds `in` the element as a property — React 19 and Vue 3 both do — and
|
|
183
|
+
* a name it cannot assign is a property that never binds.
|
|
184
|
+
*/
|
|
185
|
+
set name(name) {
|
|
186
|
+
const trimmed = name?.trim();
|
|
187
|
+
if (!trimmed) {
|
|
188
|
+
this.removeAttribute(ATTR_NAME);
|
|
189
|
+
} else if (this.getAttribute(ATTR_NAME) !== trimmed) {
|
|
190
|
+
this.setAttribute(ATTR_NAME, trimmed);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
get value() {
|
|
194
|
+
return this.valueOut$.value;
|
|
195
|
+
}
|
|
196
|
+
set value(val) {
|
|
197
|
+
this.valueIn$.set(val);
|
|
198
|
+
}
|
|
199
|
+
get shouldTrim() {
|
|
200
|
+
return this.shouldTrim$.value;
|
|
201
|
+
}
|
|
202
|
+
get entNode() {
|
|
203
|
+
return this.entNode$.value;
|
|
204
|
+
}
|
|
205
|
+
set entNode(el) {
|
|
206
|
+
this.entNode$.set(el);
|
|
207
|
+
}
|
|
208
|
+
get viewComponent() {
|
|
209
|
+
return this.viewComponent$.value;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Take up everything this element listens to.
|
|
213
|
+
*
|
|
214
|
+
* Called from {@link ShaePropElement.restore} and from nowhere else — that is the one place where
|
|
215
|
+
* this element's subscriptions begin, at the first connect as well as after a teardown.
|
|
216
|
+
*/
|
|
217
|
+
#subscribe() {
|
|
218
|
+
this.#hostBinding = this.entNode$.onChange((entNode) => {
|
|
104
219
|
if (entNode) {
|
|
105
220
|
const con = link(entNode.viewComponent$, this.viewComponent$);
|
|
106
221
|
return () => {
|
|
@@ -110,18 +225,29 @@ class ShaePropElement extends HTMLElement {
|
|
|
110
225
|
this.viewComponent$.set(void 0);
|
|
111
226
|
}
|
|
112
227
|
});
|
|
113
|
-
createEffect(() => {
|
|
228
|
+
this.#declareProperty = createEffect(() => {
|
|
229
|
+
const vc = this.viewComponent$.get();
|
|
230
|
+
const name = this.name$.get();
|
|
231
|
+
if (vc == null || !name) return;
|
|
232
|
+
const entNode = this.entNode$.value;
|
|
233
|
+
addDeclarant(vc, name);
|
|
234
|
+
return () => {
|
|
235
|
+
if (removeDeclarant(vc, name)) {
|
|
236
|
+
vc.removeProperty(name);
|
|
237
|
+
entNode?.syncShadowObjects();
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
this.#writePropertyValue = createEffect(() => {
|
|
114
242
|
const vc = this.viewComponent$.get();
|
|
115
243
|
if (vc) {
|
|
116
244
|
const name = this.name$.get();
|
|
117
245
|
if (name) {
|
|
118
246
|
const value = this.valueOut$.get();
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
});
|
|
124
|
-
}
|
|
247
|
+
this.logger.debug(`[${this.name}] view-component set-property`, name, value, vc.uuid, {
|
|
248
|
+
viewComponent: vc,
|
|
249
|
+
shaeProp: this
|
|
250
|
+
});
|
|
125
251
|
vc.setProperty(name, value);
|
|
126
252
|
if (this.isConnected) {
|
|
127
253
|
this.entNode?.syncShadowObjects();
|
|
@@ -129,165 +255,59 @@ class ShaePropElement extends HTMLElement {
|
|
|
129
255
|
}
|
|
130
256
|
}
|
|
131
257
|
});
|
|
132
|
-
createEffect(() => {
|
|
258
|
+
this.#convertValue = createEffect(() => {
|
|
133
259
|
const type = this.type$.get();
|
|
134
260
|
const shouldTrim = this.shouldTrim$.get();
|
|
135
261
|
let value = this.valueIn$.get();
|
|
136
262
|
if (shouldTrim && typeof value === "string") {
|
|
137
263
|
value = value.trim();
|
|
138
264
|
}
|
|
139
|
-
value = value
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
value
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
break;
|
|
154
|
-
case "int":
|
|
155
|
-
case "integer":
|
|
156
|
-
value = parseInt(value, 10);
|
|
157
|
-
break;
|
|
158
|
-
case "hex":
|
|
159
|
-
case "hexadecimal":
|
|
160
|
-
value = parseInt(value, 16);
|
|
161
|
-
break;
|
|
162
|
-
case "oct":
|
|
163
|
-
case "octal":
|
|
164
|
-
value = parseInt(value, 8);
|
|
165
|
-
break;
|
|
166
|
-
case "bin":
|
|
167
|
-
case "binary":
|
|
168
|
-
value = parseInt(value, 2);
|
|
169
|
-
break;
|
|
170
|
-
case "bool":
|
|
171
|
-
case "boolean":
|
|
172
|
-
value = TRUTHY_VALUES.has(value.toLowerCase());
|
|
173
|
-
break;
|
|
174
|
-
case "[]":
|
|
175
|
-
case "text[]":
|
|
176
|
-
case "string[]":
|
|
177
|
-
value = value.split(/\W+/);
|
|
178
|
-
break;
|
|
179
|
-
case "number[]":
|
|
180
|
-
value = value.split(/\s+/).map((v) => Number(v));
|
|
181
|
-
break;
|
|
182
|
-
case "float[]":
|
|
183
|
-
value = value.split(/\s+/).map((v) => parseFloat(v));
|
|
184
|
-
break;
|
|
185
|
-
case "int[]":
|
|
186
|
-
case "integer[]":
|
|
187
|
-
value = value.split(/\s+/).map((v) => parseInt(v, 10));
|
|
188
|
-
break;
|
|
189
|
-
case "hex[]":
|
|
190
|
-
case "hexadecimal[]":
|
|
191
|
-
value = value.split(/\W+/).map((v) => parseInt(v, 16));
|
|
192
|
-
break;
|
|
193
|
-
case "oct[]":
|
|
194
|
-
case "octal[]":
|
|
195
|
-
value = value.split(/\W+/).map((v) => parseInt(v, 8));
|
|
196
|
-
break;
|
|
197
|
-
case "bin[]":
|
|
198
|
-
case "binary[]":
|
|
199
|
-
value = value.split(/\W+/).map((v) => parseInt(v, 2));
|
|
200
|
-
break;
|
|
201
|
-
case "bool[]":
|
|
202
|
-
case "boolean[]":
|
|
203
|
-
value = value.split(/\W+/).map((v) => TRUTHY_VALUES.has(v.toLowerCase()));
|
|
204
|
-
break;
|
|
205
|
-
case "int8array":
|
|
206
|
-
value = new Int8Array(value.split(/\W+/).map((v) => Number(v)));
|
|
207
|
-
break;
|
|
208
|
-
case "uint8array":
|
|
209
|
-
value = new Uint8Array(value.split(/\W+/).map((v) => Number(v)));
|
|
210
|
-
break;
|
|
211
|
-
case "uint8clampedarray":
|
|
212
|
-
value = new Uint8ClampedArray(value.split(/\W+/).map((v) => Number(v)));
|
|
213
|
-
break;
|
|
214
|
-
case "int16array":
|
|
215
|
-
value = new Int16Array(value.split(/\W+/).map((v) => Number(v)));
|
|
216
|
-
break;
|
|
217
|
-
case "uint16array":
|
|
218
|
-
value = new Uint16Array(value.split(/\W+/).map((v) => Number(v)));
|
|
219
|
-
break;
|
|
220
|
-
case "int32array":
|
|
221
|
-
value = new Int32Array(value.split(/\W+/).map((v) => Number(v)));
|
|
222
|
-
break;
|
|
223
|
-
case "uint32array":
|
|
224
|
-
value = new Uint32Array(value.split(/\W+/).map((v) => Number(v)));
|
|
225
|
-
break;
|
|
226
|
-
case "float32array":
|
|
227
|
-
value = new Float32Array(value.split(/\s+/).map((v) => Number(v)));
|
|
228
|
-
break;
|
|
229
|
-
case "float64array":
|
|
230
|
-
value = new Float64Array(value.split(/\s+/).map((v) => Number(v)));
|
|
231
|
-
break;
|
|
232
|
-
case "bigint64array":
|
|
233
|
-
value = new BigInt64Array(value.split(/\W+/).map((v) => BigInt(v)));
|
|
234
|
-
break;
|
|
235
|
-
case "biguint64array":
|
|
236
|
-
value = new BigUint64Array(value.split(/\W+/).map((v) => BigInt(v)));
|
|
237
|
-
break;
|
|
238
|
-
case "json":
|
|
239
|
-
value = JSON.parse(value);
|
|
240
|
-
break;
|
|
241
|
-
default:
|
|
242
|
-
if (this.logger.isWarn) {
|
|
243
|
-
this.logger.warn(`[${this.name}] unknown type "${type}"`, {
|
|
244
|
-
value,
|
|
245
|
-
shaeProp: this
|
|
246
|
-
});
|
|
247
|
-
}
|
|
265
|
+
value = value ?? void 0;
|
|
266
|
+
if (typeof value === "string" && type) {
|
|
267
|
+
const convert = propValueConverters.get(type);
|
|
268
|
+
if (convert != null) {
|
|
269
|
+
try {
|
|
270
|
+
value = convert(value);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
this.logger.error(`[${this.name}] could not convert the value into the type "${type}"`, {
|
|
273
|
+
value,
|
|
274
|
+
error,
|
|
275
|
+
shaeProp: this
|
|
276
|
+
});
|
|
277
|
+
value = void 0;
|
|
278
|
+
}
|
|
248
279
|
}
|
|
249
280
|
}
|
|
250
281
|
this.valueOut$.set(value);
|
|
251
282
|
});
|
|
252
|
-
batch(() => {
|
|
253
|
-
this.#readNameAttribute();
|
|
254
|
-
this.#readValueAttribute();
|
|
255
|
-
this.#readTypeAttribute();
|
|
256
|
-
this.#readNoTrimAttribute();
|
|
257
|
-
});
|
|
258
|
-
this.style.display = "contents";
|
|
259
|
-
}
|
|
260
|
-
static {
|
|
261
|
-
this.observedAttributes = [ATTR_NAME, ATTR_VALUE, ATTR_TYPE, ATTR_NO_TRIM];
|
|
262
|
-
}
|
|
263
|
-
get name() {
|
|
264
|
-
return this.name$.value;
|
|
265
283
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
this
|
|
280
|
-
}
|
|
281
|
-
get viewComponent() {
|
|
282
|
-
return this.viewComponent$.value;
|
|
284
|
+
/**
|
|
285
|
+
* Take this element's own subscriptions up. Its half of {@link ShaeLifecycleElement.restore}.
|
|
286
|
+
*
|
|
287
|
+
* There is nothing to catch up on here, unlike `<shae-ent>`: `connectedCallback` reads `name`,
|
|
288
|
+
* `type` and `no-trim` off the attributes, `value` where the attribute carries one, and looks the
|
|
289
|
+
* host up again straight after this. So the attributes decide, and whatever was written to a
|
|
290
|
+
* released element through `prop.entNode` — or through `prop.value` against a `value` attribute
|
|
291
|
+
* that says something — is replaced by what the tree and the markup say. That is this element's
|
|
292
|
+
* rule in and out of a teardown alike — a `<shae-prop>` reads its position on every connect — and
|
|
293
|
+
* the documentation states it as the difference it is.
|
|
294
|
+
*/
|
|
295
|
+
restore() {
|
|
296
|
+
super.restore();
|
|
297
|
+
this.#subscribe();
|
|
283
298
|
}
|
|
284
299
|
connectedCallback() {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
300
|
+
hibernate(() => {
|
|
301
|
+
super.connectedCallback();
|
|
302
|
+
batch(() => {
|
|
303
|
+
this.#findEntNode();
|
|
304
|
+
this.#readNameAttribute();
|
|
305
|
+
if (this.#valueAttributeCarriesValue()) {
|
|
306
|
+
this.#readValueAttribute();
|
|
307
|
+
}
|
|
308
|
+
this.#readTypeAttribute();
|
|
309
|
+
this.#readNoTrimAttribute();
|
|
310
|
+
});
|
|
291
311
|
});
|
|
292
312
|
}
|
|
293
313
|
attributeChangedCallback(name) {
|
|
@@ -307,12 +327,37 @@ class ShaePropElement extends HTMLElement {
|
|
|
307
327
|
}
|
|
308
328
|
}
|
|
309
329
|
disconnectedCallback() {
|
|
330
|
+
this.#stopListeningForHostChanges();
|
|
310
331
|
this.#disconnectFromEntNode();
|
|
332
|
+
super.disconnectedCallback();
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Release this element's own subscriptions. Its half of {@link ShaeLifecycleElement.teardown}.
|
|
336
|
+
*
|
|
337
|
+
* The `link()` between the host's `viewComponent$` and this element's own needs no line of its
|
|
338
|
+
* own: it is built in the cleanup path of the `entNode$` subscription, and taking that
|
|
339
|
+
* subscription off runs the cleanup that destroys it.
|
|
340
|
+
*/
|
|
341
|
+
teardown() {
|
|
342
|
+
this.#stopListeningForHostChanges();
|
|
343
|
+
this.#hostBinding?.();
|
|
344
|
+
this.#hostBinding = void 0;
|
|
345
|
+
this.#declareProperty?.destroy();
|
|
346
|
+
this.#declareProperty = void 0;
|
|
347
|
+
this.#writePropertyValue?.destroy();
|
|
348
|
+
this.#writePropertyValue = void 0;
|
|
349
|
+
this.#convertValue?.destroy();
|
|
350
|
+
this.#convertValue = void 0;
|
|
351
|
+
super.teardown();
|
|
311
352
|
}
|
|
312
353
|
#findEntNode;
|
|
354
|
+
#onReRequestHost;
|
|
355
|
+
#listenForHostChanges;
|
|
356
|
+
#stopListeningForHostChanges;
|
|
313
357
|
#disconnectFromEntNode;
|
|
314
358
|
#readNameAttribute;
|
|
315
359
|
#readValueAttribute;
|
|
360
|
+
#valueAttributeCarriesValue;
|
|
316
361
|
#readTypeAttribute;
|
|
317
362
|
#readNoTrimAttribute;
|
|
318
363
|
}
|