Skip to content

Commit

Permalink
refactor: rewrite vaadin-iconset as vanilla custom element (#8550)
Browse files Browse the repository at this point in the history
  • Loading branch information
web-padawan authored Jan 23, 2025
1 parent e4eac52 commit 38146af
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 98 deletions.
102 changes: 66 additions & 36 deletions packages/icon/src/vaadin-iconset-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,31 +36,8 @@ function initIconsMap(iconset, name) {
*/
export const IconsetMixin = (superClass) =>
class extends superClass {
static get properties() {
return {
/**
* The name of the iconset. Every iconset is required to have its own unique name.
* All the SVG icons in the iconset must have IDs conforming to its name.
*
* See also [`name`](#/elements/vaadin-icon#property-name) property of `vaadin-icon`.
*/
name: {
type: String,
observer: '__nameChanged',
sync: true,
},
/**
* The size of an individual icon. Note that icons must be square.
*
* When using `vaadin-icon`, the size of the iconset will take precedence
* over the size defined by the user to ensure correct appearance.
*/
size: {
type: Number,
value: 24,
sync: true,
},
};
static get observedAttributes() {
return ['name', 'size'];
}

/**
Expand Down Expand Up @@ -123,23 +100,75 @@ export const IconsetMixin = (superClass) =>
initIconsMap(iconset, name);
iconset.size = size;
iconset.name = name;

// Call this function manually instead of using observer
// to make it work without appending element to the DOM.
iconset.__nameChanged(name);
}
}

/**
* The name of the iconset. Every iconset is required to have its own unique name.
* All the SVG icons in the iconset must have IDs conforming to its name.
*
* See also [`name`](#/elements/vaadin-icon#property-name) property of `vaadin-icon`.
*
* @return {string}
*/
get name() {
return this.__name;
}

/**
* @type {string}
*/
set name(name) {
const oldName = this.__name;
this.__name = name;
this.__nameChanged(name, oldName);
}

/**
* The size of an individual icon. Note that icons must be square.
*
* When using `vaadin-icon`, the size of the iconset will take precedence
* over the size defined by the user to ensure correct appearance.
*
* @return {number}
*/
get size() {
// Use default property value as a fallback here instead of the constructor
// to not override an instance property in the lazy upgrade scenario below.
return this.__size !== undefined ? this.__size : 24;
}

/**
* @type {number}
*/
set size(size) {
this.__size = size;
}

/** @protected */
connectedCallback() {
super.connectedCallback();
// A user may set a property on an _instance_ of an element
// before the custom element is lazily imported and upgraded.
// If so, we need to run it through the proper class setter.
['name', 'size'].forEach((prop) => {
// eslint-disable-next-line no-prototype-builtins
if (this.hasOwnProperty(prop)) {
const value = this[prop];
delete this[prop];
this[prop] = value;
}
});

this.style.display = 'none';
}

// Store reference and init icons.
const { name } = this;
iconsetRegistry[name] = this;
initIconsMap(this, name);
this.__updateIcons(name);
/** @protected */
attributeChangedCallback(attr, _oldValue, newValue) {
if (attr === 'name') {
this.name = newValue;
} else if (attr === 'size') {
this.size = newValue == null ? null : Number(newValue);
}
}

/**
Expand All @@ -159,10 +188,11 @@ export const IconsetMixin = (superClass) =>
/** @private */
__nameChanged(name, oldName) {
if (oldName) {
iconsetRegistry[name] = iconsetRegistry[oldName];
delete iconsetRegistry[oldName];
}
if (name) {
iconsetRegistry[name] = this;
initIconsMap(this, name);
this.__updateIcons(name);
}
}
Expand Down
3 changes: 1 addition & 2 deletions packages/icon/src/vaadin-iconset.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
* Copyright (c) 2021 - 2025 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
import type { Icon } from './vaadin-icon.js';
import type { IconSvgLiteral } from './vaadin-icon-svg.js';
import { IconsetMixin } from './vaadin-iconset-mixin.js';

/**
* `<vaadin-iconset>` is a Web Component for creating SVG icon collections.
*/
declare class Iconset extends ElementMixin(IconsetMixin(HTMLElement)) {
declare class Iconset extends IconsetMixin(HTMLElement) {
/**
* Set of the `vaadin-icon` instances in the DOM.
*/
Expand Down
9 changes: 1 addition & 8 deletions packages/icon/src/vaadin-iconset.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
* Copyright (c) 2021 - 2025 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
import { IconsetMixin } from './vaadin-iconset-mixin.js';

/**
Expand All @@ -14,13 +12,8 @@ import { IconsetMixin } from './vaadin-iconset-mixin.js';
* @customElement
* @extends HTMLElement
* @mixes IconsetMixin
* @mixes ElementMixin
*/
class Iconset extends IconsetMixin(ElementMixin(PolymerElement)) {
static get template() {
return null;
}

class Iconset extends IconsetMixin(HTMLElement) {
static get is() {
return 'vaadin-iconset';
}
Expand Down
2 changes: 1 addition & 1 deletion packages/icon/src/vaadin-lit-icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyright (c) 2021 - 2025 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import './vaadin-lit-iconset.js';
import './vaadin-iconset.js';
import { html, LitElement } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
Expand Down
6 changes: 0 additions & 6 deletions packages/icon/src/vaadin-lit-iconset.d.ts

This file was deleted.

33 changes: 0 additions & 33 deletions packages/icon/src/vaadin-lit-iconset.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/icon/test/icon-lit.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
import '../vaadin-lit-icon.js';
import '../vaadin-lit-iconset.js';
import './icon.common.js';
1 change: 0 additions & 1 deletion packages/icon/test/icon-polymer.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
import '../vaadin-icon.js';
import '../vaadin-iconset.js';
import './icon.common.js';
38 changes: 38 additions & 0 deletions packages/icon/test/iconset-lazy-upgrade.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { expect } from '@vaadin/chai-plugins';
import { fixtureSync } from '@vaadin/testing-helpers';

describe('vaadin-iconset lazy upgrade', () => {
let iconset;

const ICON = '<path d="M3 4h10l-5 7z"></path>';

before(() => {
iconset = document.createElement('vaadin-iconset');
iconset.name = 'vaadin';
iconset.size = 16;
iconset.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<g id="vaadin:caret-down">${ICON}</g>
</defs>
</svg>
`;
document.body.appendChild(iconset);
});

after(() => {
iconset.remove();
});

it('should use correct name and size set as attributes before upgrade', async () => {
const icon = fixtureSync('<vaadin-icon icon="vaadin:caret-down"></vaadin-icon>');

// Import vaadin-icon, which also imports vaadin-iconset internally.
await import('../vaadin-icon.js');

const svgElement = icon.shadowRoot.querySelector('svg');

expect(svgElement.querySelector('#svg-group > g').innerHTML).to.equal(ICON);
expect(svgElement.getAttribute('viewBox')).to.equal('0 0 16 16');
});
});
2 changes: 0 additions & 2 deletions packages/icon/test/iconset-lit.test.js

This file was deleted.

2 changes: 0 additions & 2 deletions packages/icon/test/iconset-polymer.test.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { expect } from '@vaadin/chai-plugins';
import { fixtureSync, nextFrame } from '@vaadin/testing-helpers';
import { isValidSvg } from '../src/vaadin-icon-svg.js';

const Iconset = customElements.get('vaadin-iconset');
import { Iconset } from '../vaadin-iconset.js';

describe('vaadin-iconset', () => {
let iconset;
Expand Down
1 change: 0 additions & 1 deletion packages/icon/vaadin-lit-iconset.d.ts

This file was deleted.

3 changes: 0 additions & 3 deletions packages/icon/vaadin-lit-iconset.js

This file was deleted.

0 comments on commit 38146af

Please sign in to comment.