Skip to content

Icon Service Specification

Simeon Simeonoff edited this page Apr 9, 2024 · 1 revision

Icon Service Specification [Draft]

Contents

  1. Overview
  2. Objectives
  3. User Stories
  4. API
  5. Test Scenarios
  6. Assumptions and Limitations

Owned by

Team Name: Design Team

Developer Name: Simeon Simeonoff

Signed off by

  • Damyan Petev | Date:
  • Radoslav Karaivanov | Date:

Revision History

Version Users Date Notes
1 Simeon Simeonoff 2024-04-02 Initial Draft
2 Simeon Simeonoff 2024-04-08 Updated API

The IgxIconService associates a specific resource, like an icon font or SVG, with a name and family that can later be used to reference the given resource.

Allow users to easily add and overwrite icons in their application.

Background

One of the properties of the icon service should be to provide a way to give a font family some name within the context of the service. In most cases third-party icon fonts require users to apply a specific CSS class to the element used as a placeholder for the icon. Generaly, there are two ways to consume icons from a custom font. The first maps unicode glyph code points from the icon font to CSS classes. This naming mechanism allows icons to be used in HTML in the following way:

<i class="fas fa-home"></i>

Here, the class fas refers to the general font family being used, in this case font-awesome solid and fa-car refers to the class that encapsulates the code point in the font family that is used as CSS content.

The second approach is to pass in the ligature (if available) of the glyph we want to use as text content in the HTML element. The ligature (the icon name) will then resolve to the glyph code point in the font family.

<i class="material-icons">home</i>

This will resolve the home glyph in the material icon font to the code point 0xe88a.

Requirements

  1. I want to be able to include third-party font families so that they can be consumed in a standardized way via the igx-icon component.

    /** 
    * The icon service associates a given family name (provided by the user) 
    * with a specific CSS class (as documented in the providing icon font) 
    * and corresponding icon name (documented in the icon font).
    */ 
    service.setFamily('material', { className: 'material-icons', type: 'liga' });
    service.setFamily('fa-solid', { className: 'fas', type: 'font', prefix: 'fa' });

    Later in markup:

    <igx-icon family="material" name="home"></igx-icon>
    <igx-icon family="fa-solid" name="car"></igx-icon>

    As users of the icon service, we have to know in advance what type of icon family we are dealing with and inform the icon service when setting icon families. When an icon font is ligature based, we set the type to liga in the family meta of the setFamily method. If the font family uses CSS classes that map to code points, we set the type to font.

  2. I want to be able to associate SVG images with families and give them names so that they can be included via the igx-icon component in the same way as font-based icons. The SVGs should be resolved via either strings or via absolute URI to the SVG asset.

    // Add a new 'material' icon called 'my-icon' from an SVG file
    iconService.addSvgIcon('my-icon', 'my-icon.svg', 'material');
    
    // Add a new 'fa-solid' icon called 'my-icon' from string 
    iconService.addSvgIconFromText('my-icon', '<svg>...</svg>', 'fa-solid');

    Later in markup:

    <igx-icon family="material" name="my-icon"></igx-icon>
    <igx-icon family="fa-solid" name="my-icon"></igx-icon>
  3. I want to be able to create a pseudo family map that combines icons added via either setting a family of font icons or adding SVGs under a common umbrella so that it's easier to reference them.

    // The `setIconRef` sets an icon reference in the icon map,
    // assuming material and fa-solid have been added as families,
    iconService.setIconRef('home', 'my-family', { family: 'material', name: 'home' });
    iconService.setIconRef('home-alt', 'my-family', { family: 'fa-solid', name: 'home' });
    iconService.setIconRef('car', 'my-family', { family: 'fa-solid', name: 'car' });

    Later in markup:

    <igx-icon family="my-family" name="home"></igx-icon>
    <igx-icon family="my-family" name="home-alt"></igx-icon>
    <igx-icon family="my-family" name="car"></igx-icon>
  4. I want to be able to get an icon for a given family and icon name so that I know what the original icon type, name, family and className are.

    const { family, className, name, type } = iconService.getIcon('my-family', 'car');
    
    console.log(family); // -> 'fa-solid'
    console.log(className); // -> 'fas'
    console.log(name); // -> 'fa-car'
    console.log(type); // -> 'font'
  5. I want to be able to overwrite the icons encapsulated by a given component with my own icon mappings.

    What should we do here? Do we want to support overwriting icons per component instance? If not, doing the following should be enough:

    Some component in Ignite UI for Angular:

    constructor(private iconService: IgxIconService) {}
    
    ngOnInit() {
        // Add the icon to the cache
        this.iconService.addSvgIconFromText('contains', '<svg>...</svg>', 'imx-icons');
    
        // This only adds the icon in the ref map by calling `setIconRef` if it does not exist
        this.iconService.addIconRef('contains', 'default', { family: 'imx-icons', name: 'contains' });
    }

    Component template:

    <igx-icon family="default" name="contains"></igx-icon>

    User-land component using the Ignite UI for Angular component and overwriting the contains icon in the default family:

    constructor(private iconService: IgxIconService) {}
    
    ngOnInit() {
        service.setFamily('line-awesome', { className: 'las', type: 'font' });
        this.iconService.setIconRef('contains', 'default', { family: 'line-awesome', name: 'box' });
    }
  6. I want to be able to provide a prefix when setting a font family, so that I can just call the icon by name without the given prefix. Providing the full name including the icon prefix should still work.

    setFamily(name: 'font-awesome', { className: 'fas', prefix: 'fa', type: 'font' }): IgxIconService;
    <!--You don't need to include the prefix in the icon name-->
    <igx-icon family="font-awesome" name="car"></igx-icon>
    
    <!--Providing the full name, including prefix, still works-->
    <igx-icon family="font-awesome" name="fa-car"></igx-icon>

