1- import type { Action } from 'svelte/action' ;
1+ import type { ActionReturn } from 'svelte/action' ;
22
3- import type { RouteName } from '~/models/index.js' ;
43import type { LinkNavigateFunction , LinkNavigateOptions } from '~/models/link.model.js' ;
54
6- import { getLinkNavigateFunction , getResolveFunction , normalizeLinkAttributes } from '~/models/link.model.js' ;
7- import { Logger } from '~/utils/logger.utils.js' ;
8-
9- export type LinkActionOptions < Name extends RouteName = RouteName , Path extends string = string > = LinkNavigateOptions < Name , Path > ;
5+ import { ensureLinkRouter , getNavigateFunction , getResolveFunction , normalizeLinkAttributes } from '~/models/link.model.js' ;
6+ import { getRouter } from '~/router/context.svelte.js' ;
107
118/**
129 * A svelte action to add to an element to navigate to a new location using the router.
@@ -26,7 +23,7 @@ export type LinkActionOptions<Name extends RouteName = RouteName, Path extends s
2623 * - Name takes precedence over path.
2724 * - If the host is not an anchor element, the role and tabindex attributes will be set.
2825 *
29- * Note: The action requires the router context to be present in the component tree.
26+ * Note: The action requires a router instance or the router context to be present in the component tree.
3027 *
3128 * @param node - The element to add the link action to
3229 * @param options - The options to use for the navigation
@@ -41,38 +38,26 @@ export type LinkActionOptions<Name extends RouteName = RouteName, Path extends s
4138 * <button href='/path/:param' use:link="{ params: { param: 'value' } }">button link</button>
4239 * ```
4340 */
44- export const link : Action < HTMLElement , LinkActionOptions | undefined > = ( node : HTMLElement , options : LinkActionOptions | undefined = { } ) => {
45- normalizeLinkAttributes ( node , options ) ;
46-
47- let _options = $state ( options ) ;
48- const update = ( newOptions : LinkNavigateOptions | undefined = { } ) => {
49- _options = newOptions ;
50- } ;
41+ export function link ( node : HTMLElement , options : LinkNavigateOptions | undefined = { } ) : ActionReturn < LinkNavigateOptions | undefined > {
42+ const router = options ?. router || getRouter ( ) ;
43+ if ( ! ensureLinkRouter ( node , router ) ) return { } ;
5144
52- const navigate = $derived . by < LinkNavigateFunction | undefined > ( ( ) => {
53- try {
54- const fn = getLinkNavigateFunction ( _options ) ;
55- node . removeAttribute ( 'data-error' ) ;
56- return fn ;
57- } catch ( error ) {
58- Logger . warn ( 'Router not found. Make sure you are using the link(s) action within a Router context.' , { node, options, error } ) ;
59- node . setAttribute ( 'data-error' , 'Router not found.' ) ;
60- }
61- } ) ;
45+ let _options = $state ( normalizeLinkAttributes ( node , options ) ) ;
6246
47+ const navigate = $derived < LinkNavigateFunction | undefined > ( getNavigateFunction ( router , options ) ) ;
6348 const navigateHandler = async ( event : MouseEvent | KeyboardEvent ) => navigate ?.( event , node ) ;
6449
65- // Add resolve on hover option && view params
6650 const resolve = $derived ( getResolveFunction ( navigate , _options ) ) ;
67-
6851 const resolveHandler = async ( event : FocusEvent | PointerEvent ) => resolve ( event , node ) ;
6952
7053 node . addEventListener ( 'click' , navigateHandler ) ;
7154 node . addEventListener ( 'keydown' , navigateHandler ) ;
7255 node . addEventListener ( 'pointerenter' , resolveHandler ) ;
7356 node . addEventListener ( 'focus' , resolveHandler ) ;
7457 return {
75- update,
58+ update ( newOptions : LinkNavigateOptions | undefined = { } ) {
59+ _options = newOptions ;
60+ } ,
7661 destroy ( ) {
7762 node . removeEventListener ( 'click' , navigateHandler ) ;
7863 node . removeEventListener ( 'keydown' , navigateHandler ) ;
0 commit comments