Repository: motion-canvas/motion-canvas
File: packages/2d/src/lib/components/Icon.ts (TypeScript)

Code before:

  /**
   * The color of the icon
   *
   * @remarks
   * Provide the color in one of the following formats:
   * * named color like `red`, `darkgray`, …
   * * hexadecimal string with # like `#bada55`, `#141414`
   *   Value can be either RGB or RGBA: `#bada55`, `#bada55aa` (latter is partially transparent)
   *   The shorthand version (e.g. `#abc` for `#aabbcc` is also possible.)
   *
   * @defaultValue 'white'
   */
  @initial('white')
  @colorSignal()
  public declare color: ColorSignal<this>;

  /**
   * The init check is only used to supress an error warning about setting the `src` Property.
   */
  private init = false;

  public constructor(props: IconProps) {
    super({
      ...props,
      src: null!,
    });
    this.init = true;
  }

  /**
   * Create the URL that will be used as the Image source
   * @returns Address to Iconify API for the requested Icon.
   */
  @computed()
  protected svgUrl(): string {
    const iconPathSegment = this.icon().replace(':', '/');
    const encodedColorValue = encodeURIComponent(this.color().hex());
    // Iconify API is documented here: https://docs.iconify.design/api/svg.html#color
    return `https://api.iconify.design/${iconPathSegment}.svg?color=${encodedColorValue}`;
  }

  /**
   * overrides `Image.src` getter
   */
  protected getSrc(): string {
    return this.svgUrl();
  }

  /**
   * overrides `Image.src` setter to warn the user that the value

Review comment (suggestion):
Anytime I see `!` bypassing the type system, I wonder if there's a better way. Some options:
- Maybe we check src where it's used and emit the error there, instead of making initialization / error checking more complex (and bypassing type checking at the same time). This is probably the easier option.
- Maybe the ideal is we set up an overridable function in `Node` called checkProps that is called after props are initialized (or even a `checkXXXX` function that's like the `getXXXX` function, called when the props are used) that can be overridden to add or remove the error message about `src`.

Code after:

  /**
   * The color of the icon
   *
   * @remarks
   * Provide the color in one of the following formats:
   * * named color like `red`, `darkgray`, …
   * * hexadecimal string with # like `#bada55`, `#141414`
   *   Value can be either RGB or RGBA: `#bada55`, `#bada55aa` (latter is partially transparent)
   *   The shorthand version (e.g. `#abc` for `#aabbcc` is also possible.)
   *
   * @defaultValue 'white'
   */
  @initial('white')
  @colorSignal()
  public declare color: ColorSignal<this>;

  public constructor(props: IconProps) {
    super({
      ...props,
      src: null,
    });
  }

  /**
   * Create the URL that will be used as the Image source
   * @returns Address to Iconify API for the requested Icon.
   */
  @computed()
  protected svgUrl(): string {
    const iconPathSegment = this.icon().replace(':', '/');
    const encodedColorValue = encodeURIComponent(this.color().hex());
    // Iconify API is documented here: https://docs.iconify.design/api/svg.html#color
    return `https://api.iconify.design/${iconPathSegment}.svg?color=${encodedColorValue}`;
  }

  /**
   * overrides `Image.src` getter
   */
  protected getSrc(): string {
    return this.svgUrl();
  }

  /**
   * overrides `Image.src` setter to warn the user that the value
   * is not used
   */
  protected setSrc(src: string | null) {
    if (src === null) {
      return;
    }