Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add behavior parameter to links #770

Merged
merged 1 commit into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions ember-link/src/-behavior.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type Link from './link';

export const BEHAVIOR = Symbol('prevent');

export interface Behavior {
/**
* @defaultValue 'transition'
*/
open: 'transition' | 'replace';

/**
* Prevent a link from being invoked. The default implementation is doing
* two things:
*
* 1) allow links to open in new window/tab
* 2) prevent default browser behavior on `<a>` tags (to use ember's routing
* system)
*
* @param event
* @param link
* @returns
*/
prevent: (event: Event | unknown, link: Link) => boolean;
}

const MAIN_BUTTON = 0;

function isUnmodifiedLeftClick(event: MouseEvent): boolean {
return event.button === MAIN_BUTTON && !event.ctrlKey && !event.metaKey;
}

function isMouseEvent(event: unknown): event is MouseEvent {
return typeof event === 'object' && event !== null && 'button' in event;
}

export function isRegularOpening(event: unknown) {
return isMouseEvent(event) && !isUnmodifiedLeftClick(event);
}

export function preventDefault(event?: Event | unknown) {
if (typeof (event as Event)?.preventDefault === 'function') {
(event as Event).preventDefault();
}
}

export function prevent(event: Event | unknown, _link: Link): boolean {
if (isRegularOpening(event)) {
return true;
}

preventDefault(event);

return false;
}
5 changes: 5 additions & 0 deletions ember-link/src/-models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type RouterService from '@ember/routing/router-service';

export type RouteModel = object | string | number;

export type RouteArgs = Parameters<RouterService['urlFor']>;
File renamed without changes.
69 changes: 69 additions & 0 deletions ember-link/src/-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { DEBUG } from '@glimmer/env';

import type { Behavior } from './-behavior';
import type { RouteModel } from './-models';

export type QueryParams = Record<string, unknown>;

export interface LinkParams {
/**
* The target route name.
*/
route: string;

/**
* Optional array of models / dynamic segments.
*/
models?: RouteModel[];

/**
* Optional query params object.
*/
query?: QueryParams;

behavior?: Partial<Behavior>;

/**
* An optional callback that will be fired when the Link is transitioned to.
*
* The callback is only fired if the Link is explicitly invoked, not if the
* app transitions to the Link through other means.
*/
onTransitionTo?: () => void;

/**
* An optional callback that will be fired when the current route is replaced
* with the Link.
*
* The callback is only fired if the Link is explicitly invoked, not if the
* app transitions to the Link through other means.
*/
onReplaceWith?: () => void;
}

type MaybeQueryParams =
| RouteModel
| { queryParams: object }
| {
isQueryParams: unknown;
values: QueryParams;
};

export function isQueryParams(
maybeQueryParam?: MaybeQueryParams
): maybeQueryParam is { values: QueryParams } {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return maybeQueryParam?.isQueryParams !== undefined && typeof maybeQueryParam.values === 'object';
}

export function freezeParams(params: LinkParams) {
if (DEBUG) {
if (params.models) Object.freeze(params.models);
if (params.query) Object.freeze(params.query);

return Object.freeze(params);
}

return params;
}
9 changes: 6 additions & 3 deletions ember-link/src/helpers/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import Helper from '@ember/component/helper';
import { assert } from '@ember/debug';
import { inject as service } from '@ember/service';

import { isQueryParams } from '../link';
import { isQueryParams, type LinkParams } from '../-params';

import type { RouteArgs, RouteModel } from '../-models';
import type { QueryParams } from '../-params';
import type Link from '../link';
import type { LinkParams, QueryParams, RouteArgs, RouteModel, UILinkParams } from '../link';
import type { UILinkParams } from '../link';
import type LinkManagerService from '../services/link-manager';

export type LinkHelperPositionalParams = [] | RouteArgs;
Expand Down Expand Up @@ -127,7 +129,8 @@ export default class LinkHelper extends Helper {
: undefined,
query: named.query ?? positionalQueryParameters,
onTransitionTo: named.onTransitionTo,
onReplaceWith: named.onReplaceWith
onReplaceWith: named.onReplaceWith,
behavior: named.behavior
};
}

Expand Down
5 changes: 4 additions & 1 deletion ember-link/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export { prevent } from './-behavior';
export type { LinkParams } from './-params';
export { default as link } from './helpers/link';
export type { LinkParams, UILinkParams } from './link';
export type { UILinkParams } from './link';
export { default as Link, UILink } from './link';
export type { default as LinkManagerService } from './services/link-manager';
Loading