Skip to content

Commit

Permalink
Merge branch 'master' into users/chhol/remove-hypertext-styles-from-b…
Browse files Browse the repository at this point in the history
…utton
  • Loading branch information
chrisdholt authored Jun 17, 2020
2 parents 6d4845e + 7317b41 commit 257908b
Show file tree
Hide file tree
Showing 26 changed files with 2,469 additions and 389 deletions.
52 changes: 52 additions & 0 deletions .github/workflows/cd-www-stage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: CD - FAST
on:
push:
branches:
- master

jobs:
build_deploy_linux:
runs-on: ubuntu-latest

env:
AZURE_WEBAPP_ACTIVE_STAGE_NAME: www-west-app
AZURE_WEBAPP_PASSIVE_STAGE_NAME: www-east-app
AZURE_WEBAPP_BUILD_PATH: sites/website
AZURE_WEBAPP_DIST_PATH: sites/website/static
AZURE_WEBAPP_SLOT_NAME: stage

steps:
- name: Checkout Branch
uses: actions/checkout@master

- name: Install Lerna
run: yarn global add lerna

- name: Install package dependencies / prepare workspaces
run: yarn install --frozen-lockfile

- name: Build & Prepare Web Application
run: |
cd ${{ env.AZURE_WEBAPP_BUILD_PATH }}
npm i
yarn build
cp ../site-utilities/statics/server/package.json ../site-utilities/statics/server/server.js static
cd static
npm i
ls -lta
- name: 'Deploy to Active Azure Region'
uses: azure/webapps-deploy@v2
with:
publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE_WWW_ACTIVE }}
app-name: ${{ env.AZURE_WEBAPP_ACTIVE_STAGE_NAME }}
package: ${{ env.AZURE_WEBAPP_DIST_PATH }}
slot-name: ${{ env.AZURE_WEBAPP_SLOT_NAME }}

