Skip to content

Commit 2c2e173

Browse files
added some extra tests for events using the tests from preact library, and update the removeEventListener to use useCapture also
1 parent 576569c commit 2c2e173

File tree

9 files changed

+311
-29
lines changed

9 files changed

+311
-29
lines changed

src/rendering/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,5 @@ export const SVG_TAGS = new Set([
6262
]);
6363

6464
export const MATH_NAMESPACE = "http://www.w3.org/1998/Math/MathML";
65+
66+
export const CAPTURE_REGEX = /(PointerCapture)$|Capture$/i;

src/rendering/createElements.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ function isProperty(key: string) {
118118
return key !== "children" && key !== "key" && key !== "ref";
119119
}
120120

121-
export function createNode(element: Fiber) {
121+
export function createNode(element: Fiber): HTMLElement | Text {
122122
let namespace: string | null = null;
123123

124124
if (SVG_TAGS.has(element.type as string)) namespace = SVG_NAMESPACE;
@@ -137,7 +137,7 @@ export function createNode(element: Fiber) {
137137
: // @ts-expect-error
138138
document.createElement(element.type);
139139

140-
if (!element.props) return dom;
140+
if (!element.props) return dom as HTMLElement | Text;
141141

142142
if (
143143
element.props.ref &&
@@ -161,7 +161,7 @@ export function createNode(element: Fiber) {
161161
}
162162
}
163163

164-
return dom;
164+
return dom as HTMLElement | Text;
165165
}
166166

167167
export function updateDomProp(

src/rendering/props.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ export function setReactiveAttribute(
137137
reactiveFunction.__propName = name;
138138
// registers the function in corresponding signal
139139
const val = reactiveAttribute(reactiveFunction);
140-
141140
if (val === null || val === undefined || val === false) {
142141
return;
143142
}
@@ -148,6 +147,8 @@ export function setReactiveAttribute(
148147
setReactiveAttributes(reactiveFunction, dom);
149148
}
150149

150+
const CAPTURE_REGEX = /(PointerCapture)$|Capture$/i;
151+
151152
export function setAttribute(
152153
name: string,
153154
value: any,
@@ -159,16 +160,20 @@ export function setAttribute(
159160
return;
160161
}
161162

162-
if (name[0] === "o" && name[1] === "n") {
163+
if (name[0] === "o" && name[1] === "n" && typeof value === "function") {
164+
const useCapture = name != (name = name.replace(CAPTURE_REGEX, "$1"));
165+
163166
if (
164167
name.toLowerCase() in dom ||
165168
name == "onFocusOut" ||
166-
name == "onFocusIn"
169+
name == "onFocusIn" ||
170+
name === "onGotPointerCapture" ||
171+
name === "onLostPointerCapture"
167172
)
168173
name = name.toLowerCase().slice(2);
169174
else name = name.slice(2);
170175
// handle eventListeners
171-
dom.addEventListener(name, value);
176+
dom.addEventListener(name, value, useCapture);
172177
return;
173178
}
174179

@@ -204,6 +209,7 @@ export function setAttribute(
204209
if (value != null && (value !== false || name[4] === "-")) {
205210
// For most attributes, if the value is valid, set the attribute.
206211
// Special case: for "popover", if value is true, set attribute to an empty string.
212+
207213
dom.setAttribute(
208214
name,
209215
name === "popover" && value === true ? "" : value

src/rendering/render.ts

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
import { BaseSignal, Ref } from "../signals/signal";
77
import { Fiber, FiberChildren } from "../types";
88
import { isPrimitive } from "../utils/general";
9+
import { CAPTURE_REGEX } from "./constants";
910
import {
1011
FRAGMENT_SYMBOL,
1112
createChildren,
@@ -263,11 +264,18 @@ function commitDeletion(fiber: Fiber, toClearReactiveFunction?: boolean) {
263264
delete fiber.renderFunction;
264265
}
265266
if (fiber.dom) {
266-
for (const prop of Object.keys(fiber.props)) {
267+
for (const prop in fiber.props) {
267268
if (isEvent(prop)) {
268-
const eventName = prop.toLowerCase().substring(2);
269-
270-
fiber.dom.removeEventListener(eventName, fiber.props[prop]);
269+
let eventName = prop.toLowerCase().substring(2);
270+
const useCapture =
271+
eventName !=
272+
(eventName = eventName.replace(CAPTURE_REGEX, "$1"));
273+
274+
fiber.dom.removeEventListener(
275+
eventName,
276+
fiber.props[prop],
277+
useCapture
278+
);
271279
delete fiber.props[prop];
272280
} else if (typeof fiber.props[prop] === "function") {
273281
clearReactiveAttributes(fiber.props[prop]);
@@ -348,7 +356,8 @@ function replaceChildFromParent(prev: Fiber, next: Fiber, index?: number) {
348356
});
349357
}
350358

351-
export const isEvent = (key: string) => key.startsWith("on");
359+
export const isEvent = (key: string) =>
360+
key.startsWith("on") || key == "onFocusOut" || key == "onFocusIn";
352361
export const isProperty = (key: string) =>
353362
key !== "children" && !isEvent(key) && key !== "key" && key !== "ref";
354363
const isNew = (prev: any, next: any, key: string) => prev[key] !== next[key];
@@ -400,7 +409,7 @@ function deepEqual(objA: any, objB: any): boolean {
400409

401410
for (let key of keysA) {
402411
if (key === "children") continue;
403-
if (!keysB.includes(key)) return false; // Missing key in one of them
412+
if (!objB.hasOwnProperty(key)) return false; // Missing key in one of them
404413
if (!deepEqual(objA[key], objB[key])) return false; // Recurse for nested objects/arrays
405414
}
406415

@@ -540,7 +549,7 @@ function updateNode(
540549
} else {
541550
// console.log("Node-Node");
542551
// remove old properties and event listeners from NODE
543-
for (const prop of Object.keys(prevProps)) {
552+
for (const prop in prevProps) {
544553
if (
545554
isProperty(prop) &&
546555
isGone(prevProps, nextProps, prop)
@@ -552,9 +561,19 @@ function updateNode(
552561
(!(prop in nextProps) ||
553562
isNew(prevProps, nextProps, prop))
554563
) {
555-
const eventName = prop.toLowerCase().substring(2);
556-
557-
node.removeEventListener(eventName, prevProps[prop]);
564+
let eventName = prop.toLowerCase().substring(2);
565+
const useCapture =
566+
eventName !=
567+
(eventName = eventName.replace(
568+
CAPTURE_REGEX,
569+
"$1"
570+
));
571+
572+
node.removeEventListener(
573+
eventName,
574+
prevProps[prop],
575+
useCapture
576+
);
558577
// console.log("event listener removed", prop);
559578
}
560579
}
@@ -573,7 +592,7 @@ function updateNode(
573592
// add new properties
574593
// console.log("same type", prev, next);
575594

576-
for (const prop of Object.keys(nextProps)) {
595+
for (const prop in nextProps) {
577596
if (
578597
isProperty(prop) &&
579598
isNew(prevProps, nextProps, prop)
@@ -589,9 +608,18 @@ function updateNode(
589608
isEvent(prop) &&
590609
isNew(prevProps, nextProps, prop)
591610
) {
592-
const eventName = prop.toLowerCase().substring(2);
593-
// console.log("event listener added", prop);
594-
node.addEventListener(eventName, nextProps[prop]);
611+
let eventName = prop.toLowerCase().substring(2);
612+
const useCapture =
613+
eventName !=
614+
(eventName = eventName.replace(
615+
CAPTURE_REGEX,
616+
"$1"
617+
));
618+
node.addEventListener(
619+
eventName,
620+
nextProps[prop],
621+
useCapture
622+
);
595623
prevProps[prop] = nextProps[prop];
596624
}
597625
}

src/tests/rendering/createElements.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ describe("createNode", () => {
150150
props: { onClick: clickHandler, children: [] },
151151
};
152152
const dom = createNode(element);
153-
console.log(dom, "dom ");
154153
dom.click();
155154
expect(count).toBe(1);
156155
});

0 commit comments

Comments
 (0)