@skyux/theme 12.0.0-alpha.8 → 12.0.0-beta.0

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, Optional, Directive, Input, NgModule, inject, ChangeDetectorRef, HostBinding, DestroyRef, makeEnvironmentProviders, provideAppInitializer, RendererFactory2 } from '@angular/core';
2
+ import { Injectable, Optional, Input, Directive, NgModule, inject, ChangeDetectorRef, HostBinding, NgZone, DestroyRef, makeEnvironmentProviders, provideAppInitializer, RendererFactory2 } from '@angular/core';
3
3
  import { getIconManifest } from '@skyux/icons';
4
4
  import FontFaceObserver from 'fontfaceobserver';
5
5
  import { take, takeUntil } from 'rxjs/operators';
@@ -18,16 +18,62 @@ class SkyThemeIconManifestService {
18
18
  getManifest() {
19
19
  return getIconManifest();
20
20
  }
21
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeIconManifestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
22
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeIconManifestService, providedIn: 'root' }); }
21
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeIconManifestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
22
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeIconManifestService, providedIn: 'root' }); }
23
23
  }
24
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeIconManifestService, decorators: [{
24
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeIconManifestService, decorators: [{
25
25
  type: Injectable,
26
26
  args: [{
27
27
  providedIn: 'root',
28
28
  }]
29
29
  }] });
30
30
 
