apollo-elements/apollo-elements

View on GitHub
packages/polymer/polymer-apollo-element.ts

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
import type { ApolloClient, ApolloError, NormalizedCacheObject } from '@apollo/client/core';
import type { Data, GraphQLError, Variables } from '@apollo-elements/core/types';
import type { ApolloController, VariablesOf } from '@apollo-elements/core';

import { getInitialProps, getInitialProp } from '@apollo-elements/core/decorators';
import { notify, PolymerChangeEvent } from './notify-decorator.js';
import { ApolloElementMixin } from '@apollo-elements/mixins/apollo-element-mixin';
import { GraphQLScriptChildMixin } from '@apollo-elements/mixins/graphql-script-child-mixin';

const last = Symbol('PolymerElement last known');

/**
 * See [ApolloElementInterface](/api/core/interfaces/element/) for more information.
 *
 * @fires {PolymerChangeEvent<Data<D>>} data-changed
 * @fires {PolymerChangeEvent<Variables<D, V>>} variables-changed
 * @fires {PolymerChangeEvent<Error>} error-changed
 * @fires {PolymerChangeEvent<readonly GraphQLError[]>} errors-changed
 * @fires {PolymerChangeEvent<boolean>} loading-changed
 */
export class PolymerApolloElement<D = unknown, V = VariablesOf<D>>
  extends GraphQLScriptChildMixin(ApolloElementMixin(HTMLElement))<D, V> {
  static readonly is: `polymer-apollo-${'mutation'|'query'|'subscription'}`;

  /** @ignore */
  [last] = new Map<keyof this, unknown>();

  declare client: ApolloClient<NormalizedCacheObject>;

  declare context?: Record<string, unknown>;

  declare variables: Variables<D, V> | null;

  @notify() data: Data<D> | null = null;

  @notify() error: Error | ApolloError | null = null;

  @notify() errors: readonly GraphQLError[] = [];

  @notify() loading = false;

  requestUpdate(): void {
    this[last] ??= new Map();
    for (const [k] of getInitialProps(this))
      this.maybeNotify(k as keyof this);
    super.requestUpdate();
  }

  maybeNotify(k: keyof this): void {
    if (this[k] !== this[last].get(k)) {
      this[last].set(k, this[k]);
      if (!this.controller)
        this[k] = getInitialProp(this, k) as this[keyof this];
      else
        this[k] = this.controller[k as keyof ApolloController<D, V>] as this[keyof this];
      this.dispatchEvent(new PolymerChangeEvent(k as string, this[k]));
    }
  }
}