1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-17 18:09:17 +00:00

rename bit-icon to bit-svg; create new bit-icon for font icons

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Will Martin
2026-01-26 18:47:35 -05:00
parent 36b648f5d7
commit 00b4bccfd8
12 changed files with 443 additions and 145 deletions

View File

@@ -0,0 +1,67 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { BitIconComponent } from "./icon.component";
describe("BitIconComponent", () => {
let fixture: ComponentFixture<BitIconComponent>;
let component: BitIconComponent;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BitIconComponent],
}).compileComponents();
fixture = TestBed.createComponent(BitIconComponent);
component = fixture.componentInstance;
fixture.componentRef.setInput("icon", "bwi-lock");
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
it("should apply base icon class", () => {
const el = fixture.nativeElement as HTMLElement;
expect(el.classList.contains("bwi")).toBe(true);
expect(el.classList.contains("bwi-lock")).toBe(true);
});
it("should apply fw class when fw is true", () => {
fixture.componentRef.setInput("fw", true);
fixture.detectChanges();
const el = fixture.nativeElement as HTMLElement;
expect(el.classList.contains("bwi-fw")).toBe(true);
});
it("should apply spin class when spin is true", () => {
fixture.componentRef.setInput("spin", true);
fixture.detectChanges();
const el = fixture.nativeElement as HTMLElement;
expect(el.classList.contains("bwi-spin")).toBe(true);
});
it("should apply size class when size is provided", () => {
fixture.componentRef.setInput("size", "lg");
fixture.detectChanges();
const el = fixture.nativeElement as HTMLElement;
expect(el.classList.contains("bwi-lg")).toBe(true);
});
it("should set aria-label when provided", () => {
fixture.componentRef.setInput("ariaLabel", "Lock icon");
fixture.detectChanges();
const el = fixture.nativeElement as HTMLElement;
expect(el.getAttribute("aria-label")).toBe("Lock icon");
expect(el.getAttribute("aria-hidden")).toBe(null);
});
it("should set aria-hidden when no aria-label is provided", () => {
const el = fixture.nativeElement as HTMLElement;
expect(el.getAttribute("aria-hidden")).toBe("true");
});
});

View File

@@ -1,35 +1,61 @@
import { Component, effect, input } from "@angular/core";
import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
import { ChangeDetectionStrategy, Component, computed, input } from "@angular/core";
import { Icon, isIcon } from "@bitwarden/assets/svg";
import { BitwardenIcon } from "../shared/icon";
export const BitIconSize = Object.freeze({
Xs: "xs",
Sm: "sm",
Md: "md",
Lg: "lg",
Xl: "xl",
} as const);
export type BitIconSize = (typeof BitIconSize)[keyof typeof BitIconSize];
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-icon",
standalone: true,
host: {
"[attr.aria-hidden]": "!ariaLabel()",
"[class]": "classList()",
"[attr.aria-hidden]": "ariaLabel() ? null : true",
"[attr.aria-label]": "ariaLabel()",
"[innerHtml]": "innerHtml",
class: "tw-max-h-full tw-flex tw-justify-center",
},
template: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BitIconComponent {
innerHtml: SafeHtml | null = null;
/**
* The Bitwarden icon name (e.g., "bwi-lock", "bwi-user")
*/
readonly icon = input.required<BitwardenIcon>();
readonly icon = input<Icon>();
/**
* Whether the icon should have a fixed width for alignment
*/
readonly fw = input<boolean>(false);
/**
* Icon size - applies bwi-* size classes
*/
readonly size = input<BitIconSize>();
/**
* Accessible label for the icon
*/
readonly ariaLabel = input<string>();
constructor(private domSanitizer: DomSanitizer) {
effect(() => {
const icon = this.icon();
if (!isIcon(icon)) {
return;
}
const svg = icon.svg;
this.innerHtml = this.domSanitizer.bypassSecurityTrustHtml(svg);
});
}
protected readonly classList = computed(() => {
const classes = ["bwi", this.icon()];
if (this.fw()) {
classes.push("bwi-fw");
}
const size = this.size();
if (size) {
classes.push(`bwi-${size}`);
}
return classes.join(" ");
});
}

