@rettangoli/fe 1.1.0 → 1.1.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/README.md
CHANGED
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
cleanupEventRateLimitState,
|
|
8
8
|
syncRefIds,
|
|
9
9
|
} from "./componentRuntime.js";
|
|
10
|
-
import { buildOnUpdateChanges } from "./lifecycle.js";
|
|
10
|
+
import { buildOnPropUpdateChanges, buildOnUpdateChanges } from "./lifecycle.js";
|
|
11
11
|
import { normalizeAttributeValue, toCamelCase } from "./props.js";
|
|
12
12
|
|
|
13
13
|
export const createRuntimeDepsForInstance = ({ instance }) => {
|
|
@@ -112,6 +112,39 @@ export const runAttributeChangedComponentLifecycle = ({
|
|
|
112
112
|
});
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
+
export const runPropChangedComponentLifecycle = ({
|
|
116
|
+
instance,
|
|
117
|
+
propName,
|
|
118
|
+
oldValue,
|
|
119
|
+
newValue,
|
|
120
|
+
scheduleFrameFn,
|
|
121
|
+
}) => {
|
|
122
|
+
if (oldValue === newValue || !instance.render) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (instance.isConnected === false || !instance.renderTarget) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (instance.handlers?.handleOnUpdate) {
|
|
131
|
+
const runtimeDeps = createRuntimeDepsForInstance({ instance });
|
|
132
|
+
const changes = buildOnPropUpdateChanges({
|
|
133
|
+
propName,
|
|
134
|
+
oldValue,
|
|
135
|
+
newValue,
|
|
136
|
+
deps: runtimeDeps,
|
|
137
|
+
propsSchemaKeys: instance._propsSchemaKeys,
|
|
138
|
+
});
|
|
139
|
+
instance.handlers.handleOnUpdate(runtimeDeps, changes);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
scheduleFrameFn(() => {
|
|
144
|
+
instance.render();
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
|
|
115
148
|
export const runRenderComponentLifecycle = ({
|
|
116
149
|
instance,
|
|
117
150
|
createComponentUpdateHookFn,
|
|
@@ -122,3 +122,42 @@ export const buildOnUpdateChanges = ({
|
|
|
122
122
|
newProps,
|
|
123
123
|
};
|
|
124
124
|
};
|
|
125
|
+
|
|
126
|
+
export const buildOnPropUpdateChanges = ({
|
|
127
|
+
propName,
|
|
128
|
+
oldValue,
|
|
129
|
+
newValue,
|
|
130
|
+
deps,
|
|
131
|
+
propsSchemaKeys,
|
|
132
|
+
}) => {
|
|
133
|
+
const newProps = {};
|
|
134
|
+
|
|
135
|
+
propsSchemaKeys.forEach((propKey) => {
|
|
136
|
+
const propValue = deps.props[propKey];
|
|
137
|
+
if (propValue !== undefined) {
|
|
138
|
+
newProps[propKey] = propValue;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const oldProps = {
|
|
143
|
+
...newProps,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (oldValue === undefined) {
|
|
147
|
+
delete oldProps[propName];
|
|
148
|
+
} else {
|
|
149
|
+
oldProps[propName] = oldValue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (newValue === undefined) {
|
|
153
|
+
delete newProps[propName];
|
|
154
|
+
} else {
|
|
155
|
+
newProps[propName] = newValue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
changedProp: propName,
|
|
160
|
+
oldProps,
|
|
161
|
+
newProps,
|
|
162
|
+
};
|
|
163
|
+
};
|
|
@@ -28,6 +28,81 @@ export const readPropFallbackFromAttributes = (source, propName) => {
|
|
|
28
28
|
return undefined;
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
+
const REACTIVE_PROP_VALUES = Symbol("rtglReactivePropValues");
|
|
32
|
+
|
|
33
|
+
const ensureReactivePropValues = (source) => {
|
|
34
|
+
if (!Object.prototype.hasOwnProperty.call(source, REACTIVE_PROP_VALUES)) {
|
|
35
|
+
Object.defineProperty(source, REACTIVE_PROP_VALUES, {
|
|
36
|
+
value: Object.create(null),
|
|
37
|
+
enumerable: false,
|
|
38
|
+
configurable: false,
|
|
39
|
+
writable: false,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return source[REACTIVE_PROP_VALUES];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const installReactiveProps = ({
|
|
47
|
+
source,
|
|
48
|
+
allowedKeys = [],
|
|
49
|
+
onPropChange,
|
|
50
|
+
}) => {
|
|
51
|
+
const reactiveValues = ensureReactivePropValues(source);
|
|
52
|
+
|
|
53
|
+
allowedKeys.forEach((propName) => {
|
|
54
|
+
if (typeof propName !== "string" || propName.length === 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const presetValue = Object.prototype.hasOwnProperty.call(source, propName)
|
|
59
|
+
? source[propName]
|
|
60
|
+
: undefined;
|
|
61
|
+
const hadPresetValue = Object.prototype.hasOwnProperty.call(source, propName);
|
|
62
|
+
|
|
63
|
+
if (hadPresetValue) {
|
|
64
|
+
delete source[propName];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Object.defineProperty(source, propName, {
|
|
68
|
+
configurable: true,
|
|
69
|
+
enumerable: true,
|
|
70
|
+
get() {
|
|
71
|
+
if (Object.prototype.hasOwnProperty.call(reactiveValues, propName)) {
|
|
72
|
+
return reactiveValues[propName];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return readPropFallbackFromAttributes(source, propName);
|
|
76
|
+
},
|
|
77
|
+
set(value) {
|
|
78
|
+
const oldValue = Object.prototype.hasOwnProperty.call(reactiveValues, propName)
|
|
79
|
+
? reactiveValues[propName]
|
|
80
|
+
: readPropFallbackFromAttributes(source, propName);
|
|
81
|
+
|
|
82
|
+
if (value === undefined) {
|
|
83
|
+
delete reactiveValues[propName];
|
|
84
|
+
} else {
|
|
85
|
+
reactiveValues[propName] = value;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (oldValue === value) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
onPropChange?.({
|
|
93
|
+
propName,
|
|
94
|
+
oldValue,
|
|
95
|
+
newValue: value,
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (hadPresetValue) {
|
|
101
|
+
reactiveValues[propName] = presetValue;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
31
106
|
export const createPropsProxy = (source, allowedKeys) => {
|
|
32
107
|
const allowed = new Set(allowedKeys);
|
|
33
108
|
return new Proxy(
|
package/src/web/componentDom.js
CHANGED
|
@@ -12,13 +12,61 @@ const COMMON_LINK_STYLE_TEXT = `
|
|
|
12
12
|
}
|
|
13
13
|
`;
|
|
14
14
|
|
|
15
|
+
const RENDER_TARGET_ATTR = "data-rtgl-render-target";
|
|
16
|
+
const RENDER_TARGET_FLAG = "__rtglRenderTarget";
|
|
17
|
+
|
|
18
|
+
const hasRenderTargetAttr = (node) => {
|
|
19
|
+
if (!node || typeof node !== "object") {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeof node.getAttribute === "function") {
|
|
24
|
+
return node.getAttribute(RENDER_TARGET_ATTR) !== null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return node[RENDER_TARGET_FLAG] === true;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const markRenderTarget = (node) => {
|
|
31
|
+
if (!node || typeof node !== "object") {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (typeof node.setAttribute === "function") {
|
|
36
|
+
node.setAttribute(RENDER_TARGET_ATTR, "");
|
|
37
|
+
} else {
|
|
38
|
+
node[RENDER_TARGET_FLAG] = true;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const findExistingRenderTarget = (shadow) => {
|
|
43
|
+
if (!shadow || typeof shadow !== "object") {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (typeof shadow.querySelector === "function") {
|
|
48
|
+
return shadow.querySelector(`[${RENDER_TARGET_ATTR}]`) ?? shadow.firstElementChild;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (Array.isArray(shadow.childNodes)) {
|
|
52
|
+
return shadow.childNodes.find(hasRenderTargetAttr) ?? shadow.childNodes[0];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (Array.isArray(shadow.children)) {
|
|
56
|
+
return shadow.children.find(hasRenderTargetAttr) ?? shadow.children[0];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return shadow.firstElementChild;
|
|
60
|
+
};
|
|
61
|
+
|
|
15
62
|
export const initializeComponentDom = ({
|
|
16
63
|
host,
|
|
17
64
|
cssText,
|
|
18
65
|
createStyleSheet = () => new CSSStyleSheet(),
|
|
19
66
|
createElement = (tagName) => document.createElement(tagName),
|
|
20
67
|
}) => {
|
|
21
|
-
const
|
|
68
|
+
const existingShadow = host.shadowRoot;
|
|
69
|
+
const shadow = existingShadow ?? host.attachShadow({ mode: "open" });
|
|
22
70
|
|
|
23
71
|
const commonStyleSheet = createStyleSheet();
|
|
24
72
|
commonStyleSheet.replaceSync(COMMON_LINK_STYLE_TEXT);
|
|
@@ -33,11 +81,22 @@ export const initializeComponentDom = ({
|
|
|
33
81
|
|
|
34
82
|
shadow.adoptedStyleSheets = adoptedStyleSheets;
|
|
35
83
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
84
|
+
let renderTarget = findExistingRenderTarget(shadow);
|
|
85
|
+
|
|
86
|
+
if (!renderTarget) {
|
|
87
|
+
renderTarget = createElement("div");
|
|
88
|
+
renderTarget.style.cssText = "display: contents;";
|
|
89
|
+
markRenderTarget(renderTarget);
|
|
90
|
+
shadow.appendChild(renderTarget);
|
|
91
|
+
} else {
|
|
92
|
+
renderTarget.style.cssText = "display: contents;";
|
|
93
|
+
if (!hasRenderTargetAttr(renderTarget)) {
|
|
94
|
+
markRenderTarget(renderTarget);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (renderTarget.parentNode !== shadow) {
|
|
99
|
+
shadow.appendChild(renderTarget);
|
|
41
100
|
}
|
|
42
101
|
host.style.display = "contents";
|
|
43
102
|
|
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
runAttributeChangedComponentLifecycle,
|
|
8
8
|
runConnectedComponentLifecycle,
|
|
9
9
|
runDisconnectedComponentLifecycle,
|
|
10
|
+
runPropChangedComponentLifecycle,
|
|
10
11
|
runRenderComponentLifecycle,
|
|
11
12
|
} from "../core/runtime/componentOrchestrator.js";
|
|
12
|
-
import { createPropsProxy, toKebabCase } from "../core/runtime/props.js";
|
|
13
|
+
import { createPropsProxy, installReactiveProps, toKebabCase } from "../core/runtime/props.js";
|
|
13
14
|
import {
|
|
14
15
|
buildObservedAttributes,
|
|
15
16
|
} from "../core/runtime/componentRuntime.js";
|
|
@@ -120,6 +121,19 @@ export const createWebComponentClass = ({
|
|
|
120
121
|
fileConstants: constants,
|
|
121
122
|
});
|
|
122
123
|
this.propsSchema = propsSchema;
|
|
124
|
+
installReactiveProps({
|
|
125
|
+
source: this,
|
|
126
|
+
allowedKeys: propsSchemaKeys,
|
|
127
|
+
onPropChange: ({ propName, oldValue, newValue }) => {
|
|
128
|
+
runPropChangedComponentLifecycle({
|
|
129
|
+
instance: this,
|
|
130
|
+
propName,
|
|
131
|
+
oldValue,
|
|
132
|
+
newValue,
|
|
133
|
+
scheduleFrameFn: scheduleFrame,
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
});
|
|
123
137
|
this.props = propsSchema
|
|
124
138
|
? createPropsProxy(this, propsSchemaKeys)
|
|
125
139
|
: {};
|