Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions .changeset/clear-pugs-make.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@patternfly/pfe-core": patch
"@patternfly/elements": patch
---
Enable context protocol in SSR scenarios.
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v20.10.0
v22.13.0
14 changes: 9 additions & 5 deletions core/pfe-core/controllers/light-dom-controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ReactiveController, ReactiveElement } from 'lit';
import { isServer, type ReactiveController, type ReactiveElement } from 'lit';

import { Logger } from './logger.js';

Expand Down Expand Up @@ -52,9 +52,13 @@ export class LightDOMController implements ReactiveController {
* Returns a boolean statement of whether or not this component contains any light DOM.
*/
hasLightDOM(): boolean {
return !!(
this.host.children.length > 0
|| (this.host.textContent ?? '').trim().length > 0
);
if (isServer) {
return false;
} else {
return !!(
this.host.children.length > 0
|| (this.host.textContent ?? '').trim().length > 0
);
}
}
}
4 changes: 2 additions & 2 deletions core/pfe-core/controllers/scroll-spy-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class ScrollSpyController implements ReactiveController {
#rootMargin?: string;
#threshold: number | number[];

#getRootNode: () => Node;
#getRootNode: () => Node | null;
#getHash: (el: Element) => string | null;

get #linkChildren(): Element[] {
Expand Down Expand Up @@ -92,7 +92,7 @@ export class ScrollSpyController implements ReactiveController {
this.#rootMargin = options.rootMargin;
this.#activeAttribute = options.activeAttribute ?? 'active';
this.#threshold = options.threshold ?? 0.85;
this.#getRootNode = () => options.rootNode ?? host.getRootNode();
this.#getRootNode = () => options.rootNode ?? host.getRootNode?.() ?? null;
this.#getHash = options?.getHash ?? ((el: Element) => el.getAttribute('href'));
}

Expand Down
8 changes: 6 additions & 2 deletions core/pfe-core/controllers/slot-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,12 @@ export class SlotController implements ReactiveController {
#getChildrenForSlot<T extends Element = Element>(
name: string | typeof SlotController.default,
): T[] {
const children = Array.from(this.host.children) as T[];
return children.filter(isSlot(name));
if (isServer) {
return [];
} else {
const children = Array.from(this.host.children) as T[];
return children.filter(isSlot(name));
}
}

#initSlot = (slotName: string | null) => {
Expand Down
5 changes: 5 additions & 0 deletions core/pfe-core/functions/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ function makeContextRoot() {
const root = new ContextRoot();
if (!isServer) {
root.attach(document.body);
} else {
root.attach(
// @ts-expect-error: enable context root in ssr
globalThis.litServerRoot,
);
}
return root;
}
Expand Down
4 changes: 2 additions & 2 deletions core/pfe-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@
},
"dependencies": {
"@floating-ui/dom": "^1.6.10",
"@lit/context": "^1.1.2",
"lit": "^3.2.0"
"@lit/context": "^1.1.3",
"lit": "^3.2.1"
},
"repository": {
"type": "git",
Expand Down
54 changes: 25 additions & 29 deletions core/pfe-core/ssr-shims.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { installWindowOnGlobal } from '@lit-labs/ssr/lib/dom-shim.js';

class ObserverShim {
observe(): void {
void 0;
Expand All @@ -17,33 +19,7 @@ class MiniHTMLTemplateElement extends MiniHTMLElement {
content = { cloneNode: (): string => this.innerHTML };
}

class MiniDocument {
createElement(tagName: string): MiniHTMLElement {
switch (tagName) {
case 'template':
return new MiniHTMLTemplateElement(tagName);
default:
return new MiniHTMLElement(tagName);
}
}
}

// @ts-expect-error: this runs in node
globalThis.window ??= globalThis;
// @ts-expect-error: this runs in node
globalThis.document ??= new MiniDocument();
// @ts-expect-error: this runs in node
globalThis.navigator ??= { userAgent: '' };
// @ts-expect-error: this runs in node
globalThis.ErrorEvent ??= Event;
// @ts-expect-error: this runs in node
globalThis.IntersectionObserver ??= ObserverShim;
// @ts-expect-error: this runs in node
globalThis.MutationObserver ??= ObserverShim;
// @ts-expect-error: this runs in node
globalThis.ResizeObserver ??= ObserverShim;
// @ts-expect-error: this runs in node
globalThis.getComputedStyle ??= function() {
function getComputedStyle() {
return {
getPropertyPriority() {
return '';
Expand All @@ -52,7 +28,27 @@ globalThis.getComputedStyle ??= function() {
return '';
},
};
}
};

;
// @ts-expect-error: opt in to event support in ssr
globalThis.litSsrCallConnectedCallback = true;
Comment thread
bennypowers marked this conversation as resolved.

installWindowOnGlobal({
ErrorEvent: Event,
IntersectionObserver: ObserverShim,
MutationObserver: ObserverShim,
ResizeObserver: ObserverShim,
getComputedStyle,
});

// @ts-expect-error: this runs in node
globalThis.navigator.userAgent ??= '@lit-labs/ssr';

globalThis.document.createElement = function createElement(tagName: string): HTMLElement {
switch (tagName) {
case 'template':
return new MiniHTMLTemplateElement(tagName) as unknown as HTMLElement;
default:
return new MiniHTMLElement(tagName) as HTMLElement;
}
};
2 changes: 1 addition & 1 deletion elements/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
"@lit/context": "^1.1.2",
"@patternfly/icons": "^1.0.3",
"@patternfly/pfe-core": "^4.0.1",
"lit": "^3.2.0",
"lit": "^3.2.1",
"tslib": "^2.6.3"
}
}
4 changes: 3 additions & 1 deletion elements/pf-back-to-top/pf-back-to-top.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ export class PfBackToTop extends LitElement {
}

this.#scrollSpy = !!this.scrollableSelector;
if (this.#scrollSpy && this.scrollableSelector) {
if (isServer) {
return;
} else if (this.#scrollSpy && this.scrollableSelector) {
const scrollableElement = this.#rootNode?.querySelector?.(this.scrollableSelector);
if (!scrollableElement) {
this.#logger.error(`unable to find element with selector ${this.scrollableSelector}`);
Expand Down
8 changes: 5 additions & 3 deletions elements/pf-clipboard-copy/pf-clipboard-copy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LitElement, html, type TemplateResult } from 'lit';
import { LitElement, html, isServer, type TemplateResult } from 'lit';
import { customElement } from 'lit/decorators/custom-element.js';
import { property } from 'lit/decorators/property.js';
import { classMap } from 'lit/directives/class-map.js';
Expand Down Expand Up @@ -108,7 +108,9 @@ export class PfClipboardCopy extends LitElement {
connectedCallback(): void {
super.connectedCallback();
this.#mo.observe(this, { characterData: true });
this.#onMutation();
if (!isServer) {
this.#onMutation();
}
}

/**
Expand Down Expand Up @@ -167,7 +169,7 @@ export class PfClipboardCopy extends LitElement {
}

#onMutation() {
if (this.childNodes.length > 0) {
if (this.childNodes?.length > 0) {
this.value = this.getAttribute('value') ?? this.#dedent(Array.from(this.childNodes, child =>
(child instanceof Element || child instanceof Text) ? (child.textContent ?? '') : '')
.join(''));
Expand Down
5 changes: 5 additions & 0 deletions elements/pf-table/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createContextWithRoot } from '@patternfly/pfe-core/functions/context.js';

export const thRoleContext: {
__context__: unknown;
} = createContextWithRoot<'rowheader' | 'colheader'>('pf-th-role');
9 changes: 7 additions & 2 deletions elements/pf-table/pf-table.ts
Comment thread
bennypowers marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { customElement } from 'lit/decorators/custom-element.js';
import { styleMap } from 'lit/directives/style-map.js';
import { state } from 'lit/decorators/state.js';

import { provide } from '@lit/context';
import { thRoleContext } from './context.js';

import { PfTh, RequestSortEvent } from './pf-th.js';
import { PfTd } from './pf-td.js';
import { PfTr, RequestExpandEvent } from './pf-tr.js';

export * from './pf-caption.js';
Expand All @@ -14,7 +18,6 @@ export * from './pf-th.js';
export * from './pf-td.js';

import styles from './pf-table.css';
import { PfTd } from './pf-td.js';

const rowQuery = [
':scope > pf-tbody:not([expandable]) > pf-tr',
Expand Down Expand Up @@ -671,6 +674,8 @@ export class PfTable extends LitElement {

@state() private columns = 0;

@provide({ context: thRoleContext }) private thRowContext = 'rowheader';

override connectedCallback(): void {
super.connectedCallback();
this.setAttribute('role', 'table');
Expand Down Expand Up @@ -708,7 +713,7 @@ export class PfTable extends LitElement {
}

#onSlotchange() {
this.columns = this.querySelector('pf-tr')?.querySelectorAll('pf-th')?.length ?? 0;
this.columns = this.querySelector?.('pf-tr')?.querySelectorAll('pf-th')?.length ?? 0;
this.requestUpdate();
}

Expand Down
13 changes: 8 additions & 5 deletions elements/pf-table/pf-th.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { customElement } from 'lit/decorators/custom-element.js';
import { property } from 'lit/decorators/property.js';
import { classMap } from 'lit/directives/class-map.js';

import { consume } from '@lit/context';

import { thRoleContext } from './context.js';

import '@patternfly/elements/pf-button/pf-button.js';

import styles from './pf-th.css';
Expand Down Expand Up @@ -46,13 +50,12 @@ export class PfTh extends LitElement {

@property() key!: string;

@consume({ context: thRoleContext })
private contextualRole: 'colheader' | 'rowheader' = 'rowheader';

override connectedCallback(): void {
super.connectedCallback();
const closestThead = this.closest('pf-thead');
const closestTable = this.closest('pf-table');
const isChildOfThead = !!closestThead && !!closestTable?.contains(closestThead);
const role = isChildOfThead ? 'colheader' : 'rowheader';
this.setAttribute('role', role);
this.setAttribute('role', this.contextualRole);
}

render(): TemplateResult<1> {
Expand Down
5 changes: 5 additions & 0 deletions elements/pf-table/pf-thead.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { LitElement, html, type TemplateResult } from 'lit';
import { customElement } from 'lit/decorators/custom-element.js';

import { thRoleContext } from './context.js';

import styles from './pf-thead.css';
import { provide } from '@lit/context';

/**
* Table head
Expand All @@ -11,6 +14,8 @@ import styles from './pf-thead.css';
export class PfThead extends LitElement {
static readonly styles: CSSStyleSheet[] = [styles];

@provide({ context: thRoleContext }) private thRowContext = 'colheader';

connectedCallback(): void {
super.connectedCallback();
this.setAttribute('role', 'rowgroup');
Expand Down
7 changes: 4 additions & 3 deletions elements/pf-tabs/pf-tab.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LitElement, html, type TemplateResult } from 'lit';
import { LitElement, html, isServer, type TemplateResult } from 'lit';
import { customElement } from 'lit/decorators/custom-element.js';
import { property } from 'lit/decorators/property.js';
import { queryAssignedElements } from 'lit/decorators/query-assigned-elements.js';
Expand Down Expand Up @@ -63,7 +63,7 @@ export class PfTab extends LitElement {
static readonly styles: CSSStyleSheet[] = [styles];

@queryAssignedElements({ slot: 'icon', flatten: true })
private icons!: HTMLElement[];
private icons?: HTMLElement[];

@property({ reflect: true, type: Boolean }) active = false;

Expand Down Expand Up @@ -105,13 +105,14 @@ export class PfTab extends LitElement {
const { box, fill = false, vertical = false } = this.ctx ?? {};
const light = box === 'light';
const dark = box === 'dark';
const icons = isServer ? [] : this.icons;
return html`
<div id="button"
part="button"
class="${classMap({ active, box: !!box, dark, light, fill, vertical })}">
<slot name="icon"
part="icon"
?hidden="${!this.icons.length}"
?hidden="${!icons?.length}"
@slotchange="${() => this.requestUpdate()}"></slot>
<slot part="text"></slot>
</div>
Expand Down
4 changes: 2 additions & 2 deletions elements/pf-tooltip/pf-tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,11 @@ export class PfTooltip extends LitElement {
}) flipBehavior?: Placement[];

get #invoker(): HTMLSlotElement | null {
return this.shadowRoot?.querySelector('#invoker') ?? null;
return this.shadowRoot?.querySelector?.('#invoker') ?? null;
}

get #content(): HTMLElement | null {
return this.shadowRoot?.querySelector('#tooltip') ?? null;
return this.shadowRoot?.querySelector?.('#tooltip') ?? null;
}

#referenceTrigger?: HTMLElement | null;
Expand Down
Loading