@momentum-design/components 0.22.3 → 0.22.5

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.
@@ -71,8 +71,15 @@ declare class Icon extends Component {
71
71
  private abortController;
72
72
  constructor();
73
73
  /**
74
- * Get Icon Data function which will fetch the icon (currently only svg)
75
- * and sets state and attributes once fetched successfully
74
+ * Parse the icon string to an html element, set the attributes and
75
+ * return the icon element
76
+ *
77
+ * @param iconData - The icon string to be parsed
78
+ * @returns iconElement
79
+ */
80
+ private prepareIconElement;
81
+ /**
82
+ * Fetches the icon (currently only svg) and sets state and attributes once fetched successfully
76
83
  *
77
84
  * This method uses abortController.signal to cancel the fetch request when the component is disconnected or updated.
78
85
  * If the request is aborted after the fetch() call has been fulfilled but before the response body has been read,
@@ -76,8 +76,24 @@ class Icon extends Component {
76
76
  this.abortController = new AbortController(); // Initialize AbortController
77
77
  }
78
78
  /**
79
- * Get Icon Data function which will fetch the icon (currently only svg)
80
- * and sets state and attributes once fetched successfully
79
+ * Parse the icon string to an html element, set the attributes and
80
+ * return the icon element
81
+ *
82
+ * @param iconData - The icon string to be parsed
83
+ * @returns iconElement
84
+ */
85
+ prepareIconElement(iconData) {
86
+ const iconElement = new DOMParser().parseFromString(iconData, 'text/html').body.children[0];
87
+ if (this.name) {
88
+ iconElement.setAttribute('data-name', this.name);
89
+ }
90
+ iconElement.setAttribute('part', 'icon');
91
+ // set aria-hidden=true for SVG to avoid screen readers
92
+ iconElement.setAttribute('aria-hidden', 'true');
93
+ return iconElement;
94
+ }
95
+ /**
96
+ * Fetches the icon (currently only svg) and sets state and attributes once fetched successfully
81
97
  *
82
98
  * This method uses abortController.signal to cancel the fetch request when the component is disconnected or updated.
83
99
  * If the request is aborted after the fetch() call has been fulfilled but before the response body has been read,
@@ -85,13 +101,28 @@ class Icon extends Component {
85
101
  */
86
102
  async getIconData() {
87
103
  if (this.iconProviderContext.value) {
88
- const { fileExtension, url } = this.iconProviderContext.value;
104
+ const { fileExtension, url, iconsCache, shouldCache } = this.iconProviderContext.value;
89
105
  if (url && fileExtension && this.name) {
106
+ // abort the previous fetch request if it is still pending
107
+ // before retreiving from cache
90
108
  this.abortController.abort();
109
+ // check if icon is already fetched and stored in the iconsCache map
110
+ if (iconsCache.has(this.name)) {
111
+ const iconElement = this.prepareIconElement(iconsCache.get(this.name));
112
+ this.handleIconLoadedSuccess(iconElement);
113
+ return;
114
+ }
91
115
  this.abortController = new AbortController();
92
116
  try {
93
- const iconHtml = await dynamicSVGImport(url, this.name, fileExtension, this.abortController.signal);
94
- this.handleIconLoadedSuccess(iconHtml);
117
+ // fetch icon from backend
118
+ const iconData = await dynamicSVGImport(url, this.name, fileExtension, this.abortController.signal);
119
+ // parse the fetched icon string to an html element and set the attributes
120
+ const iconElement = this.prepareIconElement(iconData);
121
+ this.handleIconLoadedSuccess(iconElement);
122
+ if (shouldCache) {
123
+ // store the fetched icon string in the iconsCache map
124
+ iconsCache.set(this.name, iconData);
125
+ }
95
126
  }
96
127
  catch (error) {
97
128
  this.handleIconLoadedFailure(error);
@@ -7,8 +7,8 @@
7
7
  * @param fileExtension - The file extension of the icon
8
8
  * @param signal - The signal to abort the fetch.
9
9
  * It is used to cancel the fetch when the component is disconnected or updated.
10
- * @returns The valid icon element
10
+ * @returns Response string from the fetch
11
11
  * @throws Error if the response is not ok
12
12
  */
13
- declare const dynamicSVGImport: (url: string, name: string, fileExtension: string, signal: AbortSignal) => Promise<Element>;
13
+ declare const dynamicSVGImport: (url: string, name: string, fileExtension: string, signal: AbortSignal) => Promise<string>;
14
14
  export { dynamicSVGImport };
@@ -8,7 +8,7 @@
8
8
  * @param fileExtension - The file extension of the icon
9
9
  * @param signal - The signal to abort the fetch.
10
10
  * It is used to cancel the fetch when the component is disconnected or updated.
11
- * @returns The valid icon element
11
+ * @returns Response string from the fetch
12
12
  * @throws Error if the response is not ok
13
13
  */
14
14
  const dynamicSVGImport = async (url, name, fileExtension, signal) => {
@@ -16,12 +16,6 @@ const dynamicSVGImport = async (url, name, fileExtension, signal) => {
16
16
  if (!response.ok) {
17
17
  throw new Error('There was a problem while fetching the icon!');
18
18
  }
19
- const iconResponse = await response.text();
20
- const returnValue = new DOMParser().parseFromString(iconResponse, 'text/html').body.children[0];
21
- returnValue.setAttribute('data-name', name);
22
- returnValue.setAttribute('part', 'icon');
23
- // set aria-hidden=true for SVG to avoid screen readers
24
- returnValue.setAttribute('aria-hidden', 'true');
25
- return returnValue;
19
+ return response.text();
26
20
  };
27
21
  export { dynamicSVGImport };
@@ -8,6 +8,12 @@ import IconProviderContext from './iconprovider.context';
8
8
  * that only a url has to be passed in from which the icons will be
9
9
  * fetched.
10
10
  *
11
+ * If `shouldCache` is set to true, the IconProvider will cache the icons
12
+ * in a Map to avoid fetching the same icon multiple times over the network.
13
+ * This is useful when the same icon is used multiple times in the application.
14
+ * Keep in mind that this cache is not persisted and will be lost when the
15
+ * IconProvider is removed from the DOM.
16
+ *
11
17
  * @tagname mdc-iconprovider
12
18
  *
13
19
  * @slot - children
@@ -18,6 +24,24 @@ declare class IconProvider extends Provider<IconProviderContext> {
18
24
  * Context object of the IconProvider, to be consumed by child components
19
25
  */
20
26
  static get Context(): {
27
+ /**
28
+ * IconProvider component, which allows to be consumed from sub components
29
+ * (see `providerUtils.consume` for how to consume)
30
+ *
31
+ * Bundling icons will be up to the consumer of this component, such
32
+ * that only a url has to be passed in from which the icons will be
33
+ * fetched.
34
+ *
35
+ * If `shouldCache` is set to true, the IconProvider will cache the icons
36
+ * in a Map to avoid fetching the same icon multiple times over the network.
37
+ * This is useful when the same icon is used multiple times in the application.
38
+ * Keep in mind that this cache is not persisted and will be lost when the
39
+ * IconProvider is removed from the DOM.
40
+ *
41
+ * @tagname mdc-iconprovider
42
+ *
43
+ * @slot - children
44
+ */
21
45
  __context__: IconProviderContext;
22
46
  };
23
47
  /**
@@ -40,6 +64,13 @@ declare class IconProvider extends Provider<IconProviderContext> {
40
64
  * @default 1
41
65
  */
42
66
  size?: number;
67
+ /**
68
+ * If the IconProvider should cache the icons
69
+ * in a Map to avoid fetching the same icon multiple times
70
+ *
71
+ * @default false
72
+ */
73
+ shouldCache?: boolean;
43
74
  private updateValuesInContext;
44
75
  protected updateContext(): void;
45
76
  }
@@ -19,6 +19,12 @@ import { ALLOWED_FILE_EXTENSIONS, DEFAULTS, ALLOWED_LENGTH_UNITS } from './iconp
19
19
  * that only a url has to be passed in from which the icons will be
20
20
  * fetched.
21
21
  *
22
+ * If `shouldCache` is set to true, the IconProvider will cache the icons
23
+ * in a Map to avoid fetching the same icon multiple times over the network.
24
+ * This is useful when the same icon is used multiple times in the application.
25
+ * Keep in mind that this cache is not persisted and will be lost when the
26
+ * IconProvider is removed from the DOM.
27
+ *
22
28
  * @tagname mdc-iconprovider
23
29
  *
24
30
  * @slot - children
@@ -46,6 +52,13 @@ class IconProvider extends Provider {
46
52
  * @default 1
47
53
  */
48
54
  this.size = DEFAULTS.SIZE;
55
+ /**
56
+ * If the IconProvider should cache the icons
57
+ * in a Map to avoid fetching the same icon multiple times
58
+ *
59
+ * @default false
60
+ */
61
+ this.shouldCache = DEFAULTS.SHOULD_CACHE;
49
62
  }
50
63
  /**
51
64
  * Context object of the IconProvider, to be consumed by child components
@@ -65,6 +78,7 @@ class IconProvider extends Provider {
65
78
  }
66
79
  this.context.value.url = this.url;
67
80
  this.context.value.size = this.size;
81
+ this.context.value.shouldCache = this.shouldCache;
68
82
  if (this.lengthUnit && ALLOWED_LENGTH_UNITS.includes(this.lengthUnit)) {
69
83
  this.context.value.lengthUnit = this.lengthUnit;
70
84
  }
@@ -78,7 +92,8 @@ class IconProvider extends Provider {
78
92
  if (this.context.value.fileExtension !== this.fileExtension
79
93
  || this.context.value.url !== this.url
80
94
  || this.context.value.lengthUnit !== this.lengthUnit
81
- || this.context.value.size !== this.size) {
95
+ || this.context.value.size !== this.size
96
+ || this.context.value.shouldCache !== this.shouldCache) {
82
97
  this.updateValuesInContext();
83
98
  this.context.updateObservers();
84
99
  }
@@ -100,4 +115,8 @@ __decorate([
100
115
  property({ type: Number, reflect: true }),
101
116
  __metadata("design:type", Number)
102
117
  ], IconProvider.prototype, "size", void 0);
118
+ __decorate([
119
+ property({ type: Boolean, attribute: 'should-cache', reflect: true }),
120
+ __metadata("design:type", Boolean)
121
+ ], IconProvider.prototype, "shouldCache", void 0);
103
122
  export default IconProvider;
@@ -6,5 +6,6 @@ declare const DEFAULTS: {
6
6
  readonly FILE_EXTENSION: "svg";
7
7
  readonly LENGTH_UNIT: "em";
8
8
  readonly SIZE: number;
9
+ readonly SHOULD_CACHE: false;
9
10
  };
10
11
  export { TAG_NAME, DEFAULTS, ALLOWED_FILE_EXTENSIONS, ALLOWED_LENGTH_UNITS, LENGTH_UNIT_SIZE };
@@ -12,5 +12,6 @@ const DEFAULTS = {
12
12
  FILE_EXTENSION: 'svg',
13
13
  LENGTH_UNIT: 'em',
14
14
  SIZE: LENGTH_UNIT_SIZE.em,
15
+ SHOULD_CACHE: false,
15
16
  };
16
17
  export { TAG_NAME, DEFAULTS, ALLOWED_FILE_EXTENSIONS, ALLOWED_LENGTH_UNITS, LENGTH_UNIT_SIZE };
@@ -3,6 +3,8 @@ declare class IconProviderContext {
3
3
  url?: string;
4
4
  lengthUnit?: string;
5
5
  size?: number;
6
+ iconsCache: Map<string, string>;
7
+ shouldCache?: boolean;
6
8
  static readonly context: {
7
9
  __context__: IconProviderContext;
8
10
  };
@@ -1,6 +1,9 @@
1
1
  import { createContext } from '@lit/context';
2
2
  import { TAG_NAME } from './iconprovider.constants';
3
3
  class IconProviderContext {
4
+ constructor() {
5
+ this.iconsCache = new Map();
6
+ }
4
7
  }
5
8
  // create typed lit context as part of the IconProviderContext
6
9
  IconProviderContext.context = createContext(TAG_NAME);