Skip to content

Commit

Permalink
Merge pull request #93 from atellmer/bugfix/bad-link
Browse files Browse the repository at this point in the history
Fixes events on links
  • Loading branch information
atellmer authored Aug 29, 2024
2 parents 426efe2 + 801c48e commit 560ee48
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 16 deletions.
2 changes: 1 addition & 1 deletion examples/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/dev
/dev-ssr
/dev-native
/dev-server
/dev-desktop
1 change: 1 addition & 0 deletions packages/platform-browser/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export const AS_ATTR = '_as';
export const DANGER_HTML_ATTR = '__danger';
export const EXCLUDE_ATTR_MARK = '$';
export const DASH_MARK = '-';
export const PREVENT = '__prevent';
7 changes: 7 additions & 0 deletions packages/platform-browser/src/dom/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
EXCLUDE_ATTR_MARK,
DANGER_HTML_ATTR,
DASH_MARK,
PREVENT,
} from '../constants';
import type {
NativeElement,
Expand Down Expand Up @@ -163,6 +164,11 @@ function performAttribute(
return null;
}

if (attrName === PREVENT) {
tagElement[PREVENT] = true;
return null;
}

if (attrName === AS_ATTR) {
attrName = attrName.slice(1, AS_ATTR.length);
}
Expand Down Expand Up @@ -282,6 +288,7 @@ function commitCreation(fiber: Fiber<NativeElement>) {
}

detectIsTagVirtualNode(fiber.inst) && addAttributes(fiber.element, fiber.inst, isHydration);
fiber.element.parentElement?.[PREVENT] && (fiber.element[PREVENT] = true);
}

function commitUpdate(fiber: Fiber<NativeElement>) {
Expand Down
9 changes: 5 additions & 4 deletions packages/platform-browser/src/events/events.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { type Scope, detectIsFunction, $$scope, detectIsArray } from '@dark-engine/core';

import type { TagNativeElement } from '../native-element';
import { PREVENT } from '../constants';

export type EventHandler<E extends Event = Event, T = unknown> =
| ((e: SyntheticEvent<E, T>) => void)
| [(...args: Array<any>) => void, ...args: Array<any>];

type BrowserEventConstructor = (type: string, event: Event) => void;
type BrowserEvent = (type: string, event: Event) => void;

class SyntheticEvent<E extends Event, T = TagNativeElement> {
type = '';
Expand Down Expand Up @@ -46,6 +47,8 @@ function delegateEvent(target: Element, eventName: string, handler: EventHandler
const target = event.target as TagNativeElement;
let $event: SyntheticEvent<Event> = null;

target[PREVENT] && event.preventDefault();

if (detectIsFunction(handler)) {
$event = new SyntheticEvent({ sourceEvent: event, target });

Expand All @@ -59,9 +62,7 @@ function delegateEvent(target: Element, eventName: string, handler: EventHandler
const shouldPropagate = $event ? $event.getPropagation() : true;

if (shouldPropagate) {
const constructor = event.constructor as BrowserEventConstructor;

target.parentElement.dispatchEvent(new constructor(event.type, event));
target.parentElement.dispatchEvent(new (event.constructor as BrowserEvent)(event.type, event));
}
}
};
Expand Down
10 changes: 8 additions & 2 deletions packages/platform-server/src/dom/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ import {
createReplacer,
detectIsTextBased,
} from '@dark-engine/core';
import { type AttributeValue, VALUE_ATTR, TEXTAREA_TAG, detectIsVoidElement } from '@dark-engine/platform-browser';
import {
type AttributeValue,
VALUE_ATTR,
TEXTAREA_TAG,
PREVENT,
detectIsVoidElement,
} from '@dark-engine/platform-browser';

import { NativeElement, TagNativeElement, TextNativeElement, CommentNativeElement } from '../native-element';

Expand All @@ -43,7 +49,7 @@ function addAttributes(element: NativeElement, vNode: TagVirtualNode) {
for (const attrName in vNode.attrs) {
const attrValue = vNode.attrs[attrName];

if (attrName === REF_ATTR || detectIsFunction(attrValue)) {
if (attrName === REF_ATTR || attrName === PREVENT || detectIsFunction(attrValue)) {
continue;
} else if (!detectIsUndefined(attrValue) && !ATTR_BLACK_LIST[attrName]) {
!patchAttributes(tagElement, attrName, attrValue) && tagElement.setAttribute(attrName, attrValue);
Expand Down
59 changes: 52 additions & 7 deletions packages/web-router/src/link/link.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,20 +112,17 @@ describe('@web-router/link', () => {
expect(host.innerHTML).toMatchInlineSnapshot(`"<a href="/" class="my-link">first</a>"`);
});

test('prevent default click event', () => {
test('prevents default click event #1', () => {
const spy = jest.fn();
const routes: Routes = [
{
path: '',
component: component(() => null),
},
];

let defaultPrevented = false;

const App = component(() => {
const handleClick = (e: SyntheticEvent<MouseEvent>) => {
defaultPrevented = e.sourceEvent.defaultPrevented;
};
const handleClick = (e: SyntheticEvent<MouseEvent>) => spy(e.sourceEvent.defaultPrevented);

return (
<Router routes={routes}>
Expand All @@ -144,6 +141,54 @@ describe('@web-router/link', () => {
expect(host.innerHTML).toMatchInlineSnapshot(`"<a href="/">first</a>"`);

click(host.querySelector('a'));
expect(defaultPrevented).toBe(true);
expect(spy).toHaveBeenCalledWith(true);
});

test('prevents default click event #2', () => {
// https://github.com/atellmer/dark/issues/77
const spy = jest.fn();
const routes: Routes = [
{
path: '',
component: component(() => <root />),
},
{
path: 'page',
component: component(() => <page />),
},
];
const App = component(() => {
const handleClick = (e: SyntheticEvent<MouseEvent>) => spy(e.sourceEvent.defaultPrevented);

return (
<Router routes={routes}>
{slot => {
return (
<>
<Link to='/page'>
<div>
<div data-link onClick={handleClick}>
page
</div>
</div>
</Link>
{slot}
</>
);
}}
</Router>
);
});

render(<App />);
expect(host.innerHTML).toMatchInlineSnapshot(
`"<a href="/page"><div><div data-link="true">page</div></div></a><root></root>"`,
);

click(host.querySelector('[data-link]'));
expect(host.innerHTML).toMatchInlineSnapshot(
`"<a href="/page"><div><div data-link="true">page</div></div></a><page></page>"`,
);
expect(spy).toHaveBeenCalledWith(true);
});
});
6 changes: 4 additions & 2 deletions packages/web-router/src/link/link.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type DarkElement, type Ref, component, useEvent, detectIsFunction } from '@dark-engine/core';
import { type SyntheticEvent, type DarkJSX } from '@dark-engine/platform-browser';
import { type SyntheticEvent, type DarkJSX, PREVENT } from '@dark-engine/platform-browser';

import { useHistory } from '../use-history';

Expand All @@ -21,7 +21,7 @@ const Link = component<LinkProps>(
});

return (
<a ref={ref} {...rest} href={to} class={className} onClick={handleClick}>
<a ref={ref} {...rest} {...prevent} href={to} class={className} onClick={handleClick}>
{slot}
</a>
);
Expand All @@ -31,4 +31,6 @@ const Link = component<LinkProps>(
},
);

const prevent = { [PREVENT]: true };

export { Link };

0 comments on commit 560ee48

Please sign in to comment.