Skip to content

Commit

Permalink
Merge branch 'master' into users/scomea/empty-no-options
Browse files Browse the repository at this point in the history
  • Loading branch information
Stephane Comeau authored Aug 8, 2023
2 parents f3892e1 + 50dba9c commit ee98166
Show file tree
Hide file tree
Showing 18 changed files with 203 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Adds volatile binding support for JavaScript optional chaining syntax",
"packageName": "@microsoft/fast-element",
"email": "[email protected]",
"dependentChangeType": "prerelease"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Prevent notification of array splices when operation does not mutate array values",
"packageName": "@microsoft/fast-element",
"email": "[email protected]",
"dependentChangeType": "prerelease"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "fix: toolbar should not throw if start or end is undefined",
"packageName": "@microsoft/fast-foundation",
"email": "[email protected]",
"dependentChangeType": "prerelease"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Prevent keyboard navigation to hidden tab",
"packageName": "@microsoft/fast-foundation",
"email": "[email protected]",
"dependentChangeType": "prerelease"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Removed the 'applyMixins' function from exported features.",
"packageName": "@microsoft/fast-foundation",
"email": "[email protected]",
"dependentChangeType": "prerelease"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "fix: add aria-orientation to divider only when role equals separator",
"packageName": "@microsoft/fast-foundation",
"email": "[email protected]",
"dependentChangeType": "prerelease"
}
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,25 @@ describe("The ArrayObserver", () => {

expect(wasCalled).to.be.false;
})

it("should not deliver splices for .splice() when .splice() does not change the items in the array", async () => {
ArrayObserver.enable();
const array = [1,2,3,4,5];
const observer = Observable.getNotifier(array);
let splices;

observer.subscribe({
handleChange(source, args) {
splices = args
}
});

array.splice(0, array.length, ...array);

await Updates.next();

expect(splices.length).to.equal(0);
})
});

