diff --git a/BREAKING.md b/BREAKING.md index 1f94825f3a91..56a457f08b3b 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -4,6 +4,7 @@ - [Remove back-compat support for loader <= 0.8](#remove-back-compat-support-for-loader-0.8) - [New Error types](#New-Error-types) - [`IComponentContext` - `createSubComponent` removed, `createComponent` signature updated](#`IComponentContext`---`createSubComponent`-removed,-`createComponent`-signature-updated) +- [Changes to the render interfaces](#Changes-to-the-render-interfaces) ## Samples and chaincode have been renamed to examples and components respectively The directories themselves have been renamed. @@ -35,6 +36,13 @@ It does not acccept a package path anymore but just a package name. To pass in p For creating a component with a specific package path, use `createComponent` or `_createComponentWithProps` in `IHostRuntime`. +## Changes to the render interfaces + +The rendering interfaces have undergone several changes: +- `IComponentHTMLRender` has been removed. `IComponentHTMLView` now has a `render()` member, and `IComponentHTMLVisual` does not. If your component renders, it should probably be an `IComponentHTMLView`. +- Since `IComponentHTMLVisual` now only has the member `addView()`, it is mandatory. If your component does not already implement `addView`, it should not be an `IComponentHTMLVisual`. +- On `IComponentHTMLView`, `remove()` is now optional. If your view component needs to perform cleanup when removed from the DOM, do it in `remove()` - otherwise there is no need to implement it. +- `IComponentHTMLView` now extends the new `IProvideComponentHTMLView`, so you can query for whether a component is a view. You must implement the `IComponentHTMLView` member if you implement the interface. # 0.13 Breaking Changes diff --git a/examples/components/badge/src/Badge.tsx b/examples/components/badge/src/Badge.tsx index 694730220f46..cf930577bb18 100644 --- a/examples/components/badge/src/Badge.tsx +++ b/examples/components/badge/src/Badge.tsx @@ -6,7 +6,10 @@ import { PrimedComponent } from "@microsoft/fluid-aqueduct"; import { IComponentReactViewable } from "@microsoft/fluid-aqueduct-react"; import { SharedCell } from "@microsoft/fluid-cell"; -import { IComponentHandle, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { + IComponentHandle, + IComponentHTMLView, +} from "@microsoft/fluid-component-core-interfaces"; import { SharedMap } from "@microsoft/fluid-map"; import { SharedObjectSequence } from "@microsoft/fluid-sequence"; // eslint-disable-next-line import/no-internal-modules @@ -17,13 +20,14 @@ import { IBadgeType } from "./IBadgeType"; import { BadgeView } from "./BadgeView"; import { IHistory } from "./IHistory"; -export class Badge extends PrimedComponent implements IComponentHTMLVisual, IComponentReactViewable { +export class Badge extends PrimedComponent implements + IComponentHTMLView, + IComponentReactViewable { currentCell: SharedCell; optionsMap: SharedMap; historySequence: SharedObjectSequence>; - public get IComponentHTMLVisual() { return this; } - public get IComponentHTMLRender() { return this; } + public get IComponentHTMLView() { return this; } public get IComponentReactViewable() { return this; } private readonly currentId: string = "value"; diff --git a/examples/components/chat/src/index.ts b/examples/components/chat/src/index.ts index db38a65ad125..0308db258f48 100644 --- a/examples/components/chat/src/index.ts +++ b/examples/components/chat/src/index.ts @@ -3,15 +3,14 @@ * Licensed under the MIT License. */ -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { IContainerContext } from "@microsoft/fluid-container-definitions"; import { renderChat } from "./chat"; // eslint-disable-next-line import/no-internal-modules import { Runtime } from "./runtime/runtime"; -export class ChatRunner implements IComponentHTMLVisual { - - public get IComponentHTMLVisual() { return this; } +export class ChatRunner implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } constructor(private readonly runtime: Runtime) { } diff --git a/examples/components/codemirror/src/codemirror.ts b/examples/components/codemirror/src/codemirror.ts index eb9a1eac5476..f5c203d97911 100644 --- a/examples/components/codemirror/src/codemirror.ts +++ b/examples/components/codemirror/src/codemirror.ts @@ -51,6 +51,8 @@ class CodemirrorView implements IComponentHTMLView { private sequenceDeltaCb: any; + public get IComponentHTMLView() { return this; } + constructor(private readonly text: SharedString, private readonly runtime: IComponentRuntime) { } @@ -211,8 +213,6 @@ export class CodeMirrorComponent private text: SharedString; private root: ISharedMap; - private defaultView: CodemirrorView; - constructor( private readonly runtime: IComponentRuntime, /* Private */ context: IComponentContext, @@ -251,14 +251,6 @@ export class CodeMirrorComponent public addView(scope: IComponent): IComponentHTMLView { return new CodemirrorView(this.text, this.runtime); } - - public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { - if (!this.defaultView) { - this.defaultView = new CodemirrorView(this.text, this.runtime); - } - - this.defaultView.render(elm, options); - } } class SmdeFactory implements IComponentFactory { diff --git a/examples/components/draft-js/src/index.tsx b/examples/components/draft-js/src/index.tsx index 82fe43d88f91..f16418f141cf 100644 --- a/examples/components/draft-js/src/index.tsx +++ b/examples/components/draft-js/src/index.tsx @@ -8,7 +8,7 @@ import { PrimedComponentFactory, SimpleModuleInstantiationFactory, } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { SharedMap } from "@microsoft/fluid-map"; import { SharedString } from "@microsoft/fluid-sequence"; @@ -22,8 +22,8 @@ import { MemberList } from "./MemberList"; const pkg = require("../package.json"); export const DraftJsName = pkg.name as string; -export class DraftJsExample extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class DraftJsExample extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } /** * Do setup work here diff --git a/examples/components/drawer/src/drawer.ts b/examples/components/drawer/src/drawer.ts index 19e5e5691f49..dc4a03e592fe 100644 --- a/examples/components/drawer/src/drawer.ts +++ b/examples/components/drawer/src/drawer.ts @@ -9,7 +9,6 @@ import { IComponentRouter, IRequest, IResponse, - IComponentHTMLOptions, IComponentHTMLVisual, IComponent, IComponentHTMLView, @@ -25,7 +24,10 @@ import { initializeIcons } from "@uifabric/icons"; import * as semver from "semver"; import { DrawerView } from "./drawerView"; -export class Drawer extends EventEmitter implements IComponentLoadable, IComponentRouter, IComponentHTMLVisual { +export class Drawer extends EventEmitter implements + IComponentLoadable, + IComponentRouter, + IComponentHTMLVisual { public static async load(runtime: IComponentRuntime, context: IComponentContext) { const collection = new Drawer(runtime, context); await collection.initialize(); @@ -120,10 +122,6 @@ export class Drawer extends EventEmitter implements IComponentLoadable, ICompone return view; } - - public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { - throw new Error("Just addView please"); - } } class DrawerFactory implements IComponentFactory { diff --git a/examples/components/drawer/src/drawerView.tsx b/examples/components/drawer/src/drawerView.tsx index b04abf2ee526..7aa8d85c4fb1 100644 --- a/examples/components/drawer/src/drawerView.tsx +++ b/examples/components/drawer/src/drawerView.tsx @@ -31,6 +31,8 @@ export class DrawerView implements IComponentHTMLView { private packages: { pkg: string; name: string; version: string; icon: string }[] = []; private elm: HTMLElement; + public get IComponentHTMLView() { return this; } + constructor( private readonly documentsFactory: IDocumentFactory, private readonly documentsMap: ISharedMap, diff --git a/examples/components/github-comment/src/main.tsx b/examples/components/github-comment/src/main.tsx index 6ab47e946133..26d2d48f17dc 100644 --- a/examples/components/github-comment/src/main.tsx +++ b/examples/components/github-comment/src/main.tsx @@ -8,9 +8,8 @@ import { PrimedComponentFactory, } from "@microsoft/fluid-aqueduct"; import { - IComponentHTMLVisual, + IComponentHTMLView, IComponentHandle, - IComponentHTMLRender, } from "@microsoft/fluid-component-core-interfaces"; import { IComponentContext, @@ -35,11 +34,8 @@ const divHTML = require("./styles/github-comment-only.html"); /* eslint-enable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires, import/no-internal-modules, import/no-unassigned-import */ -export class GithubComment - extends TextareaNoReact - implements IComponentHTMLVisual, IComponentHTMLRender { - public get IComponentHTMLVisual() { return this; } - public get IComponentHTMLRender() { return this; } +export class GithubComment extends TextareaNoReact implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } /** * Extension of the parent class function that also forces the innerHTML of diff --git a/examples/components/image-gallery/src/index.tsx b/examples/components/image-gallery/src/index.tsx index 78cda61b5b3e..1927474b8baf 100644 --- a/examples/components/image-gallery/src/index.tsx +++ b/examples/components/image-gallery/src/index.tsx @@ -4,7 +4,7 @@ */ import { PrimedComponent, PrimedComponentFactory, SimpleModuleInstantiationFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import * as React from "react"; import * as ReactDOM from "react-dom"; import ImageGallery from "react-image-gallery"; @@ -14,8 +14,8 @@ import "react-image-gallery/styles/css/image-gallery.css"; import "./Styles.css"; import { ISharedMap } from "@microsoft/fluid-map"; -export class ImageGalleryComponent extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class ImageGalleryComponent extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } imageList = [ { diff --git a/examples/components/musica/src/index.tsx b/examples/components/musica/src/index.tsx index f259aefc606a..3713bbfa2438 100644 --- a/examples/components/musica/src/index.tsx +++ b/examples/components/musica/src/index.tsx @@ -5,7 +5,7 @@ // Fluid import { PrimedComponent, PrimedComponentFactory, SimpleModuleInstantiationFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; // React import * as React from "react"; @@ -19,8 +19,8 @@ import { DAW } from "./daw"; // TODO: Is this right? const audioContext = new AudioContext(); -export class Musica extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class Musica extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } protected async componentHasInitialized() { this.player = new Player(audioContext); diff --git a/examples/components/persona/src/persona.ts b/examples/components/persona/src/persona.ts index 8c36ee84aa43..b5b7dfc74d93 100644 --- a/examples/components/persona/src/persona.ts +++ b/examples/components/persona/src/persona.ts @@ -9,7 +9,6 @@ import { IComponentRouter, IRequest, IResponse, - IComponentHTMLOptions, IComponentHTMLVisual, IComponent, IComponentHTMLView, @@ -22,7 +21,10 @@ import { ISharedObjectFactory } from "@microsoft/fluid-shared-object-base"; import { initializeIcons } from "@uifabric/icons"; import { PersonaView } from "./personaView"; -export class Persona extends EventEmitter implements IComponentLoadable, IComponentRouter, IComponentHTMLVisual { +export class Persona extends EventEmitter implements + IComponentLoadable, + IComponentRouter, + IComponentHTMLVisual { public static async load(runtime: IComponentRuntime, context: IComponentContext) { const collection = new Persona(runtime, context); await collection.initialize(); @@ -106,10 +108,6 @@ export class Persona extends EventEmitter implements IComponentLoadable, ICompon return view; } - - public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { - throw new Error("Just addView please"); - } } class PersonaFactory implements IComponentFactory { diff --git a/examples/components/persona/src/personaView.tsx b/examples/components/persona/src/personaView.tsx index 52ef4922d7f5..310ad450fb88 100644 --- a/examples/components/persona/src/personaView.tsx +++ b/examples/components/persona/src/personaView.tsx @@ -43,6 +43,8 @@ export class PersonaReactComponent extends React.Component void) { } diff --git a/examples/components/pollster/src/index.tsx b/examples/components/pollster/src/index.tsx index 38348fe4f0d9..2288e4cfd752 100644 --- a/examples/components/pollster/src/index.tsx +++ b/examples/components/pollster/src/index.tsx @@ -4,7 +4,7 @@ */ import { PrimedComponent, PrimedComponentFactory, SimpleModuleInstantiationFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual, IComponentHandle } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView, IComponentHandle } from "@microsoft/fluid-component-core-interfaces"; import { ISharedMap, SharedMap } from "@microsoft/fluid-map"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -16,8 +16,8 @@ import { Poll } from "./view/Poll"; const pkg = require("../package.json"); const chaincodeName = pkg.name; -export class Pollster extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class Pollster extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } protected async componentInitializingFirstTime() { this.root.set(pollOptionsMapKey, SharedMap.create(this.runtime).handle); diff --git a/examples/components/prosemirror/src/componentView.ts b/examples/components/prosemirror/src/componentView.ts index e452f034b9e9..1a78f2fb24d3 100644 --- a/examples/components/prosemirror/src/componentView.ts +++ b/examples/components/prosemirror/src/componentView.ts @@ -6,13 +6,13 @@ import { Node } from "prosemirror-model"; import { EditorView, NodeView } from "prosemirror-view"; import { ILoader } from "@microsoft/fluid-container-definitions"; -import { IComponent, IComponentHTMLRender, IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; +import { IComponent, IComponentHTMLView, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; export class ComponentView implements NodeView { public dom: HTMLElement; public innerView; - private renderable: IComponentHTMLView | IComponentHTMLRender; + private visual: IComponentHTMLView | IComponentHTMLVisual; constructor( public node: Node, @@ -64,7 +64,7 @@ export class ComponentView implements NodeView { } const component = result.value as IComponent; - if (!component.IComponentHTMLVisual) { + if (!component.IComponentHTMLView && !component.IComponentHTMLVisual) { return Promise.reject(); } @@ -77,13 +77,22 @@ export class ComponentView implements NodeView { this.dom.innerHTML = ""; // Remove the previous view - if (this.renderable && "remove" in this.renderable) { - this.renderable.remove(); + if (this.visual && "remove" in this.visual) { + this.visual.remove(); } - const visual = component.IComponentHTMLVisual; - this.renderable = visual.addView ? visual.addView() : visual; - this.renderable.render(this.dom); + // First try to get it as a view + this.visual = component.IComponentHTMLView; + if (!this.visual) { + // Otherwise get the visual, which is a view factory + const visual = component.IComponentHTMLVisual; + if (visual) { + this.visual = visual.addView(); + } + } + if (this.visual) { + this.visual.render(this.dom); + } }, (error) => { // Fall back to URL if can't load diff --git a/examples/components/prosemirror/src/prosemirror.ts b/examples/components/prosemirror/src/prosemirror.ts index d2ef8677db6b..2130e8e82ef1 100644 --- a/examples/components/prosemirror/src/prosemirror.ts +++ b/examples/components/prosemirror/src/prosemirror.ts @@ -65,6 +65,8 @@ class ProseMirrorView implements IComponentHTMLView { private textArea: HTMLDivElement; private readonly collabManager: FluidCollabManager; + public get IComponentHTMLView() { return this; } + public constructor( private readonly text: SharedString, private readonly runtime: IComponentRuntime, @@ -118,7 +120,6 @@ export class ProseMirror extends EventEmitter public text: SharedString; private root: ISharedMap; private collabManager: FluidCollabManager; - private defaultView: ProseMirrorView; constructor( private readonly runtime: IComponentRuntime, @@ -163,14 +164,6 @@ export class ProseMirror extends EventEmitter public addView(): IComponentHTMLView { return new ProseMirrorView(this.text, this.runtime); } - - public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { - if (!this.defaultView) { - this.defaultView = new ProseMirrorView(this.text, this.runtime); - } - - this.defaultView.render(elm, options); - } } class ProseMirrorFactory implements IComponentFactory { diff --git a/examples/components/simple-component-embed/src/index.tsx b/examples/components/simple-component-embed/src/index.tsx index 9f1f2d868003..2bd46b00024a 100644 --- a/examples/components/simple-component-embed/src/index.tsx +++ b/examples/components/simple-component-embed/src/index.tsx @@ -4,11 +4,11 @@ */ import { PrimedComponent, PrimedComponentFactory, SimpleModuleInstantiationFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { ClickerInstantiationFactory, Clicker } from "@fluid-example/clicker"; -export class SimpleComponentEmbed extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class SimpleComponentEmbed extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } private clicker: Clicker; diff --git a/examples/components/simple-data-share/src/index.tsx b/examples/components/simple-data-share/src/index.tsx index e8e7dc89ec28..0e64952e9e33 100644 --- a/examples/components/simple-data-share/src/index.tsx +++ b/examples/components/simple-data-share/src/index.tsx @@ -4,7 +4,7 @@ */ import { PrimedComponent, PrimedComponentFactory, SimpleModuleInstantiationFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { Counter, CounterValueType } from "@microsoft/fluid-map"; // Import our local components @@ -33,8 +33,8 @@ const chaincodeName = pkg.name; * There is also a Incrementor component which runs in the background and randomly increments the count value every 5 * seconds. */ -export class SimpleDataSharing extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class SimpleDataSharing extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } // Id should be unique identifiers private readonly buttonId = "button-12345"; diff --git a/examples/components/simple-data-share/src/localChaincode/Button.tsx b/examples/components/simple-data-share/src/localChaincode/Button.tsx index 5fab9fe23257..49a1e768d3fa 100644 --- a/examples/components/simple-data-share/src/localChaincode/Button.tsx +++ b/examples/components/simple-data-share/src/localChaincode/Button.tsx @@ -4,7 +4,7 @@ */ import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { Counter } from "@microsoft/fluid-map"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -16,8 +16,8 @@ const chaincodeName = pkg.name; /** * Button does not display any content but modifies the counter count on the button click. */ -export class Button extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class Button extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } public static readonly chaincodeName = `${chaincodeName}/button`; public counter: Counter; diff --git a/examples/components/simple-data-share/src/localChaincode/TextDisplay.tsx b/examples/components/simple-data-share/src/localChaincode/TextDisplay.tsx index 91159520f299..8dfc4eeb4b90 100644 --- a/examples/components/simple-data-share/src/localChaincode/TextDisplay.tsx +++ b/examples/components/simple-data-share/src/localChaincode/TextDisplay.tsx @@ -4,7 +4,7 @@ */ import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { Counter } from "@microsoft/fluid-map"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -17,8 +17,8 @@ const chaincodeName = pkg.name; * The TextDisplay does not directly manage or modify content. * It simply takes in a counter, subscribes and displays changes to that counter. */ -export class TextDisplay extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class TextDisplay extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } public static readonly chaincodeName = `${chaincodeName}/textDisplay`; public counter: Counter; diff --git a/examples/components/smde/src/smde.ts b/examples/components/smde/src/smde.ts index 987acaf8d05f..7b984d8c4154 100644 --- a/examples/components/smde/src/smde.ts +++ b/examples/components/smde/src/smde.ts @@ -11,7 +11,7 @@ import { IRequest, IResponse, IComponentHTMLOptions, - IComponentHTMLVisual, + IComponentHTMLView, IComponentHandle, } from "@microsoft/fluid-component-core-interfaces"; import { ComponentRuntime } from "@microsoft/fluid-component-runtime"; @@ -32,7 +32,10 @@ import { Viewer } from "./marked"; // eslint-disable-next-line import/no-internal-modules, import/no-unassigned-import import "simplemde/dist/simplemde.min.css"; -export class Smde extends EventEmitter implements IComponentLoadable, IComponentRouter, IComponentHTMLVisual { +export class Smde extends EventEmitter implements + IComponentLoadable, + IComponentRouter, + IComponentHTMLView { public static async load(runtime: IComponentRuntime, context: IComponentContext) { const collection = new Smde(runtime, context); await collection.initialize(); @@ -42,7 +45,7 @@ export class Smde extends EventEmitter implements IComponentLoadable, IComponent public get IComponentLoadable() { return this; } public get IComponentRouter() { return this; } - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public url: string; private root: ISharedMap; diff --git a/examples/components/spaces/src/components/button.tsx b/examples/components/spaces/src/components/button.tsx index 840613ba3e83..3e4c91e45aa1 100644 --- a/examples/components/spaces/src/components/button.tsx +++ b/examples/components/spaces/src/components/button.tsx @@ -8,7 +8,7 @@ import { PrimedComponentFactory, } from "@microsoft/fluid-aqueduct"; import { - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import * as React from "react"; @@ -39,9 +39,8 @@ export const ButtonName = "button"; /** * Clicker example using view interfaces and stock component classes. */ -export class Button extends PrimedComponent implements IComponentHTMLVisual { - - public get IComponentHTMLVisual() { return this; } +export class Button extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } private static readonly factory = new PrimedComponentFactory(Button, []); diff --git a/examples/components/spaces/src/components/componentToolbar.tsx b/examples/components/spaces/src/components/componentToolbar.tsx index 6376247d289d..659de51135da 100644 --- a/examples/components/spaces/src/components/componentToolbar.tsx +++ b/examples/components/spaces/src/components/componentToolbar.tsx @@ -8,7 +8,7 @@ import { PrimedComponentFactory, } from "@microsoft/fluid-aqueduct"; import { - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import * as React from "react"; @@ -23,9 +23,8 @@ export const ComponentToolbarName = "componentToolbar"; /** * A component to allow you to add and manipulate components */ -export class ComponentToolbar extends PrimedComponent implements IComponentHTMLVisual { - - public get IComponentHTMLVisual() { return this; } +export class ComponentToolbar extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } private static readonly factory = new PrimedComponentFactory(ComponentToolbar, []); diff --git a/examples/components/spaces/src/components/facePile.tsx b/examples/components/spaces/src/components/facePile.tsx index 0c5a127b31bd..3d4bc707d7a3 100644 --- a/examples/components/spaces/src/components/facePile.tsx +++ b/examples/components/spaces/src/components/facePile.tsx @@ -7,7 +7,7 @@ import { PrimedComponent, PrimedComponentFactory, } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { Persona, PersonaSize } from "office-ui-fabric-react/lib/Persona"; import { Icon } from "office-ui-fabric-react/lib/Icon"; @@ -15,9 +15,8 @@ import * as React from "react"; import * as ReactDOM from "react-dom"; import { IQuorum } from "@microsoft/fluid-protocol-definitions"; -export class FacePile extends PrimedComponent implements IComponentHTMLVisual { - - public get IComponentHTMLVisual() { return this; } +export class FacePile extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } private static readonly factory = new PrimedComponentFactory(FacePile, []); diff --git a/examples/components/spaces/src/components/number.tsx b/examples/components/spaces/src/components/number.tsx index f8a9b660f9b4..1b9783acc952 100644 --- a/examples/components/spaces/src/components/number.tsx +++ b/examples/components/spaces/src/components/number.tsx @@ -8,7 +8,7 @@ import { PrimedComponentFactory, } from "@microsoft/fluid-aqueduct"; import { - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import { CounterValueType, Counter } from "@microsoft/fluid-map"; @@ -21,9 +21,8 @@ export const NumberName = "number"; /** * Number clicker example using view interfaces and stock component classes. */ -export class Number extends PrimedComponent implements IComponentHTMLVisual { - - public get IComponentHTMLVisual() { return this; } +export class Number extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } private static readonly factory = new PrimedComponentFactory(Number, []); diff --git a/examples/components/spaces/src/components/textBox.tsx b/examples/components/spaces/src/components/textBox.tsx index 7915ef3647f3..24ef13f7e8e9 100644 --- a/examples/components/spaces/src/components/textBox.tsx +++ b/examples/components/spaces/src/components/textBox.tsx @@ -12,7 +12,7 @@ import { } from "@microsoft/fluid-aqueduct-react"; import { IComponentHandle, - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import { SharedString } from "@microsoft/fluid-sequence"; import * as React from "react"; @@ -24,16 +24,9 @@ export const TextBoxName = `textbox`; * TextBox is a really simple component that uses the CollaborativeTextArea to provide a * collaborative textarea. */ -export class TextBox extends PrimedComponent - implements IComponentHTMLVisual, IComponentReactViewable { - - public get IComponentHTMLVisual() { - return this; - } - - public get IComponentReactViewable() { - return this; - } +export class TextBox extends PrimedComponent implements IComponentHTMLView, IComponentReactViewable { + public get IComponentHTMLView() { return this; } + public get IComponentReactViewable() { return this; } private static readonly factory = new PrimedComponentFactory( TextBox, @@ -69,13 +62,13 @@ export class TextBox extends PrimedComponent .get(); } - // start IComponentHTMLVisual + // start IComponentHTMLView public render(div: HTMLElement) { ReactDOM.render(this.createJSXElement(), div); } - // end IComponentHTMLVisual + // end IComponentHTMLView // start IComponentReactViewable diff --git a/examples/components/spaces/src/spaces.tsx b/examples/components/spaces/src/spaces.tsx index 8c32c8e02a95..cbcd8c33f066 100644 --- a/examples/components/spaces/src/spaces.tsx +++ b/examples/components/spaces/src/spaces.tsx @@ -8,7 +8,7 @@ import { PrimedComponentFactory, } from "@microsoft/fluid-aqueduct"; import { - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import * as React from "react"; @@ -22,7 +22,7 @@ import { ComponentToolbar, ComponentToolbarName } from "./components"; /** * Spaces is the Fluid */ -export class Spaces extends PrimedComponent implements IComponentHTMLVisual { +export class Spaces extends PrimedComponent implements IComponentHTMLView { private dataModelInternal: ISpacesDataModel | undefined; private componentToolbar: ComponentToolbar | undefined; private static readonly componentToolbarId = "spaces-component-toolbar"; @@ -43,7 +43,7 @@ export class Spaces extends PrimedComponent implements IComponentHTMLVisual { return this.dataModelInternal; } - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } protected async componentInitializingFirstTime(props?: any) { this.root.createSubDirectory("component-list"); diff --git a/examples/components/sudoku/src/fluidSudoku.tsx b/examples/components/sudoku/src/fluidSudoku.tsx index be5e05ecafb8..1a860086339d 100644 --- a/examples/components/sudoku/src/fluidSudoku.tsx +++ b/examples/components/sudoku/src/fluidSudoku.tsx @@ -5,7 +5,7 @@ import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; import { IComponentReactViewable } from "@microsoft/fluid-aqueduct-react"; -import { IComponentHandle, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHandle, IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { ISharedMap, SharedMap } from "@microsoft/fluid-map"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -21,8 +21,8 @@ export const FluidSudokuName = "FluidSudoku"; * A collaborative Sudoku component built on the Fluid Framework. */ export class FluidSudoku extends PrimedComponent - implements IComponentHTMLVisual, IComponentReactViewable { - public get IComponentHTMLVisual() { + implements IComponentHTMLView, IComponentReactViewable { + public get IComponentHTMLView() { return this; } diff --git a/examples/components/textarea-noreact/src/main.tsx b/examples/components/textarea-noreact/src/main.tsx index 2c6bf898983e..32c44265bdfd 100644 --- a/examples/components/textarea-noreact/src/main.tsx +++ b/examples/components/textarea-noreact/src/main.tsx @@ -16,9 +16,8 @@ import { PrimedComponentFactory, } from "@microsoft/fluid-aqueduct"; import { - IComponentHTMLVisual, + IComponentHTMLView, IComponentHandle, - IComponentHTMLRender, } from "@microsoft/fluid-component-core-interfaces"; import { IComponentContext, @@ -47,11 +46,8 @@ interface ITextareaState { * allow collaborative editing. Heavily based on Skyler Jokiel's React-infused * CollaborativeTextArea in `packages/framework/aqueductreact`. */ -export class TextareaNoReact - extends PrimedComponent - implements IComponentHTMLVisual, IComponentHTMLRender { - public get IComponentHTMLVisual() { return this; } - public get IComponentHTMLRender() { return this; } +export class TextareaNoReact extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } protected textareaState: ITextareaState; protected textareaRootKey: string; diff --git a/examples/components/tourofheroes/src/index.ts b/examples/components/tourofheroes/src/index.ts index 02b0a75d2783..d2e8f9f9b3c6 100644 --- a/examples/components/tourofheroes/src/index.ts +++ b/examples/components/tourofheroes/src/index.ts @@ -8,7 +8,7 @@ import { APP_BASE_HREF } from "@angular/common"; import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; import { IContainerContext, IRuntime, IRuntimeFactory } from "@microsoft/fluid-container-definitions"; -import { IComponentHTMLVisual, IRequest } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView, IRequest } from "@microsoft/fluid-component-core-interfaces"; import { ContainerRuntime } from "@microsoft/fluid-container-runtime"; import { ISharedDirectory } from "@microsoft/fluid-map"; import { @@ -24,9 +24,8 @@ import { AppModule } from "./app/app.module"; import { PRAGUE_PATH, PRAGUE_ROOT } from "./app/tokens"; import { GraphQLService } from "./app/hero.service"; -export class TourOfHeroes extends PrimedComponent implements IComponentHTMLVisual { - - public get IComponentHTMLVisual() { return this; } +export class TourOfHeroes extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } public get root(): ISharedDirectory { return super.root; @@ -77,8 +76,8 @@ export class TourOfHeroes extends PrimedComponent implements IComponentHTMLVisua } } -class TourOfHeroesComponentView implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +class TourOfHeroesComponentView implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } public get id() { return this.path; @@ -110,8 +109,8 @@ class TourOfHeroesComponentView implements IComponentHTMLVisual { // Note on defining components - snapshotting does not seem like it should be part of an IChaincodeComponent given // these synthetic components don't need it. We may want this to just be "attach" -class GraphIQLView implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +class GraphIQLView implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } public readonly id = "graphiql"; diff --git a/examples/components/type-race/src/main.tsx b/examples/components/type-race/src/main.tsx index 85a587bdac0e..9442c6b4b0f6 100644 --- a/examples/components/type-race/src/main.tsx +++ b/examples/components/type-race/src/main.tsx @@ -8,7 +8,7 @@ import { PrimedComponentFactory, } from "@microsoft/fluid-aqueduct"; import { - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import { SharedMap, @@ -25,8 +25,8 @@ const style = require("./style.css"); /** * Clicker example using view interfaces and stock component classes. */ -export class TypeRace extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class TypeRace extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } private readonly textGenerator = new TextGenerator(); private username: string; diff --git a/examples/components/vltava/src/components/tabs/tabs.tsx b/examples/components/vltava/src/components/tabs/tabs.tsx index 2bfbd8cd9232..88fccbaec183 100644 --- a/examples/components/vltava/src/components/tabs/tabs.tsx +++ b/examples/components/vltava/src/components/tabs/tabs.tsx @@ -3,8 +3,8 @@ * Licensed under the MIT License. */ -import { IComponentHTMLVisual, IComponent } from "@microsoft/fluid-component-core-interfaces"; import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; +import { IComponent, IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -12,7 +12,7 @@ import * as ReactDOM from "react-dom"; import { TabsDataModel, ITabsDataModel } from "./dataModel"; import { TabsView } from "./view"; -export class TabsComponent extends PrimedComponent implements IComponentHTMLVisual { +export class TabsComponent extends PrimedComponent implements IComponentHTMLView { private dataModelInternal: ITabsDataModel | undefined; private static readonly factory = new PrimedComponentFactory(TabsComponent, []); @@ -29,7 +29,7 @@ export class TabsComponent extends PrimedComponent implements IComponentHTMLVisu return this.dataModelInternal; } - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } protected async componentInitializingFirstTime(props: any) { // create the tabs directory diff --git a/examples/components/vltava/src/components/vltava/vltava.tsx b/examples/components/vltava/src/components/vltava/vltava.tsx index 0bd9dabbaeb4..19bfd9056a73 100644 --- a/examples/components/vltava/src/components/vltava/vltava.tsx +++ b/examples/components/vltava/src/components/vltava/vltava.tsx @@ -3,8 +3,8 @@ * Licensed under the MIT License. */ -import { IComponent, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; +import { IComponent, IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -16,7 +16,7 @@ import { VltavaView } from "./view"; /** * Vltava is an application experience */ -export class Vltava extends PrimedComponent implements IComponentHTMLVisual { +export class Vltava extends PrimedComponent implements IComponentHTMLView { private dataModelInternal: IVltavaDataModel | undefined; private static readonly factory = new PrimedComponentFactory(Vltava, []); @@ -33,7 +33,7 @@ export class Vltava extends PrimedComponent implements IComponentHTMLVisual { return this.dataModelInternal; } - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } protected async componentInitializingFirstTime(props: any) { const tabsComponent = await this.createAndAttachComponent(uuid(), "tabs"); diff --git a/examples/experiments/collab-compose/src/taskpane/taskpane.ts b/examples/experiments/collab-compose/src/taskpane/taskpane.ts index 64a6f88af919..1933bf2189fa 100644 --- a/examples/experiments/collab-compose/src/taskpane/taskpane.ts +++ b/examples/experiments/collab-compose/src/taskpane/taskpane.ts @@ -119,12 +119,20 @@ async function attach(loader: ILoader, url: string, div: HTMLDivElement) { return; } + // Check if the component is viewable const component = response.value as IComponent; - const viewable = component.IComponentHTMLVisual; - - const renderable = viewable.addView ? viewable.addView() : viewable; - - renderable.render(div, { display: "block" }); + // First try to get it as a view + let renderable = component.IComponentHTMLView; + if (!renderable) { + // Otherwise get the visual, which is a view factory + const visual = component.IComponentHTMLVisual; + if (visual) { + renderable = visual.addView(); + } + } + if (renderable) { + renderable.render(div, { display: "block" }); + } const editor = (component as any).IRichTextEditor; diff --git a/examples/experiments/collab-slide/src/taskpane/taskpane.ts b/examples/experiments/collab-slide/src/taskpane/taskpane.ts index 99b21ea782a6..dbed53cb9d9d 100644 --- a/examples/experiments/collab-slide/src/taskpane/taskpane.ts +++ b/examples/experiments/collab-slide/src/taskpane/taskpane.ts @@ -113,12 +113,20 @@ async function attach(loader: ILoader, url: string, div: HTMLDivElement) { return; } + // Check if the component is viewable const component = response.value as IComponent; - const viewable = component.IComponentHTMLVisual; - - const renderable = viewable.addView ? viewable.addView() : viewable; - - renderable.render(div, { display: "block" }); + // First try to get it as a view + let renderable = component.IComponentHTMLView; + if (!renderable) { + // Otherwise get the visual, which is a view factory + const visual = component.IComponentHTMLVisual; + if (visual) { + renderable = visual.addView(); + } + } + if (renderable) { + renderable.render(div, { display: "block" }); + } const editor = (component as any).IRichTextEditor; diff --git a/examples/hosts/literate/src/utils.ts b/examples/hosts/literate/src/utils.ts index 9790d9cdc896..1109da6f3834 100644 --- a/examples/hosts/literate/src/utils.ts +++ b/examples/hosts/literate/src/utils.ts @@ -45,13 +45,18 @@ async function attachCore(loader: Loader, url: string, div: HTMLDivElement) { // Check if the component is viewable const component = response.value as IComponent; - const viewable = component.IComponentHTMLVisual; - if (!viewable) { - return; + // First try to get it as a view + let renderable = component.IComponentHTMLView; + if (!renderable) { + // Otherwise get the visual, which is a view factory + const visual = component.IComponentHTMLVisual; + if (visual) { + renderable = visual.addView(); + } + } + if (renderable) { + renderable.render(div, { display: "block" }); } - - const renderable = viewable.addView ? viewable.addView() : viewable; - renderable.render(div, { display: "block" }); } /** diff --git a/packages/agents/flow-intel-viewer/src/index.ts b/packages/agents/flow-intel-viewer/src/index.ts index 28c98e5fc295..395d88926d56 100644 --- a/packages/agents/flow-intel-viewer/src/index.ts +++ b/packages/agents/flow-intel-viewer/src/index.ts @@ -3,20 +3,16 @@ * Licensed under the MIT License. */ -import { IComponent, IComponentHTMLView, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { ISharedMap } from "@microsoft/fluid-map"; -export class FlowIntelViewer implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class FlowIntelViewer implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } private insightFound = false; constructor(private readonly insights: ISharedMap) { } - public addView(scope?: IComponent): IComponentHTMLView { - return new FlowIntelViewer(this.insights); - } - public remove(): void { } diff --git a/packages/components/canvas/src/canvas.ts b/packages/components/canvas/src/canvas.ts index 2249d4e53379..40876c778003 100644 --- a/packages/components/canvas/src/canvas.ts +++ b/packages/components/canvas/src/canvas.ts @@ -7,7 +7,7 @@ import { PrimedComponent } from "@microsoft/fluid-aqueduct"; import { IComponentHandle, IComponentHTMLOptions, - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import { IColor, IInk, Ink, InkCanvas } from "@microsoft/fluid-ink"; // eslint-disable-next-line import/no-unassigned-import @@ -27,8 +27,8 @@ const colorPickerColors: IColor[] = [ { r: 0, g: 0, b: 0, a: 1 }, ]; -export class Canvas extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class Canvas extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } private ink: IInk; private inkCanvas: InkCanvas; diff --git a/packages/components/clicker/src/index.tsx b/packages/components/clicker/src/index.tsx index c66c98e92478..fc874e703f4b 100644 --- a/packages/components/clicker/src/index.tsx +++ b/packages/components/clicker/src/index.tsx @@ -4,7 +4,7 @@ */ import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { Counter, CounterValueType } from "@microsoft/fluid-map"; import { ITask } from "@microsoft/fluid-runtime-definitions"; import * as React from "react"; @@ -18,9 +18,8 @@ export const ClickerName = pkg.name as string; /** * Basic Clicker example using new interfaces and stock component classes. */ -export class Clicker extends PrimedComponent implements IComponentHTMLVisual { - - public get IComponentHTMLVisual() { return this; } +export class Clicker extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } /** * Do setup work here @@ -37,7 +36,7 @@ export class Clicker extends PrimedComponent implements IComponentHTMLVisual { this.setupAgent(); } - // #region IComponentHTMLVisual + // #region IComponentHTMLView /** * Will return a new Clicker view @@ -52,6 +51,8 @@ export class Clicker extends PrimedComponent implements IComponentHTMLVisual { return div; } + // #endregion IComponentHTMLView + public setupAgent() { const counter: Counter = this.root.get("clicks"); const agentTask: ITask = { @@ -65,8 +66,6 @@ export class Clicker extends PrimedComponent implements IComponentHTMLVisual { console.log(err); }); } - - // #endregion IComponentHTMLVisual } // ----- REACT STUFF ----- diff --git a/packages/components/client-ui-lib/src/controls/flowView.ts b/packages/components/client-ui-lib/src/controls/flowView.ts index 841ab12e95f2..7bf729149bb6 100644 --- a/packages/components/client-ui-lib/src/controls/flowView.ts +++ b/packages/components/client-ui-lib/src/controls/flowView.ts @@ -8,7 +8,7 @@ import * as api from "@fluid-internal/client-api"; import { IComponent, IComponentHandle, - IComponentHTMLVisual, + IComponentHTMLView, IComponentLoadable, } from "@microsoft/fluid-component-core-interfaces"; import { IGenericBlob } from "@microsoft/fluid-container-definitions"; @@ -56,13 +56,13 @@ function getComponentBlock(marker: MergeTree.Marker): IBlockViewMarker { } interface IBlockViewMarker extends MergeTree.Marker { - instanceP?: Promise; - instance?: IComponentHTMLVisual & IComponent; + instanceP?: Promise; + instance?: IComponentHTMLView & IComponent; } interface IComponentViewMarker extends MergeTree.Marker { - instanceP?: Promise; - instance?: IComponentHTMLVisual; + instanceP?: Promise; + instance?: IComponentHTMLView; } interface IMathCollection { @@ -77,10 +77,9 @@ interface IMathOptions { display: string; } -export interface IMathInstance extends IComponentLoadable, IComponentHTMLVisual, IComponentCursor, +export interface IMathInstance extends IComponentLoadable, IComponentHTMLView, IComponentCursor, IComponentKeyHandlers, IComponentLayout, SearchMenu.ISearchMenuClient { IComponentLoadable: IComponentLoadable; - IComponentHTMLVisual: IComponentHTMLVisual; IComponentCursor: IComponentCursor; IComponentKeyHandlers: IComponentKeyHandlers; IComponentLayout: IComponentLayout; @@ -823,7 +822,7 @@ function renderSegmentIntoLine( } const component = response.value as IComponent; - const viewable = component.IComponentHTMLVisual; + const viewable = component.IComponentHTMLView; if (!viewable) { return Promise.reject("component is not viewable"); } @@ -2332,9 +2331,9 @@ function renderFlow(layoutContext: ILayoutContext, targetTranslation: string, de newBlock.instanceP = newBlock.properties.leafId.get() .then(async (component: IComponent) => { // TODO below is a temporary workaround. Should every QI interface also implement - // IComponent. Then you can go from IComponentHTMLVisual to IComponentLayout. + // IComponent. Then you can go from IComponentHTMLView to IComponentLayout. // Or should you query for each one individually. - const viewable = component.IComponentHTMLVisual; + const viewable = component.IComponentHTMLView; if (!viewable) { return Promise.reject("component is not viewable"); } diff --git a/packages/components/dice-roller/src/main.tsx b/packages/components/dice-roller/src/main.tsx index 1bb8d7f6b1d9..4f8a42cbeb5a 100644 --- a/packages/components/dice-roller/src/main.tsx +++ b/packages/components/dice-roller/src/main.tsx @@ -8,7 +8,7 @@ import { PrimedComponentFactory, } from "@microsoft/fluid-aqueduct"; import { - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import * as React from "react"; @@ -17,8 +17,8 @@ import * as ReactDOM from "react-dom"; /** * Dice roller example using view interfaces and stock component classes. */ -export class DiceRoller extends PrimedComponent implements IComponentHTMLVisual { - public get IComponentHTMLVisual() { return this; } +export class DiceRoller extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } /** * ComponentInitializingFirstTime is called only once, it is executed only by the first client to open the diff --git a/packages/components/external-component-loader/src/waterParkLoader/externalComponentLoader.ts b/packages/components/external-component-loader/src/waterParkLoader/externalComponentLoader.ts index 54f5d80c2d90..7c2069af04aa 100644 --- a/packages/components/external-component-loader/src/waterParkLoader/externalComponentLoader.ts +++ b/packages/components/external-component-loader/src/waterParkLoader/externalComponentLoader.ts @@ -6,7 +6,7 @@ import { PrimedComponent } from "@microsoft/fluid-aqueduct"; import { IComponent, - IComponentHTMLVisual, + IComponentHTMLView, IComponentLoadable, IResponse, } from "@microsoft/fluid-component-core-interfaces"; @@ -22,7 +22,7 @@ export const WaterParkLoaderName = `${pkg.name}-loader`; * Component that loads extneral components via their url */ export class ExternalComponentLoader extends PrimedComponent - implements IComponentHTMLVisual { + implements IComponentHTMLView { private static readonly defaultComponents = [ "@fluid-example/todo", @@ -38,7 +38,7 @@ export class ExternalComponentLoader extends PrimedComponent private savedElement: HTMLElement; private error: string; - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public setViewComponent(component: IComponentLoadable) { this.root.set(this.viewComponentMapID, component.IComponentLoadable.url); diff --git a/packages/components/external-component-loader/src/waterParkView/externalComponentView.ts b/packages/components/external-component-loader/src/waterParkView/externalComponentView.ts index 1711672891c9..8351fd91fe90 100644 --- a/packages/components/external-component-loader/src/waterParkView/externalComponentView.ts +++ b/packages/components/external-component-loader/src/waterParkView/externalComponentView.ts @@ -7,7 +7,7 @@ import { PrimedComponent } from "@microsoft/fluid-aqueduct"; import { IComponent, IComponentHandle, - IComponentHTMLVisual, + IComponentHTMLView, IComponentLoadable, } from "@microsoft/fluid-component-core-interfaces"; import { IPackage } from "@microsoft/fluid-container-definitions"; @@ -22,9 +22,11 @@ export const WaterParkViewName = `${pkg.name}-view`; /** * Component that loads extneral components via their url */ -export class ExternalComponentView extends PrimedComponent implements IComponentHTMLVisual, IComponentCollection { +export class ExternalComponentView extends PrimedComponent implements + IComponentHTMLView, + IComponentCollection { - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public get IComponentCollection() { return this; } private sequence: SharedObjectSequence; @@ -94,7 +96,7 @@ export class ExternalComponentView extends PrimedComponent implements IComponent this.sequence.getItems(0).forEach((url) => { const component = this.urlToComponent.get(url); if (component) { - const renderable = component.IComponentHTMLVisual; + const renderable = component.IComponentHTMLView; if (renderable) { const containerDiv = document.createElement("div"); diff --git a/packages/components/flow-scroll/src/host/host.ts b/packages/components/flow-scroll/src/host/host.ts index ce1a73da3598..7eb524e89b61 100644 --- a/packages/components/flow-scroll/src/host/host.ts +++ b/packages/components/flow-scroll/src/host/host.ts @@ -10,8 +10,8 @@ import { tableViewType } from "@fluid-example/table-view"; import { Editor, FlowDocument, htmlFormatter, IComponentHTMLViewFactory } from "@fluid-example/webflow"; import { IComponent, + IComponentHTMLOptions, IComponentHTMLView, - IComponentHTMLVisual, IComponentLoadable, } from "@microsoft/fluid-component-core-interfaces"; import { IComponentCollection } from "@microsoft/fluid-framework-interfaces"; @@ -61,7 +61,7 @@ export class HostView implements IComponentHTMLView, SearchMenu.ISearchMenuHost private readonly mathP: Promise, private readonly videosP: Promise, private readonly imagesP: Promise, - private readonly intelViewer: IComponentHTMLVisual, + private readonly intelViewer: IComponentHTMLView, private readonly root: ISharedDirectory, ) { } @@ -73,7 +73,7 @@ export class HostView implements IComponentHTMLView, SearchMenu.ISearchMenuHost } } - public render(elm: HTMLElement): void { + public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { const flowDiv = document.createElement("div"); const insightsDiv = document.createElement("div"); elm.style.display = "flex"; @@ -200,8 +200,7 @@ export class HostView implements IComponentHTMLView, SearchMenu.ISearchMenuHost }); flowDiv.appendChild(this.viewport); - const intelRenderable = this.intelViewer.addView(); - intelRenderable.render(insightsDiv); + this.intelViewer.render(insightsDiv); } // #endregion IComponentHTMLView diff --git a/packages/components/flow-scroll/src/host/index.ts b/packages/components/flow-scroll/src/host/index.ts index 6f959246cde2..95ca19d0da04 100644 --- a/packages/components/flow-scroll/src/host/index.ts +++ b/packages/components/flow-scroll/src/host/index.ts @@ -11,7 +11,6 @@ import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aquedu import { IComponent, IComponentHandle, - IComponentHTMLOptions, IComponentHTMLView, IComponentHTMLVisual, IResponse, @@ -60,10 +59,6 @@ export class WebFlowHost extends PrimedComponent implements IComponentHTMLVisual return response.value as T; } - public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { - this.addView().render(elm, options); - } - protected async componentInitializingFirstTime() { await Promise.all([ this.createSubComponent(this.docId, FlowDocumentType), diff --git a/packages/components/image-collection/src/images.ts b/packages/components/image-collection/src/images.ts index 9e4d7c3bf10e..a1f439c303be 100644 --- a/packages/components/image-collection/src/images.ts +++ b/packages/components/image-collection/src/images.ts @@ -8,7 +8,7 @@ import { IComponent, IComponentHandleContext, IComponentHTMLOptions, - IComponentHTMLVisual, + IComponentHTMLView, IComponentLoadable, IComponentRouter, IRequest, @@ -22,9 +22,9 @@ import { IComponentContext, IComponentFactory, IComponentRuntime } from "@micros import { ISharedObjectFactory } from "@microsoft/fluid-shared-object-base"; export class ImageComponent implements - IComponentLoadable, IComponentHTMLVisual, IComponentRouter, IComponentLayout { + IComponentLoadable, IComponentHTMLView, IComponentRouter, IComponentLayout { public get IComponentLoadable() { return this; } - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public get IComponentRouter() { return this; } public get IComponentLayout() { return this; } diff --git a/packages/components/markflow/src/host/index.ts b/packages/components/markflow/src/host/index.ts index e7a1349fde8f..20a2d3f25ab7 100644 --- a/packages/components/markflow/src/host/index.ts +++ b/packages/components/markflow/src/host/index.ts @@ -6,7 +6,6 @@ import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; import { IComponent, - IComponentHTMLOptions, IComponentHTMLView, IComponentHTMLVisual, IResponse, @@ -25,14 +24,9 @@ export class WebFlow extends PrimedComponent implements IComponentHTMLVisual { public get IComponentHTMLVisual() { return this; } // #region IComponentHTMLVisual - public addView?(scope?: IComponent): IComponentHTMLView { + public addView(scope?: IComponent): IComponentHTMLView { return new WebflowView(this.getComponent(this.docId), this.context.documentId); } - - public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { - const view = this.addView(); - view.render(elm, options); - } // #endregion IComponentHTMLVisual protected async componentInitializingFirstTime() { diff --git a/packages/components/math/src/mathComponent.ts b/packages/components/math/src/mathComponent.ts index 15bd14065baf..d133c68f4abe 100644 --- a/packages/components/math/src/mathComponent.ts +++ b/packages/components/math/src/mathComponent.ts @@ -433,7 +433,6 @@ export class MathInstance extends EventEmitter implements IComponentLoadable, IC public startMarker: MergeTree.Marker; public solnText = "x=0"; public solnVar = "x"; - private defaultView: MathView; constructor( public url: string, @@ -453,17 +452,6 @@ export class MathInstance extends EventEmitter implements IComponentLoadable, IC return new MathView(this, scope); } - public render(elm: HTMLElement, options?: IComponentHTMLOptions) { - if (!this.defaultView) { - this.defaultView = this.addView(); - } - let localOptions = this.options; - if (options) { - localOptions = options; - } - this.defaultView.render(elm, localOptions); - } - public insertText(text: string, pos: number) { this.collection.insertText(text, this.leafId, pos); } diff --git a/packages/components/monaco/src/chaincode.ts b/packages/components/monaco/src/chaincode.ts index 73e88bdceb6e..1b1feb20cb0d 100644 --- a/packages/components/monaco/src/chaincode.ts +++ b/packages/components/monaco/src/chaincode.ts @@ -8,7 +8,7 @@ import { PrimedComponent } from "@microsoft/fluid-aqueduct"; import { IComponentHandle, IComponentHTMLOptions, - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import { IComponentLayout } from "@microsoft/fluid-framework-experimental"; import { @@ -63,7 +63,7 @@ const defaultCompilerOptions = { * Component for using the Monaco text editor. */ export class MonacoRunner extends PrimedComponent implements - IComponentHTMLVisual, IComponentLayout { + IComponentHTMLView, IComponentLayout { /** * Get a new MonacoRunner with the given runtime. @@ -77,7 +77,7 @@ export class MonacoRunner extends PrimedComponent implements return runner; } - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public get IComponentLoadable() { return this; } public get IComponentLayout() { return this; } diff --git a/packages/components/owned-map/src/index.tsx b/packages/components/owned-map/src/index.tsx index 63653eced5a4..171739725860 100644 --- a/packages/components/owned-map/src/index.tsx +++ b/packages/components/owned-map/src/index.tsx @@ -7,19 +7,17 @@ import { PrimedComponent, PrimedComponentFactory, SimpleModuleInstantiationFacto import { IComponentHandle, IComponentHTMLOptions, - IComponentHTMLVisual, + IComponentHTMLView, } from "@microsoft/fluid-component-core-interfaces"; import { Counter, CounterValueType } from "@microsoft/fluid-map"; import * as React from "react"; import * as ReactDOM from "react-dom"; import { OwnedSharedMap } from "./ownedMap"; -export class OwnedMap extends PrimedComponent implements IComponentHTMLVisual { - +export class OwnedMap extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } public static getFactory() { return OwnedMap.factory; } - public get IComponentHTMLVisual() { return this; } - private static readonly factory = new PrimedComponentFactory( OwnedMap, [ @@ -30,7 +28,7 @@ export class OwnedMap extends PrimedComponent implements IComponentHTMLVisual { public ownedMap: OwnedSharedMap; public counter: Counter; - // #region IComponentHTMLVisual + // #region IComponentHTMLView public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { const render = () => this.doRender(elm); this.root.on("op", () => { @@ -43,7 +41,7 @@ export class OwnedMap extends PrimedComponent implements IComponentHTMLVisual { this.doRender(elm); } - // #endregion IComponentHTMLVisual + // #endregion IComponentHTMLView /** * The component has been loaded. Render the component into the provided div diff --git a/packages/components/pond/src/index.tsx b/packages/components/pond/src/index.tsx index 9a954c45a618..6121f491e190 100644 --- a/packages/components/pond/src/index.tsx +++ b/packages/components/pond/src/index.tsx @@ -8,7 +8,11 @@ import { PrimedComponentFactory, SimpleModuleInstantiationFactory, } from "@microsoft/fluid-aqueduct"; -import { IComponent, IComponentHandle, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { + IComponent, + IComponentHandle, + IComponentHTMLView, +} from "@microsoft/fluid-component-core-interfaces"; import { SharedDirectory } from "@microsoft/fluid-map"; import { IComponentRuntime } from "@microsoft/fluid-runtime-definitions"; @@ -26,15 +30,15 @@ export const PondName = pkg.name as string; * - Component creation with initial state * - Component creation and storage using Handles */ -export class Pond extends PrimedComponent implements IComponentHTMLVisual { +export class Pond extends PrimedComponent implements IComponentHTMLView { private readonly clickerKey = "clicker"; private readonly clickerWithInitialValueKey = "clicker-with-initial-value"; - public clicker2Render: IComponentHTMLVisual | undefined; - public clicker3Render: IComponentHTMLVisual | undefined; + public clicker2Render: IComponentHTMLView | undefined; + public clicker3Render: IComponentHTMLView | undefined; - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } /** * Do setup work here @@ -58,13 +62,13 @@ export class Pond extends PrimedComponent implements IComponentHTMLVisual { protected async componentHasInitialized() { const clicker2 = await this.root.get(this.clickerKey).get(); - this.clicker2Render = clicker2.IComponentHTMLVisual; + this.clicker2Render = clicker2.IComponentHTMLView; const clicker3 = await this.root.get(this.clickerWithInitialValueKey).get(); - this.clicker3Render = clicker3.IComponentHTMLVisual; + this.clicker3Render = clicker3.IComponentHTMLView; } - // start IComponentHTMLVisual + // start IComponentHTMLView public render(div: HTMLElement) { if (!this.clicker2Render || !this.clicker3Render) { @@ -107,7 +111,7 @@ export class Pond extends PrimedComponent implements IComponentHTMLVisual { return div; } - // end IComponentHTMLVisual + // end IComponentHTMLView // ----- COMPONENT SETUP STUFF ----- diff --git a/packages/components/pond/src/internal-components/clicker.tsx b/packages/components/pond/src/internal-components/clicker.tsx index fdae0978df99..0d4b9937cd01 100644 --- a/packages/components/pond/src/internal-components/clicker.tsx +++ b/packages/components/pond/src/internal-components/clicker.tsx @@ -4,7 +4,10 @@ */ import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHandle, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { + IComponentHandle, + IComponentHTMLView, +} from "@microsoft/fluid-component-core-interfaces"; import { Counter, CounterValueType, ISharedDirectory, ISharedMap, SharedMap } from "@microsoft/fluid-map"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -16,9 +19,8 @@ export const ClickerName = `${pkg.name as string}-clicker`; /** * Basic Clicker example using new interfaces and stock component classes. */ -export class Clicker extends PrimedComponent implements IComponentHTMLVisual { - - public get IComponentHTMLVisual() { return this; } +export class Clicker extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } private storedMap: ISharedMap | undefined; private counter: Counter | undefined; @@ -45,7 +47,7 @@ export class Clicker extends PrimedComponent implements IComponentHTMLVisual { this.storedMap = await this.root.get("storedMap").get(); } - // start IComponentHTMLVisual + // start IComponentHTMLView public render(div: HTMLElement) { if (!this.storedMap || !this.counter) { @@ -59,7 +61,7 @@ export class Clicker extends PrimedComponent implements IComponentHTMLVisual { ); } - // end IComponentHTMLVisual + // end IComponentHTMLView // ----- COMPONENT SETUP STUFF ----- diff --git a/packages/components/pond/src/internal-components/clickerWithInitialValue.tsx b/packages/components/pond/src/internal-components/clickerWithInitialValue.tsx index 081a26e563e7..33c49e891ece 100644 --- a/packages/components/pond/src/internal-components/clickerWithInitialValue.tsx +++ b/packages/components/pond/src/internal-components/clickerWithInitialValue.tsx @@ -4,7 +4,7 @@ */ import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { Counter, CounterValueType, ISharedDirectory } from "@microsoft/fluid-map"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -16,9 +16,8 @@ export const ClickerWithInitialValueName = `${pkg.name as string}-clickerWithIni /** * Basic Clicker example using new interfaces and stock component classes. */ -export class ClickerWithInitialValue extends PrimedComponent implements IComponentHTMLVisual { - - public get IComponentHTMLVisual() { return this; } +export class ClickerWithInitialValue extends PrimedComponent implements IComponentHTMLView { + public get IComponentHTMLView() { return this; } /** * Do setup work here @@ -32,7 +31,7 @@ export class ClickerWithInitialValue extends PrimedComponent implements ICompone this.root.createValueType("clicks", CounterValueType.Name, startingValue); } - // start IComponentHTMLVisual + // start IComponentHTMLView public render(div: HTMLElement) { // Get our counter object that we set in initialize and pass it in to the view. @@ -43,7 +42,7 @@ export class ClickerWithInitialValue extends PrimedComponent implements ICompone ); } - // end IComponentHTMLVisual + // end IComponentHTMLView // ----- COMPONENT SETUP STUFF ----- diff --git a/packages/components/progress-bars/src/progressBars.ts b/packages/components/progress-bars/src/progressBars.ts index 2eb0a0c972fe..205528b043e1 100644 --- a/packages/components/progress-bars/src/progressBars.ts +++ b/packages/components/progress-bars/src/progressBars.ts @@ -24,7 +24,6 @@ import { ISharedObjectFactory } from "@microsoft/fluid-shared-object-base"; require("bootstrap/dist/css/bootstrap.min.css"); class ProgressBarView implements IComponentHTMLView { - public parent: HTMLElement; private barElem: HTMLDivElement; @@ -78,9 +77,10 @@ class ProgressBarView implements IComponentHTMLView { } // The "model" side of a progress bar -export class ProgressBar extends EventEmitter implements IComponentLoadable, IComponentHTMLVisual, IComponentRouter { - private defaultView: ProgressBarView; - +export class ProgressBar extends EventEmitter implements + IComponentLoadable, + IComponentHTMLVisual, + IComponentRouter { public handle: ComponentHandle; constructor( @@ -98,14 +98,7 @@ export class ProgressBar extends EventEmitter implements IComponentLoadable, ICo public get IComponentHTMLVisual() { return this; } public get IComponentRouter() { return this; } - public render(elm: HTMLElement) { - if (!this.defaultView) { - this.defaultView = new ProgressBarView(this); - } - this.defaultView.render(elm); - } - - public addView(host: IComponent) { + public addView(scope?: IComponent) { return new ProgressBarView(this); } diff --git a/packages/components/scoreboard/src/scoreboard.tsx b/packages/components/scoreboard/src/scoreboard.tsx index adcc208365c1..3a9e2da35ddd 100644 --- a/packages/components/scoreboard/src/scoreboard.tsx +++ b/packages/components/scoreboard/src/scoreboard.tsx @@ -5,16 +5,19 @@ import { CounterValueType } from "@microsoft/fluid-map"; import { PrimedComponent, PrimedComponentFactory, SimpleModuleInstantiationFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLOptions, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { + IComponentHTMLOptions, + IComponentHTMLView, +} from "@microsoft/fluid-component-core-interfaces"; import * as React from "react"; import * as ReactDOM from "react-dom"; import { TeamScore } from "./teamScore"; import { WinnerText } from "./winnerText"; -export class Scoreboard extends PrimedComponent implements IComponentHTMLVisual { +export class Scoreboard extends PrimedComponent implements IComponentHTMLView { public static readonly componentName = "Scoreboard"; - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } /** * Setup the distributed data structures; called once when the component is created (NOT initialized) diff --git a/packages/components/scribe/src/scribe.ts b/packages/components/scribe/src/scribe.ts index 95d2384f7f18..1abb8e70e3b4 100644 --- a/packages/components/scribe/src/scribe.ts +++ b/packages/components/scribe/src/scribe.ts @@ -7,7 +7,7 @@ import { EventEmitter } from "events"; import { resolve } from "url"; import { IComponentHTMLOptions, - IComponentHTMLVisual, + IComponentHTMLView, IComponentLoadable, IComponentRouter, IRequest, @@ -376,7 +376,7 @@ const html = export class Scribe extends EventEmitter - implements IComponentLoadable, IComponentRouter, IComponentHTMLVisual { + implements IComponentLoadable, IComponentRouter, IComponentHTMLView { public static async load(runtime: IComponentRuntime, context: IComponentContext) { const collection = new Scribe(runtime, context); @@ -387,7 +387,7 @@ export class Scribe public get IComponentLoadable() { return this; } public get IComponentRouter() { return this; } - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public url: string; private root: ISharedMap; diff --git a/packages/components/shared-map-visualizer/src/maps.ts b/packages/components/shared-map-visualizer/src/maps.ts index 8140fb7282a5..1e3b39e2e5a7 100644 --- a/packages/components/shared-map-visualizer/src/maps.ts +++ b/packages/components/shared-map-visualizer/src/maps.ts @@ -7,7 +7,7 @@ import { EventEmitter } from "events"; import { IComponent, IComponentHTMLOptions, - IComponentHTMLVisual, + IComponentHTMLView, IComponentLoadable, IComponentRouter, IRequest, @@ -155,7 +155,7 @@ async function displayMap( export class ProgressCollection extends EventEmitter - implements IComponentLoadable, IComponentRouter, IComponentHTMLVisual { + implements IComponentLoadable, IComponentRouter, IComponentHTMLView { public static async load(runtime: IComponentRuntime, context: IComponentContext) { const collection = new ProgressCollection(runtime, context); @@ -166,7 +166,7 @@ export class ProgressCollection public get IComponentLoadable() { return this; } public get IComponentRouter() { return this; } - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public url: string; private root: ISharedMap; diff --git a/packages/components/shared-text/src/component.ts b/packages/components/shared-text/src/component.ts index 716a71f7d267..b27594541863 100644 --- a/packages/components/shared-text/src/component.ts +++ b/packages/components/shared-text/src/component.ts @@ -13,7 +13,7 @@ import { SharedCell } from "@microsoft/fluid-cell"; import { IComponent, IComponentHandle, - IComponentHTMLVisual, + IComponentHTMLView, IComponentLoadable, IRequest, IResponse, @@ -57,7 +57,7 @@ async function getHandle(runtimeP: Promise): Promise { const runner = new SharedTextRunner(runtime, context); @@ -67,7 +67,7 @@ export class SharedTextRunner } public get IComponentLoadable() { return this; } - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public get ISharedString() { return this.sharedString; } public readonly url = "/text"; diff --git a/packages/components/shared-text/src/graphql.ts b/packages/components/shared-text/src/graphql.ts index 5afa08dafd53..1de1d0c981c4 100644 --- a/packages/components/shared-text/src/graphql.ts +++ b/packages/components/shared-text/src/graphql.ts @@ -4,7 +4,7 @@ */ import { EventEmitter } from "events"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { ISharedMap } from "@microsoft/fluid-map"; import { SharedString } from "@microsoft/fluid-sequence"; import * as GraphiQL from "graphiql"; @@ -14,10 +14,10 @@ import { GraphQLService } from "./database"; // Note on defining components - snapshotting does not seem like it should be part of an IChaincodeComponent given // these synthetic components don't need it. We may want this to just be "attach" -export class GraphIQLView extends EventEmitter implements IComponentHTMLVisual { +export class GraphIQLView extends EventEmitter implements IComponentHTMLView { public readonly id = "graphiql"; - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } constructor(private readonly map: ISharedMap, private readonly sharedString: SharedString) { super(); diff --git a/packages/components/table-view/src/tableview.ts b/packages/components/table-view/src/tableview.ts index df36c922d9d2..3db5472f2a70 100644 --- a/packages/components/table-view/src/tableview.ts +++ b/packages/components/table-view/src/tableview.ts @@ -6,7 +6,10 @@ import { Template } from "@fluid-example/flow-util-lib"; import { TableDocument, TableDocumentType } from "@fluid-example/table-document"; import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; -import { IComponentHTMLOptions, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { + IComponentHTMLOptions, + IComponentHTMLView, +} from "@microsoft/fluid-component-core-interfaces"; import { IComponentContext, IComponentRuntime } from "@microsoft/fluid-runtime-definitions"; import { GridView } from "./grid"; import * as styles from "./index.css"; @@ -23,7 +26,7 @@ const template = new Template({ ], }); -export class TableView extends PrimedComponent implements IComponentHTMLVisual { +export class TableView extends PrimedComponent implements IComponentHTMLView { public static getFactory() { return TableView.factory; } private static readonly factory = new PrimedComponentFactory( @@ -31,13 +34,13 @@ export class TableView extends PrimedComponent implements IComponentHTMLVisual { [], ); - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } constructor(runtime: IComponentRuntime, context: IComponentContext) { super(runtime, context); } - // #region IComponentHTMLVisual + // #region IComponentHTMLView public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { const root = template.clone(); elm.append(root); @@ -74,7 +77,7 @@ export class TableView extends PrimedComponent implements IComponentHTMLVisual { }); }); } - // #endregion IComponentHTMLVisual + // #endregion IComponentHTMLView protected async componentInitializingFirstTime() { const doc = await this.createAndAttachComponent(this.docId, TableDocumentType); diff --git a/packages/components/todo/src/TextBox/TextBox.tsx b/packages/components/todo/src/TextBox/TextBox.tsx index 9ed51bcbe273..09c63713f93c 100644 --- a/packages/components/todo/src/TextBox/TextBox.tsx +++ b/packages/components/todo/src/TextBox/TextBox.tsx @@ -4,7 +4,7 @@ */ import { PrimedComponent } from "@microsoft/fluid-aqueduct"; import { CollaborativeTextArea, IComponentReactViewable } from "@microsoft/fluid-aqueduct-react"; -import { IComponentHandle, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHandle, IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { SharedString } from "@microsoft/fluid-sequence"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -17,12 +17,8 @@ export const TextBoxName = `${pkg.name as string}-textbox`; * TextBox is a really simple component that uses the CollaborativeTextArea to provide a * collaborative textarea. */ -export class TextBox extends PrimedComponent - implements - IComponentHTMLVisual, - IComponentReactViewable { - - public get IComponentHTMLVisual() { return this; } +export class TextBox extends PrimedComponent implements IComponentHTMLView, IComponentReactViewable { + public get IComponentHTMLView() { return this; } public get IComponentReactViewable() { return this; } private text: SharedString; @@ -48,7 +44,7 @@ export class TextBox extends PrimedComponent this.text = await this.root.get("text").get(); } - // start IComponentHTMLVisual + // start IComponentHTMLView public render(div: HTMLElement) { ReactDOM.render( @@ -57,7 +53,7 @@ export class TextBox extends PrimedComponent ); } - // end IComponentHTMLVisual + // end IComponentHTMLView // start IComponentReactViewable diff --git a/packages/components/todo/src/TextList/TextList.tsx b/packages/components/todo/src/TextList/TextList.tsx index 99aec0257baa..73f04fc0453b 100644 --- a/packages/components/todo/src/TextList/TextList.tsx +++ b/packages/components/todo/src/TextList/TextList.tsx @@ -4,7 +4,7 @@ */ import { PrimedComponent } from "@microsoft/fluid-aqueduct"; import { IComponentReactViewable } from "@microsoft/fluid-aqueduct-react"; -import { IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponentHTMLView } from "@microsoft/fluid-component-core-interfaces"; import { IDirectory } from "@microsoft/fluid-map"; import { SharedString } from "@microsoft/fluid-sequence"; import * as React from "react"; @@ -19,8 +19,10 @@ export const TextListName = `${pkg.name as string}-textlist`; * TextBox is a really simple component that uses the CollaborativeTextArea to provide a * collaborative textarea. */ -export class TextList extends PrimedComponent implements IComponentHTMLVisual, IComponentReactViewable { - public get IComponentHTMLVisual() { return this; } +export class TextList extends PrimedComponent implements + IComponentHTMLView, + IComponentReactViewable { + public get IComponentHTMLView() { return this; } public get IComponentReactViewable() { return this; } private textDirectory: IDirectory; @@ -46,7 +48,7 @@ export class TextList extends PrimedComponent implements IComponentHTMLVisual, I }); } - // start IComponentHTMLVisual + // start IComponentHTMLView public render(div: HTMLElement) { ReactDOM.render( @@ -55,7 +57,7 @@ export class TextList extends PrimedComponent implements IComponentHTMLVisual, I ); } - // end IComponentHTMLVisual + // end IComponentHTMLView // start IComponentReactViewable diff --git a/packages/components/todo/src/Todo/Todo.tsx b/packages/components/todo/src/Todo/Todo.tsx index c491a8e33f13..34631860286d 100644 --- a/packages/components/todo/src/Todo/Todo.tsx +++ b/packages/components/todo/src/Todo/Todo.tsx @@ -5,7 +5,10 @@ import { PrimedComponent } from "@microsoft/fluid-aqueduct"; import { IComponentReactViewable } from "@microsoft/fluid-aqueduct-react"; -import { IComponentHandle, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { + IComponentHandle, + IComponentHTMLView, +} from "@microsoft/fluid-component-core-interfaces"; import { ISharedMap, SharedMap } from "@microsoft/fluid-map"; import { IComponentRuntime } from "@microsoft/fluid-runtime-definitions"; import { SharedString } from "@microsoft/fluid-sequence"; @@ -25,7 +28,9 @@ export const TodoName = `${pkg.name as string}-todo`; * - New todo item entry * - List of todo items */ -export class Todo extends PrimedComponent implements IComponentHTMLVisual, IComponentReactViewable { +export class Todo extends PrimedComponent implements + IComponentHTMLView, + IComponentReactViewable { // DDS ids stored as variables to minimize simple string mistakes private readonly todoItemsKey = "todo-items"; @@ -33,7 +38,7 @@ export class Todo extends PrimedComponent implements IComponentHTMLVisual, IComp private todoItemsMap: ISharedMap; - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public get IComponentReactViewable() { return this; } // Would prefer not to hand this out, and instead give back a title component? @@ -65,7 +70,7 @@ export class Todo extends PrimedComponent implements IComponentHTMLVisual, IComp }); } - // start IComponentHTMLVisual + // start IComponentHTMLView /** * Creates a new view for a caller that doesn't directly support React @@ -81,7 +86,7 @@ export class Todo extends PrimedComponent implements IComponentHTMLVisual, IComp ); } - // end IComponentHTMLVisual + // end IComponentHTMLView // start IComponentReactViewable diff --git a/packages/components/todo/src/TodoItem/TodoItem.tsx b/packages/components/todo/src/TodoItem/TodoItem.tsx index b0153e2dc455..76a49dc6b264 100644 --- a/packages/components/todo/src/TodoItem/TodoItem.tsx +++ b/packages/components/todo/src/TodoItem/TodoItem.tsx @@ -7,7 +7,10 @@ import { ClickerName } from "@fluid-example/clicker"; import { PrimedComponent } from "@microsoft/fluid-aqueduct"; import { IComponentReactViewable } from "@microsoft/fluid-aqueduct-react"; import { ISharedCell, SharedCell } from "@microsoft/fluid-cell"; -import { IComponentHandle, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { + IComponentHandle, + IComponentHTMLView, +} from "@microsoft/fluid-component-core-interfaces"; import { IComponentRuntime } from "@microsoft/fluid-runtime-definitions"; import { SharedString } from "@microsoft/fluid-sequence"; import * as React from "react"; @@ -36,14 +39,14 @@ const innerComponentKey = "innerId"; */ export class TodoItem extends PrimedComponent implements - IComponentHTMLVisual, + IComponentHTMLView, IComponentReactViewable { private text: SharedString; private innerIdCell: ISharedCell; private baseUrl: string = ""; - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public get IComponentReactViewable() { return this; } /** @@ -108,7 +111,7 @@ export class TodoItem extends PrimedComponent }); } - // start IComponentHTMLVisual + // start IComponentHTMLView public render(div: HTMLElement) { ReactDOM.render( @@ -117,7 +120,7 @@ export class TodoItem extends PrimedComponent ); } - // end IComponentHTMLVisual + // end IComponentHTMLView // start IComponentReactViewable diff --git a/packages/components/video-players/src/videoPlayers.ts b/packages/components/video-players/src/videoPlayers.ts index dd211d24f8a2..58ccf9c42b58 100644 --- a/packages/components/video-players/src/videoPlayers.ts +++ b/packages/components/video-players/src/videoPlayers.ts @@ -7,7 +7,7 @@ import { EventEmitter } from "events"; import { IComponent, IComponentHandleContext, - IComponentHTMLVisual, + IComponentHTMLView, IComponentLoadable, IComponentRouter, IRequest, @@ -75,12 +75,12 @@ interface IYouTubePlayer { } export class VideoPlayer implements - IComponentLoadable, IComponentHTMLVisual, IComponentRouter, IComponentLayout { + IComponentLoadable, IComponentHTMLView, IComponentRouter, IComponentLayout { private player: IYouTubePlayer; private playerDiv: HTMLDivElement; - public get IComponentHTMLVisual() { return this; } + public get IComponentHTMLView() { return this; } public get IComponentRouter() { return this; } public get IComponentLayout() { return this; } public get IComponentLoadable() { return this; } diff --git a/packages/components/webflow/src/host/index.ts b/packages/components/webflow/src/host/index.ts index 57c1f9f2eaf5..24a471b78420 100644 --- a/packages/components/webflow/src/host/index.ts +++ b/packages/components/webflow/src/host/index.ts @@ -6,7 +6,6 @@ import { PrimedComponent, PrimedComponentFactory } from "@microsoft/fluid-aqueduct"; import { IComponent, - IComponentHTMLOptions, IComponentHTMLView, IComponentHTMLVisual, IResponse, @@ -25,14 +24,9 @@ export class WebFlow extends PrimedComponent implements IComponentHTMLVisual { public get IComponentHTMLVisual() { return this; } // #region IComponentHTMLVisual - public addView?(scope?: IComponent): IComponentHTMLView { + public addView(scope?: IComponent): IComponentHTMLView { return new WebflowView(this.getComponent(this.docId)); } - - public render(elm: HTMLElement, options?: IComponentHTMLOptions): void { - const view = this.addView(); - view.render(elm, options); - } // #endregion IComponentHTMLVisual protected async componentInitializingFirstTime() { diff --git a/packages/framework/aqueduct-react/src/react/embeddedComponent.tsx b/packages/framework/aqueduct-react/src/react/embeddedComponent.tsx index b09452bfb8a8..f1dfed68174b 100644 --- a/packages/framework/aqueduct-react/src/react/embeddedComponent.tsx +++ b/packages/framework/aqueduct-react/src/react/embeddedComponent.tsx @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { IComponent, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; +import { IComponent, IComponentHTMLView, IComponentHTMLVisual } from "@microsoft/fluid-component-core-interfaces"; import * as React from "react"; import { IComponentReactViewable } from "./interfaces"; @@ -14,7 +14,7 @@ export interface IEmbeddedComponentProps { /** * Will render a component via react if the component supports IComponentReactViewable - * or standard HTML if the component supports IComponentHTMLVisual + * or standard HTML if the component supports IComponentHTMLView * * If the component supports neither interface we render an empty */ @@ -30,9 +30,15 @@ export class EmbeddedComponent extends React.Component return; } + const htmlView = this.props.component.IComponentHTMLView; + if (htmlView) { + this.element = ; + return; + } + const htmlVisual = this.props.component.IComponentHTMLVisual; if (htmlVisual) { - this.element = ; + this.element = ; return; } @@ -44,7 +50,35 @@ export class EmbeddedComponent extends React.Component } } -interface IHTMLProps { +interface IHTMLViewProps { + component: IComponentHTMLView; + style?: React.CSSProperties; +} + +/** + * Embeds a Fluid Component that supports IComponentHTMLView + */ +class HTMLViewEmbeddedComponent extends React.Component { + private readonly ref: React.RefObject; + + constructor(props: IHTMLViewProps) { + super(props); + + this.ref = React.createRef(); + } + + public async componentDidMount() { + if (this.ref.current) { + this.props.component.render(this.ref.current); + } + } + + public render() { + return ; + } +} + +interface IHTMLVisualProps { component: IComponentHTMLVisual; style?: React.CSSProperties; } @@ -52,10 +86,10 @@ interface IHTMLProps { /** * Embeds a Fluid Component that supports IComponentHTMLVisual */ -class HTMLEmbeddedComponent extends React.Component { +class HTMLVisualEmbeddedComponent extends React.Component { private readonly ref: React.RefObject; - constructor(props: IHTMLProps) { + constructor(props: IHTMLVisualProps) { super(props); this.ref = React.createRef(); @@ -63,12 +97,8 @@ class HTMLEmbeddedComponent extends React.Component { public async componentDidMount() { if (this.ref.current) { - if (this.props.component.addView) { - const view = this.props.component.addView(); - view.render(this.ref.current); - } else { - this.props.component.render(this.ref.current); - } + const view = this.props.component.addView(); + view.render(this.ref.current); } } diff --git a/packages/framework/framework-definitions/src/discover.ts b/packages/framework/framework-definitions/src/discover.ts index ecf26cfd645b..5e5cfd130532 100644 --- a/packages/framework/framework-definitions/src/discover.ts +++ b/packages/framework/framework-definitions/src/discover.ts @@ -8,9 +8,9 @@ import { IComponent } from "@microsoft/fluid-component-core-interfaces"; /** * The interfaces in this file are related to component interface discovery. The idea * is that a component could say, for example, that it only cares about (and wants to be - * notified of) components that implement IComponentHTMLRender. Then, using these patterns, + * notified of) components that implement IComponentHTMLView. Then, using these patterns, * it will be notified of all loaded components that implement that type on load, and - * of all new components that are loaded during that session that implement IComponentHTMLRender. + * of all new components that are loaded during that session that implement IComponentHTMLView. * * Components who want their functionality to be discoverable should implement * IComponentDiscoverableInterfaces and list the interfaces they implement. Components that diff --git a/packages/hosts/base-host/src/host.ts b/packages/hosts/base-host/src/host.ts index fa47dd6712b4..b13e096a20f5 100644 --- a/packages/hosts/base-host/src/host.ts +++ b/packages/hosts/base-host/src/host.ts @@ -26,14 +26,17 @@ async function getComponentAndRender(loader: Loader, url: string, div: HTMLDivEl // Check if the component is viewable const component = response.value as IComponent; - const viewable = component.IComponentHTMLVisual; - - if (viewable) { - const renderable = - viewable.addView ? viewable.addView() : viewable; - + // First try to get it as a view + let renderable = component.IComponentHTMLView; + if (!renderable) { + // Otherwise get the visual, which is a view factory + const visual = component.IComponentHTMLVisual; + if (visual) { + renderable = visual.addView(); + } + } + if (renderable) { renderable.render(div, { display: "block" }); - return; } } diff --git a/packages/hosts/local-web-host/src/index.ts b/packages/hosts/local-web-host/src/index.ts index d09487414a23..8176fdd954eb 100644 --- a/packages/hosts/local-web-host/src/index.ts +++ b/packages/hosts/local-web-host/src/index.ts @@ -92,13 +92,16 @@ export async function renderDefaultComponent(container: Container, div: HTMLElem // Check if the component is viewable const component = response.value as IComponent; - const viewable = component.IComponentHTMLVisual; - - if (viewable) { - const renderable = - viewable.addView ? viewable.addView() : viewable; - + // First try to get it as a view + let renderable = component.IComponentHTMLView; + if (!renderable) { + // Otherwise get the visual, which is a view factory + const visual = component.IComponentHTMLVisual; + if (visual) { + renderable = visual.addView(); + } + } + if (renderable) { renderable.render(div, { display: "block" }); - return; } } diff --git a/packages/hosts/tiny-web-host/src/host.ts b/packages/hosts/tiny-web-host/src/host.ts index ccb9117f60b5..12ce0a5107b0 100644 --- a/packages/hosts/tiny-web-host/src/host.ts +++ b/packages/hosts/tiny-web-host/src/host.ts @@ -240,7 +240,7 @@ export async function loadIFramedFluidContainer( scriptUrl = `https://pragueauspkn-3873244262.azureedge.net/@fluid-example/tiny-web-host@${packageJson.version}/dist/main.bundle.js`; } - // As per IComponentHTMLVisual, if the div has a size already, the render is expected to fill the space + // As per IComponentHTMLView, if the div has a size already, the render is expected to fill the space // it has been given. If not, the render should grow based on its own content. const divRect = div.getBoundingClientRect(); const expandToGivenSize = divRect.height && divRect.width; diff --git a/packages/loader/component-core-interfaces/src/componentRender.ts b/packages/loader/component-core-interfaces/src/componentRender.ts index e4e96a83685b..b16af72ed3f4 100644 --- a/packages/loader/component-core-interfaces/src/componentRender.ts +++ b/packages/loader/component-core-interfaces/src/componentRender.ts @@ -5,31 +5,46 @@ import { IComponent } from "./components"; -// Following is what loosely-coupled hosts need to show a component +export interface IComponentHTMLOptions { + display?: "block" | "inline"; +} + +export interface IProvideComponentHTMLView { + readonly IComponentHTMLView: IComponentHTMLView; +} /** - * Render the component into an HTML element. In the case of Block display, - * elm.getBoundingClientRect() defines the dimensions of the viewport in which - * to render. Typically, this means that elm should already be placed into the DOM. - * If elm has an empty client rect, then it is assumed that it will expand to hold the - * rendered component. + * An IComponentHTMLView is a renderable component, which may or may not also be its own model. + * If it is its own model, it is a "thick" view, otherwise it is a "thin" view. */ -export interface IComponentHTMLRender { +export interface IComponentHTMLView extends IProvideComponentHTMLView { + /** + * Render the component into an HTML element. In the case of Block display, + * elm.getBoundingClientRect() defines the dimensions of the viewport in which + * to render. Typically, this means that elm should already be placed into the DOM. + * If elm has an empty client rect, then it is assumed that it will expand to hold the + * rendered component. + */ render(elm: HTMLElement, options?: IComponentHTMLOptions): void; -} -export interface IComponentHTMLOptions { - display?: "block" | "inline"; -} - -export interface IComponentHTMLView extends IComponentHTMLRender { - remove(): void; + /** + * Views which need to perform cleanup (e.g. remove event listeners, timers, etc.) when + * removed from the DOM should implement remove() and perform that cleanup within. + * Components which wish to remove views from the DOM should call remove() on the view + * before removing it from the DOM. + */ + remove?(): void; } export interface IProvideComponentHTMLVisual { readonly IComponentHTMLVisual: IComponentHTMLVisual; } -export interface IComponentHTMLVisual extends IComponentHTMLRender, IProvideComponentHTMLVisual { - addView?(scope?: IComponent): IComponentHTMLView; +/** + * An IComponentHTMLVisual is a view factory. Typically (though not necessarily) it will be a model, + * binding itself to the views it creates. + * TODO: Consider renaming to IComponentHTMLViewFactory + */ +export interface IComponentHTMLVisual extends IProvideComponentHTMLVisual { + addView(scope?: IComponent): IComponentHTMLView; } diff --git a/packages/loader/component-core-interfaces/src/components.ts b/packages/loader/component-core-interfaces/src/components.ts index 1493c0315900..5c81f933e235 100644 --- a/packages/loader/component-core-interfaces/src/components.ts +++ b/packages/loader/component-core-interfaces/src/components.ts @@ -8,7 +8,7 @@ import { IProvideComponentLoadable, IProvideComponentRunnable, } from "./componentLoadable"; -import { IProvideComponentHTMLVisual } from "./componentRender"; +import { IProvideComponentHTMLView, IProvideComponentHTMLVisual } from "./componentRender"; import { IProvideComponentRouter } from "./componentRouter"; import { IProvideComponentHandle, IProvideComponentHandleContext } from "./handles"; import { IProvideComponentSerializer } from "./serializer"; @@ -16,7 +16,8 @@ import { IProvideComponentSerializer } from "./serializer"; /* eslint-disable @typescript-eslint/no-empty-interface, @typescript-eslint/indent */ export interface IComponent extends Readonly