apollo-elements/apollo-elements

View on GitHub
packages/components/events.ts

Summary

Maintainability
C
1 day
Test Coverage
A
100%
import type { Data, Variables, VariablesOf } from '@apollo-elements/core/types';
import type { ApolloError, DocumentNode } from '@apollo/client/core';
import type { ApolloMutationElement } from './apollo-mutation.js';

export type MutationEventType = (
    'mutation-completed'
  | 'mutation-error'
  | 'will-mutate'
  | 'will-navigate'
);

export interface MutationEventDetail<D, V = VariablesOf<D>> {
  data?: Data<D> | null;
  error?: Error | ApolloError | null;
  variables?: Variables<D, V> | null;
  element: ApolloMutationElement<D, V>;
  mutation: DocumentNode | null;
}

export class MutationEvent<D, V = VariablesOf<D>> extends CustomEvent<MutationEventDetail<D, V>> {
  declare type: MutationEventType;

  declare detail: MutationEventDetail<D, V>;

  constructor(type: MutationEventType, init: CustomEventInit) {
    super(type, {
      ...init,
      bubbles: true,
      composed: true,
    });
  }
}

/* eslint-disable @typescript-eslint/no-explicit-any */

/**
 * Fired when the element is about to mutate.
 * Useful for setting variables or cancelling the mutation by calling `preventDefault`
 * Prevent default to prevent mutation. Detail is `{ element: this }`
 * @typeParam Data Element's Data type
 * @typeParam Variables Element's Variables type
 */
export class WillMutateEvent<D = unknown, V = VariablesOf<D>> extends MutationEvent<D, V> {
  static type = 'will-mutate' as const;
  public declare type: 'will-mutate';

  constructor(element: ApolloMutationElement<D, V>) {
    const { mutation, variables } = element;
    super(WillMutateEvent.type, {
      cancelable: true,
      detail: {
        element,
        mutation,
        variables,
      },
    });
  }
}

/**
 * Fired when a mutation completes.
 * `detail` is the mutation data.
 * @typeParam Data Element's Data type
 * @typeParam Variables Element's Variables type
 */
export class MutationCompletedEvent<D = unknown, V = VariablesOf<D>> extends MutationEvent<D, V> {
  static type = 'mutation-completed' as const;
  public declare type: 'mutation-completed';

  constructor(element: ApolloMutationElement<D, V>) {
    const { data, mutation, variables } = element;
    super(MutationCompletedEvent.type, {
      detail: {
        data,
        element,
        mutation,
        variables,
      },
    });
  }
}

/**
 * Fired before an <apollo-element> with a link trigger mutates.
 * Cancel the event with `event.preventDefault()` to prevent navigation.
 * @typeParam Data Element's Data type
 * @typeParam Variables Element's Variables type
 */
export class WillNavigateEvent<D = unknown, V = VariablesOf<D>> extends MutationEvent<D, V> {
  public static type = 'will-navigate' as const;
  public declare type: 'will-navigate';

  constructor(element: ApolloMutationElement<D, V>) {
    const { data, mutation, variables } = element;
    super(WillNavigateEvent.type, {
      cancelable: true,
      detail: {
        data,
        element,
        mutation,
        variables,
      },
    });
  }
}

/**
 * Fired when the mutation rejects.
 * @typeParam Data Element's Data type
 * @typeParam Variables Element's Variables type
 */
export class MutationErrorEvent<D = unknown, V = VariablesOf<D>> extends MutationEvent<D, V> {
  public static type = 'mutation-error' as const;
  public declare type: 'mutation-error';

  constructor(element: ApolloMutationElement<D, V>) {
    const { mutation, variables, error } = element;
    super(MutationErrorEvent.type, {
      detail: {
        element,
        error,
        mutation,
        variables,
      },
    });
  }
}

declare global {
  interface HTMLElementEventMap {
    'will-mutate': WillMutateEvent;
    'will-navigate': WillNavigateEvent;
    'mutation-completed': MutationCompletedEvent;
    'mutation-error': MutationErrorEvent;
  }
}