describe("The array length observer", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ let defaultSpliceStrategy: SpliceStrategy = Object.freeze({
if (changes === void 0) {
return emptyArray;
}
return changes.length > 1 ? project(current, changes) : changes;
return project(current, changes);
}

return resetSplices;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from "chai";
import { Updates } from "./update-queue.js";
import { PropertyChangeNotifier, SubscriberSet } from "./notifier.js";
import { ExecutionContext, Observable, observable, volatile } from "./observable.js";
import { ExecutionContext, Expression, Observable, observable, volatile } from "./observable.js";
import { Fake } from "../testing/fakes.js";

describe("The Observable", () => {
Expand Down Expand Up @@ -627,4 +627,34 @@ describe("The Observable", () => {
expect(model.child2ChangedCalled).to.be.true;
});
});

context("isVolatileBinding", () => {
it("should return true when expression uses ternary operator", () => {
const expression = (a) => a !== undefined ? a : undefined;

expect(Observable.isVolatileBinding(expression)).to.equal(true)
});
it("should return true when expression uses 'if' condition", () => {
const expression = (a) => { if (a !== undefined) { return a }};

expect(Observable.isVolatileBinding(expression)).to.equal(true)
});
it("should return true when expression uses '&&' operator", () => {
const expression = (a) => { a && true};

expect(Observable.isVolatileBinding(expression)).to.equal(true)
});
it("should return true when expression uses '||' operator", () => {
const expression = (a) => { a || true};

expect(Observable.isVolatileBinding(expression)).to.equal(true)
});
it("should return true when when expression uses JavaScript optional chaining", () => {
// Avoid TS Compiling Optional property syntax away into ternary
// by using Function constructor
const expression = Function("(a) => a?.b") as Expression;

expect(Observable.isVolatileBinding(expression)).to.equal(true)
})
})
});
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export interface ExpressionNotifier<TSource = any, TReturn = any, TParent = any>
*/
export const Observable = FAST.getById(KernelServiceId.observable, () => {
const queueUpdate = Updates.enqueue;
const volatileRegex = /(:|&&|\|\||if)/;
const volatileRegex = /(:|&&|\|\||if|\?\.)/;
const notifierLookup = new WeakMap<any, Notifier>();
let watcher: ExpressionNotifierImplementation | undefined = void 0;
let createArrayObserver = (array: any[]): Notifier => {
Expand Down
3 changes: 0 additions & 3 deletions packages/web-components/fast-foundation/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ export type AnchorTarget = ValuesOf<typeof AnchorTarget>;
// @public
export function anchorTemplate<T extends FASTAnchor>(options?: AnchorOptions): ViewTemplate<T>;

// @public
export function applyMixins(derivedCtor: any, ...baseCtors: any[]): void;

// @public
export class ARIAGlobalStatesAndProperties {
ariaAtomic: "true" | "false" | string | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,30 @@ test.describe("Divider", () => {
DividerOrientation.horizontal
);
});

test("should NOT set the `aria-orientation` attribute equal to the `orientation` value if the `role` is presentational", async () => {
await root.evaluate(node => {
node.innerHTML = /* html */ `
<fast-divider orientation="vertical"></fast-divider>
`;
});

await expect(element).toHaveAttribute(
"aria-orientation",
DividerOrientation.vertical
);

await element.evaluate((node: FASTDivider, DividerRole) => {
node.role = DividerRole.presentation;
}, DividerRole);

await expect(element).not.toHaveAttribute(
"aria-orientation",
DividerOrientation.horizontal
);
await expect(element).not.toHaveAttribute(
"aria-orientation",
DividerOrientation.vertical
);
});
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { ElementViewTemplate, html } from "@microsoft/fast-element";
import type { FASTDivider } from "./divider.js";
import { DividerRole } from "./divider.options.js";

/**
* The template for the {@link @microsoft/fast-foundation#FASTDivider} component.
* @public
*/
export function dividerTemplate<T extends FASTDivider>(): ElementViewTemplate<T> {
return html<T>`
<template role="${x => x.role}" aria-orientation="${x => x.orientation}">
<template
role="${x => x.role}"
aria-orientation="${x =>
x.role !== DividerRole.presentation ? x.orientation : void 0}"
>
<slot></slot>
</template>
`;
Expand Down
66 changes: 66 additions & 0 deletions packages/web-components/fast-foundation/src/tabs/tabs.pw.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,4 +386,70 @@ test.describe("Tabs", () => {

await expect(element).toHaveJSProperty("activeid", secondTabId);
});

test("should not allow selecting hidden tab using arrow keys", async () => {
test.slow();

await root.evaluate(node => {
node.innerHTML = /* html */ `
<fast-tabs>
<fast-tab>Tab one</fast-tab>
<fast-tab hidden>Tab two</fast-tab>
<fast-tab>Tab three</fast-tab>
<fast-tab-panel>Tab panel one</fast-tab-panel>
<fast-tab-panel>Tab panel two</fast-tab-panel>
<fast-tab-panel>Tab panel three</fast-tab-panel>
</fast-tabs>
`;
});

const firstTab = tabs.nth(0);

const thirdTab = tabs.nth(2);

const firstTabId = (await firstTab.getAttribute("id")) ?? "";

const thirdTabId = (await thirdTab.getAttribute("id")) ?? "";

await element.evaluate((node: FASTTabs, firstTabId) => {
node.activeid = firstTabId;
}, firstTabId);

await firstTab.press("ArrowRight");

await expect(element).toHaveJSProperty("activeid", thirdTabId);
});

test("should not allow selecting hidden tab by pressing End", async () => {
test.slow();

await root.evaluate(node => {
node.innerHTML = /* html */ `
<fast-tabs>
<fast-tab>Tab one</fast-tab>
<fast-tab>Tab two</fast-tab>
<fast-tab hidden>Tab three</fast-tab>
<fast-tab-panel>Tab panel one</fast-tab-panel>
<fast-tab-panel>Tab panel two</fast-tab-panel>
<fast-tab-panel>Tab panel three</fast-tab-panel>
</fast-tabs>
`;
});

const firstTab = tabs.nth(0);

const secondTab = tabs.nth(1);

const firstTabId = (await firstTab.getAttribute("id")) ?? "";

const secondTabId = (await secondTab.getAttribute("id")) ?? "";

await element.evaluate((node: FASTTabs, firstTabId) => {
node.activeid = firstTabId;
}, firstTabId);

await firstTab.press("End");

await expect(element).toHaveJSProperty("activeid", secondTabId);
});
});
8 changes: 6 additions & 2 deletions packages/web-components/fast-foundation/src/tabs/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,12 @@ export class FASTTabs extends FASTElement {
return el.getAttribute("aria-disabled") === "true";
};

private isHiddenElement = (el: Element): el is HTMLElement => {
return el.hasAttribute("hidden");
};

private isFocusableElement = (el: Element): el is HTMLElement => {
return !this.isDisabledElement(el);
return !this.isDisabledElement(el) && !this.isHiddenElement(el);
};

private getActiveIndex(): number {
Expand Down Expand Up @@ -272,7 +276,7 @@ export class FASTTabs extends FASTElement {
* This method allows the active index to be adjusted by numerical increments
*/
public adjust(adjustment: number): void {
const focusableTabs = this.tabs.filter(t => !this.isDisabledElement(t));
const focusableTabs = this.tabs.filter(t => this.isFocusableElement(t));
const currentActiveTabIndex = focusableTabs.indexOf(this.activetab);

const nextTabIndex = limit(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,10 @@ export class FASTToolbar extends FASTElement {
* @internal
*/
protected get allSlottedItems(): (HTMLElement | Node)[] {
return [
...this.start.assignedElements(),
...this.slottedItems,
...this.end.assignedElements(),
];
const start = this.start?.assignedElements() ?? [];
const end = this.end?.assignedElements() ?? [];

return [...start, ...this.slottedItems, ...end];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { AttributeConfiguration } from "@microsoft/fast-element";
/**
* Apply mixins to a constructor.
* Sourced from {@link https://www.typescriptlang.org/docs/handbook/mixins.html | TypeScript Documentation }.
* @public
* @internal
*/
export function applyMixins(derivedCtor: any, ...baseCtors: any[]) {
const derivedAttributes = AttributeConfiguration.locate(derivedCtor);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./apply-mixins.js";
export * from "./direction.js";
export * from "./match-media-stylesheet-behavior.js";
export * from "./property-stylesheet-behavior.js";
Expand Down

0 comments on commit ee98166

Please sign in to comment.