Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 3 additions & 16 deletions src/components/theme-provider/theme-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ export default class IgcThemeProviderComponent extends LitElement {
registerComponent(IgcThemeProviderComponent);
}

private readonly _provider: ContextProvider<typeof themeContext>;
private readonly _provider = new ContextProvider(this, {
context: themeContext,
});

/**
* The theme to provide to descendant components.
Expand All @@ -83,15 +85,6 @@ export default class IgcThemeProviderComponent extends LitElement {
@property({ reflect: true })
public variant: ThemeVariant = 'light';

constructor() {
super();

this._provider = new ContextProvider(this, {
context: themeContext,
initialValue: this._getContextValue(),
});
}

protected override update(changedProperties: PropertyValues<this>): void {
if (changedProperties.has('theme') || changedProperties.has('variant')) {
this._provider.setValue(this._getContextValue());
Expand All @@ -100,12 +93,6 @@ export default class IgcThemeProviderComponent extends LitElement {
super.update(changedProperties);
}

protected override firstUpdated(): void {
this.updateComplete.then(() => {
this._provider.setValue(this._getContextValue());
});
}

private _getContextValue(): ThemeContext {
return {
theme: this.theme,
Expand Down
33 changes: 30 additions & 3 deletions src/theming/theming-controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ describe('Theming Controller', () => {
);

expect(el.themingController.theme).to.equal('bootstrap');
expect(el.themingController.variant).to.equal('light');
});

it('should respond to global theme changes', async () => {
Expand All @@ -168,13 +169,15 @@ describe('Theming Controller', () => {
);

expect(el.themingController.theme).to.equal('bootstrap');
expect(el.themingController.variant).to.equal('light');

// Change global theme
setTimeout(() => configureTheme('material', 'light'));
await oneEvent(window, CHANGE_THEME_EVENT);
await elementUpdated(el);

expect(el.themingController.theme).to.equal('material');
expect(el.themingController.variant).to.equal('light');
});

it('should call themeChange callback when global theme changes', async () => {
Expand All @@ -192,6 +195,7 @@ describe('Theming Controller', () => {

expect(el.themeChangeCallCount).to.be.greaterThan(initialCallCount);
expect(el.lastTheme).to.equal('fluent');
expect(el.themingController.variant).to.equal('dark');
});

it('should work without themeChange callback', async () => {
Expand All @@ -201,13 +205,15 @@ describe('Theming Controller', () => {
);

expect(el.themingController.theme).to.equal('bootstrap');
expect(el.themingController.variant).to.equal('light');

// Should not throw when changing theme
setTimeout(() => configureTheme('indigo', 'light'));
await oneEvent(window, CHANGE_THEME_EVENT);
await elementUpdated(el);

expect(el.themingController.theme).to.equal('indigo');
expect(el.themingController.variant).to.equal('light');
});

it('should stop listening to global events when disconnected', async () => {
Expand Down Expand Up @@ -247,6 +253,7 @@ describe('Theming Controller', () => {
await elementUpdated(el);

expect(el.themingController.theme).to.equal('material');
expect(el.themingController.variant).to.equal('dark');
});

it('should update when theme provider theme changes', async () => {
Expand All @@ -268,12 +275,14 @@ describe('Theming Controller', () => {

await elementUpdated(el);
expect(el.themingController.theme).to.equal('bootstrap');
expect(el.themingController.variant).to.equal('light');

provider.theme = 'fluent';
await elementUpdated(provider);
await elementUpdated(el);

expect(el.themingController.theme).to.equal('fluent');
expect(el.themingController.variant).to.equal('light');
});

it('should update when theme provider variant changes', async () => {
Expand Down Expand Up @@ -321,6 +330,7 @@ describe('Theming Controller', () => {
await elementUpdated(el);

expect(el.themingController.theme).to.equal('material');
expect(el.themingController.variant).to.equal('dark');

// Change global theme - should not affect component inside provider
setTimeout(() => configureTheme('bootstrap', 'light'));
Expand All @@ -329,6 +339,7 @@ describe('Theming Controller', () => {

// Should still be material, not bootstrap
expect(el.themingController.theme).to.equal('material');
expect(el.themingController.variant).to.equal('dark');
});

it('should call themeChange callback when context theme changes', async () => {
Expand Down Expand Up @@ -357,6 +368,7 @@ describe('Theming Controller', () => {

expect(el.themeChangeCallCount).to.be.greaterThan(initialCallCount);
expect(el.lastTheme).to.equal('indigo');
expect(el.themingController.variant).to.equal('light');
});

it('should use nearest theme provider when nested', async () => {
Expand All @@ -383,7 +395,9 @@ describe('Theming Controller', () => {
await elementUpdated(innerEl);

expect(outerEl.themingController.theme).to.equal('material');
expect(outerEl.themingController.variant).to.equal('light');
expect(innerEl.themingController.theme).to.equal('fluent');
expect(innerEl.themingController.variant).to.equal('dark');
});
});

Expand All @@ -409,6 +423,7 @@ describe('Theming Controller', () => {
await elementUpdated(el);

expect(el.themingController.theme).to.equal('indigo');
expect(el.themingController.variant).to.equal('dark');
});

it('should fall back to global theme when moved outside provider', async () => {
Expand All @@ -427,17 +442,28 @@ describe('Theming Controller', () => {
const el = container.querySelector(
themedTag
) as ThemedTestComponentElement;
const provider = container.querySelector(
IgcThemeProviderComponent.tagName
)!;
await elementUpdated(el);

// After initial render, should have provider theme
expect(el.themingController.theme).to.equal('material');
expect(el.themingController.variant).to.equal('dark');

// Move outside the provider
container.appendChild(el);
await elementUpdated(el);

// Note: The component should now use global theme
// However, the context consumer may still hold the previous value
// This tests the disconnect/reconnect behavior
expect(el.themingController.theme).to.equal('bootstrap');
expect(el.themingController.variant).to.equal('light');

// Move back inside provider scope
provider.appendChild(el);
await elementUpdated(el);

expect(el.themingController.theme).to.equal('material');
expect(el.themingController.variant).to.equal('dark');
});
});

Expand Down Expand Up @@ -503,6 +529,7 @@ describe('Theming Controller', () => {
await elementUpdated(el);

expect(el.themingController.theme).to.equal(theme);
expect(el.themingController.variant).to.equal(variant);
});
}
}
Expand Down
Loading