- name: 'Deploy to Passive Azure Region'
uses: azure/webapps-deploy@v2
with:
publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE_WWW_PASSIVE }}
app-name: ${{ env.AZURE_WEBAPP_PASSIVE_STAGE_NAME }}
package: ${{ env.AZURE_WEBAPP_DIST_PATH }}
slot-name: ${{ env.AZURE_WEBAPP_SLOT_NAME }}
2 changes: 1 addition & 1 deletion packages/web-components/fast-element/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export function children<T = any>(propertyOrOptions: (keyof T & string) | Childr
//
// @public
export class ChildrenBehavior extends NodeObservationBehavior<ChildrenBehaviorOptions> {
constructor(target: HTMLSlotElement, options: ChildrenBehaviorOptions);
constructor(target: HTMLElement, options: ChildrenBehaviorOptions);
disconnect(): void;
protected getNodes(): ChildNode[];
observe(): void;
Expand Down
3 changes: 1 addition & 2 deletions packages/web-components/fast-element/docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

## Short-term

* **Feature**: Allow `repeat` to accept an expression that returns the template they generate from.
* **Feature**: Enable event delegation through a syntax like `@click.delegate=...`

## Medium-term

* **Experiment**: See if it's possible combine template instantiate and bind, and if that improves initial render time.
* **Feature**: Improve `when` to enable if/else scenarios.
* **Feature**: Dependency injection infrastructure, including simple decorator-based property injection for `FASTElement`.
* **Refactor:** Create abstraction for `ElementInternals`.
* **Test:** Include perf benchmarks in the automated build process and track changes over time.
Expand Down
139 changes: 139 additions & 0 deletions packages/web-components/fast-element/src/directives/children.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { expect } from "chai";
import { children, ChildrenBehavior } from "./children";
import { AttachedBehaviorDirective } from "./directive";
import { observable } from "../observation/observable";
import { elements } from "./node-observation";
import { DOM } from "../dom";

describe("The children", () => {
context("template function", () => {
it("returns an AttachedBehaviorDirective", () => {
const directive = children("test");
expect(directive).to.be.instanceOf(AttachedBehaviorDirective);
});
});

context("directive", () => {
it("creates a ChildrenBehavior", () => {
const directive = children("test") as AttachedBehaviorDirective;
const target = document.createElement("div");
const behavior = directive.createBehavior(target);

expect(behavior).to.be.instanceOf(ChildrenBehavior);
});
});

context("behavior", () => {
class Model {
@observable nodes;
}

function createAndAppendChildren(host: HTMLElement, elementName = "div") {
const children = new Array(10);

for (let i = 0, ii = children.length; i < ii; ++i) {
const child = document.createElement(i % 1 === 0 ? elementName : "div");
children[i] = child;
host.appendChild(child);
}

return children;
}

function createDOM(elementName: string = "div") {
const host = document.createElement("div");
const children = createAndAppendChildren(host, elementName);

return { host, children };
}

it("gathers child nodes", () => {
const { host, children } = createDOM();
const behavior = new ChildrenBehavior(host, {
property: "nodes",
childList: true,
});
const model = new Model();

behavior.bind(model);

expect(model.nodes).members(children);
});

it("gathers child nodes with a filter", () => {
const { host, children } = createDOM("foo-bar");
const behavior = new ChildrenBehavior(host, {
property: "nodes",
childList: true,
filter: elements("foo-bar"),
});
const model = new Model();

behavior.bind(model);

expect(model.nodes).members(children.filter(elements("foo-bar")));
});

it("updates child nodes when they change", async () => {
const { host, children } = createDOM("foo-bar");
const behavior = new ChildrenBehavior(host, {
property: "nodes",
childList: true,
});
const model = new Model();

behavior.bind(model);

expect(model.nodes).members(children);

const updatedChildren = children.concat(createAndAppendChildren(host));

await DOM.nextUpdate();

expect(model.nodes).members(updatedChildren);
});

it("updates child nodes when they change with a filter", async () => {
const { host, children } = createDOM("foo-bar");
const behavior = new ChildrenBehavior(host, {
property: "nodes",
childList: true,
filter: elements("foo-bar"),
});
const model = new Model();

behavior.bind(model);

expect(model.nodes).members(children);

const updatedChildren = children.concat(createAndAppendChildren(host));

await DOM.nextUpdate();

expect(model.nodes).members(updatedChildren.filter(elements("foo-bar")));
});

it("clears and unwatches when unbound", async () => {
const { host, children } = createDOM("foo-bar");
const behavior = new ChildrenBehavior(host, {
property: "nodes",
childList: true,
});
const model = new Model();

behavior.bind(model);

expect(model.nodes).members(children);

behavior.unbind();

expect(model.nodes).members([]);

host.appendChild(document.createElement("div"));

await DOM.nextUpdate();

expect(model.nodes).members([]);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class ChildrenBehavior extends NodeObservationBehavior<ChildrenBehaviorOp
* @param target - The element target to observe children on.
* @param options - The options to use when observing the element children.
*/
public constructor(target: HTMLSlotElement, options: ChildrenBehaviorOptions) {
public constructor(target: HTMLElement, options: ChildrenBehaviorOptions) {
super(target, options);
}

Expand Down Expand Up @@ -66,6 +66,8 @@ export function children<T = any>(
property: propertyOrOptions,
childList: true,
};
} else {
(propertyOrOptions as MutationObserverInit).childList = true;
}

return new AttachedBehaviorDirective(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,33 @@ export interface NodeBehaviorBehaviorOptions<T = any> {
* The property to assign the observed nodes to.
*/
property: T;

/**
* Filters nodes that are synced with the property.
* Called one time for each element in the array.
* @param value - The Node that is being inspected.
* @param index - The index of the node within the array.
* @param array - The Node array that is being filtered.
*/
filter?(value: Node, index: number, array: Node[]): boolean;
}

/**
* Filters an array of nodes to only elements.
* @param tagName - An optional tag name to restrict the filter to.
*/
export function elements(tagName?: string) {
if (tagName) {
tagName = tagName.toUpperCase();

return function (value: Node, index: number, array: Node[]): boolean {
return value.nodeType === 1 && (value as HTMLElement).tagName === tagName;
};
}

return function (value: Node, index: number, array: Node[]): boolean {
return value.nodeType === 1;
};
}

/**
Expand All @@ -27,7 +54,7 @@ export abstract class NodeObservationBehavior<T extends NodeBehaviorBehaviorOpti
* @param target - The target to assign the nodes property on.
* @param options - The options to use in configuring node observation.
*/
constructor(protected target: HTMLSlotElement, protected options: T) {}
constructor(protected target: HTMLElement, protected options: T) {}

/**
* Begins observation of the nodes.
Expand Down Expand Up @@ -55,7 +82,7 @@ export abstract class NodeObservationBehavior<T extends NodeBehaviorBehaviorOpti
(x: Accessor) => x.name === name
);
this.source = source;
this.updateTarget(this.getNodes());
this.updateTarget(this.computeNodes());

if (this.shouldUpdate) {
this.observe();
Expand All @@ -77,7 +104,17 @@ export abstract class NodeObservationBehavior<T extends NodeBehaviorBehaviorOpti

/** @internal */
public handleEvent(): void {
this.updateTarget(this.getNodes());
this.updateTarget(this.computeNodes());
}

private computeNodes() {
let nodes = this.getNodes();

if (this.options.filter !== void 0) {
nodes = nodes.filter(this.options.filter!);
}

return nodes;
}

private updateTarget(value: ReadonlyArray<any>): void {
Expand Down
Loading

0 comments on commit 257908b

Please sign in to comment.