Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
18 changes: 17 additions & 1 deletion src/components/cell.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { html, LitElement } from 'lit';
import { html, LitElement, type PropertyValues } from 'lit';
import { property } from 'lit/decorators.js';
import { cache } from 'lit/directives/cache.js';
import { AdoptedStylesController } from '../controllers/root-styles.js';
import { registerComponent } from '../internal/register.js';
import { GRID_CELL_TAG } from '../internal/tags.js';
import type { ColumnConfiguration, IgcCellContext, PropertyType } from '../internal/types.js';
Expand All @@ -21,6 +22,11 @@ export default class IgcGridLiteCell<T extends object> extends LitElement {
registerComponent(IgcGridLiteCell);
}

private readonly _adoptedStylesController = new AdoptedStylesController(this);

@property({ attribute: false })
public adoptRootStyles = false;

/**
* The value which will be rendered by the component.
*/
Expand Down Expand Up @@ -61,6 +67,16 @@ export default class IgcGridLiteCell<T extends object> extends LitElement {
} as unknown as IgcCellContext<T>;
}

protected override update(props: PropertyValues<this>): void {
if (props.has('adoptRootStyles')) {
this._adoptedStylesController.shouldAdoptStyles(
this.adoptRootStyles && this.cellTemplate != null
);
}

super.update(props);
}

