@vaadin/icon 24.4.0-alpha9 → 24.4.0-beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,6 @@ A web component for displaying SVG icons.
5
5
  [Documentation + Live Demo ↗](https://vaadin.com/docs/latest/ds/foundation/icons)
6
6
 
7
7
  [![npm version](https://badgen.net/npm/v/@vaadin/icon)](https://www.npmjs.com/package/@vaadin/icon)
8
- [![Discord](https://img.shields.io/discord/732335336448852018?label=discord)](https://discord.gg/PHmkCKC)
9
8
 
10
9
  ```html
11
10
  <vaadin-icon name="vaadin:user"></vaadin-icon>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/icon",
3
- "version": "24.4.0-alpha9",
3
+ "version": "24.4.0-beta2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -24,6 +24,8 @@
24
24
  "theme",
25
25
  "vaadin-*.d.ts",
26
26
  "vaadin-*.js",
27
+ "!vaadin-lit-*.d.ts",
28
+ "!vaadin-lit-*.js",
27
29
  "web-types.json",
28
30
  "web-types.lit.json"
29
31
  ],
@@ -36,9 +38,9 @@
36
38
  "dependencies": {
37
39
  "@open-wc/dedupe-mixin": "^1.3.0",
38
40
  "@polymer/polymer": "^3.0.0",
39
- "@vaadin/component-base": "24.4.0-alpha9",
40
- "@vaadin/vaadin-lumo-styles": "24.4.0-alpha9",
41
- "@vaadin/vaadin-themable-mixin": "24.4.0-alpha9",
41
+ "@vaadin/component-base": "24.4.0-beta2",
42
+ "@vaadin/vaadin-lumo-styles": "24.4.0-beta2",
43
+ "@vaadin/vaadin-themable-mixin": "24.4.0-beta2",
42
44
  "lit": "^3.0.0"
43
45
  },
44
46
  "devDependencies": {
@@ -50,5 +52,5 @@
50
52
  "web-types.json",
51
53
  "web-types.lit.json"
52
54
  ],
53
- "gitHead": "effb81abe3c6283a6ec620cc0cee56069af58226"
55
+ "gitHead": "886ab2e7ccb8353ac3b7a42ebb96dfe2d1211556"
54
56
  }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { SlotStylesMixinClass } from '@vaadin/component-base/src/slot-styles-mixin.js';
8
+ import type { IconFontSizeMixinClass } from './vaadin-icon-font-size-mixin.js';
9
+ import type { IconSvgLiteral } from './vaadin-icon-svg.js';
10
+
11
+ /**
12
+ * A mixin providing common icon functionality.
13
+ */
14
+ export declare function IconMixin<T extends Constructor<HTMLElement>>(
15
+ base: T,
16
+ ): Constructor<IconFontSizeMixinClass> & Constructor<IconMixinClass> & Constructor<SlotStylesMixinClass> & T;
17
+
18
+ export declare class IconMixinClass {
19
+ /**
20
+ * The name of the icon to use. The name should be of the form:
21
+ * `iconset_name:icon_name`. When using `vaadin-icons` it is possible
22
+ * to omit the first part and only use `icon_name` as a value.
23
+ *
24
+ * Setting the `icon` property updates the `svg` and `size` based on the
25
+ * values provided by the corresponding `vaadin-iconset` element.
26
+ *
27
+ * See also [`name`](#/elements/vaadin-iconset#property-name) property of `vaadin-iconset`.
28
+ *
29
+ * @attr {string} icon
30
+ */
31
+ icon: string | null;
32
+
33
+ /**
34
+ * The SVG icon wrapped in a Lit template literal.
35
+ */
36
+ svg: IconSvgLiteral | null;
37
+
38
+ /**
39
+ * The SVG source to be loaded as the icon. It can be:
40
+ * - an URL to a file containing the icon
41
+ * - an URL in the format "/path/to/file.svg#objectID", where the "objectID" refers to an ID attribute contained
42
+ * inside the SVG referenced by the path. Note that the file needs to follow the same-origin policy.
43
+ * - a string in the format "data:image/svg+xml,<svg>...</svg>". You may need to use the "encodeURIComponent"
44
+ * function for the SVG content passed
45
+ */
46
+ src: string | null;
47
+
48
+ /**
49
+ * The symbol identifier that references an ID of an element contained in the SVG element assigned to the
50
+ * `src` property
51
+ */
52
+ symbol: string | null;
53
+
54
+ /**
55
+ * Class names defining an icon font and/or a specific glyph inside an icon font.
56
+ *
57
+ * Example: "fa-solid fa-user"
58
+ *
59
+ * @attr {string} icon-class
60
+ */
61
+ iconClass: string | null;
62
+
63
+ /**
64
+ * A hexadecimal code point that specifies a glyph from an icon font.
65
+ *
66
+ * Example: "e001"
67
+ */
68
+ char: string | null;
69
+
70
+ /**
71
+ * A ligature name that specifies an icon from an icon font with support for ligatures.
72
+ *
73
+ * Example: "home".
74
+ */
75
+ ligature: string | null;
76
+
77
+ /**
78
+ * The font family to use for the font icon.
79
+ *
80
+ * @attr {string} font-family
81
+ */
82
+ fontFamily: string | null;
83
+
84
+ /**
85
+ * The size of an icon, used to set the `viewBox` attribute.
86
+ */
87
+ size: number;
88
+ }
@@ -0,0 +1,364 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { SlotStylesMixin } from '@vaadin/component-base/src/slot-styles-mixin.js';
7
+ import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
8
+ import { IconFontSizeMixin } from './vaadin-icon-font-size-mixin.js';
9
+ import { ensureSvgLiteral, renderSvg, unsafeSvgLiteral } from './vaadin-icon-svg.js';
10
+
11
+ const srcCache = new Map();
12
+
13
+ const Iconset = customElements.get('vaadin-iconset');
14
+
15
+ /**
16
+ * @polymerMixin
17
+ * @mixes SlotStylesMixin
18
+ * @mixes IconFontSizeMixin
19
+ */
20
+ export const IconMixin = (superClass) =>
21
+ class extends IconFontSizeMixin(SlotStylesMixin(superClass)) {
22
+ static get properties() {
23
+ return {
24
+ /**
25
+ * The name of the icon to use. The name should be of the form:
26
+ * `iconset_name:icon_name`. When using `vaadin-icons` it is possible
27
+ * to omit the first part and only use `icon_name` as a value.
28
+ *
29
+ * Setting the `icon` property updates the `svg` and `size` based on the
30
+ * values provided by the corresponding `vaadin-iconset` element.
31
+ *
32
+ * See also [`name`](#/elements/vaadin-iconset#property-name) property of `vaadin-iconset`.
33
+ *
34
+ * @attr {string} icon
35
+ * @type {string}
36
+ */
37
+ icon: {
38
+ type: String,
39
+ reflectToAttribute: true,
40
+ observer: '__iconChanged',
41
+ sync: true,
42
+ },
43
+
44
+ /**
45
+ * The SVG icon wrapped in a Lit template literal.
46
+ */
47
+ svg: {
48
+ type: Object,
49
+ sync: true,
50
+ },
51
+
52
+ /**
53
+ * The SVG source to be loaded as the icon. It can be:
54
+ * - an URL to a file containing the icon
55
+ * - an URL in the format "/path/to/file.svg#objectID", where the "objectID" refers to an ID attribute contained
56
+ * inside the SVG referenced by the path. Note that the file needs to follow the same-origin policy.
57
+ * - a string in the format "data:image/svg+xml,<svg>...</svg>". You may need to use the "encodeURIComponent"
58
+ * function for the SVG content passed
59
+ *
60
+ * @type {string}
61
+ */
62
+ src: {
63
+ type: String,
64
+ sync: true,
65
+ },
66
+
67
+ /**
68
+ * The symbol identifier that references an ID of an element contained in the SVG element assigned to the
69
+ * `src` property
70
+ *
71
+ * @type {string}
72
+ */
73
+ symbol: {
74
+ type: String,
75
+ sync: true,
76
+ },
77
+
78
+ /**
79
+ * Class names defining an icon font and/or a specific glyph inside an icon font.
80
+ *
81
+ * Example: "fa-solid fa-user"
82
+ *
83
+ * @attr {string} icon-class
84
+ * @type {string}
85
+ */
86
+ iconClass: {
87
+ type: String,
88
+ reflectToAttribute: true,
89
+ sync: true,
90
+ },
91
+
92
+ /**
93
+ * A hexadecimal code point that specifies a glyph from an icon font.
94
+ *
95
+ * Example: "e001"
96
+ *
97
+ * @type {string}
98
+ */
99
+ char: {
100
+ type: String,
101
+ sync: true,
102
+ },
103
+
104
+ /**
105
+ * A ligature name that specifies an icon from an icon font with support for ligatures.
106
+ *
107
+ * Example: "home".
108
+ *
109
+ * @type {string}
110
+ */
111
+ ligature: {
112
+ type: String,
113
+ sync: true,
114
+ },
115
+
116
+ /**
117
+ * The font family to use for the font icon.
118
+ *
119
+ * @attr {string} font-family
120
+ * @type {string}
121
+ */
122
+ fontFamily: {
123
+ type: String,
124
+ observer: '__fontFamilyChanged',
125
+ sync: true,
126
+ },
127
+
128
+ /**
129
+ * The size of an icon, used to set the `viewBox` attribute.
130
+ */
131
+ size: {
132
+ type: Number,
133
+ value: 24,
134
+ sync: true,
135
+ },
136
+
137
+ /** @private */
138
+ __defaultPAR: {
139
+ type: String,
140
+ value: 'xMidYMid meet',
141
+ },
142
+
143
+ /** @private */
144
+ __preserveAspectRatio: String,
145
+
146
+ /** @private */
147
+ __useRef: Object,
148
+
149
+ /** @private */
150
+ __svgElement: String,
151
+
152
+ /** @private */
153
+ __viewBox: String,
154
+
155
+ /** @private */
156
+ __fill: String,
157
+
158
+ /** @private */
159
+ __stroke: String,
160
+
161
+ /** @private */
162
+ __strokeWidth: String,
163
+
164
+ /** @private */
165
+ __strokeLinecap: String,
166
+
167
+ /** @private */
168
+ __strokeLinejoin: String,
169
+ };
170
+ }
171
+
172
+ static get observers() {
173
+ return [
174
+ '__svgChanged(svg, __svgElement)',
175
+ '__fontChanged(iconClass, char, ligature)',
176
+ '__srcChanged(src, symbol)',
177
+ ];
178
+ }
179
+
180
+ static get observedAttributes() {
181
+ return [...super.observedAttributes, 'class'];
182
+ }
183
+
184
+ constructor() {
185
+ super();
186
+ this.__fetch = fetch.bind(window);
187
+ }
188
+
189
+ /** @protected */
190
+ get slotStyles() {
191
+ const tag = this.localName;
192
+ return [
193
+ `
194
+ ${tag}[icon-class] {
195
+ display: inline-flex;
196
+ vertical-align: middle;
197
+ font-size: inherit;
198
+ }
199
+ `,
200
+ ];
201
+ }
202
+
203
+ /** @private */
204
+ get __iconClasses() {
205
+ return this.iconClass ? this.iconClass.split(' ') : [];
206
+ }
207
+
208
+ /** @protected */
209
+ ready() {
210
+ super.ready();
211
+ this.__svgElement = this.shadowRoot.querySelector('#svg-group');
212
+ this._tooltipController = new TooltipController(this);
213
+ this.addController(this._tooltipController);
214
+ }
215
+
216
+ /** @protected */
217
+ connectedCallback() {
218
+ super.connectedCallback();
219
+ Iconset.attachedIcons.add(this);
220
+ }
221
+
222
+ /** @protected */
223
+ disconnectedCallback() {
224
+ super.disconnectedCallback();
225
+ Iconset.attachedIcons.delete(this);
226
+ }
227
+
228
+ /** @protected */
229
+ _applyIcon() {
230
+ const { preserveAspectRatio, svg, size, viewBox } = Iconset.getIconSvg(this.icon);
231
+ if (viewBox) {
232
+ this.__viewBox = viewBox;
233
+ }
234
+ if (preserveAspectRatio) {
235
+ this.__preserveAspectRatio = preserveAspectRatio;
236
+ }
237
+ if (size && size !== this.size) {
238
+ this.size = size;
239
+ }
240
+ this.svg = svg;
241
+ }
242
+
243
+ /** @private */
244
+ __iconChanged(icon) {
245
+ if (icon) {
246
+ this._applyIcon();
247
+ } else {
248
+ this.svg = ensureSvgLiteral(null);
249
+ }
250
+ }
251
+
252
+ /** @private */
253
+ async __srcChanged(src, symbol) {
254
+ if (!src) {
255
+ this.svg = null;
256
+ return;
257
+ }
258
+
259
+ // Need to add the "icon" attribute to avoid issues as described in
260
+ // https://github.com/vaadin/web-components/issues/6301
261
+ this.icon = '';
262
+ if (!src.startsWith('data:') && (symbol || src.includes('#'))) {
263
+ const [path, iconId] = src.split('#');
264
+ this.__useRef = `${path}#${symbol || iconId}`;
265
+ } else {
266
+ try {
267
+ if (!srcCache.has(src)) {
268
+ srcCache.set(
269
+ src,
270
+ this.__fetch(src, {
271
+ mode: 'cors',
272
+ }).then((data) => {
273
+ if (!data.ok) {
274
+ throw new Error('Error loading icon');
275
+ }
276
+ return data.text();
277
+ }),
278
+ );
279
+ }
280
+ const svgData = await srcCache.get(src);
281
+ if (!superClass.__domParser) {
282
+ superClass.__domParser = new DOMParser();
283
+ }
284
+ const parsedResponse = superClass.__domParser.parseFromString(svgData, 'text/html');
285
+ const svgElement = parsedResponse.querySelector('svg');
286
+ if (!svgElement) {
287
+ throw new Error(`SVG element not found on path: ${src}`);
288
+ }
289
+ this.svg = unsafeSvgLiteral(svgElement.innerHTML);
290
+ if (symbol) {
291
+ this.__useRef = `#${symbol}`;
292
+ }
293
+ this.__viewBox = svgElement.getAttribute('viewBox');
294
+ this.__fill = svgElement.getAttribute('fill');
295
+ this.__stroke = svgElement.getAttribute('stroke');
296
+ this.__strokeWidth = svgElement.getAttribute('stroke-width');
297
+ this.__strokeLinecap = svgElement.getAttribute('stroke-linecap');
298
+ this.__strokeLinejoin = svgElement.getAttribute('stroke-linejoin');
299
+ } catch (e) {
300
+ console.error(e);
301
+ this.svg = null;
302
+ }
303
+ }
304
+ }
305
+
306
+ /** @private */
307
+ __svgChanged(svg, svgElement) {
308
+ if (!svgElement) {
309
+ return;
310
+ }
311
+ renderSvg(svg, svgElement);
312
+ }
313
+
314
+ /** @private */
315
+ __computePAR(defaultPAR, preserveAspectRatio) {
316
+ return preserveAspectRatio || defaultPAR;
317
+ }
318
+
319
+ /** @private */
320
+ __computeVisibility(__useRef) {
321
+ return __useRef ? 'visible' : 'hidden';
322
+ }
323
+
324
+ /** @private */
325
+ __computeViewBox(size, viewBox) {
326
+ return viewBox || `0 0 ${size} ${size}`;
327
+ }
328
+
329
+ /** @private */
330
+ __fontChanged(iconClass, char, ligature) {
331
+ this.classList.remove(...(this.__addedIconClasses || []));
332
+ if (iconClass) {
333
+ this.__addedIconClasses = [...this.__iconClasses];
334
+ this.classList.add(...this.__addedIconClasses);
335
+ }
336
+ if (char) {
337
+ this.setAttribute('font-icon-content', char.length > 1 ? String.fromCodePoint(parseInt(char, 16)) : char);
338
+ } else if (ligature) {
339
+ this.setAttribute('font-icon-content', ligature);
340
+ } else {
341
+ this.removeAttribute('font-icon-content');
342
+ }
343
+ if ((iconClass || char || ligature) && !this.icon) {
344
+ // The "icon" attribute needs to be set on the host also when using font icons
345
+ // to avoid issues such as https://github.com/vaadin/web-components/issues/6301
346
+ this.icon = '';
347
+ }
348
+ }
349
+
350
+ /** @protected */
351
+ attributeChangedCallback(name, oldValue, newValue) {
352
+ super.attributeChangedCallback(name, oldValue, newValue);
353
+
354
+ // Make sure class list always contains all the font class names
355
+ if (name === 'class' && this.__iconClasses.some((className) => !this.classList.contains(className))) {
356
+ this.classList.add(...this.__iconClasses);
357
+ }
358
+ }
359
+
360
+ /** @private */
361
+ __fontFamilyChanged(fontFamily) {
362
+ this.style.fontFamily = `'${fontFamily}'`;
363
+ }
364
+ };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { css } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
7
+
8
+ export const iconStyles = css`
9
+ :host {
10
+ display: inline-flex;
11
+ justify-content: center;
12
+ align-items: center;
13
+ box-sizing: border-box;
14
+ vertical-align: middle;
15
+ width: 24px;
16
+ height: 24px;
17
+ fill: currentColor;
18
+ container-type: size;
19
+ }
20
+
21
+ :host::after,
22
+ :host::before {
23
+ line-height: 1;
24
+ font-size: 100cqh;
25
+ -webkit-font-smoothing: antialiased;
26
+ text-rendering: optimizeLegibility;
27
+ -moz-osx-font-smoothing: grayscale;
28
+ }
29
+
30
+ :host([hidden]) {
31
+ display: none !important;
32
+ }
33
+
34
+ svg {
35
+ display: block;
36
+ width: 100%;
37
+ height: 100%;
38
+ /* prevent overflowing icon from clipping, see https://github.com/vaadin/flow-components/issues/5872 */
39
+ overflow: visible;
40
+ }
41
+
42
+ :host(:is([icon-class], [font-icon-content])) svg {
43
+ display: none;
44
+ }
45
+
46
+ :host([font-icon-content])::before {
47
+ content: attr(font-icon-content);
48
+ }
49
+ `;
@@ -5,10 +5,8 @@
5
5
  */
6
6
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
7
7
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
8
- import { SlotStylesMixin } from '@vaadin/component-base/src/slot-styles-mixin.js';
9
8
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
10
- import { IconFontSizeMixin } from './vaadin-icon-font-size-mixin.js';
11
- import type { IconSvgLiteral } from './vaadin-icon-svg.js';
9
+ import { IconMixin } from './vaadin-icon-mixin.js';
12
10
 
13
11
  /**
14
12
  * `<vaadin-icon>` is a Web Component for displaying SVG icons.
@@ -49,77 +47,7 @@ import type { IconSvgLiteral } from './vaadin-icon-svg.js';
49
47
  * }
50
48
  * ```
51
49
  */
52
- declare class Icon extends ThemableMixin(
53
- ElementMixin(ControllerMixin(SlotStylesMixin(IconFontSizeMixin(HTMLElement)))),
54
- ) {
55
- /**
56
- * The name of the icon to use. The name should be of the form:
57
- * `iconset_name:icon_name`. When using `vaadin-icons` it is possible
58
- * to omit the first part and only use `icon_name` as a value.
59
- *
60
- * Setting the `icon` property updates the `svg` and `size` based on the
61
- * values provided by the corresponding `vaadin-iconset` element.
62
- *
63
- * See also [`name`](#/elements/vaadin-iconset#property-name) property of `vaadin-iconset`.
64
- *
65
- * @attr {string} icon
66
- */
67
- icon: string | null;
68
-
69
- /**
70
- * The SVG icon wrapped in a Lit template literal.
71
- */
72
- svg: IconSvgLiteral | null;
73
-
74
- /**
75
- * The SVG source to be loaded as the icon. It can be:
76
- * - an URL to a file containing the icon
77
- * - an URL in the format "/path/to/file.svg#objectID", where the "objectID" refers to an ID attribute contained
78
- * inside the SVG referenced by the path. Note that the file needs to follow the same-origin policy.
79
- * - a string in the format "data:image/svg+xml,<svg>...</svg>". You may need to use the "encodeURIComponent"
80
- * function for the SVG content passed
81
- */
82
- src: string | null;
83
-
84
- /**
85
- * The symbol identifier that references an ID of an element contained in the SVG element assigned to the
86
- * `src` property
87
- */
88
- symbol: string | null;
89
-
90
- /**
91
- * Class names defining an icon font and/or a specific glyph inside an icon font.
92
- *
93
- * Example: "fa-solid fa-user"
94
- *
95
- * @attr {string} icon-class
96
- */
97
- iconClass: string | null;
98
-
99
- /**
100
- * A hexadecimal code point that specifies a glyph from an icon font.
101
- *
102
- * Example: "e001"
103
- */
104
- char: string | null;
105
-
106
- /**
107
- * A ligature name that specifies an icon from an icon font with support for ligatures.
108
- *
109
- * Example: "home".
110
- */
111
- ligature: string | null;
112
-
113
- /**
114
- * The font family to use for the font icon.
115
- */
116
- fontFamily: string | null;
117
-
118
- /**
119
- * The size of an icon, used to set the `viewBox` attribute.
120
- */
121
- size: number;
122
- }
50
+ declare class Icon extends ThemableMixin(ElementMixin(ControllerMixin(IconMixin(HTMLElement)))) {}
123
51
 
124
52
  declare global {
125
53
  interface HTMLElementTagNameMap {