31
+ /**
32
+ * Defines properties of a SKY UX theme mode.
33
+ */
34
+ class SkyThemeMode {
35
+ /**
36
+ * The preset themes available in SKY UX.
37
+ */
38
+ static { this.presets = {
39
+ light: new SkyThemeMode('light', 'sky-theme-mode-light'),
40
+ dark: new SkyThemeMode('dark', 'sky-theme-mode-dark'),
41
+ }; }
42
+ /**
43
+ * Creates a new theme mode.
44
+ * @param name The name of the theme mode.
45
+ * @param hostClass The class on the host element which child components should reference when
46
+ * adjusting for a specified theme mode.
47
+ */
48
+ constructor(name, hostClass) {
49
+ this.name = name;
50
+ this.hostClass = hostClass;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Defines properties of SKY UX theme spacing.
56
+ */
57
+ class SkyThemeSpacing {
58
+ /**
59
+ * The preset spacing available in SKY UX.
60
+ */
61
+ static { this.presets = {
62
+ standard: new SkyThemeSpacing('standard', 'sky-theme-spacing-standard'),
63
+ compact: new SkyThemeSpacing('compact', 'sky-theme-spacing-compact'),
64
+ }; }
65
+ /**
66
+ * Creates a new theme spacing.
67
+ * @param name The name of the theme spacing.
68
+ * @param hostClass The class on the host element which child components should reference when
69
+ * adjusting for a specified theme spacing.
70
+ */
71
+ constructor(name, hostClass) {
72
+ this.name = name;
73
+ this.hostClass = hostClass;
74
+ }
75
+ }
76
+
31
77
  /**
32
78
  * Provides methods for updating and handling changes to the current theme.
33
79
  */
@@ -39,6 +85,7 @@ class SkyThemeService {
39
85
  return this.#_settingsObs;
40
86
  }
41
87
  #current;
88
+ #brandLinkElement;
42
89
  #hostEl;
43
90
  #renderer;
44
91
  #settings;
@@ -76,6 +123,7 @@ class SkyThemeService {
76
123
  this.#applyThemeClass(previous, settings, 'theme');
77
124
  this.#applyThemeClass(previous, settings, 'mode', 'supportedModes');
78
125
  this.#applyThemeClass(previous, settings, 'spacing', 'supportedSpacing');
126
+ this.#applyThemeClass(previous, settings, 'brand');
79
127
  this.#settings.next({
80
128
  currentSettings: settings,
81
129
  previousSettings: previous,
@@ -84,29 +132,82 @@ class SkyThemeService {
84
132
  }
85
133
  #applyThemeClass(previous, current, prop, supportedProp) {
86
134
  const currentSetting = current[prop];
87
- const previousClass = previous?.[prop].hostClass;
88
- const currentClass = currentSetting.hostClass;
89
- const classChanged = !previous || previousClass !== currentClass;
90
- if (classChanged) {
91
- if (previousClass) {
92
- this.#removeHostClass(previousClass);
135
+ const previousClass = previous?.[prop]?.hostClass;
136
+ const currentClass = currentSetting?.hostClass;
137
+ if (!previousClass || previousClass !== currentClass) {
138
+ this.#updateHostClass(prop, previousClass, currentClass, currentSetting, current, supportedProp);
139
+ if (prop === 'brand') {
140
+ this.#updateBrandStylesheet(current.brand, previous?.brand);
141
+ }
142
+ }
143
+ }
144
+ #updateBrandStylesheet(currentBrand, previousBrand) {
145
+ if (currentBrand &&
146
+ currentBrand.name !== 'blackbaud' &&
147
+ previousBrand !== currentBrand) {
148
+ this.#addBrandStylesheet(currentBrand);
149
+ }
150
+ else {
151
+ this.#removeBrandStylesheet();
152
+ }
153
+ }
154
+ #updateHostClass(prop, previousClass, currentClass, currentSetting, current, supportedProp) {
155
+ if (previousClass) {
156
+ this.#removeHostClass(previousClass);
157
+ }
158
+ if (prop === 'brand') {
159
+ if (currentClass && !previousClass) {
160
+ this.#addHostClass('sky-theme-brand-base');
93
161
  }
94
- if (!supportedProp ||
95
- current.theme[supportedProp].indexOf(currentSetting) >= 0) {
96
- this.#addHostClass(currentClass);
162
+ else if (!currentClass && previousClass) {
163
+ this.#removeHostClass('sky-theme-brand-base');
97
164
  }
98
165
  }
166
+ if (currentClass &&
167
+ this.#isSupportedProperty(currentSetting, current, supportedProp)) {
168
+ this.#addHostClass(currentClass);
169
+ }
170
+ }
171
+ #addBrandStylesheet(brand) {
172
+ if (brand.name !== 'blackbaud') {
173
+ const cssPath = `https://sky.blackbaudcdn.net/static/skyux-brand-${brand.name}/${brand.version}/assets/scss/${brand.name}.css`;
174
+ // Create a link element via Angular's renderer to avoid SSR troubles
175
+ this.#brandLinkElement = this.#getRenderer().createElement('link');
176
+ // Add the style to the head section
177
+ this.#getRenderer().appendChild(this.#hostEl, this.#brandLinkElement);
178
+ // Set type of the link item and path to the css file
179
+ this.#getRenderer().setProperty(this.#brandLinkElement, 'rel', 'stylesheet');
180
+ this.#getRenderer().setProperty(this.#brandLinkElement, 'href', cssPath);
181
+ }
182
+ }
183
+ #removeBrandStylesheet() {
184
+ if (this.#brandLinkElement) {
185
+ this.#getRenderer().removeChild(this.#hostEl, this.#brandLinkElement);
186
+ this.#brandLinkElement = undefined;
187
+ }
99
188
  }
100
189
  #addHostClass(className) {
101
- this.#renderer.addClass(this.#hostEl, className);
190
+ this.#getRenderer().addClass(this.#hostEl, className);
102
191
  }
103
192
  #removeHostClass(className) {
104
- this.#renderer.removeClass(this.#hostEl, className);
193
+ this.#getRenderer().removeClass(this.#hostEl, className);
105
194
  }
106
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
107
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeService }); }
195
+ #getRenderer() {
196
+ if (!this.#renderer) {
197
+ throw new Error('Renderer is not initialized. Have you called the theme service `init` method?');
198
+ }
199
+ return this.#renderer;
200
+ }
201
+ #isSupportedProperty(currentSetting, current, supportedProp) {
202
+ return (!supportedProp ||
203
+ ((currentSetting instanceof SkyThemeMode ||
204
+ currentSetting instanceof SkyThemeSpacing) &&
205
+ current.theme[supportedProp].includes(currentSetting)));
206
+ }
207
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
208
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeService }); }
108
209
  }
