Skip to content

Commit 5d5b521

Browse files
committed
fix(attachment): simplify attachment to prevent duplication
1 parent fa9a39a commit 5d5b521

File tree

5 files changed

+25
-84
lines changed

5 files changed

+25
-84
lines changed

src/lib/action/active.action.svelte.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,9 @@ export function active(node: HTMLElement, options: ActiveOptions | undefined = {
4343
const router = options?.router || getRouter();
4444
if (!ensureActionRouter(node, router)) return {};
4545

46-
let _options = $state(options);
47-
let _path: string | null = $state(options?.path || node.getAttribute('data-path') || node.getAttribute('href'));
48-
let _name: RouteName | null = $state(options?.name || node.getAttribute('data-name'));
49-
50-
const update = (newOptions: ActiveOptions | undefined = {}) => {
51-
_options = newOptions;
52-
_path = newOptions?.path || node.getAttribute('data-path') || node.getAttribute('href');
53-
_name = newOptions?.name || node.getAttribute('data-name');
54-
55-
ensurePathName(node, { path: _path, name: _name });
56-
};
46+
let _options = $derived(options);
47+
let _path: string | null = $derived(options?.path || node.getAttribute('data-path') || node.getAttribute('href'));
48+
let _name: RouteName | null = $derived(options?.name || node.getAttribute('data-name'));
5749

5850
const caseSensitive = $derived(_options?.caseSensitive ?? router.options?.caseSensitive);
5951
const matchName = $derived(doNameMatch(router.route, _name, { caseSensitive, exact: _options?.exact }));
@@ -74,5 +66,14 @@ export function active(node: HTMLElement, options: ActiveOptions | undefined = {
7466
$effect(() => {
7567
ensurePathName(node, { path: _path, name: _name });
7668
});
77-
return { update };
69+
70+
return {
71+
update(newOptions: ActiveOptions | undefined = {}) {
72+
_options = newOptions;
73+
_path = newOptions?.path || node.getAttribute('data-path') || node.getAttribute('href');
74+
_name = newOptions?.name || node.getAttribute('data-name');
75+
76+
ensurePathName(node, { path: _path, name: _name });
77+
},
78+
};
7879
}

src/lib/action/link.action.svelte.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ import { getRouter } from '~/router/context.svelte.js';
3939
* ```
4040
*/
4141
export function link(node: HTMLElement, options: LinkNavigateOptions | undefined = {}): ActionReturn<LinkNavigateOptions | undefined> {
42-
const router = options?.router || getRouter();
42+
const router = normalizeLinkAttributes(node, options)?.router || getRouter();
4343
if (!ensureLinkRouter(node, router)) return {};
4444

45-
let _options = $state(normalizeLinkAttributes(node, options));
45+
let _options = $derived(options);
4646

4747
const navigate = $derived<LinkNavigateFunction | undefined>(getNavigateFunction(router, options));
4848
const navigateHandler = async (event: MouseEvent | KeyboardEvent) => navigate?.(event, node);
@@ -56,7 +56,7 @@ export function link(node: HTMLElement, options: LinkNavigateOptions | undefined
5656
node.addEventListener('focus', resolveHandler);
5757
return {
5858
update(newOptions: LinkNavigateOptions | undefined = {}) {
59-
_options = newOptions;
59+
_options = normalizeLinkAttributes(node, newOptions);
6060
},
6161
destroy() {
6262
node.removeEventListener('click', navigateHandler);
Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
11
import type { Attachment } from 'svelte/attachments';
22

33
import type { ActiveOptions } from '~/models/action.model.js';
4-
import type { RouteName } from '~/models/route.model.js';
54

6-
import {
7-
activeStyles,
8-
doNameMatch,
9-
doPathMatch,
10-
ensureActionRouter,
11-
ensurePathName,
12-
getOriginalStyle,
13-
restoreStyles,
14-
} from '~/models/action.model.js';
15-
import { Matcher } from '~/models/index.js';
16-
import { getRouter } from '~/router/context.svelte.js';
5+
import { active } from '~/action/index.js';
176

187
/**
198
* A svelte attachment to add an active state (class, style or attribute) to an element when the route matches.
@@ -39,33 +28,5 @@ import { getRouter } from '~/router/context.svelte.js';
3928
* ```
4029
*/
4130
export function useActive(options: ActiveOptions = {}): Attachment<HTMLElement> {
42-
const router = options?.router || getRouter();
43-
44-
return (element) => {
45-
if (!ensureActionRouter(element, router)) return;
46-
47-
const _options = $derived(options);
48-
const _path: string | null = $derived(options?.path || element.getAttribute('data-path') || element.getAttribute('href'));
49-
const _name: RouteName | null = $derived(options?.name || element.getAttribute('data-name'));
50-
51-
const caseSensitive = $derived(_options?.caseSensitive ?? router.options?.caseSensitive);
52-
const matchName = $derived(doNameMatch(router.route, _name, { caseSensitive, exact: _options?.exact }));
53-
54-
const location = $derived(router.location?.path);
55-
const matcher = $derived(_path ? new Matcher(_path) : undefined);
56-
const matchPath = $derived(doPathMatch(matcher, _name, location, _options?.exact));
57-
58-
const match = $derived(matchName || matchPath);
59-
60-
const originalStyle = $derived(getOriginalStyle(element, _options?.style));
61-
62-
$effect(() => {
63-
if (match) activeStyles(element, _options);
64-
else restoreStyles(element, originalStyle, _options);
65-
});
66-
67-
$effect(() => {
68-
ensurePathName(element, { path: _path, name: _name });
69-
});
70-
};
31+
return element => active(element, options).destroy;
7132
}

src/lib/attachment/link.attachment.svelte.ts

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import type { Attachment } from 'svelte/attachments';
22

3-
import type { LinkNavigateFunction, LinkNavigateOptions } from '~/models/link.model.js';
3+
import type { LinkNavigateOptions } from '~/models/link.model.js';
44

5-
import { ensureLinkRouter, getNavigateFunction, getResolveFunction, normalizeLinkAttributes } from '~/models/link.model.js';
6-
import { getRouter } from '~/router/context.svelte.js';
5+
import { link } from '~/action/link.action.svelte.js';
76

87
/**
98
* A svelte attachment to add to an element to navigate to a new location using the router.
@@ -38,27 +37,5 @@ import { getRouter } from '~/router/context.svelte.js';
3837
* ```
3938
*/
4039
export function useLink(options: LinkNavigateOptions = {}): Attachment<HTMLElement> {
41-
return (element) => {
42-
const _options = $state(normalizeLinkAttributes(element, options));
43-
44-
const router = _options?.router || getRouter();
45-
if (!ensureLinkRouter(element, router)) return;
46-
47-
const navigate = $derived<LinkNavigateFunction | undefined>(getNavigateFunction(router, options));
48-
const navigateHandler = async (event: MouseEvent | KeyboardEvent) => navigate?.(event, element);
49-
50-
const resolve = $derived(getResolveFunction(navigate, _options));
51-
const resolveHandler = async (event: FocusEvent | PointerEvent) => resolve(event, element);
52-
53-
element.addEventListener('click', navigateHandler);
54-
element.addEventListener('keydown', navigateHandler);
55-
element.addEventListener('pointerenter', resolveHandler);
56-
element.addEventListener('focus', resolveHandler);
57-
return () => {
58-
element.removeEventListener('click', navigateHandler);
59-
element.removeEventListener('keydown', navigateHandler);
60-
element.removeEventListener('pointerenter', resolveHandler);
61-
element.removeEventListener('focus', resolveHandler);
62-
};
63-
};
40+
return element => link(element, options).destroy;
6441
}

src/lib/models/link.model.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,10 @@ export interface LinkNavigateOptions<Name extends RouteName = RouteName, Path ex
192192
disabled?: boolean;
193193
};
194194

195-
export function getResolveFunction(navigate?: LinkNavigateFunction, options?: { resolve?: boolean | string }) {
196-
return async (event: FocusEvent | PointerEvent, node: HTMLElement) => {
195+
export type LinkResolveFunction = (event: FocusEvent | PointerEvent, node: HTMLElement) => Promise<void>;
196+
197+
export function getResolveFunction(navigate?: LinkNavigateFunction, options?: { resolve?: boolean | string }): LinkResolveFunction {
198+
return async (event, node) => {
197199
const resolve = options?.resolve;
198200
if (!resolve || !navigate) return;
199201

0 commit comments

Comments
 (0)