@furystack/shades
Version:
A lightweight UI framework for FuryStack with JSX support
65 lines • 2.77 kB
JavaScript
import { LocationService } from '../services/location-service.js';
import { createComponent } from '../shade-component.js';
import { Shade } from '../shade.js';
import { buildNestedNavigateUrl } from './nested-navigate.js';
const _NestedRouteLink = Shade({
customElementName: 'nested-route-link',
elementBase: HTMLAnchorElement,
elementBaseName: 'a',
css: {
color: 'inherit',
textDecoration: 'inherit',
},
render: ({ children, props, injector, useHostProps }) => {
const { path, params, query, hash } = props;
const resolvedUrl = buildNestedNavigateUrl({ path, params, query, hash });
useHostProps({
href: resolvedUrl,
onclick: (ev) => {
ev.preventDefault();
// eslint-disable-next-line furystack/prefer-location-service -- This IS the SPA link component; it must call pushState directly.
history.pushState('', props.title || '', resolvedUrl);
injector.get(LocationService).updateState();
},
});
return createComponent(createComponent, null, children);
},
});
/**
* A link component for NestedRouter that supports SPA navigation with
* type-safe route parameter compilation.
*
* Intercepts click events to use `history.pushState` for client-side navigation,
* compiles parameterized routes (e.g. `/users/:id`) when `params` is provided,
* serializes `query` to the URL search string and appends `hash` when set.
*
* Route parameters are automatically inferred from the `path` pattern:
* - `path="/buttons"` — `params` is optional
* - `path="/users/:id"` — `params: { id: string }` is required
*
* For additional URL validation against a route tree (including `query` and
* `hash` narrowing), use {@link createNestedRouteLink}.
*/
export const NestedRouteLink = _NestedRouteLink;
/**
* Creates a type-safe wrapper around NestedRouteLink constrained to a specific
* route tree. The returned component has the same runtime behavior but narrows
* `path` to only accept valid route paths, requires `params` when the route
* has parameters, and enforces the route's declared `query` and `hash` schemas.
*
* @typeParam TRoutes - The route tree type (use `typeof yourRoutes`)
* @returns A narrowed NestedRouteLink component
*
* @example
* ```typescript
* const AppLink = createNestedRouteLink<typeof appRoutes>()
*
* <AppLink path="/buttons">Buttons</AppLink>
* <AppLink path="/users/:id" params={{ id: '123' }}>User</AppLink>
* <AppLink path="/users/:id" params={{ id: '1' }} query={{ tab: 'profile' }} hash="notes">User</AppLink>
* ```
*/
export const createNestedRouteLink = () => {
return _NestedRouteLink;
};
//# sourceMappingURL=nested-route-link.js.map