109
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeService, decorators: [{
210
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeService, decorators: [{
110
211
  type: Injectable
111
212
  }], ctorParameters: () => [] });
112
213
 
@@ -151,10 +252,10 @@ class SkyAppStyleLoader {
151
252
  });
152
253
  });
153
254
  }
154
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyAppStyleLoader, deps: [{ token: SkyThemeService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
155
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyAppStyleLoader, providedIn: 'root' }); }
255
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyAppStyleLoader, deps: [{ token: SkyThemeService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
256
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyAppStyleLoader, providedIn: 'root' }); }
156
257
  }
157
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyAppStyleLoader, decorators: [{
258
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyAppStyleLoader, decorators: [{
158
259
  type: Injectable,
159
260
  args: [{
160
261
  providedIn: 'root',
@@ -261,10 +362,10 @@ class SkyThemeClassDirective {
261
362
  });
262
363
  }
263
364
  }
264
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeClassDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SkyThemeService, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
265
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: SkyThemeClassDirective, isStandalone: false, selector: "[skyThemeClass]", inputs: { class: "class", skyThemeClass: "skyThemeClass" }, ngImport: i0 }); }
365
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeClassDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SkyThemeService, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
366
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.1", type: SkyThemeClassDirective, isStandalone: false, selector: "[skyThemeClass]", inputs: { class: "class", skyThemeClass: "skyThemeClass" }, ngImport: i0 }); }
266
367
  }
267
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeClassDirective, decorators: [{
368
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeClassDirective, decorators: [{
268
369
  type: Directive,
269
370
  args: [{
270
371
  selector: '[skyThemeClass]',
@@ -332,10 +433,10 @@ class SkyThemeIfDirective {
332
433
  this.#hasView = false;
333
434
  }
334
435
  }
335
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeIfDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }, { token: SkyThemeService, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
336
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: SkyThemeIfDirective, isStandalone: false, selector: "[skyThemeIf]", inputs: { skyThemeIf: "skyThemeIf" }, ngImport: i0 }); }
436
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeIfDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }, { token: SkyThemeService, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
437
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.1", type: SkyThemeIfDirective, isStandalone: false, selector: "[skyThemeIf]", inputs: { skyThemeIf: "skyThemeIf" }, ngImport: i0 }); }
337
438
  }
338
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeIfDirective, decorators: [{
439
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeIfDirective, decorators: [{
339
440
  type: Directive,
340
441
  args: [{
341
442
  selector: '[skyThemeIf]',
@@ -347,52 +448,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
347
448
  type: Input
348
449
  }] } });
349
450
 
350
- /**
351
- * Defines properties of a SKY UX theme mode.
352
- */
353
- class SkyThemeMode {
354
- /**
355
- * The preset themes available in SKY UX.
356
- */
357
- static { this.presets = {
358
- light: new SkyThemeMode('light', 'sky-theme-mode-light'),
359
- dark: new SkyThemeMode('dark', 'sky-theme-mode-dark'),
360
- }; }
361
- /**
362
- * Creates a new theme mode.
363
- * @param name The name of the theme mode.
364
- * @param hostClass The class on the host element which child components should reference when
365
- * adjusting for a specified theme mode.
366
- */
367
- constructor(name, hostClass) {
368
- this.name = name;
369
- this.hostClass = hostClass;
370
- }
371
- }
372
-
373
- /**
374
- * Defines properties of SKY UX theme spacing.
375
- */
376
- class SkyThemeSpacing {
377
- /**
378
- * The preset spacing available in SKY UX.
379
- */
380
- static { this.presets = {
381
- standard: new SkyThemeSpacing('standard', 'sky-theme-spacing-standard'),
382
- compact: new SkyThemeSpacing('compact', 'sky-theme-spacing-compact'),
383
- }; }
384
- /**
385
- * Creates a new theme spacing.
386
- * @param name The name of the theme spacing.
387
- * @param hostClass The class on the host element which child components should reference when
388
- * adjusting for a specified theme spacing.
389
- */
390
- constructor(name, hostClass) {
391
- this.name = name;
392
- this.hostClass = hostClass;
393
- }
394
- }
395
-
396
451
  /**
397
452
  * Defines properties of a SKY UX theme.
398
453
  */
@@ -429,10 +484,11 @@ class SkyThemeSettings {
429
484
  * @param theme The theme configuration.
430
485
  * @param mode The theme mode.
431
486
  */
432
- constructor(theme, mode, spacing = SkyThemeSpacing.presets.standard) {
487
+ constructor(theme, mode, spacing = SkyThemeSpacing.presets.standard, brand) {
433
488
  this.theme = theme;
434
489
  this.mode = mode;
435
490
  this.spacing = spacing;
491
+ this.brand = brand;
436
492
  }
437
493
  }
438
494
 
@@ -466,10 +522,10 @@ class SkyThemeDirective {
466
522
  ngOnDestroy() {
467
523
  this.#themeSvc.destroy();
468
524
  }
469
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SkyThemeService }], target: i0.ɵɵFactoryTarget.Directive }); }
470
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: SkyThemeDirective, isStandalone: false, selector: "[skyTheme]", inputs: { skyTheme: "skyTheme" }, providers: [SkyThemeService], ngImport: i0 }); }
525
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SkyThemeService }], target: i0.ɵɵFactoryTarget.Directive }); }
526
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.1", type: SkyThemeDirective, isStandalone: false, selector: "[skyTheme]", inputs: { skyTheme: "skyTheme" }, providers: [SkyThemeService], ngImport: i0 }); }
471
527
  }
