@shimmer-from-structure/angular 2.2.3 → 2.3.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.
package/README.md CHANGED
@@ -1,11 +1,12 @@
1
1
  # ✨ Shimmer From Structure
2
2
 
3
- A **React, Vue, Svelte & Angular** shimmer/skeleton library that **automatically adapts to your component's runtime structure**. Unlike traditional shimmer libraries that require pre-defined skeleton structures, this library analyzes your actual component's DOM at runtime and generates a shimmer effect that perfectly matches its layout.
3
+ A **React, Vue, Svelte, Angular & SolidJS** shimmer/skeleton library that **automatically adapts to your component's runtime structure**. Unlike traditional shimmer libraries that require pre-defined skeleton structures, this library analyzes your actual component's DOM at runtime and generates a shimmer effect that perfectly matches its layout.
4
4
 
5
5
  ![React](https://img.shields.io/badge/React-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB)
6
6
  ![Vue](https://img.shields.io/badge/Vue.js-35495E?style=for-the-badge&logo=vuedotjs&logoColor=4FC08D)
7
7
  ![Svelte](https://img.shields.io/badge/Svelte-ff3e00?style=for-the-badge&logo=svelte&logoColor=white)
8
8
  ![Angular](https://img.shields.io/badge/Angular-DD0031?style=for-the-badge&logo=angular&logoColor=white)
9
+ ![SolidJS](https://img.shields.io/badge/SolidJS-%232c4f7c?style=for-the-badge&logo=solid&logoColor=white)
9
10
 
10
11
  ![Shimmer From Structure Demo](https://github.com/darula-hpp/shimmer-from-structure/raw/main/example/preview.gif)
11
12
 
@@ -19,7 +20,7 @@ Traditional shimmer libraries require you to:
19
20
 
20
21
  **Shimmer From Structure** eliminates all of that:
21
22
 
22
- - ✅ **Works with React, Vue, Svelte & Angular** - Simple, framework-specific adapters
23
+ - ✅ **Works with React, Vue, Svelte, Angular & SolidJS** - Simple, framework-specific adapters
23
24
  - ✅ Automatically measures your component's structure at runtime
24
25
  - ✅ Generates shimmer effects that match actual dimensions
25
26
  - ✅ Zero maintenance - works with any layout changes
@@ -44,7 +45,7 @@ Shimmer From Structure provides dedicated packages for **React and Vue**.
44
45
 
45
46
  ### React
46
47
 
47
- React support is built-in to the main package for backward compatibility:
48
+ React support is built into the main package for backward compatibility:
48
49
 
49
50
  ```javascript
50
51
  // React projects (or @shimmer-from-structure/react)
@@ -78,6 +79,15 @@ Angular support requires importing from the specific adapter:
78
79
  import { ShimmerComponent } from '@shimmer-from-structure/angular';
79
80
  ```
80
81
 
82
+ ### SolidJS
83
+
84
+ SolidJS support requires importing from the specific adapter:
85
+
86
+ ```tsx
87
+ // SolidJS projects
88
+ import { Shimmer } from '@shimmer-from-structure/solid';
89
+ ```
90
+
81
91
  ---
82
92
 
83
93
  # 📖 Basic Usage
@@ -174,6 +184,29 @@ export class UserCardComponent {
174
184
  }
175
185
  ```
176
186
 
187
+ ## SolidJS
188
+
189
+ ### Static Content
190
+
191
+ ```tsx
192
+ import { createSignal } from 'solid-js';
193
+ import { Shimmer } from '@shimmer-from-structure/solid';
194
+
195
+ function UserCard() {
196
+ const [isLoading, setIsLoading] = createSignal(true);
197
+
198
+ return (
199
+ <Shimmer loading={isLoading()}>
200
+ <div class="card">
201
+ <img src="avatar.jpg" class="avatar" />
202
+ <h2>John Doe</h2>
203
+ <p>Software Engineer</p>
204
+ </div>
205
+ </Shimmer>
206
+ );
207
+ }
208
+ ```
209
+
177
210
  ---
178
211
 
179
212
  ### Dynamic Content with `templateProps`
@@ -287,6 +320,31 @@ export class AppComponent {
287
320
  }
288
321
  ```
289
322
 
323
+ **SolidJS**
324
+
325
+ ```tsx
326
+ import { createSignal } from 'solid-js';
327
+ import { Shimmer } from '@shimmer-from-structure/solid';
328
+ import { UserCard } from './UserCard';
329
+
330
+ function App() {
331
+ const [loading, setLoading] = createSignal(true);
332
+ const [user, setUser] = createSignal(null);
333
+
334
+ const userTemplate = {
335
+ name: 'Loading...',
336
+ role: 'Loading role...',
337
+ avatar: 'placeholder.jpg',
338
+ };
339
+
340
+ return (
341
+ <Shimmer loading={loading()} templateProps={{ user: userTemplate }}>
342
+ <UserCard user={user() || userTemplate} />
343
+ </Shimmer>
344
+ );
345
+ }
346
+ ```
347
+
290
348
  The `templateProps` object is spread onto the first child component when loading, allowing it to render with mock data for measurement.
291
349
 
292
350
  ## 🎨 API Reference
@@ -378,6 +436,24 @@ The `templateProps` object is spread onto the first child component when loading
378
436
  </shimmer>
379
437
  ```
380
438
 
439
+ **SolidJS**
440
+
441
+ ```tsx
442
+ <Shimmer
443
+ loading={isLoading()}
444
+ shimmerColor="rgba(255, 255, 255, 0.2)"
445
+ backgroundColor="rgba(255, 255, 255, 0.1)"
446
+ duration={2}
447
+ fallbackBorderRadius={8}
448
+ templateProps={{
449
+ user: userTemplate,
450
+ settings: settingsTemplate,
451
+ }}
452
+ >
453
+ <MyComponent user={user()} settings={settings()} />
454
+ </Shimmer>
455
+ ```
456
+
381
457
  ## 🔧 How It Works
382
458
 
383
459
  1. **Visible Container Rendering**: When `loading={true}`, your component renders with transparent text but **visible container backgrounds**
@@ -702,6 +778,27 @@ bootstrapApplication(AppComponent, {
702
778
  });
703
779
  ```
704
780
 
781
+ ### SolidJS (ShimmerProvider)
782
+
783
+ ```tsx
784
+ import { Shimmer, ShimmerProvider } from '@shimmer-from-structure/solid';
785
+
786
+ function App() {
787
+ return (
788
+ <ShimmerProvider
789
+ config={{
790
+ shimmerColor: 'rgba(56, 189, 248, 0.4)',
791
+ backgroundColor: 'rgba(56, 189, 248, 0.1)',
792
+ duration: 2.5,
793
+ fallbackBorderRadius: 8,
794
+ }}
795
+ >
796
+ <Dashboard />
797
+ </ShimmerProvider>
798
+ );
799
+ }
800
+ ```
801
+
705
802
  ---
706
803
 
707
804
  Components inside the provider automatically inherit values. You can still override them locally:
@@ -746,6 +843,16 @@ Components inside the provider automatically inherit values. You can still overr
746
843
  <shimmer [loading]="true" [duration]="0.5"><app-fast-card /></shimmer>
747
844
  ```
748
845
 
846
+ **SolidJS**
847
+
848
+ ```tsx
849
+ <!-- Inherits blue theme from provider -->
850
+ <Shimmer loading={true()}><UserCard /></Shimmer>
851
+
852
+ <!-- Overrides provider settings -->
853
+ <Shimmer loading={true()} duration={0.5}><FastCard /></Shimmer>
854
+ ```
855
+
749
856
  ### Accessing Config in Hooks/Composables
750
857
 
751
858
  If you need to access the current configuration in your own components:
@@ -794,6 +901,17 @@ export class MyComponent {
794
901
  }
795
902
  ```
796
903
 
904
+ **SolidJS**
905
+
906
+ ```tsx
907
+ import { useShimmerConfig } from '@shimmer-from-structure/solid';
908
+
909
+ function MyComponent() {
910
+ const config = useShimmerConfig();
911
+ return <div style={{ background: config.backgroundColor }}>...</div>;
912
+ }
913
+ ```
914
+
797
915
  ## Best Practices
798
916
 
799
917
  ### 1. Use `templateProps` for Dynamic Data
@@ -890,9 +1008,10 @@ This library is organized as a monorepo with four packages:
890
1008
  | `@shimmer-from-structure/vue` | Vue 3 adapter | 3.89 kB |
891
1009
  | `@shimmer-from-structure/svelte` | Svelte adapter | 4.60 kB |
892
1010
  | `@shimmer-from-structure/angular` | Angular adapter | 6.83 kB |
1011
+ | `@shimmer-from-structure/solid` | SolidJS adapter | 4.01 kB |
893
1012
  | `shimmer-from-structure` | Main package (React backward compatibility) | 0.93 kB |
894
1013
 
895
- The core package contains all DOM measurement logic, while React, Vue, Svelte and Angular packages are thin wrappers that provide framework-specific APIs.
1014
+ The core package contains all DOM measurement logic, while React, Vue, Svelte, Angular and SolidJS packages are thin wrappers that provide framework-specific APIs.
896
1015
 
897
1016
  ## 🚧 Roadmap
898
1017
 
@@ -902,6 +1021,7 @@ The core package contains all DOM measurement logic, while React, Vue, Svelte an
902
1021
  - [x] **Vue.js adapter**
903
1022
  - [x] **Svelte adapter**
904
1023
  - [x] **Angular adapter**
1024
+ - [x] **SolidJS adapter**
905
1025
  - [ ] Better async component support
906
1026
  - [ ] Customizable shimmer direction (vertical, diagonal)
907
1027
  - [ ] React Native support
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "./node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "./dist",
4
+ "lib": {
5
+ "entryFile": "src/public-api.ts"
6
+ },
7
+ "allowedNonPeerDependencies": ["@shimmer-from-structure/core"]
8
+ }
package/package.json CHANGED
@@ -1,14 +1,36 @@
1
1
  {
2
2
  "name": "@shimmer-from-structure/angular",
3
- "version": "2.2.3",
3
+ "version": "2.3.0",
4
4
  "description": "Angular adapter for shimmer-from-structure",
5
5
  "peerDependencies": {
6
- "@angular/core": "^19.0.0 || ^20.0.0 || ^21.0.0",
7
- "@angular/common": "^19.0.0 || ^20.0.0 || ^21.0.0"
6
+ "@angular/common": "^19.0.0 || ^20.0.0 || ^21.0.0",
7
+ "@angular/core": "^19.0.0 || ^20.0.0 || ^21.0.0"
8
8
  },
9
9
  "dependencies": {
10
- "@shimmer-from-structure/core": "*",
11
- "tslib": "^2.3.0"
10
+ "@shimmer-from-structure/core": "*"
11
+ },
12
+ "devDependencies": {
13
+ "@analogjs/vite-plugin-angular": "^2.2.3",
14
+ "@angular/common": "^19.0.0",
15
+ "@angular/compiler": "^19.0.0",
16
+ "@angular/compiler-cli": "^19.0.0",
17
+ "@angular/core": "^19.0.0",
18
+ "@angular/platform-browser": "^19.0.0",
19
+ "@angular/platform-browser-dynamic": "^19.0.0",
20
+ "@testing-library/dom": "^10.4.1",
21
+ "jsdom": "^27.4.0",
22
+ "ng-packagr": "^19.0.0",
23
+ "rxjs": "~7.8.0",
24
+ "typescript": "~5.6.0",
25
+ "vite": "^7.3.1",
26
+ "vitest": "^4.0.17",
27
+ "zone.js": "~0.15.0"
28
+ },
29
+ "scripts": {
30
+ "build": "ng-packagr -p ng-package.json",
31
+ "test": "vitest run",
32
+ "format": "prettier --write .",
33
+ "prepublishOnly": "cp ../../README.md ."
12
34
  },
13
35
  "keywords": [
14
36
  "angular",
@@ -22,17 +44,5 @@
22
44
  "directory": "packages/angular"
23
45
  },
24
46
  "author": "Olebogeng Mbedzi",
25
- "license": "MIT",
26
- "module": "fesm2022/shimmer-from-structure-angular.mjs",
27
- "typings": "index.d.ts",
28
- "exports": {
29
- "./package.json": {
30
- "default": "./package.json"
31
- },
32
- ".": {
33
- "types": "./index.d.ts",
34
- "default": "./fesm2022/shimmer-from-structure-angular.mjs"
35
- }
36
- },
37
- "sideEffects": false
38
- }
47
+ "license": "MIT"
48
+ }
@@ -0,0 +1,9 @@
1
+ // Public API Surface
2
+ export { ShimmerComponent } from './shimmer.component';
3
+ export {
4
+ SHIMMER_CONFIG,
5
+ provideShimmerConfig,
6
+ injectShimmerConfig,
7
+ shimmerDefaults,
8
+ } from './shimmer-config.service';
9
+ export type { ShimmerInputs, ShimmerConfig, ShimmerContextValue, ElementInfo } from './types';
@@ -0,0 +1,88 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { TestBed } from '@angular/core/testing';
3
+ import {
4
+ provideShimmerConfig,
5
+ injectShimmerConfig,
6
+ shimmerDefaults,
7
+ SHIMMER_CONFIG,
8
+ } from './shimmer-config.service';
9
+
10
+ describe('shimmer-config.service', () => {
11
+ describe('shimmerDefaults', () => {
12
+ it('exports default values', () => {
13
+ expect(shimmerDefaults).toBeDefined();
14
+ expect(shimmerDefaults.shimmerColor).toBeDefined();
15
+ expect(shimmerDefaults.backgroundColor).toBeDefined();
16
+ expect(shimmerDefaults.duration).toBeDefined();
17
+ expect(shimmerDefaults.fallbackBorderRadius).toBeDefined();
18
+ });
19
+ });
20
+
21
+ describe('provideShimmerConfig', () => {
22
+ it('creates a provider object', () => {
23
+ const config = { shimmerColor: '#fff', duration: 2 };
24
+ const provider = provideShimmerConfig(config);
25
+
26
+ expect(provider.provide).toBe(SHIMMER_CONFIG);
27
+ expect(provider.useValue).toBe(config);
28
+ });
29
+ });
30
+
31
+ describe('injectShimmerConfig', () => {
32
+ it('returns defaults when no provider is configured', () => {
33
+ TestBed.configureTestingModule({});
34
+
35
+ TestBed.runInInjectionContext(() => {
36
+ const config = injectShimmerConfig();
37
+
38
+ expect(config.shimmerColor).toBe(shimmerDefaults.shimmerColor);
39
+ expect(config.backgroundColor).toBe(shimmerDefaults.backgroundColor);
40
+ expect(config.duration).toBe(shimmerDefaults.duration);
41
+ expect(config.fallbackBorderRadius).toBe(shimmerDefaults.fallbackBorderRadius);
42
+ });
43
+ });
44
+
45
+ it('merges provided config with defaults', () => {
46
+ TestBed.configureTestingModule({
47
+ providers: [
48
+ provideShimmerConfig({
49
+ shimmerColor: 'rgba(255, 255, 255, 0.8)',
50
+ duration: 3,
51
+ }),
52
+ ],
53
+ });
54
+
55
+ TestBed.runInInjectionContext(() => {
56
+ const config = injectShimmerConfig();
57
+
58
+ expect(config.shimmerColor).toBe('rgba(255, 255, 255, 0.8)');
59
+ expect(config.duration).toBe(3);
60
+ // Should use defaults for non-provided values
61
+ expect(config.backgroundColor).toBe(shimmerDefaults.backgroundColor);
62
+ expect(config.fallbackBorderRadius).toBe(shimmerDefaults.fallbackBorderRadius);
63
+ });
64
+ });
65
+
66
+ it('returns fully resolved ShimmerContextValue', () => {
67
+ TestBed.configureTestingModule({
68
+ providers: [
69
+ provideShimmerConfig({
70
+ shimmerColor: '#aaa',
71
+ backgroundColor: '#bbb',
72
+ duration: 1.5,
73
+ fallbackBorderRadius: 10,
74
+ }),
75
+ ],
76
+ });
77
+
78
+ TestBed.runInInjectionContext(() => {
79
+ const config = injectShimmerConfig();
80
+
81
+ expect(config.shimmerColor).toBe('#aaa');
82
+ expect(config.backgroundColor).toBe('#bbb');
83
+ expect(config.duration).toBe(1.5);
84
+ expect(config.fallbackBorderRadius).toBe(10);
85
+ });
86
+ });
87
+ });
88
+ });
@@ -1,11 +1,13 @@
1
- import { InjectionToken } from '@angular/core';
1
+ import { InjectionToken, inject } from '@angular/core';
2
2
  import type { ShimmerConfig, ShimmerContextValue } from '@shimmer-from-structure/core';
3
3
  import { shimmerDefaults } from '@shimmer-from-structure/core';
4
+
4
5
  /**
5
6
  * Injection token for global shimmer configuration.
6
7
  * Use `provideShimmerConfig()` to configure in your app.
7
8
  */
8
- export declare const SHIMMER_CONFIG: InjectionToken<ShimmerConfig>;
9
+ export const SHIMMER_CONFIG = new InjectionToken<ShimmerConfig>('SHIMMER_CONFIG');
10
+
9
11
  /**
10
12
  * Provider function for shimmer configuration.
11
13
  * Use in your app's providers array.
@@ -22,14 +24,25 @@ export declare const SHIMMER_CONFIG: InjectionToken<ShimmerConfig>;
22
24
  * });
23
25
  * ```
24
26
  */
25
- export declare function provideShimmerConfig(config: ShimmerConfig): {
26
- provide: InjectionToken<ShimmerConfig>;
27
- useValue: ShimmerConfig;
28
- };
27
+ export function provideShimmerConfig(config: ShimmerConfig) {
28
+ return { provide: SHIMMER_CONFIG, useValue: config };
29
+ }
30
+
29
31
  /**
30
32
  * Inject and resolve shimmer configuration.
31
33
  * Merges injected config with defaults.
32
34
  * Returns fully resolved ShimmerContextValue with all properties defined.
33
35
  */
34
- export declare function injectShimmerConfig(): ShimmerContextValue;
36
+ export function injectShimmerConfig(): ShimmerContextValue {
37
+ const config = inject(SHIMMER_CONFIG, { optional: true }) ?? {};
38
+
39
+ return {
40
+ shimmerColor: config.shimmerColor ?? shimmerDefaults.shimmerColor,
41
+ backgroundColor: config.backgroundColor ?? shimmerDefaults.backgroundColor,
42
+ duration: config.duration ?? shimmerDefaults.duration,
43
+ fallbackBorderRadius: config.fallbackBorderRadius ?? shimmerDefaults.fallbackBorderRadius,
44
+ };
45
+ }
46
+
47
+ // Re-export defaults for testing and reference
35
48
  export { shimmerDefaults };
@@ -0,0 +1,175 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { Component, NO_ERRORS_SCHEMA, signal, ChangeDetectorRef } from '@angular/core';
3
+ import { TestBed, ComponentFixture } from '@angular/core/testing';
4
+ import { By } from '@angular/platform-browser';
5
+ import { ShimmerComponent } from './shimmer.component';
6
+ import { provideShimmerConfig, SHIMMER_CONFIG } from './shimmer-config.service';
7
+
8
+ // Test wrapper component for content projection
9
+ @Component({
10
+ selector: 'test-host',
11
+ standalone: true,
12
+ imports: [ShimmerComponent],
13
+ template: `
14
+ <shimmer [loading]="loading">
15
+ <div class="test-content" style="width: 100px; height: 50px;">Content</div>
16
+ </shimmer>
17
+ `,
18
+ schemas: [NO_ERRORS_SCHEMA],
19
+ })
20
+ class TestHostComponent {
21
+ loading = true;
22
+ }
23
+
24
+ describe('ShimmerComponent', () => {
25
+ let fixture: ComponentFixture<TestHostComponent>;
26
+ let hostComponent: TestHostComponent;
27
+
28
+ beforeEach(async () => {
29
+ await TestBed.configureTestingModule({
30
+ imports: [TestHostComponent, ShimmerComponent],
31
+ }).compileComponents();
32
+
33
+ fixture = TestBed.createComponent(TestHostComponent);
34
+ hostComponent = fixture.componentInstance;
35
+ });
36
+
37
+ // Helper to wait for async operations
38
+ const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms || 50));
39
+
40
+ it('renders children normally when loading=false', async () => {
41
+ fixture.detectChanges();
42
+ const shimmerEl = fixture.debugElement.query(By.directive(ShimmerComponent));
43
+ const shimmerInstance = shimmerEl.componentInstance;
44
+
45
+ Object.defineProperty(shimmerInstance, 'loading', { value: signal(false) });
46
+ shimmerEl.injector.get(ChangeDetectorRef).detectChanges();
47
+
48
+ fixture.detectChanges();
49
+ await wait(0);
50
+ fixture.detectChanges();
51
+
52
+ const content = fixture.nativeElement.querySelector('.test-content');
53
+ expect(content).toBeTruthy();
54
+ expect(content.textContent).toBe('Content');
55
+
56
+ // Should not have the measure container when not loading
57
+ const measureContainer = fixture.nativeElement.querySelector('.shimmer-measure-container');
58
+ expect(measureContainer).toBeFalsy();
59
+ });
60
+
61
+ it('renders shimmer structure when loading=true', async () => {
62
+ hostComponent.loading = true;
63
+ fixture.detectChanges();
64
+ await wait(0);
65
+ fixture.detectChanges();
66
+
67
+ // Should render the measure container
68
+ const measureContainer = fixture.nativeElement.querySelector('.shimmer-measure-container');
69
+ expect(measureContainer).toBeTruthy();
70
+ });
71
+
72
+ it('applies transparent text style to measure container', async () => {
73
+ hostComponent.loading = true;
74
+ fixture.detectChanges();
75
+ await wait(0);
76
+ fixture.detectChanges();
77
+
78
+ // Check that the measure container has the class
79
+ const measureContainer = fixture.nativeElement.querySelector('.shimmer-measure-container');
80
+ expect(measureContainer).toBeTruthy();
81
+ expect(measureContainer.classList.contains('shimmer-measure-container')).toBe(true);
82
+ });
83
+ });
84
+
85
+ describe('ShimmerComponent with config provider', () => {
86
+ let fixture: ComponentFixture<TestHostComponent>;
87
+ const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms || 50));
88
+
89
+ beforeEach(async () => {
90
+ await TestBed.configureTestingModule({
91
+ imports: [TestHostComponent, ShimmerComponent],
92
+ providers: [
93
+ provideShimmerConfig({
94
+ shimmerColor: 'rgba(255, 0, 0, 0.5)',
95
+ backgroundColor: '#ff0000',
96
+ duration: 2,
97
+ fallbackBorderRadius: 8,
98
+ }),
99
+ ],
100
+ }).compileComponents();
101
+
102
+ fixture = TestBed.createComponent(TestHostComponent);
103
+ });
104
+
105
+ it('uses provided config values', async () => {
106
+ fixture.componentInstance.loading = true;
107
+ fixture.detectChanges();
108
+ await wait(0);
109
+ fixture.detectChanges();
110
+
111
+ // The config should be injected - we can verify by checking the SHIMMER_CONFIG token
112
+ const config = TestBed.inject(SHIMMER_CONFIG);
113
+ expect(config.shimmerColor).toBe('rgba(255, 0, 0, 0.5)');
114
+ expect(config.backgroundColor).toBe('#ff0000');
115
+ expect(config.duration).toBe(2);
116
+ expect(config.fallbackBorderRadius).toBe(8);
117
+ });
118
+ });
119
+
120
+ describe('ShimmerComponent input overrides', () => {
121
+ const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms || 50));
122
+
123
+ @Component({
124
+ selector: 'test-override-host',
125
+ standalone: true,
126
+ imports: [ShimmerComponent],
127
+ template: `
128
+ <shimmer
129
+ [loading]="true"
130
+ [shimmerColor]="'#00ff00'"
131
+ [backgroundColor]="'#0000ff'"
132
+ [duration]="3"
133
+ [fallbackBorderRadius]="12"
134
+ >
135
+ <div>Content</div>
136
+ </shimmer>
137
+ `,
138
+ schemas: [NO_ERRORS_SCHEMA],
139
+ })
140
+ class TestOverrideHostComponent {}
141
+
142
+ beforeEach(async () => {
143
+ await TestBed.configureTestingModule({
144
+ imports: [TestOverrideHostComponent, ShimmerComponent],
145
+ providers: [
146
+ provideShimmerConfig({
147
+ shimmerColor: 'rgba(255, 0, 0, 0.5)',
148
+ duration: 1,
149
+ }),
150
+ ],
151
+ }).compileComponents();
152
+ });
153
+
154
+ it('component inputs override provider config', async () => {
155
+ const fixture = TestBed.createComponent(TestOverrideHostComponent);
156
+ fixture.detectChanges();
157
+
158
+ // Manual override for input signals
159
+ const shimmer = fixture.debugElement.children[0].componentInstance as ShimmerComponent;
160
+ Object.defineProperty(shimmer, 'shimmerColor', { value: signal('#00ff00') });
161
+ Object.defineProperty(shimmer, 'backgroundColor', { value: signal('#0000ff') });
162
+ Object.defineProperty(shimmer, 'duration', { value: signal(3) });
163
+ Object.defineProperty(shimmer, 'fallbackBorderRadius', { value: signal(12) });
164
+
165
+ fixture.detectChanges();
166
+ await wait(0);
167
+ fixture.detectChanges();
168
+
169
+ // The shimmer component should use input values over config
170
+ expect(shimmer.resolvedShimmerColor()).toBe('#00ff00');
171
+ expect(shimmer.resolvedBackgroundColor()).toBe('#0000ff');
172
+ expect(shimmer.resolvedDuration()).toBe(3);
173
+ expect(shimmer.resolvedFallbackBorderRadius()).toBe(12);
174
+ });
175
+ });