protected override render() {
return html`${cache(
this.cellTemplate
Expand Down
5 changes: 5 additions & 0 deletions src/components/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ export class IgcGridLite<T extends object = any> extends EventEmitterBase<IgcGri
@state()
protected _dataState: T[] = [];

@property({ type: Boolean, reflect: true, attribute: 'adopt-root-styles' })
public adoptRootStyles = false;

/** The data source for the grid. */
@property({ attribute: false })
public data: T[] = [];
Expand Down Expand Up @@ -455,6 +458,7 @@ export class IgcGridLite<T extends object = any> extends EventEmitterBase<IgcGri
part="row"
exportparts="cell"
style=${styleMap(styles)}
.adoptRootStyles=${this.adoptRootStyles}
.index=${index}
.activeNode=${activeNode}
.data=${item}
Expand All @@ -468,6 +472,7 @@ export class IgcGridLite<T extends object = any> extends EventEmitterBase<IgcGri
<igc-grid-lite-header-row
tabindex="0"
style=${styleMap(this._domController.columnSizes)}
.adoptRootStyles=${this.adoptRootStyles}
.columns=${this._stateController.columns}
></igc-grid-lite-header-row>
`;
Expand Down
31 changes: 19 additions & 12 deletions src/components/header-row.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { consume } from '@lit/context';
import { html, LitElement, nothing, type PropertyValues } from 'lit';
import { html, LitElement, type PropertyValues } from 'lit';
import { property } from 'lit/decorators.js';
import { map } from 'lit/directives/map.js';
import { repeat } from 'lit/directives/repeat.js';
import type { StateController } from '../controllers/state.js';
import { GRID_STATE_CONTEXT } from '../internal/context.js';
import { getElementFromEventPath } from '../internal/element-from-event-path.js';
Expand All @@ -25,6 +25,9 @@ export default class IgcGridLiteHeaderRow<T extends object> extends LitElement {
@consume({ context: GRID_STATE_CONTEXT, subscribe: true })
private readonly _state?: StateController<T>;

@property({ attribute: false })
public adoptRootStyles = false;

@property({ attribute: false })
public columns: ColumnConfiguration<T>[] = [];

Expand Down Expand Up @@ -54,17 +57,21 @@ export default class IgcGridLiteHeaderRow<T extends object> extends LitElement {

protected override render() {
const filterRow = this._state?.filtering.filterRow;
const columns = this.columns.filter((column) => !column.hidden);

return html`${map(this.columns, (column) =>
column.hidden
? nothing
: html`
<igc-grid-lite-header
part=${partMap({ filtered: column.field === filterRow?.column?.field })}
.column=${column}
></igc-grid-lite-header>
`
)}`;
return html`
${repeat(
columns,
(column) => column,
(column) => html`
<igc-grid-lite-header
part=${partMap({ filtered: column.field === filterRow?.column?.field })}
.adoptRootStyles=${this.adoptRootStyles}
.column=${column}
></igc-grid-lite-header>
`
)}
`;
}
}

Expand Down
29 changes: 27 additions & 2 deletions src/components/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {
θaddThemingController as addThemingController,
IgcIconComponent,
} from 'igniteui-webcomponents';
import { html, LitElement, nothing } from 'lit';
import { html, LitElement, nothing, type PropertyValues } from 'lit';
import { property } from 'lit/decorators.js';
import { AdoptedStylesController } from '../controllers/root-styles.js';
import type { StateController } from '../controllers/state.js';
import {
MIN_COL_RESIZE_WIDTH,
Expand All @@ -30,6 +31,8 @@ export default class IgcGridLiteHeader<T extends object> extends LitElement {
registerComponent(IgcGridLiteHeader, IgcIconComponent);
}

private readonly _adoptedStylesController = new AdoptedStylesController(this);

protected get context(): IgcHeaderContext<T> {
return {
parent: this,
Expand All @@ -52,10 +55,32 @@ export default class IgcGridLiteHeader<T extends object> extends LitElement {
@property({ attribute: false })
public column!: ColumnConfiguration<T>;

@property({ attribute: false })
public adoptRootStyles = false;

constructor() {
super();

addThemingController(this, all);
addThemingController(this, all, {
themeChange: this._handleThemeChange,
});
}

protected override update(props: PropertyValues<this>): void {
if (props.has('adoptRootStyles')) {
this._adoptedStylesController.shouldAdoptStyles(
this.adoptRootStyles && this.column.headerTemplate != null
);
}

super.update(props);
}

private _handleThemeChange() {
AdoptedStylesController.invalidateCache(this.ownerDocument);
this._adoptedStylesController.shouldAdoptStyles(
this.adoptRootStyles && this.column.headerTemplate != null
);
}

#addResizeEventHandlers() {
Expand Down
36 changes: 22 additions & 14 deletions src/components/row.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { html, LitElement, nothing } from 'lit';
import { html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { map } from 'lit/directives/map.js';
import { repeat } from 'lit/directives/repeat.js';
import { registerComponent } from '../internal/register.js';
import { GRID_ROW_TAG } from '../internal/tags.js';
import type { ActiveNode, ColumnConfiguration } from '../internal/types.js';
Expand All @@ -21,6 +21,9 @@ export default class IgcGridLiteRow<T extends object> extends LitElement {
registerComponent(IgcGridLiteRow, IgcGridLiteCell);
}

@property({ attribute: false })
public adoptRootStyles = false;

@property({ attribute: false })
public data?: T;

Expand All @@ -43,19 +46,24 @@ export default class IgcGridLiteRow<T extends object> extends LitElement {
const { column: key, row: index } = this.activeNode ?? {};
const data = this.data ?? ({} as T);

const columns = this.columns.filter((column) => !column.hidden);

return html`
${map(this.columns, (column) =>
column.hidden
? nothing
: html`<igc-grid-lite-cell
part="cell"
.active=${key === column.field && index === this.index}
.column=${column}
.cellTemplate=${column.cellTemplate}
.row=${this as IgcGridLiteRow<T>}
.rowIndex=${this.index}
.value=${resolveFieldValue(data, column.field)}
></igc-grid-lite-cell>`
${repeat(
columns,
(column) => column,
(column) => html`
<igc-grid-lite-cell
part="cell"
.adoptRootStyles=${this.adoptRootStyles}
.active=${key === column.field && index === this.index}
.column=${column}
.cellTemplate=${column.cellTemplate}
.row=${this as IgcGridLiteRow<T>}
.rowIndex=${this.index}
.value=${resolveFieldValue(data, column.field)}
></igc-grid-lite-cell>
`
)}
`;
}
Expand Down
95 changes: 95 additions & 0 deletions src/controllers/root-styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {
adoptStyles,
type LitElement,
type ReactiveController,
type ReactiveControllerHost,
} from 'lit';

export class AdoptedStylesController implements ReactiveController {
private static _cachedSheets = new WeakMap<Document, CSSStyleSheet[]>();

private readonly _host: ReactiveControllerHost & LitElement;
private _hasAdoptedStyles = false;

public get hasAdoptedStyles(): boolean {
return this._hasAdoptedStyles;
}

public static invalidateCache(owner?: Document): void {
AdoptedStylesController._cachedSheets.delete(owner ?? document);
}

public constructor(host: ReactiveControllerHost & LitElement) {
this._host = host;
host.addController(this);
}

public shouldAdoptStyles(condition: boolean): void {
condition ? this._adoptRootStyles() : this._clearAdoptedStyles();
}

/** @internal */
public hostDisconnected(): void {
this._clearAdoptedStyles();
}

private _adoptRootStyles(): void {
const ownerDocument = this._host.ownerDocument;

if (!AdoptedStylesController._cachedSheets.has(ownerDocument)) {
AdoptedStylesController._cachedSheets.set(
ownerDocument,
this._cloneDocumentStyleSheets(ownerDocument)
);
}

const ctor = this._host.constructor as typeof LitElement;
adoptStyles(this._host.shadowRoot!, [
...ctor.elementStyles,
...AdoptedStylesController._cachedSheets.get(ownerDocument)!,
]);
this._hasAdoptedStyles = true;
}

private _cloneDocumentStyleSheets(ownerDocument: Document): CSSStyleSheet[] {
const sheets: CSSStyleSheet[] = [];

for (const sheet of ownerDocument.styleSheets) {
try {
const constructed = new CSSStyleSheet();
let hasRules = false;

for (const rule of sheet.cssRules) {
if (rule instanceof CSSImportRule) {
continue;
}

try {
constructed.insertRule(rule.cssText);
hasRules = true;
} catch {
// Ignore rules that can't be adopted.
}
}

if (hasRules) {
sheets.push(constructed);
}
} catch {
// Ignore stylesheets we can't access due to CORS.
}
}
return sheets;
}

private _clearAdoptedStyles(): void {
const shadowRoot = this._host.shadowRoot;
if (shadowRoot) {
shadowRoot.adoptedStyleSheets = shadowRoot.adoptedStyleSheets.filter(
(sheet) =>
!AdoptedStylesController._cachedSheets.get(this._host.ownerDocument)?.includes(sheet)
);
}
this._hasAdoptedStyles = false;
}
}
Loading