Types

  • Icons can be one of three types: SVG, font and ligature.

    type IconType = "svg" | "font" | "liga";
  • Icons are represented in the following way:

    interface IconMeta {
        name: string;
        family: string;
        type?: IconType;
    }
  • Icon Families are registered with the following metadata:

    interface FamilyMeta {
        className: string;
        type: IconType;
        prefix?: string;
    }
  • Mapped icons are represented using the following type:

    type IconReference = IconMeta & IconFamilyMeta;

Data Structures

Families are stored in a Map with the following signature:

Map<string, IconFamilyMeta>

Example:

iconService.setFamily('fa-solid', { class: 'fas', type: 'font', prefix: 'fa' });

// The map holding the families now looks like this:
[{
    key: 'fa-solid',
    value: {
        className: 'fas',
        type: 'font',
        prefix: 'fa'
    }
}]

The key is the family name, the value is the metadata.

Icon mappings are stored in a Map with the following signature:

Map<string, Map<string, IconMeta>>

Example:

iconService.setIconRef('car', 'default', { family: 'fa-solid', name: 'car', type: 'font' });

// The mapped icons map now looks like this:
[{
    key: 'default',
    value: [{
        key: 'car',
        value: {
            family: "fa-solid",
            name: "car",
            type: "font",
            prefix: "fa"
        }
    }]
}]

The key is the name of the pseudo family collection, the value is the map of icon names to icons in the actual icon families.

Methods

  • Register a new family:

    setFamily(name: string, meta: IconFamilyMeta): IgxIconService;
  • Add an Icon reference ONLY if NOT already present the icon map:

    addIconRef(name: string, family: string, icon: IconMeta): void;
  • Set an Icon reference in the icon map:

    setIconRef(name: string, family: string, icon: IconMeta): void;
  • Get an Icon reference from the icon map:

    getIconRef(family: string, name: string): IconReference;
  • Add an SVG icon from URI:

    addSvgIcon(name: string, url: string, family: string, stripMeta = false): void;
  • Add an SVG icon from string:

    addSvgIconFromText(name: string, iconText: string, family: string, stripMeta = false): void;
  1. The end user is responsible for linking and settings font families in their applications.
  2. Adding multiple icons and/or families with the same name is supported, but the last declaration will overwrite any previous icon/family. It is highly recommended to use unique names for icons and families.
  3. Providing a combination of non-existing (not previously set) icons and families will silently fail and nothing will be displayed by the igx-icon component.
Clone this wiki locally