diff --git a/.changeset/clear-pugs-make.md b/.changeset/clear-pugs-make.md new file mode 100644 index 0000000000..2bc7175b94 --- /dev/null +++ b/.changeset/clear-pugs-make.md @@ -0,0 +1,31 @@ +--- +"@patternfly/pfe-core": major +"@patternfly/elements": patch +--- +Enable `connectedCallback()` and context protocol in SSR scenarios. + +BREAKING CHANGE +This change affects any element which is expected to execute in node JS when +lit-ssr shims are present. By enabling the `connectedCallback()` to execute +server side. Elements must ensure that their connectedCallbacks do not try to +access the DOM. + +Before: + +```js +connectedCallback() { + super.connectedCallback(); + this.items = this.querySelectorAll('my-item'); +} +``` + +After: +```js +connectedCallback() { + super.connectedCallback(); + if (!isServer) { + this.items = this.querySelectorAll('my-item'); + } +} +``` + diff --git a/.nvmrc b/.nvmrc index 790e1105f2..2c022021b8 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20.10.0 +v22.13.0 diff --git a/core/pfe-core/controllers/light-dom-controller.ts b/core/pfe-core/controllers/light-dom-controller.ts index e53d11cd5c..321010a467 100644 --- a/core/pfe-core/controllers/light-dom-controller.ts +++ b/core/pfe-core/controllers/light-dom-controller.ts @@ -1,4 +1,4 @@ -import type { ReactiveController, ReactiveElement } from 'lit'; +import { isServer, type ReactiveController, type ReactiveElement } from 'lit'; import { Logger } from './logger.js'; @@ -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 + ); + } } } diff --git a/core/pfe-core/controllers/scroll-spy-controller.ts b/core/pfe-core/controllers/scroll-spy-controller.ts index 89af9d2481..90cb254b1d 100644 --- a/core/pfe-core/controllers/scroll-spy-controller.ts +++ b/core/pfe-core/controllers/scroll-spy-controller.ts @@ -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[] { @@ -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')); } diff --git a/core/pfe-core/controllers/slot-controller.ts b/core/pfe-core/controllers/slot-controller.ts index a18344b989..63dc3bf444 100644 --- a/core/pfe-core/controllers/slot-controller.ts +++ b/core/pfe-core/controllers/slot-controller.ts @@ -1,7 +1,5 @@ import { isServer, type ReactiveController, type ReactiveElement } from 'lit'; -import { Logger } from './logger.js'; - interface AnonymousSlot { hasContent: boolean; elements: Element[]; @@ -15,8 +13,10 @@ interface NamedSlot extends AnonymousSlot { export type Slot = NamedSlot | AnonymousSlot; +export type SlotName = string | null; + export interface SlotsConfig { - slots: (string | null)[]; + slots: SlotName[]; /** * Object mapping new slot name keys to deprecated slot name values * @example `pf-modal--header` is deprecated in favour of `header` @@ -32,9 +32,9 @@ export interface SlotsConfig { deprecations?: Record; } -function isObjectConfigSpread( - config: ([SlotsConfig] | (string | null)[]), -): config is [SlotsConfig] { +export type SlotControllerArgs = [SlotsConfig] | SlotName[]; + +export function isObjectSpread(config: SlotControllerArgs): config is [SlotsConfig] { return config.length === 1 && typeof config[0] === 'object' && config[0] !== null; } @@ -57,58 +57,92 @@ export class SlotController implements ReactiveController { #nodes = new Map(); - #logger: Logger; - - #firstUpdated = false; + #slotMapInitialized = false; - #mo = new MutationObserver(records => this.#onMutation(records)); - - #slotNames: (string | null)[]; + #slotNames: (string | null)[] = []; #deprecations: Record = {}; - constructor(public host: ReactiveElement, ...config: ([SlotsConfig] | (string | null)[])) { - this.#logger = new Logger(this.host); + #mo = new MutationObserver(this.#initSlotMap.bind(this)); - if (isObjectConfigSpread(config)) { + constructor(public host: ReactiveElement, ...args: SlotControllerArgs) { + this.#initialize(...args); + host.addController(this); + if (!this.#slotNames.length) { + this.#slotNames = [null]; + } + } + + #initialize(...config: SlotControllerArgs) { + if (isObjectSpread(config)) { const [{ slots, deprecations }] = config; this.#slotNames = slots; this.#deprecations = deprecations ?? {}; } else if (config.length >= 1) { this.#slotNames = config; this.#deprecations = {}; - } else { - this.#slotNames = [null]; } - - - host.addController(this); } async hostConnected(): Promise { - this.host.addEventListener('slotchange', this.#onSlotChange as EventListener); - this.#firstUpdated = false; this.#mo.observe(this.host, { childList: true }); // Map the defined slots into an object that is easier to query this.#nodes.clear(); - // Loop over the properties provided by the schema - this.#slotNames.forEach(this.#initSlot); - Object.values(this.#deprecations).forEach(this.#initSlot); - this.host.requestUpdate(); + this.#initSlotMap(); // insurance for framework integrations await this.host.updateComplete; this.host.requestUpdate(); } + hostDisconnected(): void { + this.#mo.disconnect(); + } + hostUpdated(): void { - if (!this.#firstUpdated) { - this.#slotNames.forEach(this.#initSlot); - this.#firstUpdated = true; + if (!this.#slotMapInitialized) { + this.#initSlotMap(); } } - hostDisconnected(): void { - this.#mo.disconnect(); + #initSlotMap() { + // Loop over the properties provided by the schema + for (const slotName of this.#slotNames + .concat(Object.values(this.#deprecations))) { + const slotId = slotName || SlotController.default; + const name = slotName ?? ''; + const elements = this.#getChildrenForSlot(slotId); + const slot = this.#getSlotElement(slotId); + const hasContent = + !isServer + && !!elements.length + || !!slot?.assignedNodes?.()?.filter(x => x.textContent?.trim()).length; + this.#nodes.set(slotId, { elements, name, hasContent, slot }); + } + this.host.requestUpdate(); + this.#slotMapInitialized = true; + } + + #getSlotElement(slotId: string | symbol) { + if (isServer) { + return null; + } else { + const selector = + slotId === SlotController.default ? 'slot:not([name])' : `slot[name="${slotId as string}"]`; + return this.host.shadowRoot?.querySelector?.(selector) ?? null; + } + } + + #getChildrenForSlot( + name: string | typeof SlotController.default, + ): T[] { + if (isServer) { + return []; + } else if (this.#nodes.has(name)) { + return (this.#nodes.get(name)!.slot?.assignedElements?.() ?? []) as T[]; + } else { + const children = Array.from(this.host.children) as T[]; + return children.filter(isSlot(name)); + } } /** @@ -143,19 +177,11 @@ export class SlotController implements ReactiveController { * @example this.hasSlotted('header'); */ hasSlotted(...names: (string | null | undefined)[]): boolean { - if (isServer) { - return this.host - .getAttribute('ssr-hint-has-slotted') - ?.split(',') - .map(name => name.trim()) - .some(name => names.includes(name === 'default' ? null : name)) ?? false; - } else { - const slotNames = Array.from(names, x => x == null ? SlotController.default : x); - if (!slotNames.length) { - slotNames.push(SlotController.default); - } - return slotNames.some(x => this.#nodes.get(x)?.hasContent ?? false); + const slotNames = Array.from(names, x => x == null ? SlotController.default : x); + if (!slotNames.length) { + slotNames.push(SlotController.default); } + return slotNames.some(x => this.#nodes.get(x)?.hasContent ?? false); } /** @@ -168,42 +194,4 @@ export class SlotController implements ReactiveController { isEmpty(...names: (string | null | undefined)[]): boolean { return !this.hasSlotted(...names); } - - #onSlotChange = (event: Event & { target: HTMLSlotElement }) => { - const slotName = event.target.name; - this.#initSlot(slotName); - this.host.requestUpdate(); - }; - - #onMutation = async (records: MutationRecord[]) => { - const changed = []; - for (const { addedNodes, removedNodes } of records) { - for (const node of [...addedNodes, ...removedNodes]) { - if (node instanceof HTMLElement && node.slot) { - this.#initSlot(node.slot); - changed.push(node.slot); - } - } - } - this.host.requestUpdate(); - }; - - #getChildrenForSlot( - name: string | typeof SlotController.default, - ): T[] { - const children = Array.from(this.host.children) as T[]; - return children.filter(isSlot(name)); - } - - #initSlot = (slotName: string | null) => { - const name = slotName || SlotController.default; - const elements = this.#nodes.get(name)?.slot?.assignedElements?.() - ?? this.#getChildrenForSlot(name); - const selector = slotName ? `slot[name="${slotName}"]` : 'slot:not([name])'; - const slot = this.host.shadowRoot?.querySelector?.(selector) ?? null; - const nodes = slot?.assignedNodes?.(); - const hasContent = !!elements.length || !!nodes?.filter(x => x.textContent?.trim()).length; - this.#nodes.set(name, { elements, name: slotName ?? '', hasContent, slot }); - this.#logger.debug(slotName, hasContent); - }; } diff --git a/core/pfe-core/functions/context.ts b/core/pfe-core/functions/context.ts index 2e109b6b2c..d3ebc1f0e4 100644 --- a/core/pfe-core/functions/context.ts +++ b/core/pfe-core/functions/context.ts @@ -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; } diff --git a/core/pfe-core/package.json b/core/pfe-core/package.json index 55fdb012d6..fb4aa7744d 100644 --- a/core/pfe-core/package.json +++ b/core/pfe-core/package.json @@ -32,7 +32,10 @@ "./controllers/property-observer-controller.js": "./controllers/property-observer-controller.js", "./controllers/roving-tabindex-controller.js": "./controllers/roving-tabindex-controller.js", "./controllers/scroll-spy-controller.js": "./controllers/scroll-spy-controller.js", - "./controllers/slot-controller.js": "./controllers/slot-controller.js", + "./controllers/slot-controller.js": { + "import": "./controllers/slot-controller.js", + "default": "./controllers/slot-controller.js" + }, "./controllers/style-controller.js": "./controllers/style-controller.js", "./controllers/timestamp-controller.js": "./controllers/timestamp-controller.js", "./controllers/tabs-controller.js": "./controllers/tabs-controller.js", @@ -62,8 +65,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", diff --git a/core/pfe-core/ssr-shims.ts b/core/pfe-core/ssr-shims.ts index 2fe31e6d6a..32d0168960 100644 --- a/core/pfe-core/ssr-shims.ts +++ b/core/pfe-core/ssr-shims.ts @@ -1,3 +1,5 @@ +import { installWindowOnGlobal } from '@lit-labs/ssr/lib/dom-shim.js'; + class ObserverShim { observe(): void { void 0; @@ -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 ''; @@ -52,7 +28,27 @@ globalThis.getComputedStyle ??= function() { return ''; }, }; -} +}; -; +// @ts-expect-error: opt in to event support in ssr +globalThis.litSsrCallConnectedCallback = true; +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; + } +}; diff --git a/elements/package.json b/elements/package.json index 4b159d1d9c..f82c073a11 100644 --- a/elements/package.json +++ b/elements/package.json @@ -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" } } diff --git a/elements/pf-back-to-top/pf-back-to-top.ts b/elements/pf-back-to-top/pf-back-to-top.ts index 7912dcd2eb..3d3da33ec9 100644 --- a/elements/pf-back-to-top/pf-back-to-top.ts +++ b/elements/pf-back-to-top/pf-back-to-top.ts @@ -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}`); diff --git a/elements/pf-clipboard-copy/pf-clipboard-copy.ts b/elements/pf-clipboard-copy/pf-clipboard-copy.ts index 6b69717f93..1dfbf823a7 100644 --- a/elements/pf-clipboard-copy/pf-clipboard-copy.ts +++ b/elements/pf-clipboard-copy/pf-clipboard-copy.ts @@ -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'; @@ -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(); + } } /** @@ -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('')); diff --git a/elements/pf-table/context.ts b/elements/pf-table/context.ts new file mode 100644 index 0000000000..d128980e17 --- /dev/null +++ b/elements/pf-table/context.ts @@ -0,0 +1,5 @@ +import { createContextWithRoot } from '@patternfly/pfe-core/functions/context.js'; + +export const thRoleContext: { + __context__: unknown; +} = createContextWithRoot<'rowheader' | 'colheader'>('pf-th-role'); diff --git a/elements/pf-table/pf-table.ts b/elements/pf-table/pf-table.ts index 4611daf11c..94034a1ee1 100644 --- a/elements/pf-table/pf-table.ts +++ b/elements/pf-table/pf-table.ts @@ -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'; @@ -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', @@ -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'); @@ -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(); } diff --git a/elements/pf-table/pf-th.ts b/elements/pf-table/pf-th.ts index ed95cee6ed..9effd562bf 100644 --- a/elements/pf-table/pf-th.ts +++ b/elements/pf-table/pf-th.ts @@ -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'; @@ -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> { diff --git a/elements/pf-table/pf-thead.ts b/elements/pf-table/pf-thead.ts index 35bc35c897..c46a51ccb4 100644 --- a/elements/pf-table/pf-thead.ts +++ b/elements/pf-table/pf-thead.ts @@ -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 @@ -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'); diff --git a/elements/pf-tabs/pf-tab.ts b/elements/pf-tabs/pf-tab.ts index 69c9b1ca71..601daa5e9d 100644 --- a/elements/pf-tabs/pf-tab.ts +++ b/elements/pf-tabs/pf-tab.ts @@ -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'; @@ -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; @@ -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`
diff --git a/elements/pf-tooltip/pf-tooltip.ts b/elements/pf-tooltip/pf-tooltip.ts index e97344d9a1..6bd4954c3a 100644 --- a/elements/pf-tooltip/pf-tooltip.ts +++ b/elements/pf-tooltip/pf-tooltip.ts @@ -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; diff --git a/package-lock.json b/package-lock.json index 196e03c708..033bc9e7ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,7 @@ "fuse.js": "^7.0.0", "husky": "^9.1.4", "leasot": "^14.4.0", - "lit": "^3.2.0", + "lit": "^3.2.1", "nunjucks": "^3.2.4", "postcss-nesting": "^13.0.0", "prompts": "^2.4.2", @@ -53,23 +53,23 @@ }, "core/pfe-core": { "name": "@patternfly/pfe-core", - "version": "4.0.1", + "version": "4.0.4", "license": "MIT", "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" } }, "elements": { "name": "@patternfly/elements", - "version": "4.0.1", + "version": "4.0.2", "license": "MIT", "dependencies": { "@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" } }, @@ -2795,13 +2795,13 @@ } }, "node_modules/@lit-labs/ssr": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@lit-labs/ssr/-/ssr-3.2.2.tgz", - "integrity": "sha512-He5TzeNPM9ECmVpgXRYmVlz0UA5YnzHlT43kyLi2Lu6mUidskqJVonk9W5K699+2DKhoXp8Ra4EJmHR6KrcW1Q==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr/-/ssr-3.3.0.tgz", + "integrity": "sha512-OGlPfWfJIC2CXQLuXXRtbWlgidryVI8VOEFUPc++Vk7gQ4aapAJwHJFi7Mi614ekebNLzhkpA/10IZy5g+nGcQ==", "peer": true, "dependencies": { "@lit-labs/ssr-client": "^1.1.7", - "@lit-labs/ssr-dom-shim": "^1.2.0", + "@lit-labs/ssr-dom-shim": "^1.3.0", "@lit/reactive-element": "^2.0.4", "@parse5/tools": "^0.3.0", "@types/node": "^16.0.0", @@ -2828,9 +2828,9 @@ } }, "node_modules/@lit-labs/ssr-dom-shim": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.1.tgz", - "integrity": "sha512-wx4aBmgeGvFmOKucFKY+8VFJSYZxs9poN3SDNQFF6lT6NrQUnHiPB2PWz2sc4ieEcAaYYzN+1uWahEeTq2aRIQ==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.3.0.tgz", + "integrity": "sha512-nQIWonJ6eFAvUUrSlwyHDm/aE8PBDu5kRpL0vHMg6K8fK3Diq1xdPjTnsJSwxABhaZ+5eBi1btQB5ShUTKo4nQ==" }, "node_modules/@lit-labs/ssr/node_modules/@types/node": { "version": "16.18.105", @@ -2839,9 +2839,10 @@ "peer": true }, "node_modules/@lit/context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.2.tgz", - "integrity": "sha512-S0nw2C6Tkm7fVX5TGYqeROGD+Z9Coa2iFpW+ysYBDH3YvCqOY3wVQvSgwbaliLJkjTnSEYCBe9qFqKV8WUFpVw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.3.tgz", + "integrity": "sha512-Auh37F4S0PZM93HTDfZWs97mmzaQ7M3vnTc9YvxAGyP3UItSK/8Fs0vTOGT+njuvOwbKio/l8Cx/zWL4vkutpQ==", + "license": "BSD-3-Clause", "dependencies": { "@lit/reactive-element": "^1.6.2 || ^2.0.0" } @@ -11441,9 +11442,10 @@ "peer": true }, "node_modules/lit": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.2.0.tgz", - "integrity": "sha512-s6tI33Lf6VpDu7u4YqsSX78D28bYQulM+VAzsGch4fx2H0eLZnJsUBsPWmGYSGoKDNbjtRv02rio1o+UdPVwvw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.2.1.tgz", + "integrity": "sha512-1BBa1E/z0O9ye5fZprPtdqnc0BFzxIxTTOO/tQFmyC/hj1O3jL4TfmLBw0WEwjAokdLwpclkvGgDJwTIh0/22w==", + "license": "BSD-3-Clause", "dependencies": { "@lit/reactive-element": "^2.0.4", "lit-element": "^4.1.0", @@ -17593,7 +17595,7 @@ }, "tools/pfe-tools": { "name": "@patternfly/pfe-tools", - "version": "3.0.1", + "version": "4.0.1", "license": "MIT", "devDependencies": { "@types/dedent": "^0.7.2", @@ -17611,14 +17613,14 @@ "node": ">=18" }, "peerDependencies": { - "@11ty/eleventy": "^2.0.1", + "@11ty/eleventy": "^2.0.1 || ^3.0.0", "@11ty/eleventy-plugin-directory-output": "^1.0.1", "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", "@changesets/cli": "^2.27.1", "@custom-elements-manifest/analyzer": "^0.5.7", "@jspm/generator": "^2.0.1", "@koa/router": "^12.0.1", - "@lit-labs/ssr": "^3.2.2", + "@lit-labs/ssr": "^3.3.0", "@open-wc/testing": "^4.0.0", "@playwright/test": "^1.44.0", "@rollup/plugin-replace": "^5.0.5", @@ -17648,7 +17650,7 @@ "eslint": "^9.0.0", "execa": "^9.3.0", "glob": "^10.3.12", - "lit": "^3.1.2", + "lit": "^3.2.1", "markdown-it-anchor": "^8.6.7", "nunjucks": "^3.2.4", "patch-package": "^8.0.0", diff --git a/package.json b/package.json index 6bf63797e6..4f6d8fee37 100644 --- a/package.json +++ b/package.json @@ -314,7 +314,7 @@ "fuse.js": "^7.0.0", "husky": "^9.1.4", "leasot": "^14.4.0", - "lit": "^3.2.0", + "lit": "^3.2.1", "nunjucks": "^3.2.4", "postcss-nesting": "^13.0.0", "prompts": "^2.4.2", diff --git a/tools/pfe-tools/package.json b/tools/pfe-tools/package.json index c8df6670bb..185ef125dd 100644 --- a/tools/pfe-tools/package.json +++ b/tools/pfe-tools/package.json @@ -70,7 +70,7 @@ "@custom-elements-manifest/analyzer": "^0.5.7", "@jspm/generator": "^2.0.1", "@koa/router": "^12.0.1", - "@lit-labs/ssr": "^3.2.2", + "@lit-labs/ssr": "^3.3.0", "@open-wc/testing": "^4.0.0", "@playwright/test": "^1.44.0", "@rollup/plugin-replace": "^5.0.5", @@ -100,7 +100,7 @@ "eslint": "^9.0.0", "execa": "^9.3.0", "glob": "^10.3.12", - "lit": "^3.1.2", + "lit": "^3.2.1", "markdown-it-anchor": "^8.6.7", "nunjucks": "^3.2.4", "patch-package": "^8.0.0", diff --git a/tools/pfe-tools/ssr/global.ts b/tools/pfe-tools/ssr/global.ts index 5209242b4f..eecb84a620 100644 --- a/tools/pfe-tools/ssr/global.ts +++ b/tools/pfe-tools/ssr/global.ts @@ -8,10 +8,10 @@ export async function renderGlobal( html: string, importSpecifiers: string[], ): Promise { - // avoid tsconfig problems - await import(['@patternfly', 'pfe-core', 'ssr-shims.js'].join('/')); + // hack to avoid circular typescript project reference + const spec = '@patternfly/pfe-core/ssr-shims.js'; + await import(spec); const { ssr } = await import('./ssr.js'); await Promise.all(importSpecifiers.map(x => import(x))); return ssr(html); } - diff --git a/tools/pfe-tools/ssr/ssr.ts b/tools/pfe-tools/ssr/ssr.ts index a7a956fbac..4239b6c0e8 100644 --- a/tools/pfe-tools/ssr/ssr.ts +++ b/tools/pfe-tools/ssr/ssr.ts @@ -1,9 +1,9 @@ -import { render } from '@lit-labs/ssr'; +import { render, html } from '@lit-labs/ssr'; import { collectResult } from '@lit-labs/ssr/lib/render-result.js'; -import { html } from 'lit'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; /** + * composes the `unsafeHTML`, `html`, `render`, and `collectResult` functions from lit ssr * @param input html partial */ export async function ssr(input: string): Promise {