472
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeDirective, decorators: [{
528
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeDirective, decorators: [{
473
529
  type: Directive,
474
530
  args: [{
475
531
  selector: '[skyTheme]',
@@ -481,13 +537,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
481
537
  }] } });
482
538
 
483
539
  class SkyThemeModule {
484
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
485
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeModule, declarations: [SkyThemeClassDirective,
540
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
541
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeModule, declarations: [SkyThemeClassDirective,
486
542
  SkyThemeDirective,
487
543
  SkyThemeIfDirective], exports: [SkyThemeClassDirective, SkyThemeDirective, SkyThemeIfDirective] }); }
488
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeModule }); }
544
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeModule }); }
489
545
  }
490
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeModule, decorators: [{
546
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeModule, decorators: [{
491
547
  type: NgModule,
492
548
  args: [{
493
549
  declarations: [
@@ -499,6 +555,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
499
555
  }]
500
556
  }] });
501
557
 
558
+ /**
559
+ * @internal
560
+ * Defines properties of SKY UX theme branding.
561
+ */
562
+ class SkyThemeBrand {
563
+ get hostClass() {
564
+ return this.#hostClass || `sky-theme-brand-${this.name}`;
565
+ }
566
+ set hostClass(value) {
567
+ this.#hostClass = value;
568
+ }
569
+ #hostClass;
570
+ /**
571
+ * Creates a new theme brand.
572
+ * @param name The name of the theme brand.
573
+ * @param hostClass The class on the host element which child components should reference when
574
+ * adjusting for a specified theme brand. This defaults to `sky-theme-brand-<name>
575
+ */
576
+ constructor(name, version, hostClass) {
577
+ this.name = name;
578
+ this.version = version;
579
+ this.hostClass = hostClass;
580
+ if (!/\d+\.\d+\.\d+(?:-(?:alpha|beta|rc)\.\d)*$/.test(version)) {
581
+ throw new Error(`Invalid version format "${version}" for theme brand "${name}".`);
582
+ }
583
+ }
584
+ }
585
+
502
586
  class SkyThemeComponentClassDirective {
503
587
  #changeDetector;
504
588
  #themeService;
@@ -513,10 +597,10 @@ class SkyThemeComponentClassDirective {
513
597
  this.#changeDetector.markForCheck();
514
598
  });
515
599
  }
516
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeComponentClassDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
517
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: SkyThemeComponentClassDirective, isStandalone: true, selector: "[skyThemeClass]", host: { properties: { "class": "this.theme" } }, ngImport: i0 }); }
600
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeComponentClassDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
601
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.1", type: SkyThemeComponentClassDirective, isStandalone: true, selector: "[skyThemeClass]", host: { properties: { "class": "this.theme" } }, ngImport: i0 }); }
518
602
  }
