diff --git a/.storybook/preview.ts b/.storybook/preview.ts
index 6d63698..1a190e6 100644
--- a/.storybook/preview.ts
+++ b/.storybook/preview.ts
@@ -1,6 +1,7 @@
import { withThemeByClassName } from '@storybook/addon-themes';
import type { Preview } from '@storybook/web-components';
import '../global-styles.css';
+import './registerIcons';
const preview: Preview = {
parameters: {
diff --git a/.storybook/registerIcons.ts b/.storybook/registerIcons.ts
new file mode 100644
index 0000000..b290a7c
--- /dev/null
+++ b/.storybook/registerIcons.ts
@@ -0,0 +1,8 @@
+import { addIcons } from '../src/components/icon';
+import * as cxIcons from '../src/components/icon/iconRegistry';
+
+const iconObj = Object.entries(cxIcons)
+ .map(([_, icon]) => icon as cxIcons.SVGIcon)
+ .filter((icon) => !!icon.name && !!icon.data);
+
+addIcons(...iconObj);
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c435dd9..5213488 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -51,3 +51,9 @@ The web components are located in the `src/components` folder, where each compon
2. Try to add your submissions through small, focused and well described commits. This makes it easier to do QA. Use the [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/) syntax if you feel like doing so.
3. When you're done implementing your feature, create a pull request for your branch to be merged into the `main` branch. This will automatically run linting, and will create a preview URL of your feature branch. At least one approval is required to merge the pull request.
4. When a reviewer has approved your pull request; merge your branch and delete it.
+
+## How to add new icons
+
+1. Add the new or changed SVG icon to the folder `/src/components/icon/svg`.
+2. Ensure that the icon has a width and height of 24px, and that fill and/or stroke is defined as `currentColor`.
+3. Run the script `bun run create-icon-registry`.
diff --git a/biome.json b/biome.json
index fd5cb9c..cd5b2f6 100644
--- a/biome.json
+++ b/biome.json
@@ -7,7 +7,7 @@
},
"files": {
"ignoreUnknown": false,
- "ignore": ["./src/routeTree.gen.ts", "./src/ui/Icon/name.d.ts"]
+ "ignore": ["./src/components/icon/iconRegistry.ts"]
},
"formatter": {
"enabled": true,
diff --git a/bun.lockb b/bun.lockb
index d6563dd..b6c7a90 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/dist/package.json b/dist/package.json
index 5505ab4..a1892af 100644
--- a/dist/package.json
+++ b/dist/package.json
@@ -1,6 +1,6 @@
{
"name": "@computas/designsystem",
- "version": "0.0.4",
+ "version": "0.0.5",
"description": "The Computas design system",
"type": "module",
"license": "MIT",
diff --git a/package.json b/package.json
index 34563b9..d8717d5 100644
--- a/package.json
+++ b/package.json
@@ -9,27 +9,28 @@
"lint": "biome check ./src",
"build-docs": "tsc && storybook build",
"build-styles": "tsup global-styles.css --out-dir dist",
- "build-designsystem": "bun run build-styles & bun --filter '*' build"
+ "build-designsystem": "bun run build-styles & bun --filter '*' build",
+ "create-icon-registry": "bun --filter '@computas/designsystem-icon' create-icon-registry"
},
"dependencies": {
"@lit/react": "^1.0.6",
- "@storybook/addon-themes": "^8.4.6",
"lit": "^3.2.1"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@chromatic-com/storybook": "^3.2.2",
- "@computas/designsystem-breadcrumbs": "workspace:*",
+ "@computas/designsystem-icon": "workspace:*",
"@storybook/addon-essentials": "^8.4.6",
+ "@storybook/addon-themes": "^8.4.6",
"@storybook/blocks": "^8.4.6",
"@storybook/manager-api": "^8.4.6",
"@storybook/test": "^8.4.6",
"@storybook/theming": "^8.4.6",
"@storybook/web-components": "^8.4.6",
"@storybook/web-components-vite": "^8.4.6",
- "@types/node": "^22.9.0",
+ "@types/node": "^22.10.1",
"storybook": "^8.4.6",
- "typescript": "~5.7.0",
- "vite": "^6.0.0"
+ "typescript": "~5.7.2",
+ "vite": "^6.0.2"
}
}
diff --git a/src/components/breadcrumbs/breadcrumbs.story.ts b/src/components/breadcrumbs/breadcrumbs.story.ts
deleted file mode 100644
index ffb2b66..0000000
--- a/src/components/breadcrumbs/breadcrumbs.story.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { Meta, StoryObj } from '@storybook/web-components';
-import { html } from 'lit-html';
-
-import './breadcrumbs';
-
-export default {
- title: 'Components/Breadcrumbs (do not use this component)',
-} satisfies Meta;
-
-export const Default: StoryObj = {
- render: ({ variant }) => html`I'm a breadcrumbs`,
- argTypes: {
- variant: {
- control: 'radio',
- options: ['primary', 'secondary'],
- description: 'Changes the visual appearance of the button',
- },
- },
- args: {
- variant: 'primary',
- },
-};
diff --git a/src/components/breadcrumbs/breadcrumbs.ts b/src/components/breadcrumbs/breadcrumbs.ts
deleted file mode 100644
index c80e709..0000000
--- a/src/components/breadcrumbs/breadcrumbs.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { LitElement, css, html } from 'lit';
-import { customElement, property } from 'lit/decorators.js';
-import { classMap } from 'lit/directives/class-map.js';
-
-@customElement('cx-breadcrumbs')
-export class Breadcrumbs extends LitElement {
- static styles = css``;
-
- /**
- * @description Controls the appearance of the button
- * @default "primary"
- */
- @property()
- variant: 'primary' | 'secondary' = 'primary';
-
- render() {
- return html`
-
- `;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'cx-breadcrumbs': Breadcrumbs;
- }
-}
diff --git a/src/components/breadcrumbs/index.ts b/src/components/breadcrumbs/index.ts
deleted file mode 100644
index 8d59853..0000000
--- a/src/components/breadcrumbs/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './breadcrumbs';
diff --git a/src/components/breadcrumbs/package.json b/src/components/breadcrumbs/package.json
deleted file mode 100644
index f29f61b..0000000
--- a/src/components/breadcrumbs/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "@computas/designsystem-breadcrumbs",
- "version": "1.0.0",
- "type": "module",
- "private": "true",
- "scripts": {
- "build": "tsup"
- },
- "devDependencies": {
- "tsup": "^8.3.5"
- }
-}
diff --git a/src/components/breadcrumbs/react.ts b/src/components/breadcrumbs/react.ts
deleted file mode 100644
index 6c36d79..0000000
--- a/src/components/breadcrumbs/react.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { createComponent } from '@lit/react';
-import * as React from 'react';
-
-import { Breadcrumbs } from './index';
-
-export const CxBreadcrumbs = createComponent({
- tagName: 'cx-breadcrumbs',
- elementClass: Breadcrumbs,
- react: React,
-});
diff --git a/src/components/button/button.css b/src/components/button/button.css
index 8f8822e..34fe6d2 100644
--- a/src/components/button/button.css
+++ b/src/components/button/button.css
@@ -5,7 +5,7 @@
--cx-gradient-highlight-size: 500%;
display: inline-flex;
- gap: var(--cx-spacing-1);
+ gap: var(--cx-spacing-2);
align-items: center;
justify-content: center;
text-align: center;
diff --git a/src/components/icon/Overview.mdx b/src/components/icon/Overview.mdx
new file mode 100644
index 0000000..81b83fe
--- /dev/null
+++ b/src/components/icon/Overview.mdx
@@ -0,0 +1,90 @@
+import {
+ Canvas,
+ Description,
+ IconGallery,
+ IconItem,
+ Meta,
+ Source,
+ Subtitle,
+ Title,
+} from "@storybook/blocks";
+
+import * as stories from "./icon.stories";
+import * as cxIcons from "./iconRegistry";
+
+
+
+
+
+The icon component is implemented as a web component where you manually register each icon you want to use in your application.
+This ensures that you only include the icons that you need in your bundle. To register an icon for use, please use the `addIcons()`
+function with a list of your icons, as such:
+
+
+
+The registration of icons is usually done at the root level of your application, and makes the icons globally available.
+After registering an icon, use it through the `cx-icon` component. Start by importing the component. If you use the
+web component, you only need to import the component once in your app, preferably at the root level. If you use the
+React component, you must import the component in each place you need it.
+
+
+
+Then simply use the component and provide the name of the icon you wish to display:
+
+
+
+// React
+
+`} language="tsx" dark />
+
+If you try to use an icon that is not registered, the component throws an error.
+
+
+## Icon overview
+
+
+ {Object.entries(cxIcons)
+ .map(([, icon]) => icon)
+ .filter((icon) => !!icon.data)
+ .map((icon) => (
+
+
+
+ ))}
+
+
+## Sizing
+
+The icon component can be sized through the `size` prop. The prop accepts the same values as our spacing tokens, in other words a number between 1 and 20.
+The numbers are on a relative scale, and aligns with our 4px grid. If you want your icon to be 32px, use `size="8"` (since 32 / 4 = 8).
+
+
+
+## Color
+
+By default, the icon inherits the font color of the container it's within.
+If you want to use a custom color, apply a CSS class where you use the `color` property to colorize the icon.
+
+
diff --git a/src/components/icon/icon.stories.ts b/src/components/icon/icon.stories.ts
new file mode 100644
index 0000000..2cae5e3
--- /dev/null
+++ b/src/components/icon/icon.stories.ts
@@ -0,0 +1,59 @@
+import type { Meta, StoryObj } from '@storybook/web-components';
+import { html } from 'lit';
+
+import './icon';
+
+export default {
+ title: 'Components/Icon',
+} satisfies Meta;
+
+export const Sizing: StoryObj = {
+ render: () => html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
+};
+
+export const Color: StoryObj = {
+ render: () => html`
+
+
+
+
+
+
+ `,
+};
diff --git a/src/components/icon/icon.ts b/src/components/icon/icon.ts
new file mode 100644
index 0000000..00af16d
--- /dev/null
+++ b/src/components/icon/icon.ts
@@ -0,0 +1,86 @@
+import { LitElement, css, html } from 'lit';
+import { customElement, property } from 'lit/decorators.js';
+import { unsafeHTML } from 'lit/directives/unsafe-html.js';
+
+import type { IconName } from './iconRegistry';
+import { getIcon } from './store';
+
+type IconSize =
+ | '1'
+ | '2'
+ | '3'
+ | '4'
+ | '5'
+ | '6'
+ | '7'
+ | '8'
+ | '9'
+ | '10'
+ | '11'
+ | '12'
+ | '13'
+ | '14'
+ | '15'
+ | '16'
+ | '17'
+ | '18'
+ | '19'
+ | '20';
+
+@customElement('cx-icon')
+export class Icon extends LitElement {
+ static readonly styles = css`
+ :host {
+ --_icon-size: 1.5rem;
+
+ display: inline-block;
+ width: var(--_icon-size);
+ height: var(--_icon-size);
+ line-height: 0;
+ }
+
+ :host([size='1']) { --_icon-size: 0.25rem; }
+ :host([size='2']) { --_icon-size: 0.5rem; }
+ :host([size='3']) { --_icon-size: 0.75rem; }
+ :host([size='4']) { --_icon-size: 1rem; }
+ :host([size='5']) { --_icon-size: 1.25rem; }
+ :host([size='6']) { --_icon-size: 1.5rem; }
+ :host([size='7']) { --_icon-size: 1.75rem; }
+ :host([size='8']) { --_icon-size: 2rem; }
+ :host([size='9']) { --_icon-size: 2.25rem; }
+ :host([size='10']) { --_icon-size: 2.5rem; }
+ :host([size='11']) { --_icon-size: 2.75rem; }
+ :host([size='12']) { --_icon-size: 3rem; }
+ :host([size='13']) { --_icon-size: 3.25rem; }
+ :host([size='14']) { --_icon-size: 3.5rem; }
+ :host([size='15']) { --_icon-size: 3.75rem; }
+ :host([size='16']) { --_icon-size: 4rem; }
+ :host([size='17']) { --_icon-size: 4.25rem; }
+ :host([size='18']) { --_icon-size: 4.5rem; }
+ :host([size='19']) { --_icon-size: 4.75rem; }
+ :host([size='20']) { --_icon-size: 5rem; }
+
+ svg {
+ width: 100%;
+ height: 100%;
+ }
+ `;
+
+ @property({ type: String, reflect: true })
+ name: IconName | null = null;
+
+ // Setting this to reflect: true will make the size attribute reflect to the DOM, which makes the current
+ // CSS-selector-based approach for sizing work in React. If another approach is used, this whole property may be removed.
+ @property({ type: String, reflect: true })
+ size: IconSize | undefined = undefined;
+
+ render() {
+ return html`${unsafeHTML(getIcon(this.name)?.data ?? '')}`;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'cx-icon': Icon;
+ }
+}
diff --git a/src/components/icon/iconRegistry.ts b/src/components/icon/iconRegistry.ts
new file mode 100644
index 0000000..b0fe45d
--- /dev/null
+++ b/src/components/icon/iconRegistry.ts
@@ -0,0 +1,559 @@
+/* 🤖 this file was generated by svg-to-ts */
+export const add: {
+ name: 'add';
+ data: string;
+} = {
+ name: 'add',
+ data: ``,
+};
+export const agenda: {
+ name: 'agenda';
+ data: string;
+} = {
+ name: 'agenda',
+ data: ``,
+};
+export const alarm: {
+ name: 'alarm';
+ data: string;
+} = {
+ name: 'alarm',
+ data: ``,
+};
+export const attachment: {
+ name: 'attachment';
+ data: string;
+} = {
+ name: 'attachment',
+ data: ``,
+};
+export const baby: {
+ name: 'baby';
+ data: string;
+} = {
+ name: 'baby',
+ data: ``,
+};
+export const back: {
+ name: 'back';
+ data: string;
+} = {
+ name: 'back',
+ data: ``,
+};
+export const beer: {
+ name: 'beer';
+ data: string;
+} = {
+ name: 'beer',
+ data: ``,
+};
+export const bin: {
+ name: 'bin';
+ data: string;
+} = {
+ name: 'bin',
+ data: ``,
+};
+export const book: {
+ name: 'book';
+ data: string;
+} = {
+ name: 'book',
+ data: ``,
+};
+export const bookmark: {
+ name: 'bookmark';
+ data: string;
+} = {
+ name: 'bookmark',
+ data: ``,
+};
+export const checkCircle: {
+ name: 'check-circle';
+ data: string;
+} = {
+ name: 'check-circle',
+ data: ``,
+};
+export const check: {
+ name: 'check';
+ data: string;
+} = {
+ name: 'check',
+ data: ``,
+};
+export const chess: {
+ name: 'chess';
+ data: string;
+} = {
+ name: 'chess',
+ data: ``,
+};
+export const close: {
+ name: 'close';
+ data: string;
+} = {
+ name: 'close',
+ data: ``,
+};
+export const computas: {
+ name: 'computas';
+ data: string;
+} = {
+ name: 'computas',
+ data: ``,
+};
+export const down: {
+ name: 'down';
+ data: string;
+} = {
+ name: 'down',
+ data: ``,
+};
+export const download: {
+ name: 'download';
+ data: string;
+} = {
+ name: 'download',
+ data: ``,
+};
+export const edit: {
+ name: 'edit';
+ data: string;
+} = {
+ name: 'edit',
+ data: ``,
+};
+export const email: {
+ name: 'email';
+ data: string;
+} = {
+ name: 'email',
+ data: ``,
+};
+export const errorCircle: {
+ name: 'error-circle';
+ data: string;
+} = {
+ name: 'error-circle',
+ data: ``,
+};
+export const external: {
+ name: 'external';
+ data: string;
+} = {
+ name: 'external',
+ data: ``,
+};
+export const forward: {
+ name: 'forward';
+ data: string;
+} = {
+ name: 'forward',
+ data: ``,
+};
+export const headphones: {
+ name: 'headphones';
+ data: string;
+} = {
+ name: 'headphones',
+ data: ``,
+};
+export const history: {
+ name: 'history';
+ data: string;
+} = {
+ name: 'history',
+ data: ``,
+};
+export const hyperlink: {
+ name: 'hyperlink';
+ data: string;
+} = {
+ name: 'hyperlink',
+ data: ``,
+};
+export const image: {
+ name: 'image';
+ data: string;
+} = {
+ name: 'image',
+ data: ``,
+};
+export const infoCircle: {
+ name: 'info-circle';
+ data: string;
+} = {
+ name: 'info-circle',
+ data: ``,
+};
+export const laptop: {
+ name: 'laptop';
+ data: string;
+} = {
+ name: 'laptop',
+ data: ``,
+};
+export const left: {
+ name: 'left';
+ data: string;
+} = {
+ name: 'left',
+ data: ``,
+};
+export const location: {
+ name: 'location';
+ data: string;
+} = {
+ name: 'location',
+ data: ``,
+};
+export const logOut: {
+ name: 'log-out';
+ data: string;
+} = {
+ name: 'log-out',
+ data: ``,
+};
+export const meatballMenu: {
+ name: 'meatball-menu';
+ data: string;
+} = {
+ name: 'meatball-menu',
+ data: ``,
+};
+export const message: {
+ name: 'message';
+ data: string;
+} = {
+ name: 'message',
+ data: ``,
+};
+export const microphone: {
+ name: 'microphone';
+ data: string;
+} = {
+ name: 'microphone',
+ data: ``,
+};
+export const multipleActionsQuestion: {
+ name: 'multiple-actions-question';
+ data: string;
+} = {
+ name: 'multiple-actions-question',
+ data: ``,
+};
+export const phone: {
+ name: 'phone';
+ data: string;
+} = {
+ name: 'phone',
+ data: ``,
+};
+export const playCircle: {
+ name: 'play-circle';
+ data: string;
+} = {
+ name: 'play-circle',
+ data: ``,
+};
+export const presenter: {
+ name: 'presenter';
+ data: string;
+} = {
+ name: 'presenter',
+ data: ``,
+};
+export const preview: {
+ name: 'preview';
+ data: string;
+} = {
+ name: 'preview',
+ data: ``,
+};
+export const profile: {
+ name: 'profile';
+ data: string;
+} = {
+ name: 'profile',
+ data: ``,
+};
+export const qr: {
+ name: 'qr';
+ data: string;
+} = {
+ name: 'qr',
+ data: ``,
+};
+export const right: {
+ name: 'right';
+ data: string;
+} = {
+ name: 'right',
+ data: ``,
+};
+export const search: {
+ name: 'search';
+ data: string;
+} = {
+ name: 'search',
+ data: ``,
+};
+export const security: {
+ name: 'security';
+ data: string;
+} = {
+ name: 'security',
+ data: ``,
+};
+export const send: {
+ name: 'send';
+ data: string;
+} = {
+ name: 'send',
+ data: ``,
+};
+export const settings: {
+ name: 'settings';
+ data: string;
+} = {
+ name: 'settings',
+ data: ``,
+};
+export const sick: {
+ name: 'sick';
+ data: string;
+} = {
+ name: 'sick',
+ data: ``,
+};
+export const slack: {
+ name: 'slack';
+ data: string;
+} = {
+ name: 'slack',
+ data: ``,
+};
+export const social: {
+ name: 'social';
+ data: string;
+} = {
+ name: 'social',
+ data: ``,
+};
+export const sortAscending: {
+ name: 'sort-ascending';
+ data: string;
+} = {
+ name: 'sort-ascending',
+ data: ``,
+};
+export const sortDescending: {
+ name: 'sort-descending';
+ data: string;
+} = {
+ name: 'sort-descending',
+ data: ``,
+};
+export const sorting: {
+ name: 'sorting';
+ data: string;
+} = {
+ name: 'sorting',
+ data: ``,
+};
+export const starFilled: {
+ name: 'star-filled';
+ data: string;
+} = {
+ name: 'star-filled',
+ data: ``,
+};
+export const star: {
+ name: 'star';
+ data: string;
+} = {
+ name: 'star',
+ data: ``,
+};
+export const tech: {
+ name: 'tech';
+ data: string;
+} = {
+ name: 'tech',
+ data: ``,
+};
+export const time: {
+ name: 'time';
+ data: string;
+} = {
+ name: 'time',
+ data: ``,
+};
+export const timer: {
+ name: 'timer';
+ data: string;
+} = {
+ name: 'timer',
+ data: ``,
+};
+export const up: {
+ name: 'up';
+ data: string;
+} = {
+ name: 'up',
+ data: ``,
+};
+export const upload: {
+ name: 'upload';
+ data: string;
+} = {
+ name: 'upload',
+ data: ``,
+};
+export const vacation: {
+ name: 'vacation';
+ data: string;
+} = {
+ name: 'vacation',
+ data: ``,
+};
+export const warning: {
+ name: 'warning';
+ data: string;
+} = {
+ name: 'warning',
+ data: ``,
+};
+export type IconName =
+ | 'add'
+ | 'agenda'
+ | 'alarm'
+ | 'attachment'
+ | 'baby'
+ | 'back'
+ | 'beer'
+ | 'bin'
+ | 'book'
+ | 'bookmark'
+ | 'check-circle'
+ | 'check'
+ | 'chess'
+ | 'close'
+ | 'computas'
+ | 'down'
+ | 'download'
+ | 'edit'
+ | 'email'
+ | 'error-circle'
+ | 'external'
+ | 'forward'
+ | 'headphones'
+ | 'history'
+ | 'hyperlink'
+ | 'image'
+ | 'info-circle'
+ | 'laptop'
+ | 'left'
+ | 'location'
+ | 'log-out'
+ | 'meatball-menu'
+ | 'message'
+ | 'microphone'
+ | 'multiple-actions-question'
+ | 'phone'
+ | 'play-circle'
+ | 'presenter'
+ | 'preview'
+ | 'profile'
+ | 'qr'
+ | 'right'
+ | 'search'
+ | 'security'
+ | 'send'
+ | 'settings'
+ | 'sick'
+ | 'slack'
+ | 'social'
+ | 'sort-ascending'
+ | 'sort-descending'
+ | 'sorting'
+ | 'star-filled'
+ | 'star'
+ | 'tech'
+ | 'time'
+ | 'timer'
+ | 'up'
+ | 'upload'
+ | 'vacation'
+ | 'warning';
+export interface SVGIcon {
+ name: IconName;
+ data: string;
+}
+export type SVGIconNameSubset> =
+ T[number]['name'];
+export const completeIconSet = [
+ add,
+ agenda,
+ alarm,
+ attachment,
+ baby,
+ back,
+ beer,
+ bin,
+ book,
+ bookmark,
+ checkCircle,
+ check,
+ chess,
+ close,
+ computas,
+ down,
+ download,
+ edit,
+ email,
+ errorCircle,
+ external,
+ forward,
+ headphones,
+ history,
+ hyperlink,
+ image,
+ infoCircle,
+ laptop,
+ left,
+ location,
+ logOut,
+ meatballMenu,
+ message,
+ microphone,
+ multipleActionsQuestion,
+ phone,
+ playCircle,
+ presenter,
+ preview,
+ profile,
+ qr,
+ right,
+ search,
+ security,
+ send,
+ settings,
+ sick,
+ slack,
+ social,
+ sortAscending,
+ sortDescending,
+ sorting,
+ starFilled,
+ star,
+ tech,
+ time,
+ timer,
+ up,
+ upload,
+ vacation,
+ warning,
+];
diff --git a/src/components/icon/index.ts b/src/components/icon/index.ts
new file mode 100644
index 0000000..4fd61ea
--- /dev/null
+++ b/src/components/icon/index.ts
@@ -0,0 +1,2 @@
+export { Icon } from './icon';
+export { addIcons } from './store';
diff --git a/src/components/icon/package.json b/src/components/icon/package.json
new file mode 100644
index 0000000..3bcd5b2
--- /dev/null
+++ b/src/components/icon/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "@computas/designsystem-icon",
+ "version": "1.0.0",
+ "type": "module",
+ "private": "true",
+ "scripts": {
+ "create-icon-registry": "svg-to-ts-constants",
+ "build": "tsup index.ts react.ts iconRegistry.ts"
+ },
+ "devDependencies": {
+ "svg-to-ts": "^12.0.0",
+ "tsup": "^8.3.5"
+ },
+ "svg-to-ts": {
+ "srcFiles": ["svg/*.svg"],
+ "outputDirectory": "./",
+ "prefix": "",
+ "typeName": "IconName",
+ "fileName": "iconRegistry",
+ "delimiter": "KEBAB",
+ "interfaceName": "SVGIcon"
+ }
+}
diff --git a/src/components/icon/react.ts b/src/components/icon/react.ts
new file mode 100644
index 0000000..cc0f36c
--- /dev/null
+++ b/src/components/icon/react.ts
@@ -0,0 +1,10 @@
+import { createComponent } from '@lit/react';
+import * as React from 'react';
+
+import { Icon } from './index';
+
+export const CxIcon = createComponent({
+ tagName: 'cx-icon',
+ elementClass: Icon,
+ react: React,
+});
diff --git a/src/components/icon/store.ts b/src/components/icon/store.ts
new file mode 100644
index 0000000..9e7075a
--- /dev/null
+++ b/src/components/icon/store.ts
@@ -0,0 +1,33 @@
+import type { IconName, SVGIcon } from './iconRegistry';
+
+type IconRegistry = Record;
+
+const _cxGlobalIconsStore: IconRegistry = {};
+
+/**
+ * Add icons to the global icon store to make them available for use in the `/CxIcon` component.
+ * You can add multiple icons at once.
+ *
+ * @example
+ * ```ts
+ * import { addIcons } from '@computas/designsystem/icon';
+ * import { bin, download } from '@computas/designsystem/icon/iconRegistry';
+ *
+ * addIcons(bin, download);
+ * ```
+ */
+export const addIcons = (...icons: SVGIcon[]) => {
+ icons.forEach((icon) => {
+ _cxGlobalIconsStore[icon.name] = icon;
+ });
+};
+
+export const getIcon = (name: IconName | null): SVGIcon | undefined => {
+ // Need to check `name` because it can be `undefined` on initial render depending on property vs attribute
+ if (name && !_cxGlobalIconsStore[name]) {
+ throw new Error(
+ `Icon "${name}" not found. Ensure the icon name is correct and that it has been added to the global icon store using \`addIcons\`.`,
+ );
+ }
+ return _cxGlobalIconsStore[name ?? ''];
+};
diff --git a/src/components/icon/svg/add.svg b/src/components/icon/svg/add.svg
new file mode 100644
index 0000000..36e9a3f
--- /dev/null
+++ b/src/components/icon/svg/add.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/agenda.svg b/src/components/icon/svg/agenda.svg
new file mode 100644
index 0000000..6639946
--- /dev/null
+++ b/src/components/icon/svg/agenda.svg
@@ -0,0 +1,26 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/alarm.svg b/src/components/icon/svg/alarm.svg
new file mode 100644
index 0000000..f84cf2f
--- /dev/null
+++ b/src/components/icon/svg/alarm.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/attachment.svg b/src/components/icon/svg/attachment.svg
new file mode 100644
index 0000000..5272beb
--- /dev/null
+++ b/src/components/icon/svg/attachment.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/baby.svg b/src/components/icon/svg/baby.svg
new file mode 100644
index 0000000..0e7a9b5
--- /dev/null
+++ b/src/components/icon/svg/baby.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/back.svg b/src/components/icon/svg/back.svg
new file mode 100644
index 0000000..8336fcf
--- /dev/null
+++ b/src/components/icon/svg/back.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/beer.svg b/src/components/icon/svg/beer.svg
new file mode 100644
index 0000000..e0af4f5
--- /dev/null
+++ b/src/components/icon/svg/beer.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/bin.svg b/src/components/icon/svg/bin.svg
new file mode 100644
index 0000000..46698f5
--- /dev/null
+++ b/src/components/icon/svg/bin.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/book.svg b/src/components/icon/svg/book.svg
new file mode 100644
index 0000000..8830033
--- /dev/null
+++ b/src/components/icon/svg/book.svg
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/bookmark.svg b/src/components/icon/svg/bookmark.svg
new file mode 100644
index 0000000..80dc126
--- /dev/null
+++ b/src/components/icon/svg/bookmark.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/check-circle.svg b/src/components/icon/svg/check-circle.svg
new file mode 100644
index 0000000..2078e0d
--- /dev/null
+++ b/src/components/icon/svg/check-circle.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/check.svg b/src/components/icon/svg/check.svg
new file mode 100644
index 0000000..fd75345
--- /dev/null
+++ b/src/components/icon/svg/check.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/chess.svg b/src/components/icon/svg/chess.svg
new file mode 100644
index 0000000..a603c0c
--- /dev/null
+++ b/src/components/icon/svg/chess.svg
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/close.svg b/src/components/icon/svg/close.svg
new file mode 100644
index 0000000..5ec9146
--- /dev/null
+++ b/src/components/icon/svg/close.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/computas.svg b/src/components/icon/svg/computas.svg
new file mode 100644
index 0000000..7c4e963
--- /dev/null
+++ b/src/components/icon/svg/computas.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/down.svg b/src/components/icon/svg/down.svg
new file mode 100644
index 0000000..79a3123
--- /dev/null
+++ b/src/components/icon/svg/down.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/download.svg b/src/components/icon/svg/download.svg
new file mode 100644
index 0000000..b9a4315
--- /dev/null
+++ b/src/components/icon/svg/download.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/edit.svg b/src/components/icon/svg/edit.svg
new file mode 100644
index 0000000..b424a75
--- /dev/null
+++ b/src/components/icon/svg/edit.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/email.svg b/src/components/icon/svg/email.svg
new file mode 100644
index 0000000..512b4a6
--- /dev/null
+++ b/src/components/icon/svg/email.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/error-circle.svg b/src/components/icon/svg/error-circle.svg
new file mode 100644
index 0000000..9d6c52b
--- /dev/null
+++ b/src/components/icon/svg/error-circle.svg
@@ -0,0 +1,14 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/external.svg b/src/components/icon/svg/external.svg
new file mode 100644
index 0000000..1602d6b
--- /dev/null
+++ b/src/components/icon/svg/external.svg
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/forward.svg b/src/components/icon/svg/forward.svg
new file mode 100644
index 0000000..30dfc9b
--- /dev/null
+++ b/src/components/icon/svg/forward.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/headphones.svg b/src/components/icon/svg/headphones.svg
new file mode 100644
index 0000000..4c11968
--- /dev/null
+++ b/src/components/icon/svg/headphones.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/history.svg b/src/components/icon/svg/history.svg
new file mode 100644
index 0000000..49b2624
--- /dev/null
+++ b/src/components/icon/svg/history.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/hyperlink.svg b/src/components/icon/svg/hyperlink.svg
new file mode 100644
index 0000000..e7733ec
--- /dev/null
+++ b/src/components/icon/svg/hyperlink.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/image.svg b/src/components/icon/svg/image.svg
new file mode 100644
index 0000000..b631d2a
--- /dev/null
+++ b/src/components/icon/svg/image.svg
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/info-circle.svg b/src/components/icon/svg/info-circle.svg
new file mode 100644
index 0000000..337bfd2
--- /dev/null
+++ b/src/components/icon/svg/info-circle.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/laptop.svg b/src/components/icon/svg/laptop.svg
new file mode 100644
index 0000000..a22a2d8
--- /dev/null
+++ b/src/components/icon/svg/laptop.svg
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/left.svg b/src/components/icon/svg/left.svg
new file mode 100644
index 0000000..5f9b6f5
--- /dev/null
+++ b/src/components/icon/svg/left.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/location.svg b/src/components/icon/svg/location.svg
new file mode 100644
index 0000000..dca4f31
--- /dev/null
+++ b/src/components/icon/svg/location.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/log-out.svg b/src/components/icon/svg/log-out.svg
new file mode 100644
index 0000000..070373c
--- /dev/null
+++ b/src/components/icon/svg/log-out.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/meatball-menu.svg b/src/components/icon/svg/meatball-menu.svg
new file mode 100644
index 0000000..a527320
--- /dev/null
+++ b/src/components/icon/svg/meatball-menu.svg
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/message.svg b/src/components/icon/svg/message.svg
new file mode 100644
index 0000000..a7d47f8
--- /dev/null
+++ b/src/components/icon/svg/message.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/microphone.svg b/src/components/icon/svg/microphone.svg
new file mode 100644
index 0000000..b77467f
--- /dev/null
+++ b/src/components/icon/svg/microphone.svg
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/multiple-actions-question.svg b/src/components/icon/svg/multiple-actions-question.svg
new file mode 100644
index 0000000..d8c6a8b
--- /dev/null
+++ b/src/components/icon/svg/multiple-actions-question.svg
@@ -0,0 +1,20 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/phone.svg b/src/components/icon/svg/phone.svg
new file mode 100644
index 0000000..9c52434
--- /dev/null
+++ b/src/components/icon/svg/phone.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/play-circle.svg b/src/components/icon/svg/play-circle.svg
new file mode 100644
index 0000000..2b416e3
--- /dev/null
+++ b/src/components/icon/svg/play-circle.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/presenter.svg b/src/components/icon/svg/presenter.svg
new file mode 100644
index 0000000..c2c5572
--- /dev/null
+++ b/src/components/icon/svg/presenter.svg
@@ -0,0 +1,23 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/preview.svg b/src/components/icon/svg/preview.svg
new file mode 100644
index 0000000..0432d85
--- /dev/null
+++ b/src/components/icon/svg/preview.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/profile.svg b/src/components/icon/svg/profile.svg
new file mode 100644
index 0000000..013ce4e
--- /dev/null
+++ b/src/components/icon/svg/profile.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/qr.svg b/src/components/icon/svg/qr.svg
new file mode 100644
index 0000000..5344ce9
--- /dev/null
+++ b/src/components/icon/svg/qr.svg
@@ -0,0 +1,38 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/right.svg b/src/components/icon/svg/right.svg
new file mode 100644
index 0000000..52dea61
--- /dev/null
+++ b/src/components/icon/svg/right.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/search.svg b/src/components/icon/svg/search.svg
new file mode 100644
index 0000000..e7bd2e1
--- /dev/null
+++ b/src/components/icon/svg/search.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/security.svg b/src/components/icon/svg/security.svg
new file mode 100644
index 0000000..aedd463
--- /dev/null
+++ b/src/components/icon/svg/security.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/send.svg b/src/components/icon/svg/send.svg
new file mode 100644
index 0000000..0bee3f5
--- /dev/null
+++ b/src/components/icon/svg/send.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/settings.svg b/src/components/icon/svg/settings.svg
new file mode 100644
index 0000000..3a7cd1a
--- /dev/null
+++ b/src/components/icon/svg/settings.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/sick.svg b/src/components/icon/svg/sick.svg
new file mode 100644
index 0000000..702091c
--- /dev/null
+++ b/src/components/icon/svg/sick.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/slack.svg b/src/components/icon/svg/slack.svg
new file mode 100644
index 0000000..2fa03c2
--- /dev/null
+++ b/src/components/icon/svg/slack.svg
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/social.svg b/src/components/icon/svg/social.svg
new file mode 100644
index 0000000..9e3cdaa
--- /dev/null
+++ b/src/components/icon/svg/social.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/sort-ascending.svg b/src/components/icon/svg/sort-ascending.svg
new file mode 100644
index 0000000..591fb23
--- /dev/null
+++ b/src/components/icon/svg/sort-ascending.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/sort-descending.svg b/src/components/icon/svg/sort-descending.svg
new file mode 100644
index 0000000..695ad6e
--- /dev/null
+++ b/src/components/icon/svg/sort-descending.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/sorting.svg b/src/components/icon/svg/sorting.svg
new file mode 100644
index 0000000..2e5c612
--- /dev/null
+++ b/src/components/icon/svg/sorting.svg
@@ -0,0 +1,14 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/star-filled.svg b/src/components/icon/svg/star-filled.svg
new file mode 100644
index 0000000..fa6e4b0
--- /dev/null
+++ b/src/components/icon/svg/star-filled.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/star.svg b/src/components/icon/svg/star.svg
new file mode 100644
index 0000000..e2d3436
--- /dev/null
+++ b/src/components/icon/svg/star.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/tech.svg b/src/components/icon/svg/tech.svg
new file mode 100644
index 0000000..8497edf
--- /dev/null
+++ b/src/components/icon/svg/tech.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/time.svg b/src/components/icon/svg/time.svg
new file mode 100644
index 0000000..7b9aae4
--- /dev/null
+++ b/src/components/icon/svg/time.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/timer.svg b/src/components/icon/svg/timer.svg
new file mode 100644
index 0000000..a1ad2d8
--- /dev/null
+++ b/src/components/icon/svg/timer.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/up.svg b/src/components/icon/svg/up.svg
new file mode 100644
index 0000000..7412670
--- /dev/null
+++ b/src/components/icon/svg/up.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/upload.svg b/src/components/icon/svg/upload.svg
new file mode 100644
index 0000000..cdffbbe
--- /dev/null
+++ b/src/components/icon/svg/upload.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/vacation.svg b/src/components/icon/svg/vacation.svg
new file mode 100644
index 0000000..3acdd60
--- /dev/null
+++ b/src/components/icon/svg/vacation.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svg/warning.svg b/src/components/icon/svg/warning.svg
new file mode 100644
index 0000000..e31ca86
--- /dev/null
+++ b/src/components/icon/svg/warning.svg
@@ -0,0 +1,14 @@
+
\ No newline at end of file
diff --git a/src/components/icon/svgo.config.js b/src/components/icon/svgo.config.js
new file mode 100644
index 0000000..791ae63
--- /dev/null
+++ b/src/components/icon/svgo.config.js
@@ -0,0 +1,12 @@
+export default {
+ plugins: [
+ {
+ name: 'preset-default',
+ params: {
+ overrides: {
+ removeViewBox: false,
+ },
+ },
+ },
+ ],
+};
diff --git a/tsconfig.json b/tsconfig.json
index 9912d36..a9ebc1d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -23,5 +23,5 @@
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts"],
- "exclude": ["src/**/*.stories.ts"] // <-- this is the line we need to add
+ "exclude": ["src/**/*.stories.ts"]
}
diff --git a/src/vite-env.d.ts b/vite-env.d.ts
similarity index 100%
rename from src/vite-env.d.ts
rename to vite-env.d.ts