diff --git a/index.html b/index.html index a122125e07..8802061130 100644 --- a/index.html +++ b/index.html @@ -72,7 +72,7 @@

Developer test page

mgt-login

- + +

mgt-file-composite

+ +
diff --git a/packages/mgt-components/package.json b/packages/mgt-components/package.json index 102f9a77c9..28a918f7f1 100644 --- a/packages/mgt-components/package.json +++ b/packages/mgt-components/package.json @@ -40,7 +40,7 @@ "@microsoft/microsoft-graph-client": "^3.0.0", "@microsoft/microsoft-graph-types": "^2.0.0", "@microsoft/microsoft-graph-types-beta": "^0.16.0-preview", - "@fluentui/web-components": "^2.5.3", + "@fluentui/web-components": "^2.5.12", "office-ui-fabric-core": "^11.0.0" }, "publishConfig": { diff --git a/packages/mgt-components/src/__mocks__/mock-media-match.ts b/packages/mgt-components/src/__mocks__/mock-media-match.ts new file mode 100644 index 0000000000..5fba089791 --- /dev/null +++ b/packages/mgt-components/src/__mocks__/mock-media-match.ts @@ -0,0 +1,20 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn() + })) +}); diff --git a/packages/mgt-components/src/components/components.ts b/packages/mgt-components/src/components/components.ts index 3fcc390222..bd3f587cd4 100644 --- a/packages/mgt-components/src/components/components.ts +++ b/packages/mgt-components/src/components/components.ts @@ -19,11 +19,13 @@ import './mgt-person/mgt-person-types'; import './mgt-tasks/mgt-tasks'; import './mgt-teams-channel-picker/mgt-teams-channel-picker'; import './mgt-todo/mgt-todo'; +import './mgt-breadcrumb/mgt-breadcrumb'; import './mgt-contact/mgt-contact'; import './mgt-messages/mgt-messages'; import './mgt-organization/mgt-organization'; import './mgt-profile/mgt-profile'; import './mgt-theme-toggle/mgt-theme-toggle'; +import './mgt-file-composite/mgt-file-composite'; export * from './mgt-agenda/mgt-agenda'; export * from './mgt-file/mgt-file'; @@ -39,9 +41,11 @@ export * from './mgt-person/mgt-person-types'; export * from './mgt-tasks/mgt-tasks'; export * from './mgt-teams-channel-picker/mgt-teams-channel-picker'; export * from './mgt-todo/mgt-todo'; +export * from './mgt-breadcrumb/mgt-breadcrumb'; export * from './mgt-contact/mgt-contact'; export * from './mgt-contact/mgt-contact'; export * from './mgt-messages/mgt-messages'; export * from './mgt-organization/mgt-organization'; export * from './mgt-profile/mgt-profile'; export * from './mgt-theme-toggle/mgt-theme-toggle'; +export * from './mgt-file-composite/mgt-file-composite'; diff --git a/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.scss b/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.scss new file mode 100644 index 0000000000..f341d4d3f3 --- /dev/null +++ b/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.scss @@ -0,0 +1,33 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + +@import '../../../../../node_modules/office-ui-fabric-core/dist/sass/References'; +@import '../../styles/shared-styles.scss'; +@import './mgt-breadcrumb.theme.scss'; + +:host { + --type-ramp-base-font-size: var(--breadcrumb-base-font-size, 18px); + --type-ramp-base-line-height: var(--breadcrumb-base-line-height, 36px); + + &::part(crumb), + &::part(control) { + padding: 0 calc((10 + (var(--design-unit) * 2 * var(--density))) * 1px); + } + + &::part(crumb) { + font-weight: 600; + } + &::part(control) { + background-color: var(--neutral-fill-rest); + background: var(--neutral-fill-rest); + padding: 0 calc((10 + (var(--design-unit) * 2 * var(--density))) * 1px); + &:hover { + background-color: var(--neutral-fill-stealth-hover); + background: var(--neutral-fill-stealth-hover); + } + } +} diff --git a/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.tests.ts b/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.tests.ts new file mode 100644 index 0000000000..26f709e3b1 --- /dev/null +++ b/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.tests.ts @@ -0,0 +1,212 @@ +import '../../__mocks__/mock-media-match'; +import { screen } from 'testing-library__dom'; +import userEvent from '@testing-library/user-event'; +import { fixture } from '@open-wc/testing-helpers'; +import './mgt-breadcrumb'; +import { BreadcrumbInfo, MgtBreadcrumb } from './mgt-breadcrumb'; + +describe('mgt-breadcrumb - tests', () => { + it('should render', async () => { + const component = await fixture(` + + `); + expect(component).toBeDefined(); + }); + it('should render with a single node', async () => { + const component: MgtBreadcrumb = await fixture(` + + `); + component.breadcrumb = [ + { + id: 'root-item', + name: 'root-item' + } + ]; + await component.updateComplete; + const listItems = await screen.findAllByRole('listitem'); + expect(listItems?.length).toBe(1); + const root = await screen.findByText('root-item'); + expect(root).toBeDefined(); + }); + it('should render with three nodes', async () => { + const component: MgtBreadcrumb = await fixture(` + + `); + component.breadcrumb = [ + { + id: '0', + name: 'root-item' + }, + { + id: '1', + name: 'node-1' + }, + { + id: '2', + name: 'node-2' + } + ]; + await component.updateComplete; + const listItems = await screen.findAllByRole('listitem'); + expect(listItems?.length).toBe(3); + const root = await screen.findByText('root-item'); + expect(root).toBeDefined(); + + const buttons = await screen.findAllByRole('button'); + + expect(buttons?.length).toBe(2); + }); + + it('should emit a clicked event when a button is clicked', async () => { + const component: MgtBreadcrumb = await fixture(` + + `); + let eventEmitted; + component.addEventListener('breadcrumbclick', (e: CustomEvent) => { + eventEmitted = e.detail; + }); + + const rootNode = { + id: '0', + name: 'root-item' + }; + component.breadcrumb = [ + rootNode, + { + id: '1', + name: 'node-1' + } + ]; + await component.updateComplete; + + const buttons = await screen.findAllByRole('button'); + expect(buttons?.length).toBe(1); + + buttons[0].click(); + expect(eventEmitted).toBeDefined(); + expect(eventEmitted).toBe(rootNode); + }); + + it('should emit a clicked event when the enter button is pressed', async () => { + const user = userEvent.setup(); + const component: MgtBreadcrumb = await fixture(` + + `); + let eventEmitted; + component.addEventListener('breadcrumbclick', (e: CustomEvent) => { + eventEmitted = e.detail; + }); + + const rootNode = { + id: '0', + name: 'root-item' + }; + component.breadcrumb = [ + rootNode, + { + id: '1', + name: 'node-1' + } + ]; + await component.updateComplete; + + const buttons = await screen.findAllByRole('button'); + expect(buttons?.length).toBe(1); + buttons[0].focus(); + + await user.keyboard('{Enter}'); + expect(eventEmitted).toBeDefined(); + expect(eventEmitted).toBe(rootNode); + }); + + it('should emit a clicked event when the space button is pressed', async () => { + const user = userEvent.setup(); + const component: MgtBreadcrumb = await fixture(` + + `); + let eventEmitted; + component.addEventListener('breadcrumbclick', (e: CustomEvent) => { + eventEmitted = e.detail; + }); + + const rootNode = { + id: '0', + name: 'root-item' + }; + component.breadcrumb = [ + rootNode, + { + id: '1', + name: 'node-1' + } + ]; + await component.updateComplete; + + const buttons = await screen.findAllByRole('button'); + expect(buttons?.length).toBe(1); + buttons[0].focus(); + + await user.keyboard(' '); + expect(eventEmitted).toBeDefined(); + expect(eventEmitted).toBe(rootNode); + }); + + it('should not emit a clicked event when a regular character button is pressed', async () => { + const user = userEvent.setup(); + const component: MgtBreadcrumb = await fixture(` + + `); + let eventEmitted; + component.addEventListener('breadcrumbclick', (e: CustomEvent) => { + eventEmitted = e.detail; + }); + + const rootNode = { + id: '0', + name: 'root-item' + }; + component.breadcrumb = [ + rootNode, + { + id: '1', + name: 'node-1' + } + ]; + await component.updateComplete; + + const buttons = await screen.findAllByRole('button'); + expect(buttons?.length).toBe(1); + buttons[0].focus(); + + await user.keyboard('r'); + expect(eventEmitted).toBeUndefined(); + }); + + it('should not emit a clicked event when the last node is clicked', async () => { + const component: MgtBreadcrumb = await fixture(` + + `); + let eventEmitted; + component.addEventListener('breadcrumbclick', (e: CustomEvent) => { + eventEmitted = e.detail; + }); + + const rootNode = { + id: '0', + name: 'root-item' + }; + component.breadcrumb = [ + rootNode, + { + id: '1', + name: 'node-1' + } + ]; + await component.updateComplete; + + const notButton = await screen.findByText('node-1'); + notButton.click(); + + expect(eventEmitted).toBeUndefined(); + }); +}); diff --git a/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.theme.scss b/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.theme.scss new file mode 100644 index 0000000000..19c6215d33 --- /dev/null +++ b/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.theme.scss @@ -0,0 +1,12 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + +@import '../../styles/shared-sass-variables.scss'; + +$breadcrumb: (); + +@include create-themes($breadcrumb); diff --git a/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.ts b/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.ts new file mode 100644 index 0000000000..abef3e911c --- /dev/null +++ b/packages/mgt-components/src/components/mgt-breadcrumb/mgt-breadcrumb.ts @@ -0,0 +1,116 @@ +import { html, TemplateResult } from 'lit'; +import { property } from 'lit/decorators.js'; +import { repeat } from 'lit/directives/repeat.js'; +import { fluentBreadcrumb, fluentBreadcrumbItem, fluentButton } from '@fluentui/web-components'; +import { registerFluentComponents } from '../../utils/FluentComponents'; +import { customElement, MgtBaseComponent } from '@microsoft/mgt-element'; +import { styles } from './mgt-breadcrumb-css'; + +registerFluentComponents(fluentButton, fluentBreadcrumb, fluentBreadcrumbItem); + +/** + * Defines a base type for breadcrumb data + */ +export type BreadcrumbInfo = { + /** + * unique identifier for the breadcrumb + * + * @type {string} + */ + id: string; + /** + * Name of the breadcrumb, used to display the item. + * + * @type {string} + */ + name: string; +}; + +/** + * Custom breadcrumb component + * + * @fires {CustomEvent} breadcrumbclick - Fired when a breadcrumb is clicked. Will not fire when the last breadcrumb is clicked. + * + * @cssprop --breadcrumb-base-font-size - {Length} Breadcrumb base font size. Default is 18px. + * @cssprop --breadcrumb-base-line-height - {Length} Breadcrumb line height. Default is 36px + * + * @export + * @class MgtBreadcrumb + * @extends {MgtBaseComponent} + */ +@customElement('breadcrumb') +export class MgtBreadcrumb extends MgtBaseComponent { + /** + * Array of styles to apply to the element. The styles should be defined + * using the `css` tag function. + */ + static get styles() { + return styles; + } + + private _breadcrumb: BreadcrumbInfo[] = []; + /** + * An array of nodes to show in the breadcrumb + * + * @type {BreadcrumbInfo[]} + * @readonly + * @memberof MgtFileList + */ + @property({ + attribute: false + }) + public get breadcrumb(): BreadcrumbInfo[] { + return this._breadcrumb; + } + public set breadcrumb(value: BreadcrumbInfo[]) { + this._breadcrumb = value; + // this is needed to trigger a re-render + this.requestUpdate(); + } + + private isLastCrumb = (b: BreadcrumbInfo): boolean => this.breadcrumb.indexOf(b) === this.breadcrumb.length - 1; + + /** + * Renders the component + * + * @return {*} {TemplateResult} + * @memberof MgtBreadcrumb + */ + public render(): TemplateResult { + return html` + + ${repeat( + this.breadcrumb, + b => b.id, + b => + !this.isLastCrumb(b) + ? html` + + this.handleBreadcrumbClick(b)} + > + ${b.name} + + + ` + : html` + + ${b.name} + + ` + )} + + `; + } + + private handleBreadcrumbClick(b: BreadcrumbInfo): void { + // last crumb does nothing + if (this.isLastCrumb(b)) return; + this.fireCustomEvent('breadcrumbclick', b); + } +} diff --git a/packages/mgt-components/src/components/mgt-file-composite/mgt-file-composite.ts b/packages/mgt-components/src/components/mgt-file-composite/mgt-file-composite.ts new file mode 100644 index 0000000000..89b2abe314 --- /dev/null +++ b/packages/mgt-components/src/components/mgt-file-composite/mgt-file-composite.ts @@ -0,0 +1,410 @@ +import { customElement, mgtHtml, MgtTemplatedComponent } from '@microsoft/mgt-element'; +import { DriveItem } from '@microsoft/microsoft-graph-types'; +import { html, nothing } from 'lit'; +import { property, state } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { OfficeGraphInsightString, ViewType } from '../../graph/types'; +import { BreadcrumbInfo } from '../mgt-breadcrumb/mgt-breadcrumb'; +import { strings } from './strings'; + +/** + * FileListBreadCrumb interface + */ +type FileListBreadCrumb = { + // tslint:disable: completed-docs + name: string; + fileListQuery?: string; + itemId?: string; + itemPath?: string; + files?: DriveItem[]; + fileQueries?: string[]; + groupId?: string; + driveId?: string; + siteId?: string; + userId?: string; + insightType?: OfficeGraphInsightString; + fileExtensions?: string[]; + // tslint:enable: completed-docs +} & BreadcrumbInfo; + +/** + * A File list composite component + * Provides a breadcrumb navigation to support folder navigation + * + * @class MgtFileComposite + * @extends {MgtTemplatedComponent} + */ +@customElement('file-composite') +class MgtFileComposite extends MgtTemplatedComponent { + constructor() { + super(); + } + + private _breadcrumbRootName: string = strings.rootNode; + /** + * Name to be used for the root node of the breadcrumb + * + * @type {string} + * @memberof MgtFileComposite + */ + @property({ + attribute: 'breadcrumb-root-name' + }) + public get breadcrumbRootName(): string { + return this._breadcrumbRootName; + } + public set breadcrumbRootName(value: string) { + this._breadcrumbRootName = value; + } + + /** + * allows developer to provide query for a file list + * + * @type {string} + * @memberof MgtFileList + */ + @property({ + attribute: 'file-list-query' + }) + public fileListQuery: string; + + /** + * allows developer to provide an array of file queries + * + * @type {string[]} + * @memberof MgtFileList + */ + @property({ + attribute: 'file-queries', + converter: (value, type) => { + if (value) { + return value.split(',').map(v => v.trim()); + } else { + return null; + } + } + }) + public fileQueries: string[]; + + /** + * allows developer to provide an array of files + * + * @type {MicrosoftGraph.DriveItem[]} + * @memberof MgtFileList + */ + @property({ type: Object }) + public files: DriveItem[]; + + /** + * allows developer to provide site id for a file + * + * @type {string} + * @memberof MgtFileList + */ + @property({ + attribute: 'site-id' + }) + public siteId: string; + + /** + * allows developer to provide drive id for a file + * + * @type {string} + * @memberof MgtFileList + */ + @property({ + attribute: 'drive-id' + }) + public driveId: string; + + /** + * allows developer to provide group id for a file + * + * @type {string} + * @memberof MgtFileList + */ + @property({ + attribute: 'group-id' + }) + public groupId: string; + + /** + * allows developer to provide item id for a file + * + * @type {string} + * @memberof MgtFileList + */ + @property({ + attribute: 'item-id' + }) + public itemId: string; + + /** + * allows developer to provide item path for a file + * + * @type {string} + * @memberof MgtFileList + */ + @property({ + attribute: 'item-path' + }) + public itemPath: string; + + /** + * allows developer to provide user id for a file + * + * @type {string} + * @memberof MgtFile + */ + @property({ + attribute: 'user-id' + }) + public userId: string; + + /** + * allows developer to provide insight type for a file + * can be trending, used, or shared + * + * @type {OfficeGraphInsightString} + * @memberof MgtFileList + */ + @property({ + attribute: 'insight-type' + }) + public insightType: OfficeGraphInsightString; + + /** + * Sets what data to be rendered (file icon only, oneLine, twoLines threeLines). + * Default is 'threeLines'. + * + * @type {ViewType} + * @memberof MgtFileList + */ + @property({ + attribute: 'item-view', + converter: value => { + if (!value || value.length === 0) { + return ViewType.threelines; + } + + value = value.toLowerCase(); + + if (typeof ViewType[value] === 'undefined') { + return ViewType.threelines; + } else { + return ViewType[value]; + } + } + }) + public itemView: ViewType; + + /** + * allows developer to provide file type to filter the list + * can be docx + * + * @type {string[]} + * @memberof MgtFileList + */ + @property({ + attribute: 'file-extensions', + converter: (value, type) => { + return value.split(',').map(v => v.trim()); + } + }) + public fileExtensions: string[]; + + /** + * A number value to indicate the number of more files to load when show more button is clicked + * @type {number} + * @memberof MgtFileList + */ + @property({ + attribute: 'page-size', + type: Number + }) + public pageSize: number; + + /** + * A boolean value indication if 'show-more' button should be disabled + * @type {boolean} + * @memberof MgtFileList + */ + @property({ + attribute: 'hide-more-files-button', + type: Boolean + }) + public hideMoreFilesButton: boolean; + + /** + * A number value indication for file size upload (KB) + * @type {number} + * @memberof MgtFileList + */ + @property({ + attribute: 'max-file-size', + type: Number + }) + public maxFileSize: number; + + /** + * A boolean value indication if file upload extension should be enable or disabled + * @type {boolean} + * @memberof MgtFileList + */ + @property({ + attribute: 'enable-file-upload', + type: Boolean + }) + public enableFileUpload: boolean; + + /** + * A number value to indicate the max number allowed of files to upload. + * @type {number} + * @memberof MgtFileList + */ + @property({ + attribute: 'max-upload-file', + type: Number + }) + public maxUploadFile: number; + + /** + * A Array of file extensions to be excluded from file upload. + * + * @type {string[]} + * @memberof MgtFileList + */ + @property({ + attribute: 'excluded-file-extensions', + converter: value => { + return value.split(',').map(v => v.trim()); + } + }) + public excludedFileExtensions: string[]; + + /** + * Override connectedCallback to set initial breadcrumbstate. + * + * @memberof MgtFileList + */ + public connectedCallback(): void { + super.connectedCallback(); + this.breadcrumb.push({ + name: this.breadcrumbRootName, + siteId: this.siteId, + groupId: this.groupId, + driveId: this.driveId, + userId: this.userId, + files: this.files, + fileExtensions: this.fileExtensions, + fileListQuery: this.fileListQuery, + fileQueries: this.fileQueries, + itemPath: this.itemPath, + insightType: this.insightType, + itemId: this.itemId, + id: 'root-item' + }); + } + + /** + * Strings for localization + * + * @readonly + * @protected + * @memberof MgtFileComposite + */ + protected get strings() { + return strings; + } + + /** + * An array of nodes to show in the breadcrumb + * + * @type {BreadcrumbInfo[]} + * @readonly + * @memberof MgtFileList + */ + @state() + private breadcrumb: FileListBreadCrumb[] = []; + + /** + * Render the component + * + * @return {*} + * @memberof MgtFileComposite + */ + public render() { + return html` + ${this.renderBreadcrumb()} + + `; + } + + private renderBreadcrumb() { + return mgtHtml` + +`; + } + + private handleItemClick(e: CustomEvent): void { + const item = e.detail; + if (item.folder) { + // load folder contents, update breadcrumb + this.breadcrumb = [...this.breadcrumb, { name: item.name, itemId: item.id, id: item.id }]; + // clear any existing query properties + this.siteId = null; + this.groupId = null; + this.driveId = null; + this.userId = null; + this.files = null; + this.fileExtensions = null; + this.fileListQuery = null; + this.fileQueries = null; + this.itemPath = null; + this.insightType = null; + // set the item id to load the folder + this.itemId = item.id; + this.fireCustomEvent('itemClick', item); + } + } + + private handleBreadcrumbClick(e: CustomEvent): void { + const b = e.detail; + this.breadcrumb = this.breadcrumb.slice(0, this.breadcrumb.indexOf(b) + 1); + this.siteId = b.siteId; + this.groupId = b.groupId; + this.driveId = b.driveId; + this.userId = b.userId; + this.files = b.files; + this.fileExtensions = b.fileExtensions; + this.fileListQuery = b.fileListQuery; + this.fileQueries = b.fileQueries; + this.itemPath = b.itemPath; + this.insightType = b.insightType; + this.itemId = b.itemId; + this.fireCustomEvent('breadcrumbclick', b); + } +} diff --git a/packages/mgt-components/src/components/mgt-file-composite/strings.ts b/packages/mgt-components/src/components/mgt-file-composite/strings.ts new file mode 100644 index 0000000000..5d25171e24 --- /dev/null +++ b/packages/mgt-components/src/components/mgt-file-composite/strings.ts @@ -0,0 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + +export const strings = { + rootNode: 'Home' +}; diff --git a/packages/mgt-components/src/components/mgt-file-list/mgt-file-list.scss b/packages/mgt-components/src/components/mgt-file-list/mgt-file-list.scss index cb1e646829..63dbdaf8cf 100644 --- a/packages/mgt-components/src/components/mgt-file-list/mgt-file-list.scss +++ b/packages/mgt-components/src/components/mgt-file-list/mgt-file-list.scss @@ -31,6 +31,7 @@ $progress-ring-size: var(--progress-ring-size, 24px); :host { font-family: $font-family; font-size: $font-size; + color: $color; .title { font-size: 14px; @@ -73,11 +74,11 @@ $progress-ring-size: var(--progress-ring-size, 24px); &:focus, &:focus-within { - --file-background-color: var(--file-background-color-focus,var(--neutral-layer-2)); + --file-background-color: var(--file-background-color-focus, var(--neutral-layer-2)); } - &.selected{ - --file-background-color: var(--file-background-color-active,var(--neutral-layer-3)); + &.selected { + --file-background-color: var(--file-background-color-active, var(--neutral-layer-3)); } .mgt-file-item { @@ -115,4 +116,7 @@ $progress-ring-size: var(--progress-ring-size, 24px); font-size: $show-more-button-font-size; } } + .interactive-breadcrumb { + cursor: pointer; + } } 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 8eb160ad43..32b2a8b513 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 @@ -570,6 +570,12 @@ export class MgtFileList extends MgtTemplatedComponent { this.files = null; } + /** + * Render the file list + * + * @return {*} + * @memberof MgtFileList + */ public render() { if (!this.files && this.isLoadingState) { return this.renderLoading(); @@ -799,7 +805,7 @@ export class MgtFileList extends MgtTemplatedComponent { const file = focusedItem.children[0] as MgtFile; event.preventDefault(); - this.fireCustomEvent('itemClick', file.fileDetails); + this.raiseItemClickedEvent(file.fileDetails); this.updateItemBackgroundColor(fileList, focusedItem, 'selected'); } @@ -809,6 +815,10 @@ export class MgtFileList extends MgtTemplatedComponent { } } + private raiseItemClickedEvent(file: DriveItem) { + this.fireCustomEvent('itemClick', file); + } + /** * Remove accessibility keyboard focused when out of file list * @@ -920,7 +930,7 @@ export class MgtFileList extends MgtTemplatedComponent { } filteredByFileExtension = files.filter(file => { for (const e of this.fileExtensions) { - if (e == this.getFileExtension(file.name)) { + if (e === this.getFileExtension(file.name)) { return file; } } @@ -947,7 +957,7 @@ export class MgtFileList extends MgtTemplatedComponent { */ protected handleItemSelect(item: DriveItem, event: UIEvent): void { this.handleFileClick(item); - this.fireCustomEvent('itemClick', item); + this.raiseItemClickedEvent(item); // handle accessibility updates when item clicked if (event) { @@ -1010,7 +1020,7 @@ export class MgtFileList extends MgtTemplatedComponent { } private handleFileClick(file: DriveItem) { - if (file && file.webUrl) { + if (file?.webUrl) { window.open(file.webUrl, '_blank', 'noreferrer'); } } diff --git a/packages/mgt-components/src/components/mgt-theme-toggle/mgt-theme-toggle.tests.ts b/packages/mgt-components/src/components/mgt-theme-toggle/mgt-theme-toggle.tests.ts index e70d69a9a5..e468cb0ba8 100644 --- a/packages/mgt-components/src/components/mgt-theme-toggle/mgt-theme-toggle.tests.ts +++ b/packages/mgt-components/src/components/mgt-theme-toggle/mgt-theme-toggle.tests.ts @@ -5,7 +5,7 @@ * ------------------------------------------------------------------------------------------- */ // import the mock for media match first to ensure it's hoisted and available for our dependencies -import './mock-media-match'; +import '../../__mocks__/mock-media-match'; import { screen } from 'testing-library__dom'; import { fixture } from '@open-wc/testing-helpers'; import './mgt-theme-toggle'; diff --git a/packages/mgt-components/src/styles/shared-sass-variables.scss b/packages/mgt-components/src/styles/shared-sass-variables.scss index 62640c9c36..c638f27a00 100644 --- a/packages/mgt-components/src/styles/shared-sass-variables.scss +++ b/packages/mgt-components/src/styles/shared-sass-variables.scss @@ -212,6 +212,11 @@ $themes: ('light', 'dark'); $theme-default: 'light'; $common: ( + fluent-color: ( + _var: --neutral-foreground-rest, + dark: $text__color__main--dark, + light: $text__color__main--light + ), color: ( _var: --color, dark: $text__color__main--dark, diff --git a/stories/components/breadcrumb/breadcrumb.js b/stories/components/breadcrumb/breadcrumb.js new file mode 100644 index 0000000000..bc3394ebc7 --- /dev/null +++ b/stories/components/breadcrumb/breadcrumb.js @@ -0,0 +1,60 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + +import { html } from 'lit'; +import { withCodeEditor } from '../../../.storybook/addons/codeEditorAddon/codeAddon'; + +export default { + title: 'Components/mgt-breadcrumb', + component: 'breadcrumb', + decorators: [withCodeEditor] +}; + +export const breadcrumb = () => html` + + +`; + +export const events = () => html` + + +`; diff --git a/stories/components/filesComposite/filesComposite.js b/stories/components/filesComposite/filesComposite.js new file mode 100644 index 0000000000..10bea5c25d --- /dev/null +++ b/stories/components/filesComposite/filesComposite.js @@ -0,0 +1,37 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + +import { html } from 'lit'; +import { withCodeEditor } from '../../../.storybook/addons/codeEditorAddon/codeAddon'; + +export default { + title: 'Components/mgt-file-composite', + component: 'file-composite', + decorators: [withCodeEditor] +}; + +export const fileComposite = () => html` + +`; + +export const BreadcrumbRootName = () => html` + +`; + +export const events = () => html` + + + +`; diff --git a/stories/components/person/person.js b/stories/components/person/person.js index 817a8cc437..26f4780761 100644 --- a/stories/components/person/person.js +++ b/stories/components/person/person.js @@ -9,7 +9,7 @@ import { html } from 'lit'; import { withCodeEditor } from '../../../.storybook/addons/codeEditorAddon/codeAddon'; export default { - title: 'Components | mgt-person', + title: 'Components/mgt-person', component: 'person', decorators: [withCodeEditor] }; diff --git a/yarn.lock b/yarn.lock index 62ffa5f3be..4aad8e04c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2370,7 +2370,7 @@ "@uifabric/utilities" "^7.38.2" tslib "^1.10.0" -"@fluentui/web-components@^2.5.3": +"@fluentui/web-components@^2.5.12": version "2.5.12" resolved "https://registry.yarnpkg.com/@fluentui/web-components/-/web-components-2.5.12.tgz#c58893f5d3904281849ff1a91f1ea843f09c4247" integrity sha512-g5mbTMUo6cs6oPSy8qjtPiCP2hgsThPvyTPqfRgkBoaFhJgAd4nmrhbWh6+yRpU6ZR2kQqg5jRQMiBmnnzw57g==