519
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyThemeComponentClassDirective, decorators: [{
603
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyThemeComponentClassDirective, decorators: [{
520
604
  type: Directive,
521
605
  args: [{
522
606
  selector: '[skyThemeClass]',
@@ -537,7 +621,10 @@ class SkyAppViewportService {
537
621
  #reserveItems;
538
622
  #conditionallyReserveItems;
539
623
  #document;
624
+ #ngZone;
625
+ // Observe elements crossing the browser's viewport boundaries.
540
626
  #intersectionObserver;
627
+ #reservedSpaces;
541
628
  constructor() {
542
629
  /**
543
630
  * Updated when the viewport becomes visible. While the page is rendered, the
@@ -552,18 +639,15 @@ class SkyAppViewportService {
552
639
  this.#reserveItems = new Map();
553
640
  this.#conditionallyReserveItems = new Map();
554
641
  this.#document = inject(DOCUMENT);
555
- this.#intersectionObserver = new IntersectionObserver((entries) => {
556
- entries.forEach((entry) => {
557
- const item = this.#conditionallyReserveItems.get(entry.target);
558
- if (item) {
559
- item.active = entry.isIntersecting;
560
- }
561
- });
562
- this.#updateViewportArea();
563
- }, {
564
- root: this.#document,
565
- threshold: Array.from({ length: 11 }, (_, i) => i / 10),
566
- });
642
+ this.#ngZone = inject(NgZone);
643
+ // Observe elements crossing the browser's viewport boundaries.
644
+ this.#intersectionObserver = this.#ngZone.runOutsideAngular(() => new IntersectionObserver(() => this.#ngZone.run(() => this.#updateViewportArea()), { threshold: Array.from({ length: 101 }, (_, i) => i / 100) }));
645
+ this.#reservedSpaces = {
646
+ bottom: 0,
647
+ left: 0,
648
+ right: 0,
649
+ top: 0,
650
+ };
567
651
  const onScroll = () => {
568
652
  if (this.#conditionallyReserveItems.size > 0) {
569
653
  this.#updateViewportArea();
@@ -571,6 +655,10 @@ class SkyAppViewportService {
571
655
  };
572
656
  this.#document.addEventListener('scroll', onScroll);
573
657
  inject(DestroyRef).onDestroy(() => {
658
+ /* istanbul ignore next */
659
+ if (this.#updateRequest !== undefined) {
660
+ cancelAnimationFrame(this.#updateRequest);
661
+ }
574
662
  this.#intersectionObserver.disconnect();
575
663
  this.#document.removeEventListener('scroll', onScroll);
576
664
  });
@@ -582,8 +670,7 @@ class SkyAppViewportService {
582
670
  reserveSpace(args) {
583
671
  const item = {
584
672
  ...args,
585
- active: !args.reserveForElement ||
586
- this.#isElementVisible(args.reserveForElement),
673
+ active: this.#isElementVisible({ ...args, active: false }),
587
674
  };
588
675
  this.#reserveItems.set(args.id, item);
589
676
  this.#watchVisibility(item);
@@ -604,23 +691,24 @@ class SkyAppViewportService {
604
691
  }
605
692
  #updateViewportArea() {
606
693
  this.#updateRequest ??= requestAnimationFrame(() => {
694
+ this.#updateRequest = undefined;
607
695
  const reservedSpaces = {
608
696
  bottom: 0,
609
697
  left: 0,
610
698
  right: 0,
611
699
  top: 0,
612
700
  };
613
- for (const { position, size, active, reserveForElement, } of this.#reserveItems.values()) {
614
- if (active &&
615
- (!reserveForElement || this.#isElementVisible(reserveForElement))) {
616
- reservedSpaces[position] += size;
701
+ for (const args of this.#reserveItems.values()) {
702
+ args.active = this.#isElementVisible(args, reservedSpaces);
703
+ if (args.active) {
704
+ reservedSpaces[args.position] += args.size;
617
705
  }
618
706
  }
707
+ this.#reservedSpaces = reservedSpaces;
619
708
  const documentElementStyle = this.#document.documentElement.style;
620
709
  for (const [position, size] of Object.entries(reservedSpaces)) {
621
710
  documentElementStyle.setProperty(`--sky-viewport-${position}`, size + 'px');
622
711
  }
623
- this.#updateRequest = undefined;
624
712
  });
625
713
  }
626
714
  #watchVisibility(item) {
@@ -629,22 +717,50 @@ class SkyAppViewportService {
629
717
  this.#intersectionObserver.observe(item.reserveForElement);
630
718
  }
631
719
  }
632
- #isElementVisible(element) {
633
- const rect = element.getBoundingClientRect();
634
- return (
720
+ #isElementVisible(args, reservedSpaces = this
721
+ .#reservedSpaces) {
722
+ if (!args.reserveForElement) {
723
+ return true;
724
+ }
725
+ const rect = args.reserveForElement.getBoundingClientRect();
726
+ if (!rect || !rect.height || !rect.width) {
727
+ return false;
728
+ }
729
+ const midpoint = {
730
+ x: rect.x + Math.floor(rect.width / 2),
731
+ y: rect.y + Math.floor(rect.height / 2),
732
+ };
733
+ if (
635
734
  // Vertically in view
636
- rect.y <= window.innerHeight &&
637
- rect.y >= 0 &&
735
+ midpoint.y <= window.innerHeight &&
736
+ midpoint.y >= 0 &&
638
737
  // Horizontally in view
639
- rect.x <= window.innerWidth &&
640
- rect.x >= 0 &&
738
+ midpoint.x <= window.innerWidth &&
739
+ midpoint.x >= 0) {
641
740
  // Element is not hidden by another element
642
- element.contains(this.#document.elementFromPoint(rect.x + 1, rect.y + 1)));
741
+ if (args.reserveForElement.contains(this.#document.elementFromPoint(midpoint.x, midpoint.y))) {
742
+ return true;
743
+ }
744
+ // Check if the item's midpoint is visible based on current reserved spaces.
745
+ // Assumes reserved spaces are intended to be additive and not overlapping.
746
+ const threshold = reservedSpaces[args.position];
747
+ switch (args.position) {
748
+ case 'top':
749
+ return midpoint.y >= threshold;
750
+ case 'right':
751
+ return midpoint.x <= window.innerWidth - threshold;
752
+ case 'bottom':
753
+ return midpoint.y <= window.innerHeight - threshold;
754
+ case 'left':
755
+ return midpoint.x >= threshold;
756
+ }
757
+ }
758
+ return false;
643
759
  }
644
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyAppViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
645
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyAppViewportService, providedIn: 'root' }); }
760
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyAppViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
761
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyAppViewportService, providedIn: 'root' }); }
646
762
  }
647
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SkyAppViewportService, decorators: [{
763
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SkyAppViewportService, decorators: [{
648
764
  type: Injectable,
649
765
  args: [{
650
766
  providedIn: 'root',
@@ -669,5 +785,5 @@ function provideInitialTheme(name = 'default', options) {
669
785
  * Generated bundle index. Do not edit.
670
786
  */
671
787
 
672
- export { SkyAppStyleLoader, SkyAppViewportService, SkyTheme, SkyThemeComponentClassDirective, SkyThemeIconManifestService, SkyThemeMode, SkyThemeModule, SkyThemeService, SkyThemeSettings, SkyThemeSpacing, provideInitialTheme, SkyThemeDirective as λ1, SkyThemeClassDirective as λ2, SkyThemeIfDirective as λ3 };
788
+ export { SkyAppStyleLoader, SkyAppViewportService, SkyTheme, SkyThemeBrand, SkyThemeComponentClassDirective, SkyThemeIconManifestService, SkyThemeMode, SkyThemeModule, SkyThemeService, SkyThemeSettings, SkyThemeSpacing, provideInitialTheme, SkyThemeDirective as λ1, SkyThemeClassDirective as λ2, SkyThemeIfDirective as λ3 };
673
789
  //# sourceMappingURL=skyux-theme.mjs.map