View File

@@ -8,113 +8,70 @@ import * as stories from "./icon.stories";
import { IconModule } from "@bitwarden/components";
```
# Icon Use Instructions
# Icon
- Icons will generally be attached to the associated Jira task.
- Designers should minify any SVGs before attaching them to Jira using a tool like
[SVGOMG](https://jakearchibald.github.io/svgomg/).
- **Note:** Ensure the "Remove viewbox" option is toggled off if responsive resizing of the icon
is desired.
The `bit-icon` component renders Bitwarden Web Icons (bwi) using icon font classes.
## Developer Instructions
## Basic Usage
1. **Download the SVG** and import it as an `.svg` initially into the IDE of your choice.
- The SVG should be formatted using either a built-in formatter or an external tool like
[SVG Formatter Beautifier](https://codebeautify.org/svg-formatter-beautifier) to make applying
classes easier.
```html
<bit-icon icon="bwi-lock"></bit-icon>
```
2. **Rename the file** as a `<name>.icon.ts` TypeScript file and place it in the `libs/assets/svg`
lib.
## Icon Names
3. **Import** `svgIcon` from `./icon-service`.
All available icon names are defined in the `BitwardenIcon` type. Icons use the `bwi-*` naming
convention (e.g., `bwi-lock`, `bwi-user`, `bwi-key`).
4. **Define and export** a `const` to represent your `svgIcon`.
## Modifiers
```typescript
export const ExampleIcon = svgIcon`<svg … </svg>`;
```
### Fixed Width
5. **Replace any hardcoded strokes or fills** with the appropriate Tailwind class.
- **Note:** Stroke is used when styling the outline of an SVG path, while fill is used when
styling the inside of an SVG path.
Use the `fw` input to give icons a fixed width for alignment:
- A non-comprehensive list of common colors and their associated classes is below:
```html
<bit-icon icon="bwi-lock" [fw]="true"></bit-icon>
```
| Hardcoded Value | Tailwind Stroke Class | Tailwind Fill Class | Tailwind Variable |
| ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------------------------- | ----------------------------------- |
| `#020F66` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#020F66"}}></span> | `tw-stroke-illustration-outline` | `tw-fill-illustration-outline` | `--color-illustration-outline` |
| `#DBE5F6` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#DBE5F6"}}></span> | `tw-stroke-illustration-bg-primary` | `tw-fill-illustration-bg-primary` | `--color-illustration-bg-primary` |
| `#AAC3EF` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#AAC3EF"}}></span> | `tw-stroke-illustration-bg-secondary` | `tw-fill-illustration-bg-secondary` | `--color-illustration-bg-secondary` |
| `#FFFFFF` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#FFFFFF"}}></span> | `tw-stroke-illustration-bg-tertiary` | `tw-fill-illustration-bg-tertiary` | `--color-illustration-bg-tertiary` |
| `#FFBF00` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#FFBF00"}}></span> | `tw-stroke-illustration-tertiary` | `tw-fill-illustration-tertiary` | `--color-illustration-tertiary` |
| `#175DDC` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#175DDC"}}></span> | `tw-stroke-illustration-logo` | `tw-fill-illustration-logo` | `--color-illustration-logo` |
This is useful when aligning icons in lists or menus.
- If the hex that you have on an SVG path is not listed above, there are a few ways to figure out
the appropriate Tailwind class:
- **Option 1: Figma**
- Open the SVG in Figma.
- Click on an individual path on the SVG until you see the path's properties in the
right-hand panel.
- Scroll down to the Colors section.
- Example: `Color/Illustration/Outline`
- This also includes Hex or RGB values that can be used to find the appropriate Tailwind
variable as well if you follow the manual search option below.
- Create the appropriate stroke or fill class from the color used.
- Example: `Color/Illustration/Outline` corresponds to `--color-illustration-outline` which
corresponds to `tw-stroke-illustration-outline` or `tw-fill-illustration-outline`.
- **Option 2: Manual Search**
- Take the path's stroke or fill hex value and convert it to RGB using a tool like
[Hex to RGB](https://www.rgbtohex.net/hex-to-rgb/).
- Search for the RGB value without commas in our `tw-theme.css` to find the Tailwind variable
that corresponds to the color.
- Create the appropriate stroke or fill class using the Tailwind variable.
- Example: `--color-illustration-outline` corresponds to `tw-stroke-illustration-outline`
or `tw-fill-illustration-outline`.
### Spin
6. **Remove any hardcoded width or height attributes** if your SVG has a configured
[viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) attribute in order
to allow the SVG to scale to fit its container.
- **Note:** Scaling is required for any SVG used as an
[AnonLayout](?path=/docs/component-library-anon-layout--docs) `pageIcon`.
Use the `spin` input to animate icons:
7. **Replace any generic `clipPath` ids** (such as `id="a"`) with a unique id, and update the
referencing element to use the new id (such as `clip-path="url(#unique-id-here)"`).
```html
<bit-icon icon="bwi-spinner" [spin]="true"></bit-icon>
```
8. **Import your SVG const** anywhere you want to use the SVG.
- **Angular Component Example:**
- **TypeScript:**
### Size
```typescript
import { Component } from "@angular/core";
import { IconModule } from '@bitwarden/components';
import { ExampleIcon, Example2Icon } from "@bitwarden/assets/svg";
Use the `size` input to control icon size:
@Component({
selector: "app-example",
standalone: true,
imports: [IconModule],
templateUrl: "./example.component.html",
})
export class ExampleComponent {
readonly Icons = { ExampleIcon, Example2Icon };
...
}
```
```html
<bit-icon icon="bwi-lock" size="lg"></bit-icon>
```
- **HTML:**
Available sizes: `xs`, `sm`, `md`, `lg`, `xl`
> NOTE: SVG icons are treated as decorative by default and will be `aria-hidden` unless an
> `ariaLabel` is explicitly provided to the `<bit-icon>` component
## Accessibility
```html
<bit-icon [icon]="Icons.ExampleIcon"></bit-icon>
```
By default, icons are decorative and marked with `aria-hidden="true"`. To make an icon accessible,
provide an `ariaLabel`:
With `ariaLabel`
```html
<bit-icon icon="bwi-lock" [ariaLabel]="'Secure lock'"></bit-icon>
```
```html
<bit-icon [icon]="Icons.ExampleIcon" [ariaLabel]="Your custom label text here"></bit-icon>
```
## Styling
9. **Ensure your SVG renders properly** according to Figma in both light and dark modes on a client
which supports multiple style modes.
The component renders as an inline element. Apply standard CSS classes or styles to customize
appearance:
```html
<bit-icon icon="bwi-lock" class="tw-text-primary-500 tw-text-2xl"></bit-icon>
```
## Note on SVG Icons
For SVG illustrations (not font icons), use the `bit-svg` component instead. See the Svg component
documentation for details.

View File

@@ -1,6 +1,6 @@
import { Meta } from "@storybook/angular";
import { Meta, StoryObj } from "@storybook/angular";
import * as SvgIcons from "@bitwarden/assets/svg";
import { BITWARDEN_ICONS } from "../shared/icon";
import { BitIconComponent } from "./icon.component";
@@ -13,38 +13,73 @@ export default {
url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21662-50335&t=k6OTDDPZOTtypRqo-11",
},
},
} as Meta;
argTypes: {
icon: {
control: { type: "select" },
options: BITWARDEN_ICONS,
},
size: {
control: { type: "select" },
options: ["xs", "sm", "md", "lg", "xl"],
},
},
} as Meta<BitIconComponent>;
const {
// Filtering out the few non-icons in the libs/assets/svg import
// eslint-disable-next-line @typescript-eslint/no-unused-vars
DynamicContentNotAllowedError: _DynamicContentNotAllowedError,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
isIcon,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
svgIcon,
...Icons
}: {
[key: string]: any;
} = SvgIcons;
type Story = StoryObj<BitIconComponent>;
export const Default = {
render: (args: { icons: [string, any][] }) => ({
props: args,
template: /*html*/ `
<div class="tw-bg-secondary-100 tw-p-2 tw-grid tw-grid-cols-[repeat(auto-fit,minmax(224px,1fr))] tw-gap-2">
@for (icon of icons; track icon[0]) {
<div class="tw-size-56 tw-border tw-border-secondary-300 tw-rounded-md">
<div class="tw-text-xs tw-text-center">{{icon[0]}}</div>
<div class="tw-size-52 tw-w-full tw-content-center">
<bit-icon [icon]="icon[1]"></bit-icon>
</div>
</div>
}
</div>
`,
}),
export const Default: Story = {
args: {
icons: Object.entries(Icons),
icon: "bwi-lock",
},
};
export const AllIcons: Story = {
render: () => ({
template: `
<div class="tw-grid tw-grid-cols-[repeat(auto-fit,minmax(150px,1fr))] tw-gap-4 tw-p-4">
@for (icon of icons; track icon) {
<div class="tw-flex tw-flex-col tw-items-center tw-p-2 tw-border tw-border-secondary-300 tw-rounded">
<bit-icon [icon]="icon" class="tw-text-2xl tw-mb-2"></bit-icon>
<span class="tw-text-xs tw-text-center">{{ icon }}</span>
</div>
}
</div>
`,
props: {
icons: BITWARDEN_ICONS,
},
}),
};
export const WithFixedWidth: Story = {
render: () => ({
template: `
<div class="tw-space-y-2">
<div><bit-icon icon="bwi-lock" [fw]="true"></bit-icon> Lock</div>
<div><bit-icon icon="bwi-user" [fw]="true"></bit-icon> User</div>
<div><bit-icon icon="bwi-key" [fw]="true"></bit-icon> Key</div>
</div>
`,
}),
};
export const WithSizes: Story = {
render: () => ({
template: `
<div class="tw-flex tw-items-end tw-gap-4">
<bit-icon icon="bwi-lock" size="xs"></bit-icon>
<bit-icon icon="bwi-lock" size="sm"></bit-icon>
<bit-icon icon="bwi-lock" size="md"></bit-icon>
<bit-icon icon="bwi-lock" size="lg"></bit-icon>
<bit-icon icon="bwi-lock" size="xl"></bit-icon>
</div>
`,
}),
};
export const WithAriaLabel: Story = {
args: {
icon: "bwi-lock",
ariaLabel: "Secure lock icon",
},
};

View File

@@ -1 +1,2 @@
export * from "./icon.module";
export * from "./icon.component";

View File

@@ -22,6 +22,7 @@ export * from "./form-field";
export * from "./header";
export * from "./icon-button";
export * from "./icon";
export * from "./svg";
export * from "./icon-tile";
export * from "./input";
export * from "./item";

View File

@@ -0,0 +1 @@
export * from "./svg.module";

View File

@@ -0,0 +1,31 @@
import { ChangeDetectionStrategy, Component, computed, inject, input } from "@angular/core";
import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
import { Icon, isIcon } from "@bitwarden/assets/svg";
@Component({
selector: "bit-svg",
host: {
"[attr.aria-hidden]": "!ariaLabel()",
"[attr.aria-label]": "ariaLabel()",
"[innerHtml]": "innerHtml()",
class: "tw-max-h-full tw-flex tw-justify-center",
},
template: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SvgComponent {
private domSanitizer = inject(DomSanitizer);
readonly icon = input<Icon>();
readonly ariaLabel = input<string>();
protected readonly innerHtml = computed<SafeHtml | null>(() => {
const icon = this.icon();
if (!isIcon(icon)) {
return null;
}
const svg = icon.svg;
return this.domSanitizer.bypassSecurityTrustHtml(svg);
});
}

View File

@@ -2,17 +2,17 @@ import { ComponentFixture, TestBed } from "@angular/core/testing";
import { Icon, svgIcon } from "@bitwarden/assets/svg";
import { BitIconComponent } from "./icon.component";
import { SvgComponent } from "./svg.component";
describe("IconComponent", () => {
let fixture: ComponentFixture<BitIconComponent>;
describe("SvgComponent", () => {
let fixture: ComponentFixture<SvgComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BitIconComponent],
imports: [SvgComponent],
}).compileComponents();
fixture = TestBed.createComponent(BitIconComponent);
fixture = TestBed.createComponent(SvgComponent);
fixture.detectChanges();
});

View File

@@ -0,0 +1,120 @@
import { Meta, Story, Controls } from "@storybook/addon-docs/blocks";
import * as stories from "./svg.stories";
<Meta of={stories} />
```ts
import { SvgModule } from "@bitwarden/components";
```
# Svg Use Instructions
- Icons will generally be attached to the associated Jira task.
- Designers should minify any SVGs before attaching them to Jira using a tool like
[SVGOMG](https://jakearchibald.github.io/svgomg/).
- **Note:** Ensure the "Remove viewbox" option is toggled off if responsive resizing of the icon
is desired.
## Developer Instructions
1. **Download the SVG** and import it as an `.svg` initially into the IDE of your choice.
- The SVG should be formatted using either a built-in formatter or an external tool like
[SVG Formatter Beautifier](https://codebeautify.org/svg-formatter-beautifier) to make applying
classes easier.
2. **Rename the file** as a `<name>.icon.ts` TypeScript file and place it in the `libs/assets/svg`
lib.
3. **Import** `svgIcon` from `./icon-service`.
4. **Define and export** a `const` to represent your `svgIcon`.
```typescript
export const ExampleIcon = svgIcon`<svg … </svg>`;
```
5. **Replace any hardcoded strokes or fills** with the appropriate Tailwind class.
- **Note:** Stroke is used when styling the outline of an SVG path, while fill is used when
styling the inside of an SVG path.
- A non-comprehensive list of common colors and their associated classes is below:
| Hardcoded Value | Tailwind Stroke Class | Tailwind Fill Class | Tailwind Variable |
| ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------------------------- | ----------------------------------- |
| `#020F66` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#020F66"}}></span> | `tw-stroke-illustration-outline` | `tw-fill-illustration-outline` | `--color-illustration-outline` |
| `#DBE5F6` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#DBE5F6"}}></span> | `tw-stroke-illustration-bg-primary` | `tw-fill-illustration-bg-primary` | `--color-illustration-bg-primary` |
| `#AAC3EF` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#AAC3EF"}}></span> | `tw-stroke-illustration-bg-secondary` | `tw-fill-illustration-bg-secondary` | `--color-illustration-bg-secondary` |
| `#FFFFFF` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#FFFFFF"}}></span> | `tw-stroke-illustration-bg-tertiary` | `tw-fill-illustration-bg-tertiary` | `--color-illustration-bg-tertiary` |
| `#FFBF00` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#FFBF00"}}></span> | `tw-stroke-illustration-tertiary` | `tw-fill-illustration-tertiary` | `--color-illustration-tertiary` |
| `#175DDC` <span style={{ display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#175DDC"}}></span> | `tw-stroke-illustration-logo` | `tw-fill-illustration-logo` | `--color-illustration-logo` |
- If the hex that you have on an SVG path is not listed above, there are a few ways to figure out
the appropriate Tailwind class:
- **Option 1: Figma**
- Open the SVG in Figma.
- Click on an individual path on the SVG until you see the path's properties in the
right-hand panel.
- Scroll down to the Colors section.
- Example: `Color/Illustration/Outline`
- This also includes Hex or RGB values that can be used to find the appropriate Tailwind
variable as well if you follow the manual search option below.
- Create the appropriate stroke or fill class from the color used.
- Example: `Color/Illustration/Outline` corresponds to `--color-illustration-outline` which
corresponds to `tw-stroke-illustration-outline` or `tw-fill-illustration-outline`.
- **Option 2: Manual Search**
- Take the path's stroke or fill hex value and convert it to RGB using a tool like
[Hex to RGB](https://www.rgbtohex.net/hex-to-rgb/).
- Search for the RGB value without commas in our `tw-theme.css` to find the Tailwind variable
that corresponds to the color.
- Create the appropriate stroke or fill class using the Tailwind variable.
- Example: `--color-illustration-outline` corresponds to `tw-stroke-illustration-outline`
or `tw-fill-illustration-outline`.
6. **Remove any hardcoded width or height attributes** if your SVG has a configured
[viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) attribute in order
to allow the SVG to scale to fit its container.
- **Note:** Scaling is required for any SVG used as an
[AnonLayout](?path=/docs/component-library-anon-layout--docs) `pageIcon`.
7. **Replace any generic `clipPath` ids** (such as `id="a"`) with a unique id, and update the
referencing element to use the new id (such as `clip-path="url(#unique-id-here)"`).
8. **Import your SVG const** anywhere you want to use the SVG.
- **Angular Component Example:**
- **TypeScript:**
```typescript
import { Component } from "@angular/core";
import { SvgModule } from '@bitwarden/components';
import { ExampleIcon, Example2Icon } from "@bitwarden/assets/svg";
@Component({
selector: "app-example",
standalone: true,
imports: [SvgModule],
templateUrl: "./example.component.html",
})
export class ExampleComponent {
readonly Icons = { ExampleIcon, Example2Icon };
...
}
```
- **HTML:**
> NOTE: SVG icons are treated as decorative by default and will be `aria-hidden` unless an
> `ariaLabel` is explicitly provided to the `<bit-svg>` component
```html
<bit-svg [icon]="Icons.ExampleIcon"></bit-svg>
```
With `ariaLabel`
```html
<bit-svg [icon]="Icons.ExampleIcon" [ariaLabel]="Your custom label text here"></bit-svg>
```
9. **Ensure your SVG renders properly** according to Figma in both light and dark modes on a client
which supports multiple style modes.

View File

@@ -0,0 +1,9 @@
import { NgModule } from "@angular/core";
import { SvgComponent } from "./svg.component";
@NgModule({
imports: [SvgComponent],
exports: [SvgComponent],
})
export class SvgModule {}

View File

@@ -0,0 +1,50 @@
import { Meta } from "@storybook/angular";
import * as SvgIcons from "@bitwarden/assets/svg";
import { SvgComponent } from "./svg.component";
export default {
title: "Component Library/Svg",
component: SvgComponent,
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=21662-50335&t=k6OTDDPZOTtypRqo-11",
},
},
} as Meta;
const {
// Filtering out the few non-icons in the libs/assets/svg import
// eslint-disable-next-line @typescript-eslint/no-unused-vars
DynamicContentNotAllowedError: _DynamicContentNotAllowedError,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
isIcon,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
svgIcon,
...Icons
}: {
[key: string]: any;
} = SvgIcons;
export const Default = {
render: (args: { icons: [string, any][] }) => ({
props: args,
template: /*html*/ `
<div class="tw-bg-secondary-100 tw-p-2 tw-grid tw-grid-cols-[repeat(auto-fit,minmax(224px,1fr))] tw-gap-2">
@for (icon of icons; track icon[0]) {
<div class="tw-size-56 tw-border tw-border-secondary-300 tw-rounded-md">
<div class="tw-text-xs tw-text-center">{{icon[0]}}</div>
<div class="tw-size-52 tw-w-full tw-content-center">
<bit-svg [icon]="icon[1]"></bit-svg>
</div>
</div>
}
</div>
`,
}),
args: {
icons: Object.entries(Icons),
},
};