From bbd5da4896c522fd916aa90b7006bfd89003a926 Mon Sep 17 00:00:00 2001
From: Gavin Barron
Date: Mon, 6 Feb 2023 08:35:25 -0800
Subject: [PATCH] feat: typed events (#1981)
* feat: typed events
adds typings to events
Changes the package use to generate the custom-elements.json file used to build React components
and tell Storybook about the web-components definitions
mgt- prefix from story component names to correct the connection to the data in custom-elements.json
set code pane content on agenda
disable ArgsTable on docs pages by default
show ArgsTable on base agenda stories
BREAKING CHANGE: moves agenda eventClick event from a property of e.detail to be the value of e.detail
BREAKING CHANGE: all events for mgt-task now emit a CustomEvent
---
.storybook/preview.js | 29 ++-
.storybook/story-elements/defaultDocsPage.js | 14 ++
.storybook/story-elements/noArgsDocsPage.js | 13 ++
{stories => .storybook}/versionInfo.js | 0
package.json | 4 +-
.../src/components/mgt-agenda/mgt-agenda.ts | 4 +-
.../components/mgt-file-list/mgt-file-list.ts | 8 +-
.../src/components/mgt-get/mgt-get.ts | 12 +-
.../src/components/mgt-login/mgt-login.ts | 10 +-
.../mgt-people-picker/mgt-people-picker.ts | 2 +-
.../mgt-person-card/mgt-person-card.ts | 40 ++--
.../src/components/mgt-person/mgt-person.ts | 8 +-
.../src/components/mgt-tasks/mgt-tasks.ts | 18 +-
.../src/components/mgt-tasks/task-sources.ts | 4 +-
.../mgt-teams-channel-picker.ts | 6 +-
.../src/components/mgt-todo/mgt-todo.ts | 3 +-
.../src/components/templatedComponent.ts | 13 +-
packages/mgt-react/package.json | 3 +-
packages/mgt-react/scripts/generate.js | 94 +++++---
packages/mgt-react/src/generated/react.ts | 201 +++++++++---------
stories/components/agenda/agenda.a.js | 28 ++-
.../components/agenda/agenda.properties.js | 6 +-
stories/components/agenda/agenda.style.js | 6 +-
.../components/agenda/agenda.templating.js | 6 +-
stories/components/file/file.a.js | 6 +-
stories/components/file/file.properties.js | 6 +-
stories/components/file/file.style.js | 6 +-
stories/components/file/file.templating.js | 6 +-
stories/components/fileList/fileList.a.js | 6 +-
.../fileList/fileList.properties.js | 6 +-
stories/components/fileList/fileList.style.js | 6 +-
.../fileList/fileList.templating.js | 6 +-
stories/components/get.stories.js | 6 +-
stories/components/login/login.stories.js | 6 +-
stories/components/login/login.styles.js | 6 +-
stories/components/people/people.a.js | 6 +-
.../components/people/people.properties.js | 6 +-
stories/components/people/people.styles.js | 6 +-
.../components/people/people.templating.js | 6 +-
.../components/peoplePicker/peoplePicker.a.js | 6 +-
.../peoplePicker/peoplePicker.properties.js | 6 +-
.../peoplePicker/peoplePicker.style.js | 6 +-
.../peoplePicker/peoplePicker.templating.js | 6 +-
stories/components/person/person.js | 6 +-
.../components/person/person.properties.js | 48 ++---
stories/components/person/person.style.js | 6 +-
.../components/person/person.templating.js | 6 +-
stories/components/personCard/personCard.a.js | 6 +-
.../personCard/personCard.properties.js | 6 +-
.../components/personCard/personCard.style.js | 6 +-
.../personCard/personCard.templating.js | 6 +-
stories/components/tasks.stories.js | 6 +-
.../teamsChannelPicker.a.js | 6 +-
.../teamsChannelPicker.style.js | 6 +-
.../teamsChannelPicker.templating.js | 6 +-
stories/components/todo.stories.js | 6 +-
stories/overview.stories.mdx | 2 +-
stories/samples/editor.stories.js | 4 -
stories/samples/general.stories.js | 5 -
stories/samples/templating.stories.js | 6 +-
yarn.lock | 98 ++++++++-
61 files changed, 468 insertions(+), 413 deletions(-)
create mode 100644 .storybook/story-elements/defaultDocsPage.js
create mode 100644 .storybook/story-elements/noArgsDocsPage.js
rename {stories => .storybook}/versionInfo.js (100%)
diff --git a/.storybook/preview.js b/.storybook/preview.js
index c0d64bfbe4..525938e797 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -8,11 +8,30 @@
/* global window */
import { addParameters, setCustomElements } from '@storybook/web-components';
-
import '../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js';
import customElements from '../custom-elements.json';
+import { versionInfo } from './versionInfo';
+import { noArgsDocsPage } from './story-elements/noArgsDocsPage.js';
+
+const setCustomElementsManifestWithOptions = (customElements, options) => {
+ let { privateFields = true } = options;
+ if (!privateFields) {
+ customElements?.modules?.forEach(module => {
+ module?.declarations?.forEach(declaration => {
+ Object.keys(declaration).forEach(key => {
+ if (Array.isArray(declaration[key])) {
+ declaration[key] = declaration[key].filter(
+ member => !member.privacy?.includes('private') && !member.privacy?.includes('protected')
+ );
+ }
+ });
+ });
+ });
+ }
+ return setCustomElements(customElements);
+};
-setCustomElements(customElements);
+setCustomElementsManifestWithOptions(customElements, { privateFields: false });
addParameters({
previewTabs: {
@@ -22,8 +41,10 @@ addParameters({
},
docs: {
iframeHeight: '400px',
- inlineStories: false
- }
+ inlineStories: false,
+ page: noArgsDocsPage
+ },
+ version: versionInfo
});
const req = require.context('../stories', true, /\.(js|mdx)$/);
diff --git a/.storybook/story-elements/defaultDocsPage.js b/.storybook/story-elements/defaultDocsPage.js
new file mode 100644
index 0000000000..9f13b0f894
--- /dev/null
+++ b/.storybook/story-elements/defaultDocsPage.js
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import { Title, Subtitle, Description, Primary, ArgsTable, Stories, PRIMARY_STORY } from '@storybook/addon-docs';
+
+export const defaultDocsPage = () => (
+ <>
+
+
+
+
+
+
+ >
+);
diff --git a/.storybook/story-elements/noArgsDocsPage.js b/.storybook/story-elements/noArgsDocsPage.js
new file mode 100644
index 0000000000..5367c68d59
--- /dev/null
+++ b/.storybook/story-elements/noArgsDocsPage.js
@@ -0,0 +1,13 @@
+import React from 'react';
+
+import { Title, Subtitle, Description, Primary, ArgsTable, Stories, PRIMARY_STORY } from '@storybook/addon-docs';
+
+export const noArgsDocsPage = () => (
+ <>
+
+
+
+
+
+ >
+);
diff --git a/stories/versionInfo.js b/.storybook/versionInfo.js
similarity index 100%
rename from stories/versionInfo.js
rename to .storybook/versionInfo.js
diff --git a/package.json b/package.json
index 81fbf6e153..f784298033 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
]
},
"scripts": {
+ "analyze": "custom-elements-manifest analyze --litelement --globs \"./packages/*/src/**/*.ts\"",
"build": "npm run prettier:check && npm run clean && lerna run build --scope @microsoft/*",
"build:compile": "npm run prettier:check && npm run clean && lerna run build:compile --scope @microsoft/*",
"build:mgt": "cd ./packages/mgt && npm run build",
@@ -51,7 +52,7 @@
"prettier:check": "npm run prettier:base -- --check \"packages/**/*.{ts,tsx}\"",
"prettier:write": "npm run prettier:base -- --write \"packages/**/*.{ts,tsx}\"",
"storybook": "start-storybook -p 6006 -s assets",
- "storybook:dev": "npm run build:compile && wca analyze packages --format json --outFile custom-elements.json",
+ "storybook:dev": "npm run build:compile && npm run analyze",
"storybook:watch": "npm-run-all --parallel watch storybook:bundle:watch storybook",
"storybook:bundle": "rollup -c ./.storybook/rollup.config.js",
"storybook:bundle:watch": "rollup -c ./.storybook/rollup.config.js --watch",
@@ -74,6 +75,7 @@
"@babel/preset-env": "^7.12.7",
"@babel/preset-react": "^7.12.7",
"@babel/preset-typescript": "^7.12.7",
+ "@custom-elements-manifest/analyzer": "^0.6.6",
"@octokit/rest": "^18.5.3",
"@open-wc/testing-helpers": "^2.1.4",
"@storybook/addon-a11y": "^6.4.4",
diff --git a/packages/mgt-components/src/components/mgt-agenda/mgt-agenda.ts b/packages/mgt-components/src/components/mgt-agenda/mgt-agenda.ts
index 09ccfea93e..8872fc496a 100644
--- a/packages/mgt-components/src/components/mgt-agenda/mgt-agenda.ts
+++ b/packages/mgt-components/src/components/mgt-agenda/mgt-agenda.ts
@@ -30,7 +30,7 @@ import { MgtPeople } from '../mgt-people/mgt-people';
* @class MgtAgenda
* @extends {MgtTemplatedComponent}
*
- * @fires eventClick - Fired when user click an event
+ * @fires {CustomEvent} eventClick - Fired when user click an event
*
* @cssprop --event-box-shadow - {String} Event box shadow color and size
* @cssprop --event-margin - {String} Event margin
@@ -538,7 +538,7 @@ export class MgtAgenda extends MgtTemplatedComponent {
}
private eventClicked(event: MicrosoftGraph.Event) {
- this.fireCustomEvent('eventClick', { event });
+ this.fireCustomEvent('eventClick', event);
}
private getEventTimeString(event: MicrosoftGraph.Event) {
diff --git a/packages/mgt-components/src/components/mgt-file-list/mgt-file-list.ts b/packages/mgt-components/src/components/mgt-file-list/mgt-file-list.ts
index 8252b51c3c..1d4bb077f7 100644
--- a/packages/mgt-components/src/components/mgt-file-list/mgt-file-list.ts
+++ b/packages/mgt-components/src/components/mgt-file-list/mgt-file-list.ts
@@ -51,14 +51,14 @@ registerFluentComponents(fluentProgressRing, fluentDesignSystemProvider);
/**
* The File List component displays a list of multiple folders and files by
- * using the file/folder name, an icon, and other properties specicified by the developer.
+ * using the file/folder name, an icon, and other properties specified by the developer.
* This component uses the mgt-file component.
*
* @export
* @class MgtFileList
* @extends {MgtTemplatedComponent}
*
- * @fires itemClick - Fired when user click a file. Returns the file (DriveItem) details.
+ * @fires {CustomEvent} itemClick - Fired when user click a file. Returns the file (DriveItem) details.
* @cssprop --file-upload-border- {String} File upload border top style
* @cssprop --file-upload-background-color - {Color} File upload background color with opacity style
* @cssprop --file-upload-button-float - {string} Upload button float position
@@ -712,7 +712,7 @@ export class MgtFileList extends MgtTemplatedComponent {
*/
private onFileListKeyDown(event: KeyboardEvent): void {
const fileList = this.renderRoot.querySelector('.file-list');
- let focusedItem;
+ let focusedItem: Element;
if (!fileList || !fileList.children.length) {
return;
@@ -736,7 +736,7 @@ export class MgtFileList extends MgtTemplatedComponent {
if (event.code === 'Enter' || event.code === 'Space') {
focusedItem = fileList.children[this._focusedItemIndex];
- const file = focusedItem.children[0] as any;
+ const file = focusedItem.children[0] as MgtFile;
event.preventDefault();
this.fireCustomEvent('itemClick', file.fileDetails);
diff --git a/packages/mgt-components/src/components/mgt-get/mgt-get.ts b/packages/mgt-components/src/components/mgt-get/mgt-get.ts
index cbdc730a26..4c392733a7 100644
--- a/packages/mgt-components/src/components/mgt-get/mgt-get.ts
+++ b/packages/mgt-components/src/components/mgt-get/mgt-get.ts
@@ -65,10 +65,20 @@ const getResponseInvalidationTime = (currentInvalidationPeriod: number): number
const getIsResponseCacheEnabled = (): boolean =>
CacheService.config.response.isEnabled && CacheService.config.isEnabled;
+/**
+ * Holder type emitted with the dataChange event
+ */
+export type DataChangedDetail = {
+ // tslint:disable: completed-docs
+ response?: any;
+ error?: any;
+ // tslint:enable: completed-docs
+};
+
/**
* Custom element for making Microsoft Graph get queries
*
- * @fires dataChange - Fired when data changes
+ * @fires {CustomEvent} dataChange - Fired when data changes
*
* @export
* @class mgt-get
diff --git a/packages/mgt-components/src/components/mgt-login/mgt-login.ts b/packages/mgt-components/src/components/mgt-login/mgt-login.ts
index 3b40391510..4501401f37 100644
--- a/packages/mgt-components/src/components/mgt-login/mgt-login.ts
+++ b/packages/mgt-components/src/components/mgt-login/mgt-login.ts
@@ -55,11 +55,11 @@ type PersonViewConfig = {
* @class MgtLogin
* @extends {MgtBaseComponent}
*
- * @fires loginInitiated - Fired when login is initiated by the user
- * @fires loginCompleted - Fired when login completes
- * @fires loginFailed - Fired when login fails
- * @fires logoutInitiated - Fired when logout is initiated by the user
- * @fires logoutCompleted - Fired when logout completed
+ * @fires {CustomEvent} loginInitiated - Fired when login is initiated by the user
+ * @fires {CustomEvent} loginCompleted - Fired when login completes
+ * @fires {CustomEvent} loginFailed - Fired when login fails
+ * @fires {CustomEvent} logoutInitiated - Fired when logout is initiated by the user
+ * @fires {CustomEvent} logoutCompleted - Fired when logout completed
*
* @template signed-in-button-content (dataContext: {personDetails, personImage})
* @template signed-out-button-content (dataContext: null)
diff --git a/packages/mgt-components/src/components/mgt-people-picker/mgt-people-picker.ts b/packages/mgt-components/src/components/mgt-people-picker/mgt-people-picker.ts
index dbaf403d13..824e5ee4e7 100644
--- a/packages/mgt-components/src/components/mgt-people-picker/mgt-people-picker.ts
+++ b/packages/mgt-components/src/components/mgt-people-picker/mgt-people-picker.ts
@@ -68,7 +68,7 @@ interface IFocusable {
* @class MgtPicker
* @extends {MgtTemplatedComponent}
*
- * @fires selectionChanged - Fired when selection changes
+ * @fires {CustomEvent} selectionChanged - Fired when set of selected people changes
*
* @cssprop --color - {Color} Default font color
*
diff --git a/packages/mgt-components/src/components/mgt-person-card/mgt-person-card.ts b/packages/mgt-components/src/components/mgt-person-card/mgt-person-card.ts
index b4c60506d4..0fcd4a410d 100644
--- a/packages/mgt-components/src/components/mgt-person-card/mgt-person-card.ts
+++ b/packages/mgt-components/src/components/mgt-person-card/mgt-person-card.ts
@@ -65,7 +65,7 @@ type HoverStatesActions = 'email' | 'chat' | 'video' | 'call';
* @class MgtPersonCard
* @extends {MgtTemplatedComponent}
*
- * @fires expanded - Fired when expanded details section is opened
+ * @fires {CustomEvent} expanded - Fired when expanded details section is opened
*
* @cssprop --person-card-display-name-font-size - {Length} Font size of display name title
* @cssprop --person-card-display-name-line-height - {Length} Line height of display name
@@ -784,26 +784,26 @@ export class MgtPersonCard extends MgtTemplatedComponent {
});
return html`
- this.handleSectionScroll(e)}
+ this.handleSectionScroll(e)}
+ >
+ this.updateCurrentSection(null)}"
+ @click=${() => this.updateCurrentSection(null)}
>
- this.updateCurrentSection(null)}"
- @click=${() => this.updateCurrentSection(null)}
- >
- ${getSvg(SvgIcon.Overview)}
-
- ${additionalSectionTemplates}
-
- ${!this._currentSection ? this.renderOverviewSection() : null}
-
- ${additionalPanelTemplates}
-
- `;
+ ${getSvg(SvgIcon.Overview)}
+
+ ${additionalSectionTemplates}
+
+ ${!this._currentSection ? this.renderOverviewSection() : null}
+
+ ${additionalPanelTemplates}
+
+ `;
}
/**
diff --git a/packages/mgt-components/src/components/mgt-person/mgt-person.ts b/packages/mgt-components/src/components/mgt-person/mgt-person.ts
index 3ed2371e13..0dc0fe8b15 100644
--- a/packages/mgt-components/src/components/mgt-person/mgt-person.ts
+++ b/packages/mgt-components/src/components/mgt-person/mgt-person.ts
@@ -53,10 +53,10 @@ const defaultPersonProperties = [
* @class MgtPerson
* @extends {MgtTemplatedComponent}
*
- * @fires line1clicked - Fired when line1 is clicked
- * @fires line2clicked - Fired when line2 is clicked
- * @fires line3clicked - Fired when line3 is clicked
- * @fires line4clicked - Fired when line4 is clicked
+ * @fires {CustomEvent} line1clicked - Fired when line1 is clicked
+ * @fires {CustomEvent} line2clicked - Fired when line2 is clicked
+ * @fires {CustomEvent} line3clicked - Fired when line3 is clicked
+ * @fires {CustomEvent} line4clicked - Fired when line4 is clicked
*
* @cssprop --avatar-size - {Length} Avatar size
* @cssprop --avatar-border - {String} Avatar border
diff --git a/packages/mgt-components/src/components/mgt-tasks/mgt-tasks.ts b/packages/mgt-components/src/components/mgt-tasks/mgt-tasks.ts
index 19879e3c4e..7453df770a 100644
--- a/packages/mgt-components/src/components/mgt-tasks/mgt-tasks.ts
+++ b/packages/mgt-components/src/components/mgt-tasks/mgt-tasks.ts
@@ -134,10 +134,10 @@ const plannerAssignment = {
* @class MgtTasks
* @extends {MgtBaseComponent}
*
- * @fires taskAdded - Fires when a new task has been created.
- * @fires taskChanged - Fires when task metadata has been changed, such as marking completed.
- * @fires taskClick - Fires when the user clicks or taps on a task.
- * @fires taskRemoved - Fires when an existing task has been deleted.
+ * @fires {CustomEvent} taskAdded - Fires when a new task has been created.
+ * @fires {CustomEvent} taskChanged - Fires when task metadata has been changed, such as marking completed.
+ * @fires {CustomEvent} taskClick - Fires when the user clicks or taps on a task.
+ * @fires {CustomEvent} taskRemoved - Fires when an existing task has been deleted.
*
* @cssprop --tasks-header-padding - {String} Tasks header padding
* @cssprop --tasks-header-margin - {String} Tasks header margin
@@ -224,7 +224,7 @@ export class MgtTasks extends MgtTemplatedComponent {
*
* @memberof MgtTasks
*/
- public get isNewTaskVisible() {
+ public get isNewTaskVisible(): boolean {
return this._isNewTaskVisible;
}
@@ -650,8 +650,8 @@ export class MgtTasks extends MgtTemplatedComponent {
} as ITask;
this._newTaskBeingAdded = true;
- const task = await ts.addTask(newTask);
- this.fireCustomEvent('taskAdded', task);
+ newTask._raw = await ts.addTask(newTask);
+ this.fireCustomEvent('taskAdded', newTask);
await this.requestStateUpdate();
this._newTaskBeingAdded = false;
@@ -1334,7 +1334,7 @@ export class MgtTasks extends MgtTemplatedComponent {
private handleTaskClick(task: ITask) {
if (task) {
- this.fireCustomEvent('taskClick', { task: task._raw });
+ this.fireCustomEvent('taskClick', task);
}
}
@@ -1478,3 +1478,5 @@ export class MgtTasks extends MgtTemplatedComponent {
return null;
}
}
+
+export { ITask };
diff --git a/packages/mgt-components/src/components/mgt-tasks/task-sources.ts b/packages/mgt-components/src/components/mgt-tasks/task-sources.ts
index 894d5c161a..de912dd5be 100644
--- a/packages/mgt-components/src/components/mgt-tasks/task-sources.ts
+++ b/packages/mgt-components/src/components/mgt-tasks/task-sources.ts
@@ -32,7 +32,7 @@ import {
} from './mgt-tasks.graph.todo';
/**
- * Itask
+ * ITask
*
* @export
* @interface ITask
@@ -611,7 +611,7 @@ export class TodoTaskSource extends TaskSourceBase implements ITaskSource {
* @returns {Promise}
* @memberof TodoTaskSource
*/
- public async addTask(newTask: ITask): Promise {
+ public async addTask(newTask: ITask): Promise {
const task = {
parentFolderId: newTask.immediateParentId,
subject: newTask.name
diff --git a/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.ts b/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.ts
index ba4e7f9849..2079146046 100644
--- a/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.ts
+++ b/packages/mgt-components/src/components/mgt-teams-channel-picker/mgt-teams-channel-picker.ts
@@ -139,7 +139,7 @@ export interface MgtTeamsChannelPickerConfig {
* @class MgtTeamsChannelPicker
* @extends {MgtTemplatedComponent}
*
- * @fires selectionChanged - Fired when the selection changes
+ * @fires {CustomEvent} selectionChanged - Fired when the selection changes
*
* @cssprop --color - {font} Default font color
*
@@ -199,7 +199,7 @@ export class MgtTeamsChannelPicker extends MgtTemplatedComponent {
* @type {SelectedChannel}
* @memberof MgtTeamsChannelPicker
*/
- public get selectedItem(): SelectedChannel {
+ public get selectedItem(): SelectedChannel | null {
if (this._selectedItemState) {
return { channel: this._selectedItemState.item, team: this._selectedItemState.parent.item };
} else {
@@ -896,7 +896,7 @@ export class MgtTeamsChannelPicker extends MgtTemplatedComponent {
private selectChannel(item: ChannelPickerItemState) {
if (this._selectedItemState !== item) {
this._selectedItemState = item;
- this.fireCustomEvent('selectionChanged', item ? [this.selectedItem] : []);
+ this.fireCustomEvent('selectionChanged', this.selectedItem);
}
const input = this._input;
diff --git a/packages/mgt-components/src/components/mgt-todo/mgt-todo.ts b/packages/mgt-components/src/components/mgt-todo/mgt-todo.ts
index 361540d712..25dc71602e 100644
--- a/packages/mgt-components/src/components/mgt-todo/mgt-todo.ts
+++ b/packages/mgt-components/src/components/mgt-todo/mgt-todo.ts
@@ -29,10 +29,9 @@ import {
import { styles } from './mgt-todo-css';
import { strings } from './strings';
-/*
+/**
* Filter function
*/
-// tslint:disable-next-line: completed-docs
export type TodoFilter = (task: TodoTask) => boolean;
/**
diff --git a/packages/mgt-element/src/components/templatedComponent.ts b/packages/mgt-element/src/components/templatedComponent.ts
index 3471f88810..45424ff061 100644
--- a/packages/mgt-element/src/components/templatedComponent.ts
+++ b/packages/mgt-element/src/components/templatedComponent.ts
@@ -29,6 +29,14 @@ interface RenderedTemplates {
};
}
+// tslint:disable: completed-docs
+export interface TemplateRenderedData {
+ templateType: string;
+ context: Record;
+ element: HTMLElement;
+}
+// tslint:enable: completed-docs
+
/**
* An abstract class that defines a templatable web component
*
@@ -37,7 +45,7 @@ interface RenderedTemplates {
* @class MgtTemplatedComponent
* @extends {MgtBaseComponent}
*
- * @fires templateRendered - fires when a template is rendered
+ * @fires {CustomEvent} templateRendered - fires when a template is rendered
*/
export abstract class MgtTemplatedComponent extends MgtBaseComponent {
/**
@@ -135,7 +143,8 @@ export abstract class MgtTemplatedComponent extends MgtBaseComponent {
this._renderedTemplates[slotName] = { context: dataContext, slot: div };
- this.fireCustomEvent('templateRendered', { templateType, context: dataContext, element: div });
+ const templateRenderedData: TemplateRenderedData = { templateType, context: dataContext, element: div };
+ this.fireCustomEvent('templateRendered', templateRenderedData);
return template;
}
diff --git a/packages/mgt-react/package.json b/packages/mgt-react/package.json
index 017e32f47b..043615b148 100644
--- a/packages/mgt-react/package.json
+++ b/packages/mgt-react/package.json
@@ -28,7 +28,8 @@
"build": "npm run clean && npm run generate && tsc",
"clean": "node ./scripts/clean.js",
"postpack": "cpx *.tgz ../../artifacts",
- "generate": "wca analyze ../mgt-components/src --format json --outFile temp/web-components.json && node ./scripts/generate.js"
+ "analyze": "custom-elements-manifest analyze --litelement --globs \"../*/src/**/*.ts\" --outdir temp",
+ "generate": "npm run analyze && node ./scripts/generate.js"
},
"dependencies": {
"@microsoft/mgt-components": "*",
diff --git a/packages/mgt-react/scripts/generate.js b/packages/mgt-react/scripts/generate.js
index 82ba113e09..6bc2741c2e 100644
--- a/packages/mgt-react/scripts/generate.js
+++ b/packages/mgt-react/scripts/generate.js
@@ -1,8 +1,8 @@
var fs = require('fs-extra');
-let wc = JSON.parse(fs.readFileSync(`${__dirname}/../temp/web-components.json`));
+let wc = JSON.parse(fs.readFileSync(`${__dirname}/../temp/custom-elements.json`));
-const primitives = new Set(['string', 'boolean', 'number', 'any']);
+const primitives = new Set(['string', 'boolean', 'number', 'any', 'void', 'null', 'undefined']);
const mgtComponentImports = new Set();
const mgtElementImports = new Set();
@@ -25,29 +25,65 @@ let output = '';
const wrappers = [];
-for (const tag of wc.tags) {
- if (!tags.has(tag.name)) {
- continue;
+const customTags = [];
+for (const module of wc.modules) {
+ for (const d of module.declarations) {
+ if (d.customElement && d.tagName && tags.has(d.tagName)) {
+ customTags.push(d);
+ }
+ }
+}
+
+const removeGenericTypeDecoration = type => {
+ if (type.endsWith('[]')) {
+ return type.substring(0, type.length - 2);
+ } else if (type.startsWith('Array<')) {
+ return removeGenericTypeDecoration(type.substring(6, type.length - 1));
+ } else if (type.startsWith('CustomEvent<')) {
+ return removeGenericTypeDecoration(type.substring(12, type.length - 1));
+ }
+ return type;
+};
+
+const addTypeToImports = type => {
+ if (type === '*') {
+ return;
+ }
+ // make sure to remove any generic type decorations before trying to split for union types
+ type = removeGenericTypeDecoration(type);
+ for (let t of type.split('|')) {
+ t = removeGenericTypeDecoration(t.trim());
+ if (t.startsWith('MicrosoftGraph.') || t.startsWith('MicrosoftGraphBeta.')) {
+ return;
+ }
+
+ if (t.startsWith('MgtElement.') && !mgtElementImports.has(t)) {
+ mgtElementImports.add(t.split('.')[1]);
+ } else if (!primitives.has(t) && !mgtComponentImports.has(t)) {
+ mgtComponentImports.add(t);
+ }
}
+};
- const className = tag.name
+for (const tag of customTags.sort((a, b) => (a.tagName > b.tagName ? 1 : -1))) {
+ const className = tag.tagName
.split('-')
.map(t => t[0].toUpperCase() + t.substring(1))
.join('');
wrappers.push({
- tag: tag.name,
+ tag: tag.tagName,
propsType: className + 'Props',
className: className
});
const props = {};
- for (let i = 0; i < tag.properties.length; ++i) {
- const prop = tag.properties[i];
- let type = prop.type;
+ for (let i = 0; i < tag.members.length; ++i) {
+ const prop = tag.members[i];
+ let type = prop.type?.text;
- if (type) {
+ if (type && prop.kind === 'field' && prop.privacy === 'public' && !prop.static) {
if (prop.name) {
props[prop.name] = type;
}
@@ -55,30 +91,16 @@ for (const tag of wc.tags) {
if (type.includes('|')) {
const types = type.split('|');
for (const t of types) {
- tag.properties.push({
- type: t.trim()
+ tag.members.push({
+ kind: 'field',
+ privacy: 'public',
+ type: { text: t.trim() }
});
}
continue;
}
- if (type.endsWith('[]')) {
- type = type.substring(0, type.length - 2);
- } else if (type.startsWith('Array<')) {
- type = type.substring(6, type.length - 1);
- } else if (type === '*') {
- continue;
- }
-
- if (type.startsWith('MicrosoftGraph.') || type.startsWith('MicrosoftGraphBeta.')) {
- continue;
- }
-
- if (type.startsWith('MgtElement.') && !mgtElementImports.has(type)) {
- mgtElementImports.add(type.split('.')[1]);
- } else if (!primitives.has(type) && !mgtComponentImports.has(type)) {
- mgtComponentImports.add(type);
- }
+ addTypeToImports(type);
}
}
@@ -94,7 +116,17 @@ for (const tag of wc.tags) {
if (tag.events) {
for (const event of tag.events) {
- propsType += `\t${event.name}?: (e: Event) => void;\n`;
+ if (event.type && event.type.text) {
+ // remove MgtElement. prefix as this it only used to ensure it's imported from the correct package
+ propsType += `\t${event.name}?: (e: ${event.type.text.replace(
+ 'CustomEvent void;\n`;
+ // also ensure that the necessary import is added to either mgt-element or mgt-component imports
+ addTypeToImports(event.type.text);
+ } else {
+ propsType += `\t${event.name}?: (e: Event) => void;\n`;
+ }
}
}
diff --git a/packages/mgt-react/src/generated/react.ts b/packages/mgt-react/src/generated/react.ts
index 3cb64475e6..580e1fbdbf 100644
--- a/packages/mgt-react/src/generated/react.ts
+++ b/packages/mgt-react/src/generated/react.ts
@@ -1,5 +1,5 @@
-import { OfficeGraphInsightString,ViewType,ResponseType,IDynamicPerson,LoginViewType,PersonType,GroupType,UserType,PersonCardInteraction,MgtPersonConfig,AvatarSize,PersonViewType,TasksStringResource,TasksSource,TaskFilter,SelectedChannel,TodoFilter } from '@microsoft/mgt-components';
-import { TemplateContext,ComponentMediaQuery } from '@microsoft/mgt-element';
+import { OfficeGraphInsightString,ViewType,ResponseType,DataChangedDetail,IDynamicPerson,LoginViewType,PersonCardInteraction,PersonType,GroupType,UserType,AvatarSize,PersonViewType,TasksStringResource,TasksSource,TaskFilter,ITask,SelectedChannel,TodoFilter } from '@microsoft/mgt-components';
+import { TemplateContext,ComponentMediaQuery,TemplateRenderedData } from '@microsoft/mgt-element';
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
import * as MicrosoftGraphBeta from '@microsoft/microsoft-graph-types-beta';
import {wrapMgt} from '../Mgt';
@@ -15,33 +15,8 @@ export type AgendaProps = {
preferredTimezone?: string;
templateContext?: TemplateContext;
mediaQuery?: ComponentMediaQuery;
- eventClick?: (e: Event) => void;
- templateRendered?: (e: Event) => void;
-}
-
-export type FileListProps = {
- fileListQuery?: string;
- fileQueries?: string[];
- files?: MicrosoftGraph.DriveItem[];
- siteId?: string;
- driveId?: string;
- groupId?: string;
- itemId?: string;
- itemPath?: string;
- userId?: string;
- insightType?: OfficeGraphInsightString;
- fileExtensions?: string[];
- hideMoreFilesButton?: boolean;
- maxFileSize?: number;
- excludedFileExtensions?: string[];
- pageSize?: number;
- itemView?: ViewType;
- maxUploadFile?: number;
- enableFileUpload?: boolean;
- templateContext?: TemplateContext;
- mediaQuery?: ComponentMediaQuery;
- itemClick?: (e: Event) => void;
- templateRendered?: (e: Event) => void;
+ eventClick?: (e: CustomEvent) => void;
+ templateRendered?: (e: CustomEvent) => void;
}
export type FileProps = {
@@ -64,7 +39,32 @@ export type FileProps = {
view?: ViewType;
templateContext?: TemplateContext;
mediaQuery?: ComponentMediaQuery;
- templateRendered?: (e: Event) => void;
+ templateRendered?: (e: CustomEvent) => void;
+}
+
+export type FileListProps = {
+ fileListQuery?: string;
+ fileQueries?: string[];
+ files?: MicrosoftGraph.DriveItem[];
+ siteId?: string;
+ driveId?: string;
+ groupId?: string;
+ itemId?: string;
+ itemPath?: string;
+ userId?: string;
+ insightType?: OfficeGraphInsightString;
+ itemView?: ViewType;
+ fileExtensions?: string[];
+ pageSize?: number;
+ hideMoreFilesButton?: boolean;
+ maxFileSize?: number;
+ enableFileUpload?: boolean;
+ maxUploadFile?: number;
+ excludedFileExtensions?: string[];
+ templateContext?: TemplateContext;
+ mediaQuery?: ComponentMediaQuery;
+ itemClick?: (e: CustomEvent) => void;
+ templateRendered?: (e: CustomEvent) => void;
}
export type GetProps = {
@@ -76,10 +76,12 @@ export type GetProps = {
pollingRate?: number;
cacheEnabled?: boolean;
cacheInvalidationPeriod?: number;
+ response?: any;
+ error?: any;
templateContext?: TemplateContext;
mediaQuery?: ComponentMediaQuery;
- dataChange?: (e: Event) => void;
- templateRendered?: (e: Event) => void;
+ dataChange?: (e: CustomEvent) => void;
+ templateRendered?: (e: CustomEvent) => void;
}
export type LoginProps = {
@@ -88,12 +90,29 @@ export type LoginProps = {
loginView?: LoginViewType;
templateContext?: TemplateContext;
mediaQuery?: ComponentMediaQuery;
- loginInitiated?: (e: Event) => void;
- loginCompleted?: (e: Event) => void;
- loginFailed?: (e: Event) => void;
- logoutInitiated?: (e: Event) => void;
- logoutCompleted?: (e: Event) => void;
- templateRendered?: (e: Event) => void;
+ loginInitiated?: (e: CustomEvent) => void;
+ loginCompleted?: (e: CustomEvent) => void;
+ loginFailed?: (e: CustomEvent) => void;
+ logoutInitiated?: (e: CustomEvent) => void;
+ logoutCompleted?: (e: CustomEvent) => void;
+ templateRendered?: (e: CustomEvent) => void;
+}
+
+export type PeopleProps = {
+ groupId?: string;
+ userIds?: string[];
+ people?: IDynamicPerson[];
+ peopleQueries?: string[];
+ showMax?: number;
+ showPresence?: boolean;
+ personCardInteraction?: PersonCardInteraction;
+ resource?: string;
+ version?: string;
+ scopes?: string[];
+ fallbackDetails?: IDynamicPerson[];
+ templateContext?: TemplateContext;
+ mediaQuery?: ComponentMediaQuery;
+ templateRendered?: (e: CustomEvent) => void;
}
export type PeoplePickerProps = {
@@ -104,70 +123,38 @@ export type PeoplePickerProps = {
userType?: UserType;
transitiveSearch?: boolean;
people?: IDynamicPerson[];
+ showMax?: number;
+ disableImages?: boolean;
selectedPeople?: IDynamicPerson[];
defaultSelectedUserIds?: string[];
defaultSelectedGroupIds?: string[];
placeholder?: string;
+ disabled?: boolean;
+ allowAnyEmail?: boolean;
selectionMode?: string;
userIds?: string[];
userFilters?: string;
peopleFilters?: string;
groupFilters?: string;
ariaLabel?: string;
- showMax?: number;
- disableImages?: boolean;
- disabled?: boolean;
- allowAnyEmail?: boolean;
- templateContext?: TemplateContext;
- mediaQuery?: ComponentMediaQuery;
- selectionChanged?: (e: Event) => void;
- templateRendered?: (e: Event) => void;
-}
-
-export type PeopleProps = {
- groupId?: string;
- userIds?: string[];
- people?: IDynamicPerson[];
- peopleQueries?: string[];
- showPresence?: boolean;
- personCardInteraction?: PersonCardInteraction;
- resource?: string;
- version?: string;
- scopes?: string[];
- fallbackDetails?: IDynamicPerson[];
- showMax?: number;
- templateContext?: TemplateContext;
- mediaQuery?: ComponentMediaQuery;
- templateRendered?: (e: Event) => void;
-}
-
-export type PersonCardProps = {
- personDetails?: IDynamicPerson;
- personQuery?: string;
- lockTabNavigation?: boolean;
- userId?: string;
- personImage?: string;
- fetchImage?: boolean;
- isExpanded?: boolean;
- inheritDetails?: boolean;
- showPresence?: boolean;
- personPresence?: MicrosoftGraph.Presence;
templateContext?: TemplateContext;
mediaQuery?: ComponentMediaQuery;
- expanded?: (e: Event) => void;
- templateRendered?: (e: Event) => void;
+ selectionChanged?: (e: CustomEvent) => void;
+ templateRendered?: (e: CustomEvent) => void;
}
export type PersonProps = {
- config?: MgtPersonConfig;
personQuery?: string;
fallbackDetails?: IDynamicPerson;
userId?: string;
usage?: string;
showPresence?: boolean;
+ avatarSize?: AvatarSize;
personDetails?: IDynamicPerson;
personImage?: string;
fetchImage?: boolean;
+ disableImageFetch?: boolean;
+ verticalLayout?: boolean;
avatarType?: string;
personPresence?: MicrosoftGraph.Presence;
personCardInteraction?: PersonCardInteraction;
@@ -176,16 +163,30 @@ export type PersonProps = {
line3Property?: string;
line4Property?: string;
view?: ViewType | PersonViewType;
- avatarSize?: AvatarSize;
- disableImageFetch?: boolean;
- verticalLayout?: boolean;
templateContext?: TemplateContext;
mediaQuery?: ComponentMediaQuery;
- line1clicked?: (e: Event) => void;
- line2clicked?: (e: Event) => void;
- line3clicked?: (e: Event) => void;
- line4clicked?: (e: Event) => void;
- templateRendered?: (e: Event) => void;
+ line1clicked?: (e: CustomEvent) => void;
+ line2clicked?: (e: CustomEvent) => void;
+ line3clicked?: (e: CustomEvent) => void;
+ line4clicked?: (e: CustomEvent) => void;
+ templateRendered?: (e: CustomEvent) => void;
+}
+
+export type PersonCardProps = {
+ personDetails?: IDynamicPerson;
+ personQuery?: string;
+ lockTabNavigation?: boolean;
+ userId?: string;
+ personImage?: string;
+ fetchImage?: boolean;
+ isExpanded?: boolean;
+ inheritDetails?: boolean;
+ showPresence?: boolean;
+ personPresence?: MicrosoftGraph.Presence;
+ templateContext?: TemplateContext;
+ mediaQuery?: ComponentMediaQuery;
+ expanded?: (e: CustomEvent) => void;
+ templateRendered?: (e: CustomEvent) => void;
}
export type TasksProps = {
@@ -203,19 +204,19 @@ export type TasksProps = {
taskFilter?: TaskFilter;
templateContext?: TemplateContext;
mediaQuery?: ComponentMediaQuery;
- taskAdded?: (e: Event) => void;
- taskChanged?: (e: Event) => void;
- taskClick?: (e: Event) => void;
- taskRemoved?: (e: Event) => void;
- templateRendered?: (e: Event) => void;
+ taskAdded?: (e: CustomEvent) => void;
+ taskChanged?: (e: CustomEvent) => void;
+ taskClick?: (e: CustomEvent) => void;
+ taskRemoved?: (e: CustomEvent) => void;
+ templateRendered?: (e: CustomEvent) => void;
}
export type TeamsChannelPickerProps = {
selectedItem?: SelectedChannel;
templateContext?: TemplateContext;
mediaQuery?: ComponentMediaQuery;
- selectionChanged?: (e: Event) => void;
- templateRendered?: (e: Event) => void;
+ selectionChanged?: (e: CustomEvent) => void;
+ templateRendered?: (e: CustomEvent) => void;
}
export type TodoProps = {
@@ -227,27 +228,27 @@ export type TodoProps = {
initialId?: string;
templateContext?: TemplateContext;
mediaQuery?: ComponentMediaQuery;
- templateRendered?: (e: Event) => void;
+ templateRendered?: (e: CustomEvent) => void;
}
export const Agenda = wrapMgt('agenda');
-export const FileList = wrapMgt('file-list');
-
export const File = wrapMgt('file');
+export const FileList = wrapMgt('file-list');
+
export const Get = wrapMgt('get');
export const Login = wrapMgt('login');
-export const PeoplePicker = wrapMgt('people-picker');
-
export const People = wrapMgt('people');
-export const PersonCard = wrapMgt('person-card');
+export const PeoplePicker = wrapMgt('people-picker');
export const Person = wrapMgt('person');
+export const PersonCard = wrapMgt('person-card');
+
export const Tasks = wrapMgt('tasks');
export const TeamsChannelPicker = wrapMgt('teams-channel-picker');
diff --git a/stories/components/agenda/agenda.a.js b/stories/components/agenda/agenda.a.js
index 12aa5573ec..e7a96981fc 100644
--- a/stories/components/agenda/agenda.a.js
+++ b/stories/components/agenda/agenda.a.js
@@ -7,15 +7,18 @@
import { html } from 'lit';
import { withCodeEditor } from '../../../.storybook/addons/codeEditorAddon/codeAddon';
-import { versionInfo } from '../../versionInfo';
+import { defaultDocsPage } from '../../../.storybook/story-elements/defaultDocsPage';
export default {
- parameters: {
- version: versionInfo
- },
title: 'Components / mgt-agenda',
- component: 'mgt-agenda',
- decorators: [withCodeEditor]
+ component: 'agenda',
+ decorators: [withCodeEditor],
+ parameters: {
+ docs: {
+ page: defaultDocsPage,
+ source: { code: '' }
+ }
+ }
};
export const simple = () => html`
@@ -30,7 +33,7 @@ export const events = () => html`
`;
@@ -40,3 +43,14 @@ export const RTL = () => html`
+
+