import { html, css, TemplateResult } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { OmniElement } from '../core/OmniElement.js'; /** * Component that displays an icon. * * @import * ```js * import '@capitec/omni-components/icon'; * ``` * * @example * ```html * * * * ``` * * @example * ```html * * * ``` * * @element omni-icon * * Registry of all properties defined by the component. * * @slot - The icon to be displayed * * @cssprop --omni-icon-fill - Icon fill color. * @cssprop --omni-icon-background-color - Icon background color. * @cssprop --omni-icon-size-large - Icon large size. * @cssprop --omni-icon-size-medium - Icon medium size. * @cssprop --omni-icon-size-small - Icon small size. * @cssprop --omni-icon-size-extra-small - Icon extra small size. * @cssprop --omni-icon-size-default - Icon default size. * */ @customElement('omni-icon') export class Icon extends OmniElement { /** * Size to display the icon at * @attr [size="default"] */ @property({ type: String, reflect: true }) size: 'default' | 'extra-small' | 'small' | 'medium' | 'large' = 'default'; /** * Name of the icon to display. Takes preference over the slotted icon. * @attr */ @property({ type: String, reflect: true }) icon?: string; /** * When true, enforces 1:1 width and height of the icon. * @attr */ @property({ type: Boolean, reflect: true }) symmetrical?: boolean; static override get styles() { return [ super.styles, css` :host { width: fit-content; justify-content: center; color: var(--omni-icon-fill, currentColor); fill: var(--omni-icon-fill, currentColor); background-color: var(--omni-icon-background-color); } /* MATERIAL ICON STYLES */ .material-icon { font-family: 'Material Icons'; font-weight: normal; font-style: normal; display: inline-block; line-height: 1; text-transform: none; letter-spacing: normal; word-wrap: normal; white-space: nowrap; direction: ltr; padding: 0px; margin: 0px; align-self: center; justify-self: center; /* Support for all WebKit browsers. */ -webkit-font-smoothing: antialiased; /* Support for Safari and Chrome. */ text-rendering: optimizeLegibility; /* Support for Firefox. */ -moz-osx-font-smoothing: grayscale; /* Support for IE. */ font-feature-settings: 'liga'; } .material-icon.large { font-size: var(--omni-icon-size-large, 48px); } .material-icon.medium { font-size: var(--omni-icon-size-medium, 32px); } .material-icon.small { font-size: var(--omni-icon-size-small, 16px); } .material-icon.extra-small { font-size: var(--omni-icon-size-extra-small, 8.25px); } .material-icon.default { font-size: var(--omni-icon-size-default, 24px); } /* SVG ICON STYLES */ .svg-icon.large { height: var(--omni-icon-size-large, 48px); } .svg-icon.large.symmetrical { width: var(--omni-icon-size-large, 48px); } .svg-icon.medium { height: var(--omni-icon-size-medium, 32px); } .svg-icon.medium.symmetrical { width: var(--omni-icon-size-medium, 32px); } .svg-icon.small { height: var(--omni-icon-size-small, 16px); } .svg-icon.small.symmetrical { width: var(--omni-icon-size-small, 16px); } .svg-icon.extra-small { height: var(--omni-icon-size-extra-small, 8.25px); } .svg-icon.extra-small.symmetrical { width: var(--omni-icon-size-extra-small, 8.25px); } .svg-icon.default { height: var(--omni-icon-size-default, 24px); } .svg-icon.default.symmetrical { width: var(--omni-icon-size-default, 24px); } ` ]; } override render(): TemplateResult { const iconClassMap = classMap({ ['svg-icon']: true, [`${this.size}`]: this.size, [`symmetrical`]: this.symmetrical ?? false }); if (this.icon) { if (this.icon.startsWith('@material/')) { return html`
${this.icon.replace('@material/', '')}
`; } return html` ${this.icon} `; } return html`
`; } } declare global { interface HTMLElementTagNameMap { 'omni-icon': Icon; } }