@cockroachlabs/icons

Icons for Cockroach UI exported as React Components

Usage no npm install needed!

<script type="module">
  import cockroachlabsIcons from 'https://cdn.skypack.dev/@cockroachlabs/icons';
</script>

README

@cockroachlabs/icons

a package containing Cockroach Labs icons as SVG for consumption by other components

This package serves as a store for SVG icons that are converted and published as React components.

Example Usage

import { Time } from "@cockroachlabs/icons";

const TimeButton = ({ timestamp }) => (
  <button>
    <Time /> {timestamp}
  </button>
);
import * as Icons from "@cockroachlabs/icons";

// ...

<EditMessage icon={Icons.Pencil} />;

Each Icon component will render an <svg /> element with an unbounded size and may not have a default fill color. These properties can be passed in as props.


  import { CheckCircleFilled } from "@cockroachlabs/icons";

  <CheckCircleFilled fill="green" height="24px" width="24px" />

  // or

  <CheckCircleFilled style={{ fill: "green", height: "24px", width: "24px" }} />

How does this package work?

This package serves as a store for SVG icons that are converted and published as React components. The SVGs are stored in the /svg directory and @svgr/cli is used to convert them to React components in TypeScript.

Since the components are generated from .svg files they are not committed in this repository. The only file that is kept under source control is the index.ts. The components are generated to the directory src/components by the npm script build:generate:*. Once the components are generated, they are transpiled and TypeScript declarations are generated by the TypeScript Compiler (npm script build:typescript).

To generate the files locally run npm run build or yarn run build.

Preserving or removing fill attributes

This package is used to process several icon sets. Some icons, like our System Icons, will have their fills altered to match an intent while some others, like flags or third party icons, should have their fill attributes preserved and not allow the user to modify them. To accomodate each of these needs the svg directory has two sub-directories, preserveFill and customFill. Each of these sub-directories will be process by a command run by an npm lifecycle script; build:generate:stripfill to remove fill attributes and build:generate:preserve to leave the fill attributes alone. This works by having the stripfill script run an svgr command that will pick up configuration options found in .svgo.yaml. These configuration options follow the SVGO format, in this case using removeAttr. The preserve script on the other hand uses the --no-runtime-config cli option to suppress this config file, therefor leaving fill attributes in tact.

Historic reference

Our first pass at this used SVGR as a webpack plugin, @svgr/webpack. While this worked fine for generating the code it made it difficult to work with in TypeScript. The first issue was that the index.ts file would export .svg files. For example,

export { default as ArrowLeft } from "../svg/arrow-left.svg";
export { default as Aws } from "../svg/aws.svg";
export { default as Backup } from "../svg/backup.svg";
export { default as CancelCircleFilled } from "../svg/cancel-circle-filled.svg";
export { default as CancelCircle } from "../svg/cancel-circle.svg";
// etc etc

This vexed TypeScript as it could not process the module arrow-left.svg without a little help. This was alleviated by setting up module declaration for svg assets. Something like,

./src/@types/assets/index.d.ts

declare module "\*.svg" {
  import { FunctionComponent, SVGProps } from "react";
  export const ReactComponent: FunctionComponent<SVGProps<SVGSVGElement>>;
  const src: string;
  export default src;
}

./tsconfig.json

{
  "compilerOptions": {
    // ...
    "typeRoots": ["./src/@types", "./node_module/@types"]
    // ...
  }
  // ...
}

This resolved the first issue (that the svg imports would fail type checking), but the second issue was how to export declarations for the components bundled by Webpack. This would lead to removing Webpack entirely as it was far too heavy a tool to simply generate React Components.

I'm leaving this here as a learning because I think this technique would be useful in an application where lots of bundling is happening for React Components and preprocessed CSS. Dropping in the @svgr/webpack plugin and adding the module declaration to an existing declarations file would be trivial and could result in an effective way to handle svg icons.