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

Code before:
   * Internal cache
   */
  private static iconContentsPool: Record<string, HTMLImageElement> = {};

  /**
   * Expects an Icon Identifier.
   * You can find identifiers on [Icônes](https://icones.js.org).
   * They can look like this:
   * * mdi:language-typescript
   * * ph:anchor-simple-bold
   * * ph:activity-bold
   */
  @signal()
  public declare icon: SimpleSignal<string, this>;

  /**
   * Color of the Icon. Defaults to white.
   * Provide the color in one of the following formats:
   * * named color like `red`, `darkgray`, …
   * * hexadecimal string, with or without # `#bada55`,`141414`
   *
   * Values can be either RGB or RGBA: `#bada55` or `#bada55aa` (latter is partially transparent)
   */
  @initial('white')
  @signal()
  public declare color: SimpleSignal<string, this>;

  public constructor(props: IconProps) {
    super(props);
  }

  /**
   * This creates 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(':', '/');

    // iconify API is documented here: https://docs.iconify.design/api/svg.html#color
    const url = `https://api.iconify.design/${iconPathSegment}.svg?color=${
      Icon.normalizeColorInput(this.color()) ?? 'white'
    }`; // Use white as a fallback if the user-provided color could not be parsed.
    return url;
  }

  private static isNamedColorString(color: string) {
    const style = new Option().style;
    style.color = color;
    return style.color === color;
  }

Review comment (suggestion):
Any reason we're not using the `Color` signal?
```suggestion
  @initial('white')
  @colorSignal()
  public declare color: ColorSignal<this>;
```

This automates the conversion from all string color formats to a common `Color` class provided by `chroma-js`

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.)
   *
   * @default 'white'
   */
  @initial('white')
  @colorSignal()
  public declare color: ColorSignal<this>;

  public constructor(props: IconProps) {
    super(props);
  }

  /**
   * 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() {
    useLogger().warn(
      "The Icon Component does not accept setting the `src`. If you need access to `src`, use '<Image/>` instead.",
    );
  }
}