Skip to content

Commit

Permalink
feat: update divider to use element internals (#31627)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisdholt authored Jun 10, 2024
1 parent e796341 commit 32e259d
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "feat: update divider to leverage ElementInternals",
"packageName": "@fluentui/web-components",
"email": "[email protected]",
"dependentChangeType": "patch"
}
11 changes: 10 additions & 1 deletion packages/web-components/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -1888,14 +1888,23 @@ export function display(displayValue: CSSDisplayPropertyValue): string;
//
// @public
export class Divider extends FASTElement {
constructor();
// (undocumented)
alignContent?: DividerAlignContent;
// (undocumented)
appearance?: DividerAppearance;
// (undocumented)
connectedCallback(): void;
// @internal
elementInternals: ElementInternals;
// (undocumented)
inset?: boolean;
orientation: DividerOrientation;
orientation?: DividerOrientation;
// @internal
orientationChanged(previous: string | null, next: string | null): void;
role: DividerRole;
// @internal
roleChanged(previous: string | null, next: string | null): void;
}

// @public
Expand Down
16 changes: 8 additions & 8 deletions packages/web-components/src/divider/divider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ test.describe('Divider', () => {
`;
});

await expect(element).toHaveAttribute('role', 'separator');
await expect(element).toHaveJSProperty('elementInternals.role', 'separator');
});

test('should set the `role` attribute equal to the role provided', async () => {
Expand All @@ -39,13 +39,13 @@ test.describe('Divider', () => {
`;
});

await expect(element).toHaveAttribute('role', 'presentation');
await expect(element).toHaveJSProperty('elementInternals.role', 'presentation');

await element.evaluate((node: Divider) => {
node.role = 'separator';
});

await expect(element).toHaveAttribute('role', 'separator');
await expect(element).toHaveJSProperty('elementInternals.role', 'separator');
});

test('should set the `aria-orientation` attribute equal to the `orientation` value', async () => {
Expand All @@ -55,13 +55,13 @@ test.describe('Divider', () => {
`;
});

await expect(element).toHaveAttribute('aria-orientation', 'vertical');
await expect(element).toHaveJSProperty('elementInternals.ariaOrientation', 'vertical');

await element.evaluate((node: Divider) => {
node.orientation = 'horizontal';
});

await expect(element).toHaveAttribute('aria-orientation', 'horizontal');
await expect(element).toHaveJSProperty('elementInternals.ariaOrientation', 'horizontal');
});

test('should NOT set the `aria-orientation` property equal to `orientation` value if the `role` is presentational', async () => {
Expand All @@ -71,14 +71,14 @@ test.describe('Divider', () => {
`;
});

await expect(element).toHaveAttribute('aria-orientation', 'vertical');
await expect(element).toHaveJSProperty('elementInternals.ariaOrientation', 'vertical');

await element.evaluate((node: Divider) => {
node.role = 'presentation';
});

await expect(element).not.toHaveJSProperty('aria-orientation', 'vertical');
await expect(element).not.toHaveJSProperty('aria-orientation', 'horizontal');
await expect(element).not.toHaveJSProperty('elementInternals.ariaOrientation', 'vertical');
await expect(element).not.toHaveJSProperty('elementInternals.ariaOrientation', 'horizontal');
});

test('should initialize to the provided value attribute if set post-connection', async () => {
Expand Down
1 change: 0 additions & 1 deletion packages/web-components/src/divider/divider.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export default {
content: 'Section One',
alignContent: undefined,
appearance: undefined,
role: DividerRole.separator,
inset: false,
orientation: undefined,
},
Expand Down
10 changes: 1 addition & 9 deletions packages/web-components/src/divider/divider.template.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { ElementViewTemplate, html } from '@microsoft/fast-element';
import type { Divider } from './divider.js';
import { DividerRole } from './divider.options.js';

export function dividerTemplate<T extends Divider>(): ElementViewTemplate<T> {
return html<T>`
<template
role="${x => x.role}"
aria-orientation="${x => (x.role !== DividerRole.presentation ? x.orientation : void 0)}"
>
<slot></slot>
</template>
`;
return html<T>`<slot></slot>`;
}

/**
Expand Down
51 changes: 49 additions & 2 deletions packages/web-components/src/divider/divider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import { DividerAlignContent, DividerAppearance, DividerOrientation, DividerRole
* A divider groups sections of content to create visual rhythm and hierarchy. Use dividers along with spacing and headers to organize content in your layout.
*/
export class Divider extends FASTElement {
/**
* The internal {@link https://developer.mozilla.org/docs/Web/API/ElementInternals | `ElementInternals`} instance for the component.
*
* @internal
*/
public elementInternals: ElementInternals = this.attachInternals();

/**
* The role of the element.
*
Expand All @@ -16,7 +23,7 @@ export class Divider extends FASTElement {
* HTML Attribute: role
*/
@attr
public role: DividerRole = DividerRole.separator;
public role!: DividerRole;

/**
* The orientation of the divider.
Expand All @@ -26,7 +33,7 @@ export class Divider extends FASTElement {
* HTML Attribute: orientation
*/
@attr
public orientation: DividerOrientation = DividerOrientation.horizontal;
public orientation?: DividerOrientation;

/**
* @public
Expand All @@ -51,4 +58,44 @@ export class Divider extends FASTElement {
*/
@attr({ mode: 'boolean' })
public inset?: boolean;

public connectedCallback(): void {
super.connectedCallback();

this.elementInternals.role = this.role ?? DividerRole.separator;

if (this.role !== DividerRole.presentation) {
this.elementInternals.ariaOrientation = this.orientation ?? DividerOrientation.horizontal;
}
}

/**
* Sets the element's internal role when the role attribute changes.
*
* @param previous - the previous role value
* @param next - the current role value
* @internal
*/
public roleChanged(previous: string | null, next: string | null): void {
if (this.$fastController.isConnected) {
this.elementInternals.role = `${next ?? DividerRole.separator}`;
}

if (next === DividerRole.presentation) {
this.elementInternals.ariaOrientation = null;
}
}

/**
* Sets the element's internal orientation when the orientation attribute changes.
*
* @param previous - the previous orientation value
* @param next - the current orientation value
* @internal
*/
public orientationChanged(previous: string | null, next: string | null): void {
if (this.$fastController.isConnected) {
this.elementInternals.ariaOrientation = this.role !== DividerRole.presentation ? next : null;
}
}
}

0 comments on commit 32e259d

Please sign in to comment.