Skip to content

Commit 344cc2b

Browse files
authored
feat: make tree and tree-item SSR compatible (microsoft#35091)
1 parent 6fdc5fa commit 344cc2b

11 files changed

+68
-32
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "feat: make tree and tree-item SSR compatible",
4+
"packageName": "@fluentui/web-components",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

packages/web-components/docs/web-components.api.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4349,9 +4349,13 @@ export const TooltipTemplate: ViewTemplate<Tooltip, any>;
43494349
// @public
43504350
export class Tree extends BaseTree {
43514351
appearance: TreeItemAppearance;
4352+
// (undocumented)
4353+
protected appearanceChanged(): void;
43524354
// @internal
43534355
childTreeItemsChanged(): void;
43544356
size: TreeItemSize;
4357+
// (undocumented)
4358+
protected sizeChanged(): void;
43554359
updateSizeAndAppearance(): void;
43564360
}
43574361

@@ -4364,8 +4368,12 @@ export const TreeDefinition: FASTElementDefinition<typeof Tree>;
43644368
export class TreeItem extends BaseTreeItem {
43654369
appearance: TreeItemAppearance;
43664370
// @internal
4371+
protected appearanceChanged(): void;
4372+
// @internal
43674373
childTreeItemsChanged(): void;
43684374
size: TreeItemSize;
4375+
// @internal
4376+
protected sizeChanged(): void;
43694377
updateSizeAndAppearance(): void;
43704378
}
43714379

packages/web-components/src/tree-item/tree-item.base.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export class BaseTreeItem extends FASTElement {
5858
* @internal
5959
*/
6060
protected selectedChanged(prev: boolean, next: boolean): void {
61+
this.updateTabindexBySelected();
6162
this.$emit('change');
6263
toggleState(this.elementInternals, 'selected', next);
6364
this.elementInternals.ariaSelected = next ? 'true' : 'false';
@@ -81,7 +82,7 @@ export class BaseTreeItem extends FASTElement {
8182
@attr({ attribute: 'data-indent' })
8283
public dataIndent!: number | undefined;
8384

84-
private dataIndentChanged(prev: number, next: number) {
85+
protected dataIndentChanged(prev: number, next: number) {
8586
if (this.styles !== undefined) {
8687
this.$fastController.removeStyles(this.styles);
8788
}
@@ -108,6 +109,11 @@ export class BaseTreeItem extends FASTElement {
108109
this.updateChildTreeItems();
109110
}
110111

112+
connectedCallback() {
113+
super.connectedCallback();
114+
this.updateTabindexBySelected();
115+
}
116+
111117
/**
112118
* Updates the childrens indent
113119
*
@@ -154,4 +160,10 @@ export class BaseTreeItem extends FASTElement {
154160
get isNestedItem() {
155161
return isTreeItem(this.parentElement);
156162
}
163+
164+
protected updateTabindexBySelected() {
165+
if (this.$fastController.isConnected) {
166+
this.tabIndex = this.selected ? 0 : -1;
167+
}
168+
}
157169
}

packages/web-components/src/tree-item/tree-item.styles.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ export const styles = css`
9494
transform: rotate(180deg);
9595
}
9696
97+
.chevron svg {
98+
inline-size: 12px;
99+
block-size: 12px;
100+
}
101+
97102
.aside {
98103
display: flex;
99104
align-items: center;
Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,20 @@
1-
import { children, html } from '@microsoft/fast-element';
1+
import { elements, html, slotted } from '@microsoft/fast-element';
2+
import { FluentDesignSystem } from '../fluent-design-system.js';
23
import type { TreeItem } from './tree-item.js';
3-
import { isTreeItem } from './tree-item.options.js';
44

55
const chevronIcon = html`
6-
<svg width="12" height="12" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
6+
<svg viewBox="0 0 12 12" fill="currentColor">
77
<path
88
d="M4.65 2.15a.5.5 0 000 .7L7.79 6 4.65 9.15a.5.5 0 10.7.7l3.5-3.5a.5.5 0 000-.7l-3.5-3.5a.5.5 0 00-.7 0z"
99
></path>
1010
</svg>
1111
`;
1212

1313
export const template = html<TreeItem>`
14-
<template
15-
tabindex="${x => (x.selected ? 0 : -1)}"
16-
slot="${x => (x.isNestedItem ? 'item' : void 0)}"
17-
${children({
18-
property: 'childTreeItems',
19-
filter: node => isTreeItem(node),
20-
})}
21-
>
14+
<template slot="${x => (x.isNestedItem ? 'item' : void 0)}">
2215
<div class="positioning-region" part="positioning-region">
2316
<div class="content" part="content">
24-
<span class="chevron" part="chevron">
17+
<span class="chevron" part="chevron" aria-hidden="true">
2518
<slot name="chevron">${chevronIcon}</slot>
2619
</span>
2720
<slot name="start"></slot>
@@ -33,7 +26,13 @@ export const template = html<TreeItem>`
3326
</div>
3427
</div>
3528
<div role="group" class="items" part="items">
36-
<slot name="item"></slot>
29+
<slot
30+
name="item"
31+
${slotted({
32+
property: 'childTreeItems',
33+
filter: elements(`${FluentDesignSystem.prefix}-tree-item`),
34+
})}
35+
></slot>
3736
</div>
3837
</template>
3938
`;

packages/web-components/src/tree-item/tree-item.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { attr } from '@microsoft/fast-element';
2-
import { TreeItemAppearance, TreeItemSize } from './tree-item.options.js';
32
import { BaseTreeItem } from './tree-item.base.js';
3+
import { TreeItemAppearance, TreeItemSize } from './tree-item.options.js';
44

55
/**
66
* The Fluent Tree Item Element. Implements {@link @microsoft/fast-foundation#BaseTreeItem}.
@@ -21,7 +21,7 @@ export class TreeItem extends BaseTreeItem {
2121
* we update the child tree items' size based on the size
2222
* @internal
2323
*/
24-
private sizeChanged() {
24+
protected sizeChanged() {
2525
this.updateSizeAndAppearance();
2626
}
2727

@@ -37,7 +37,7 @@ export class TreeItem extends BaseTreeItem {
3737
*
3838
* @internal
3939
*/
40-
private appearanceChanged() {
40+
protected appearanceChanged() {
4141
this.updateSizeAndAppearance();
4242
}
4343

packages/web-components/src/tree/tree.base.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import {
1010
keyHome,
1111
keySpace,
1212
} from '@microsoft/fast-web-utilities';
13+
import type { BaseTreeItem } from '../tree-item/tree-item.base';
1314
import { isTreeItem } from '../tree-item/tree-item.options';
14-
import { BaseTreeItem } from '../tree-item/tree-item.base';
1515

1616
export class BaseTree extends FASTElement {
1717
/**
@@ -146,6 +146,9 @@ export class BaseTree extends FASTElement {
146146

147147
if (e.target === this) {
148148
this.currentFocused = this.getValidFocusableItem();
149+
if (this.currentFocused && this.currentFocused.tabIndex < 0) {
150+
this.currentFocused.tabIndex = 0;
151+
}
149152
this.currentFocused?.focus();
150153

151154
return;

packages/web-components/src/tree/tree.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ test.describe('Tree', () => {
212212
const treeItem1 = element.locator('fluent-tree-item').nth(0);
213213
expect(await treeItem1.getAttribute('selected')).toBeNull();
214214

215-
await treeItem1.focus();
215+
await element.focus();
216216
expect(await elementHandle).toBe(false);
217217
await page.keyboard.press('Space');
218218

packages/web-components/src/tree/tree.styles.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { css } from '@microsoft/fast-element';
2-
import { display } from '../utils/display';
2+
import { display } from '../utils/display.js';
33

44
export const styles = css`
55
${display('block')}
6+
67
:host {
78
outline: none;
89
}
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { children, elements, html } from '@microsoft/fast-element';
2-
import { isTreeItem } from '../tree-item/tree-item.options.js';
1+
import { elements, html, slotted } from '@microsoft/fast-element';
2+
import { FluentDesignSystem } from '../fluent-design-system.js';
33
import type { Tree } from './tree.js';
44

55
export const template = html<Tree>`
@@ -10,11 +10,12 @@ export const template = html<Tree>`
1010
@focusout="${(x, c) => x.blurHandler(c.event as FocusEvent)}"
1111
@keydown="${(x, c) => x.keydownHandler(c.event as KeyboardEvent)}"
1212
@change="${(x, c) => x.changeHandler(c.event)}"
13-
${children({
14-
property: 'childTreeItems',
15-
filter: node => isTreeItem(node),
16-
})}
1713
>
18-
<slot></slot>
14+
<slot
15+
${slotted({
16+
property: 'childTreeItems',
17+
filter: elements(`${FluentDesignSystem.prefix}-tree-item`),
18+
})}
19+
></slot>
1920
</template>
2021
`;

0 commit comments

Comments
 (0)