mirror of
https://github.com/pnp/sp-dev-fx-webparts.git
synced 2025-02-13 00:15:35 +00:00
Merge pull request #5283 from petkir/react-organization-chart
This commit is contained in:
commit
48d50e3d79
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "SPFx 1.18.2",
|
||||
"image": "docker.io/m365pnp/spfx:1.18.2",
|
||||
"name": "SPFx 1.20.2",
|
||||
"image": "docker.io/m365pnp/spfx:1.20.2",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
|
@ -20,39 +20,6 @@ module.exports = {
|
||||
'@rushstack/security/no-unsafe-regexp': 1,
|
||||
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
|
||||
'@typescript-eslint/adjacent-overload-signatures': 1,
|
||||
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
|
||||
//
|
||||
// CONFIGURATION: By default, these are banned: String, Boolean, Number, Object, Symbol
|
||||
'@typescript-eslint/ban-types': [
|
||||
1,
|
||||
{
|
||||
'extendDefaults': false,
|
||||
'types': {
|
||||
'String': {
|
||||
'message': 'Use \'string\' instead',
|
||||
'fixWith': 'string'
|
||||
},
|
||||
'Boolean': {
|
||||
'message': 'Use \'boolean\' instead',
|
||||
'fixWith': 'boolean'
|
||||
},
|
||||
'Number': {
|
||||
'message': 'Use \'number\' instead',
|
||||
'fixWith': 'number'
|
||||
},
|
||||
'Object': {
|
||||
'message': 'Use \'object\' instead, or else define a proper TypeScript type:'
|
||||
},
|
||||
'Symbol': {
|
||||
'message': 'Use \'symbol\' instead',
|
||||
'fixWith': 'symbol'
|
||||
},
|
||||
'Function': {
|
||||
'message': 'The \'Function\' type accepts any function-like value.\nIt provides no type safety when calling the function, which can be a common source of bugs.\nIt also accepts things like class declarations, which will throw at runtime as they will not be called with \'new\'.\nIf you are expecting the function to accept certain arguments, you should explicitly define the function shape.'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
// RATIONALE: Code is more readable when the type of every variable is immediately obvious.
|
||||
// Even if the compiler may be able to infer a type, this inference will be unavailable
|
||||
// to a person who is reviewing a GitHub diff. This rule makes writing code harder,
|
||||
|
@ -1 +1 @@
|
||||
v18.19.1
|
||||
v18.20.3
|
@ -2,12 +2,13 @@
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"plusBeta": false,
|
||||
"isCreatingSolution": true,
|
||||
"nodeVersion": "18.19.1",
|
||||
"nodeVersion": "18.20.3",
|
||||
"sdksVersions": {
|
||||
"@microsoft/microsoft-graph-client": "3.0.2",
|
||||
"@microsoft/teams-js": "2.12.0"
|
||||
"@microsoft/teams-js": "2.24.0"
|
||||
},
|
||||
"version": "1.18.2",
|
||||
"isDomainIsolated": false,
|
||||
"version": "1.20.0",
|
||||
"libraryName": "react-organization-chart",
|
||||
"libraryId": "0b4a3e5d-123f-41ea-96c4-538c6a19932b",
|
||||
"environment": "onprem19",
|
||||
|
@ -19,8 +19,8 @@ This web part shows an organization chart based on specified user, and user can
|
||||
|
||||
This sample is optimally compatible with the following environment configuration:
|
||||
|
||||
![SPFx 1.18.2](https://img.shields.io/badge/SPFx-1.18.2-green.svg)
|
||||
![Node.js v16 | v18](https://img.shields.io/badge/Node.js-v16%20%7C%20v18-green.svg)
|
||||
![SPFx 1.20.0](https://img.shields.io/badge/SPFx-1.20.0-green.svg)
|
||||
![Node.js v18](https://img.shields.io/badge/Node.js-v18-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
|
||||
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
|
||||
@ -34,13 +34,16 @@ This sample is optimally compatible with the following environment configuration
|
||||
|
||||
## Contributors
|
||||
|
||||
|
||||
- [João Mendes](https://github.com/joaojmendes)
|
||||
- [Passoli Mirko](https://github.com/Paxol)
|
||||
- [Peter Paul Kirschner](https://github.com/petkir)
|
||||
|
||||
## Version history
|
||||
|
||||
|Version|Date|Comments|
|
||||
|-------|----|--------|
|
||||
|1.2|Oct, 2024|SPFx 1.20.0|
|
||||
|1.1|Feb, 2024|Guest user filter + update to SPFx 1.18.2|
|
||||
|1.0|May, 2021|Initial release|
|
||||
|
||||
|
@ -2,15 +2,15 @@
|
||||
{
|
||||
"name": "pnp-sp-dev-spfx-web-parts-react-organization-chart",
|
||||
"source": "pnp",
|
||||
"title": "Organization Chart Web Part (SP2019 and Online)",
|
||||
"title": "Organization Chart Web Part",
|
||||
"shortDescription": "Shows an organization chart based on specified user, and user can navigate to show company organization",
|
||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-organization-chart",
|
||||
"longDescription": [
|
||||
"This web part shows an organization chart based on specified user, and user can navigate to show company organization.",
|
||||
"Can be installed on SharePoint Server 2019, and SharePoint Online."
|
||||
"Can be installed on SharePoint Online."
|
||||
],
|
||||
"creationDateTime": "2021-05-03",
|
||||
"updateDateTime": "2024-02-25",
|
||||
"updateDateTime": "2024-10-04",
|
||||
"products": [
|
||||
"SharePoint"
|
||||
],
|
||||
@ -21,7 +21,7 @@
|
||||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.18.2"
|
||||
"value": "1.20.0"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
@ -55,6 +55,13 @@
|
||||
{
|
||||
"gitHubAccount": "Paxol",
|
||||
"pictureUrl": "https://github.com/Paxol.png"
|
||||
},
|
||||
{
|
||||
"gitHubAccount": "petkir",
|
||||
"company": "ACP CUBIDO Digital Solutions GmbH",
|
||||
"pictureUrl": "https://github.com/petkir.png",
|
||||
"name": "Peter Paul Kirschner",
|
||||
"twitter": "petkir_at"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./temp/deploy/",
|
||||
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "react-organization-chart",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
"accessKey": "<!-- ACCESS KEY -->",
|
||||
"workingDir": "./release/assets/"
|
||||
}
|
@ -3,9 +3,40 @@
|
||||
"solution": {
|
||||
"name": "react-organization-chart",
|
||||
"id": "0b4a3e5d-123f-41ea-96c4-538c6a19932b",
|
||||
"version": "1.1.0.0",
|
||||
"version": "1.2.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false,
|
||||
"developer": {
|
||||
"name": "",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"websiteUrl": "",
|
||||
"mpnId": "Undefined-1.20.0"
|
||||
},
|
||||
"metadata": {
|
||||
"shortDescription": {
|
||||
"default": "react-organization-chart description"
|
||||
},
|
||||
"longDescription": {
|
||||
"default": "react-organization-chart description"
|
||||
},
|
||||
"screenshotPaths": [],
|
||||
"videoUrl": "",
|
||||
"categories": []
|
||||
},
|
||||
"features": [
|
||||
{
|
||||
"title": "react-organization-chart OrganizationChartWebPart Feature",
|
||||
"description": "The feature that activates OrganizationChartWebPart from the react-organization-chart solution.",
|
||||
"id": "0338da15-07f9-4a53-b267-d790fb495cca",
|
||||
"version": "1.2.0.0",
|
||||
"componentIds": [
|
||||
"0338da15-07f9-4a53-b267-d790fb495cca"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-organization-chart.sppkg"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||
"port": 4321,
|
||||
"https": true,
|
||||
"initialPage": "https://{tenantDomain}/_layouts/workbench.aspx"
|
||||
"initialPage": "https://enter-your-SharePoint-site/_layouts/workbench.aspx"
|
||||
}
|
||||
|
18031
samples/react-organization-chart/package-lock.json
generated
18031
samples/react-organization-chart/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "react-organization-chart",
|
||||
"version": "0.0.1",
|
||||
"version": "1.2.0.0",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=16.13.0 <17.0.0 || >=18.17.1 <19.0.0"
|
||||
"node": ">=18.17.1 <19.0.0"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
@ -29,19 +29,26 @@
|
||||
"tslib": "2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/eslint-config-spfx": "1.18.2",
|
||||
"@microsoft/eslint-plugin-spfx": "1.18.2",
|
||||
"@microsoft/eslint-config-spfx": "1.20.2",
|
||||
"@microsoft/eslint-plugin-spfx": "1.20.2",
|
||||
"@microsoft/rush-stack-compiler-4.5": "0.5.0",
|
||||
"@microsoft/rush-stack-compiler-4.7": "0.1.0",
|
||||
"@microsoft/sp-build-web": "1.18.2",
|
||||
"@microsoft/sp-module-interfaces": "1.18.2",
|
||||
"@rushstack/eslint-config": "2.5.1",
|
||||
"@microsoft/sp-build-web": "1.20.2",
|
||||
"@microsoft/sp-module-interfaces": "1.20.2",
|
||||
"@microsoft/sp-tslint-rules": "1.14.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.12.1",
|
||||
"@rushstack/eslint-config": "4.0.1",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/mocha": "2.2.38",
|
||||
"@types/react": "17.0.45",
|
||||
"@types/react-dom": "17.0.17",
|
||||
"@types/webpack-env": "~1.15.2",
|
||||
"ajv": "^6.12.5",
|
||||
"eslint": "8.7.0",
|
||||
"@types/webpack-env": "1.15.2",
|
||||
"ajv": "6.12.5",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-plugin-react-hooks": "4.3.0",
|
||||
"gulp": "4.0.2",
|
||||
"tslint-microsoft-contrib": "5.0.0",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ export const getMd5HashForUrl = async (url: string): Promise<Maybe<string>> => {
|
||||
return convertedHash;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return url;
|
||||
}
|
||||
};
|
||||
@ -73,14 +74,15 @@ export const getImageBase64 = async (pictureUrl: string): Promise<string> => {
|
||||
const image = new Image();
|
||||
image.addEventListener("load", () => {
|
||||
const tempCanvas = document.createElement("canvas");
|
||||
// eslint-disable-next-line no-unused-expressions, no-sequences
|
||||
// eslint-disable-next-line no-unused-expressions, no-sequences, @typescript-eslint/no-unused-expressions
|
||||
(tempCanvas.width = image.width),
|
||||
(tempCanvas.height = image.height),
|
||||
tempCanvas.getContext("2d")?.drawImage(image, 0, 0);
|
||||
let base64Str;
|
||||
try {
|
||||
base64Str = tempCanvas.toDataURL("image/png");
|
||||
} catch (e) {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return "";
|
||||
}
|
||||
base64Str = base64Str.replace(/^data:image\/png;base64,/, "");
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
|
||||
@import '~@fluentui/react/dist/sass/References.scss';
|
||||
|
||||
.OrgChart {
|
||||
.container {
|
||||
|
@ -19,12 +19,14 @@ import {
|
||||
Text,
|
||||
} from "@fluentui/react";
|
||||
|
||||
import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder";
|
||||
|
||||
|
||||
import { getGUID } from "@pnp/common";
|
||||
import { useOrgChartStyles } from "./useOrgChartStyles";
|
||||
|
||||
import "./OrgChart.module.scss";
|
||||
import { Placeholder } from "../Placeholder/PlaceholderComponent";
|
||||
|
||||
|
||||
const initialState: IOrgChartState = {
|
||||
isLoading: true,
|
||||
@ -236,15 +238,17 @@ export const OrgChart: React.FunctionComponent<IOrgChartProps> = (
|
||||
if (!startFromUser) {
|
||||
return (
|
||||
<Placeholder
|
||||
iconName="Edit"
|
||||
iconText="Configure your Organization Chart Web Part"
|
||||
description={"Please configure web part"}
|
||||
buttonLabel="Configure"
|
||||
onConfigure={context.propertyPane.open}
|
||||
/>
|
||||
iconName="Edit"
|
||||
iconText="Configure your Organization Chart Web Part"
|
||||
description={"Please configure web part"}
|
||||
buttonLabel="Configure"
|
||||
onConfigure={context.propertyPane.open}
|
||||
/>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Overlay style={{ height: "100%", position: "fixed" }}>
|
||||
|
@ -0,0 +1,67 @@
|
||||
import { mergeStyleSets } from '@fluentui/merge-styles';
|
||||
import { FontSizes, IPartialTheme, ITheme } from '@fluentui/react/lib/Styling';
|
||||
|
||||
export interface IPlaceholderComponentClassNames {
|
||||
placeholder: string;
|
||||
placeholderContainer: string;
|
||||
placeholderHead: string;
|
||||
placeholderHeadContainer: string;
|
||||
placeholderIcon: string;
|
||||
placeholderText: string;
|
||||
hide: string;
|
||||
placeholderDescription: string;
|
||||
placeholderDescriptionText: string;
|
||||
}
|
||||
|
||||
export const getClassNames = (theme: IPartialTheme | ITheme): IPlaceholderComponentClassNames => {
|
||||
return mergeStyleSets({
|
||||
placeholder: {
|
||||
display: "flex"
|
||||
},
|
||||
placeholderContainer: {
|
||||
alignItems: "center",
|
||||
color: theme.palette.neutralSecondary,
|
||||
backgroundColor: theme.palette.neutralLighter,
|
||||
width: "100%",
|
||||
padding: "80px 0"
|
||||
},
|
||||
placeholderHead: {
|
||||
color: theme.palette.neutralPrimary
|
||||
},
|
||||
placeholderHeadContainer: {
|
||||
height: "100%",
|
||||
whiteSpace: "nowrap",
|
||||
textAlign: "center"
|
||||
},
|
||||
placeholderIcon: {
|
||||
display: "inline-block",
|
||||
verticalAlign: "middle",
|
||||
whiteSpace: "normal",
|
||||
fontSize: FontSizes.size42
|
||||
},
|
||||
placeholderText: {
|
||||
display: "inline",
|
||||
verticalAlign: "middle",
|
||||
whiteSpace: "normal",
|
||||
fontWeight: 100,
|
||||
fontSize: FontSizes.size28,
|
||||
paddingLeft: "20px"
|
||||
},
|
||||
hide: {
|
||||
display: "none"
|
||||
},
|
||||
placeholderDescription: {
|
||||
width: "65%",
|
||||
verticalAlign: "middle",
|
||||
margin: "0 auto",
|
||||
textAlign: "center"
|
||||
},
|
||||
placeholderDescriptionText: {
|
||||
color: theme.palette.neutralSecondary,
|
||||
fontSize: "17px",
|
||||
display: "inline-block",
|
||||
margin: "24px 0",
|
||||
fontWeight: "100"
|
||||
}
|
||||
});
|
||||
};
|
@ -0,0 +1,199 @@
|
||||
import { IPartialTheme, ITheme } from '@fluentui/react/lib/Styling';
|
||||
|
||||
/**
|
||||
* Used to display a placeholder in case of no or temporary content. Button is optional.
|
||||
*
|
||||
*/
|
||||
export interface IPlaceholderProps {
|
||||
|
||||
/**
|
||||
* Text description or component for the placeholder. Appears bellow the Icon and IconText.
|
||||
*/
|
||||
description: string | ((defaultClassNames: string) => React.ReactElement);
|
||||
/**
|
||||
* Icon name used for the className from the MDL2 set. Example: 'Add'.
|
||||
*/
|
||||
iconName: string;
|
||||
/**
|
||||
* Heading displayed against the Icon.
|
||||
*/
|
||||
iconText: string | ((defaultClassNames: string) => React.ReactElement);
|
||||
/**
|
||||
* Text label to be displayed on button below the description.
|
||||
* Optional: As the button is optional.
|
||||
*/
|
||||
buttonLabel?: string;
|
||||
/**
|
||||
* This className is applied to the root element of content. Use this to
|
||||
* apply custom styles to the placeholder.
|
||||
*/
|
||||
contentClassName?: string;
|
||||
/**
|
||||
* Specify if you want to hide the config button
|
||||
*/
|
||||
hideButton?: boolean;
|
||||
/**
|
||||
* onConfigure handler for the button.
|
||||
* Optional: As the button is optional.
|
||||
*/
|
||||
onConfigure?: () => void;
|
||||
|
||||
/**
|
||||
* Set Fluent UI Theme.
|
||||
* If not set or set to null or not defined, the theme passed through context will be used, or the default theme of the page will be loaded.
|
||||
*/
|
||||
theme?: IPartialTheme | ITheme;
|
||||
}
|
||||
|
||||
export interface IPlaceholderState {
|
||||
width: number;
|
||||
}
|
||||
|
||||
|
||||
import { ThemeContext } from '@fluentui/react-theme-provider/lib/ThemeContext';
|
||||
import { Theme } from '@fluentui/react-theme-provider/lib/types';
|
||||
import { PrimaryButton } from '@fluentui/react/lib/Button';
|
||||
import { Icon } from '@fluentui/react/lib/Icon';
|
||||
import * as React from 'react';
|
||||
import { getFluentUIThemeOrDefault } from './ThemeUtility';
|
||||
import { getClassNames } from './PlaceholderComponent.styles';
|
||||
|
||||
|
||||
/**
|
||||
* Placeholder component
|
||||
*/
|
||||
export class Placeholder extends React.Component<IPlaceholderProps, IPlaceholderState> {
|
||||
private _crntElm: HTMLDivElement = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
constructor(props: IPlaceholderProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
width: null
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* componentDidMount lifecycle hook
|
||||
*/
|
||||
public componentDidMount(): void {
|
||||
this._setZoneWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* componentDidUpdate lifecycle hook
|
||||
* @param prevProps
|
||||
* @param prevState
|
||||
*/
|
||||
public componentDidUpdate(prevProps: IPlaceholderProps, prevState: IPlaceholderState): void {
|
||||
this._setZoneWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* shouldComponentUpdate lifecycle hook
|
||||
* @param nextProps
|
||||
* @param nextState
|
||||
*/
|
||||
public shouldComponentUpdate(nextProps: IPlaceholderProps, nextState: IPlaceholderState): boolean {
|
||||
/*
|
||||
* compare the props object for changes in primative values
|
||||
* Return/re-render, bexeting the function, if the props change
|
||||
*/
|
||||
for (const property in nextProps) {
|
||||
if (property !== '_onConfigure') {
|
||||
if (nextProps[property as keyof IPlaceholderProps] !== this.props[property as keyof IPlaceholderProps]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.state.width !== nextState.width || this.props.hideButton !== nextProps.hideButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the onConfigure function
|
||||
*/
|
||||
private _handleBtnClick = (event?: React.MouseEvent<HTMLButtonElement>): void => {
|
||||
this.props.onConfigure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current zone width
|
||||
*/
|
||||
private _setZoneWidth = (): void => {
|
||||
this.setState({
|
||||
width: this._crntElm.clientWidth
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the current element
|
||||
*/
|
||||
private _linkElm = (e: HTMLDivElement): void => {
|
||||
this._crntElm = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default React component render method
|
||||
*/
|
||||
public render(): React.ReactElement<IPlaceholderProps> {
|
||||
|
||||
const {
|
||||
iconName,
|
||||
iconText,
|
||||
description,
|
||||
children,
|
||||
buttonLabel,
|
||||
hideButton,
|
||||
theme
|
||||
} = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<ThemeContext.Consumer>
|
||||
{(contextTheme: Theme | undefined) => {
|
||||
|
||||
const themeToApply = getFluentUIThemeOrDefault((theme) ? theme : contextTheme);
|
||||
const styles = getClassNames(themeToApply);
|
||||
|
||||
const iconTextClassNames = `${styles.placeholderText} ${(this.state.width && this.state.width <= 380) ? styles.hide : ""}`;
|
||||
const iconTextEl = typeof iconText === 'string' ? <span className={iconTextClassNames}>{this.props.iconText}</span> : iconText(iconTextClassNames);
|
||||
const descriptionEl = typeof description === 'string' ? <span className={styles.placeholderDescriptionText}>{this.props.description}</span> : description(styles.placeholderDescriptionText);
|
||||
|
||||
return (
|
||||
<div className={`${styles.placeholder} ${this.props.contentClassName ? this.props.contentClassName : ''}`} ref={this._linkElm}>
|
||||
<div className={styles.placeholderContainer}>
|
||||
<div className={styles.placeholderHead}>
|
||||
<div className={styles.placeholderHeadContainer}>
|
||||
{
|
||||
iconName && <Icon iconName={iconName} className={styles.placeholderIcon} />
|
||||
}
|
||||
{iconTextEl}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.placeholderDescription}>
|
||||
{descriptionEl}
|
||||
</div>
|
||||
{children}
|
||||
<div className={styles.placeholderDescription}>
|
||||
{
|
||||
(buttonLabel && !hideButton) &&
|
||||
<PrimaryButton
|
||||
text={buttonLabel}
|
||||
ariaLabel={buttonLabel}
|
||||
ariaDescription={typeof description === 'string' ? description : ''}
|
||||
onClick={this._handleBtnClick}
|
||||
theme={themeToApply} />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>);
|
||||
}}
|
||||
</ThemeContext.Consumer>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,448 @@
|
||||
import {
|
||||
mergeThemes,
|
||||
ThemeInput,
|
||||
teamsTheme,
|
||||
teamsDarkTheme,
|
||||
teamsHighContrastTheme
|
||||
} from "@fluentui/react-northstar";
|
||||
import { createTheme, getTheme, IPalette, IPartialTheme, ITheme } from "@fluentui/react/lib/Styling";
|
||||
|
||||
import { ComponentVariablesObject } from "@fluentui/styles";
|
||||
import { getVariant, VariantThemeType } from "@fluentui/scheme-utilities";
|
||||
|
||||
const colorPaletteV2 = {
|
||||
black: "#000",
|
||||
white: "#fff",
|
||||
grey: {
|
||||
25: "#fafafa",
|
||||
50: "#f5f5f5",
|
||||
100: "#f0f0f0",
|
||||
150: "#ebebeb",
|
||||
200: "#e0e0e0",
|
||||
220: "#d6d6d6",
|
||||
230: "#d1d1d1",
|
||||
250: "#c7c7c7",
|
||||
270: "#bdbdbd",
|
||||
300: "#b3b3b3",
|
||||
310: "#adadad",
|
||||
350: "#949494",
|
||||
400: "#8a8a8a",
|
||||
430: "#707070",
|
||||
440: "#666",
|
||||
450: "#616161",
|
||||
460: "#5c5c5c",
|
||||
500: "#424242",
|
||||
550: "#3d3d3d",
|
||||
600: "#333",
|
||||
650: "#2e2e2e",
|
||||
700: "#292929",
|
||||
750: "#242424",
|
||||
800: "#1f1f1f",
|
||||
850: "#1a1a1a",
|
||||
870: "#141414",
|
||||
900: "#0f0f0f",
|
||||
910: "#0a0a0a",
|
||||
},
|
||||
brand: {
|
||||
50: "#e9eaf6",
|
||||
100: "#dbdcf0",
|
||||
200: "#c7c9ff",
|
||||
300: "#b2b5ff",
|
||||
400: "#a6a7dc",
|
||||
450: "#9ea2ff",
|
||||
500: "#7479dc",
|
||||
600: "#6264a7",
|
||||
700: "#494b83",
|
||||
800: "#464775",
|
||||
900: "#3d3e66",
|
||||
1000: "#323348",
|
||||
},
|
||||
};
|
||||
const teamsNextThemeSiteVariables = {
|
||||
teamsTheme: {
|
||||
theme: "teamsTheme",
|
||||
colors: colorPaletteV2,
|
||||
colorScheme: {
|
||||
elevations: {
|
||||
4: "0px 0.3px 0.9px rgba(0, 0, 0, 0.07), 0px 1.6px 3.6px rgba(0, 0, 0, 0.11)",
|
||||
8: "0px 3.2px 7.2px rgba(0, 0, 0, 0.13), 0px 0.6px 1.8px rgba(0, 0, 0, 0.11)",
|
||||
16: "0px 6.4px 14.4px rgba(0, 0, 0, 0.07), 0px 1.2px 3.6px rgba(0, 0, 0, 0.03)",
|
||||
},
|
||||
default: {
|
||||
foreground: colorPaletteV2.grey["750"],
|
||||
foreground1: colorPaletteV2.grey["500"],
|
||||
foreground2: colorPaletteV2.grey["450"],
|
||||
foreground3: colorPaletteV2.white,
|
||||
foreground4: colorPaletteV2.white,
|
||||
|
||||
background: colorPaletteV2.white,
|
||||
background1: colorPaletteV2.grey["25"],
|
||||
background2: colorPaletteV2.grey["50"],
|
||||
background3: colorPaletteV2.grey["100"],
|
||||
background4: colorPaletteV2.grey["150"],
|
||||
background5: colorPaletteV2.grey["200"],
|
||||
|
||||
border: colorPaletteV2.grey["230"],
|
||||
border1: colorPaletteV2.grey["100"],
|
||||
border2: colorPaletteV2.grey["200"],
|
||||
border3: colorPaletteV2.grey["100"],
|
||||
|
||||
foregroundHover: colorPaletteV2.grey["750"],
|
||||
foregroundHover1: colorPaletteV2.white,
|
||||
foregroundHover2: colorPaletteV2.white,
|
||||
|
||||
backgroundHover: colorPaletteV2.grey["50"],
|
||||
backgroundHover1: colorPaletteV2.grey["25"],
|
||||
backgroundHover2: "transparent",
|
||||
backgroundHover3: colorPaletteV2.grey["150"],
|
||||
backgroundHover4: colorPaletteV2.grey["25"],
|
||||
|
||||
borderHover: colorPaletteV2.grey["250"],
|
||||
|
||||
foregroundPressed: colorPaletteV2.grey["750"],
|
||||
backgroundPressed: colorPaletteV2.grey["200"],
|
||||
|
||||
foregroundActive: colorPaletteV2.grey["750"],
|
||||
foregroundActive1: colorPaletteV2.white,
|
||||
|
||||
backgroundActive: colorPaletteV2.grey["150"],
|
||||
backgroundActive1: colorPaletteV2.white,
|
||||
|
||||
borderActive: colorPaletteV2.grey["270"],
|
||||
|
||||
// foregroundFocus: not specified,
|
||||
// backgroundFocus: not specified,
|
||||
|
||||
borderFocus: colorPaletteV2.black,
|
||||
borderFocusWithin: colorPaletteV2.white,
|
||||
|
||||
foregroundDisabled: colorPaletteV2.grey["250"],
|
||||
foregroundDisabled1: colorPaletteV2.grey["250"],
|
||||
|
||||
borderDisabled: colorPaletteV2.grey["200"],
|
||||
|
||||
backgroundDisabled: colorPaletteV2.grey["100"],
|
||||
backgroundDisabled1: colorPaletteV2.grey["100"],
|
||||
},
|
||||
brand: {
|
||||
background: colorPaletteV2.brand["600"],
|
||||
background1: colorPaletteV2.brand["50"],
|
||||
background2: colorPaletteV2.brand["900"],
|
||||
background3: colorPaletteV2.brand["1000"],
|
||||
background4: colorPaletteV2.brand["800"],
|
||||
|
||||
foreground: colorPaletteV2.brand["600"],
|
||||
foreground1: colorPaletteV2.brand["600"],
|
||||
foreground2: colorPaletteV2.brand["700"],
|
||||
foreground3: colorPaletteV2.brand["200"],
|
||||
foreground4: colorPaletteV2.white,
|
||||
|
||||
border: colorPaletteV2.grey["200"],
|
||||
border1: colorPaletteV2.brand["300"],
|
||||
border2: colorPaletteV2.brand["200"],
|
||||
|
||||
foregroundHover: colorPaletteV2.brand["600"],
|
||||
foregroundHover1: colorPaletteV2.white,
|
||||
foregroundHover2: colorPaletteV2.brand["200"],
|
||||
|
||||
borderHover: colorPaletteV2.brand["300"],
|
||||
|
||||
backgroundHover: colorPaletteV2.brand["700"],
|
||||
backgroundHover1: colorPaletteV2.brand["50"],
|
||||
|
||||
foregroundPressed: colorPaletteV2.brand["700"],
|
||||
foregroundPressed1: colorPaletteV2.white,
|
||||
|
||||
backgroundPressed: colorPaletteV2.brand["800"],
|
||||
|
||||
borderPressed: colorPaletteV2.brand["300"],
|
||||
|
||||
foregroundActive: colorPaletteV2.brand["600"],
|
||||
foregroundActive1: colorPaletteV2.brand["600"],
|
||||
foregroundActive2: colorPaletteV2.brand["50"],
|
||||
|
||||
backgroundActive: colorPaletteV2.brand["600"],
|
||||
backgroundActive1: colorPaletteV2.brand["600"],
|
||||
|
||||
borderActive: colorPaletteV2.grey["200"],
|
||||
borderActive1: colorPaletteV2.brand["50"],
|
||||
borderActive2: colorPaletteV2.brand["300"],
|
||||
|
||||
foregroundFocus: colorPaletteV2.brand["600"],
|
||||
foregroundFocus1: colorPaletteV2.brand["600"],
|
||||
foregroundFocus2: colorPaletteV2.brand["700"],
|
||||
foregroundFocus3: colorPaletteV2.brand["50"],
|
||||
foregroundFocus4: colorPaletteV2.white,
|
||||
|
||||
backgroundFocus: colorPaletteV2.brand["600"],
|
||||
backgroundFocus1: colorPaletteV2.brand["50"],
|
||||
backgroundFocus2: colorPaletteV2.brand["900"],
|
||||
backgroundFocus3: colorPaletteV2.brand["1000"],
|
||||
|
||||
borderFocus: colorPaletteV2.black,
|
||||
borderFocus1: colorPaletteV2.brand["600"],
|
||||
|
||||
borderFocusWithin: colorPaletteV2.white,
|
||||
|
||||
foregroundDisabled: colorPaletteV2.grey["250"],
|
||||
foregroundDisabled1: colorPaletteV2.grey["250"],
|
||||
|
||||
borderDisabled: colorPaletteV2.grey["550"],
|
||||
|
||||
backgroundDisabled: colorPaletteV2.grey["100"],
|
||||
backgroundDisabled1: colorPaletteV2.grey["100"],
|
||||
},
|
||||
},
|
||||
},
|
||||
teamsDarkTheme: {
|
||||
theme: "teamsDarkTheme",
|
||||
colors: colorPaletteV2,
|
||||
colorScheme: {
|
||||
elevations: {
|
||||
8: "0px 3.2px 7.2px rgba(0, 0, 0, 0.13), 0px 0.6px 1.8px rgba(0, 0, 0, 0.11)",
|
||||
16: "0px 6.4px 14.4px rgba(0, 0, 0, 0.32), 0px 1.2px 3.6px rgba(0, 0, 0, 0.28)",
|
||||
},
|
||||
default: {
|
||||
foreground: colorPaletteV2.white,
|
||||
foreground1: colorPaletteV2.grey["220"],
|
||||
foreground2: colorPaletteV2.grey["310"],
|
||||
foreground3: colorPaletteV2.white,
|
||||
foreground4: colorPaletteV2.white,
|
||||
|
||||
background: colorPaletteV2.grey["700"],
|
||||
background1: colorPaletteV2.grey["750"],
|
||||
background2: colorPaletteV2.grey["800"],
|
||||
background3: colorPaletteV2.grey["870"],
|
||||
background4: colorPaletteV2.grey["550"],
|
||||
background5: colorPaletteV2.grey["600"],
|
||||
|
||||
border: colorPaletteV2.grey["450"],
|
||||
border1: colorPaletteV2.grey["850"],
|
||||
border2: colorPaletteV2.grey["900"],
|
||||
border3: colorPaletteV2.grey["550"],
|
||||
|
||||
foregroundHover: colorPaletteV2.white,
|
||||
foregroundHover1: colorPaletteV2.white,
|
||||
foregroundHover2: colorPaletteV2.white,
|
||||
|
||||
backgroundHover: colorPaletteV2.grey["550"],
|
||||
backgroundHover1: colorPaletteV2.grey["750"],
|
||||
backgroundHover2: "transparent",
|
||||
backgroundHover3: colorPaletteV2.grey["650"],
|
||||
backgroundHover4: colorPaletteV2.grey["750"],
|
||||
|
||||
borderHover: colorPaletteV2.grey["430"],
|
||||
|
||||
foregroundPressed: colorPaletteV2.white,
|
||||
backgroundPressed: colorPaletteV2.grey["650"],
|
||||
|
||||
foregroundActive: colorPaletteV2.white,
|
||||
foregroundActive1: colorPaletteV2.white,
|
||||
|
||||
backgroundActive: colorPaletteV2.grey["600"],
|
||||
backgroundActive1: colorPaletteV2.grey["800"],
|
||||
|
||||
borderActive: colorPaletteV2.grey["440"],
|
||||
|
||||
// foregroundFocus: not specified,
|
||||
// backgroundFocus: not specified,
|
||||
|
||||
borderFocus: colorPaletteV2.white,
|
||||
borderFocusWithin: colorPaletteV2.black,
|
||||
|
||||
foregroundDisabled: colorPaletteV2.grey["460"],
|
||||
foregroundDisabled1: colorPaletteV2.grey["460"],
|
||||
|
||||
borderDisabled: colorPaletteV2.grey["500"],
|
||||
|
||||
backgroundDisabled: colorPaletteV2.grey["800"],
|
||||
backgroundDisabled1: colorPaletteV2.grey["800"],
|
||||
},
|
||||
brand: {
|
||||
background: colorPaletteV2.brand["600"],
|
||||
background1: colorPaletteV2.brand["1000"],
|
||||
background2: colorPaletteV2.brand["900"],
|
||||
background3: colorPaletteV2.brand["1000"],
|
||||
background4: colorPaletteV2.grey["910"],
|
||||
|
||||
foreground: colorPaletteV2.brand["450"],
|
||||
foreground1: colorPaletteV2.brand["450"],
|
||||
foreground2: colorPaletteV2.brand["450"],
|
||||
foreground3: colorPaletteV2.brand["200"],
|
||||
foreground4: colorPaletteV2.white,
|
||||
|
||||
border: colorPaletteV2.grey["450"],
|
||||
border1: colorPaletteV2.brand["800"],
|
||||
border2: colorPaletteV2.brand["800"],
|
||||
|
||||
foregroundHover: colorPaletteV2.brand["450"],
|
||||
foregroundHover1: colorPaletteV2.white,
|
||||
foregroundHover2: colorPaletteV2.brand["200"],
|
||||
|
||||
borderHover: colorPaletteV2.brand["600"],
|
||||
|
||||
backgroundHover: colorPaletteV2.brand["700"],
|
||||
backgroundHover1: colorPaletteV2.brand["900"],
|
||||
|
||||
foregroundPressed: colorPaletteV2.brand["200"],
|
||||
foregroundPressed1: colorPaletteV2.white,
|
||||
|
||||
backgroundPressed: colorPaletteV2.brand["800"],
|
||||
|
||||
borderPressed: colorPaletteV2.brand["800"],
|
||||
|
||||
foregroundActive: colorPaletteV2.brand["450"],
|
||||
foregroundActive1: colorPaletteV2.brand["450"],
|
||||
foregroundActive2: colorPaletteV2.brand["50"],
|
||||
|
||||
backgroundActive: colorPaletteV2.brand["450"],
|
||||
backgroundActive1: colorPaletteV2.brand["450"],
|
||||
|
||||
borderActive: colorPaletteV2.grey["450"],
|
||||
borderActive1: colorPaletteV2.brand["800"],
|
||||
borderActive2: colorPaletteV2.brand["800"],
|
||||
|
||||
foregroundFocus: colorPaletteV2.brand["450"],
|
||||
foregroundFocus1: colorPaletteV2.brand["450"],
|
||||
foregroundFocus2: colorPaletteV2.brand["450"],
|
||||
foregroundFocus3: colorPaletteV2.brand["50"],
|
||||
foregroundFocus4: colorPaletteV2.white,
|
||||
|
||||
backgroundFocus: colorPaletteV2.brand["450"],
|
||||
backgroundFocus1: colorPaletteV2.brand["1000"],
|
||||
backgroundFocus2: colorPaletteV2.brand["900"],
|
||||
backgroundFocus3: colorPaletteV2.brand["1000"],
|
||||
|
||||
borderFocus: colorPaletteV2.white,
|
||||
borderFocus1: colorPaletteV2.brand["450"],
|
||||
|
||||
borderFocusWithin: colorPaletteV2.black,
|
||||
|
||||
foregroundDisabled: colorPaletteV2.grey["460"],
|
||||
foregroundDisabled1: colorPaletteV2.grey["460"],
|
||||
|
||||
borderDisabled: colorPaletteV2.grey["500"],
|
||||
|
||||
backgroundDisabled: colorPaletteV2.grey["800"],
|
||||
backgroundDisabled1: colorPaletteV2.grey["800"],
|
||||
},
|
||||
},
|
||||
},
|
||||
teamsHighContrastTheme: {
|
||||
theme: "teamsHighContrastTheme",
|
||||
colorScheme: {
|
||||
elevations: {
|
||||
8: "none",
|
||||
16: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
export const themes: { [themeKey: string]: ThemeInput<any> } = { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
teamsTheme: mergeThemes(teamsTheme, {
|
||||
siteVariables: teamsNextThemeSiteVariables.teamsTheme,
|
||||
}),
|
||||
teamsDarkTheme: mergeThemes(teamsDarkTheme, {
|
||||
siteVariables: teamsNextThemeSiteVariables.teamsDarkTheme,
|
||||
}),
|
||||
teamsHighContrastTheme: mergeThemes(teamsHighContrastTheme, {
|
||||
siteVariables: teamsNextThemeSiteVariables.teamsHighContrastTheme,
|
||||
}),
|
||||
};
|
||||
export const teamsNextVariableAssignments = {
|
||||
componentStyles: {
|
||||
Box: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
backgroundColor: variables.backgroundColor,
|
||||
boxShadow: variables.elevation,
|
||||
}),
|
||||
},
|
||||
Button: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
color: variables.color,
|
||||
}),
|
||||
},
|
||||
ButtonContent: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
fontWeight: variables.fontWeight,
|
||||
}),
|
||||
},
|
||||
Card: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
boxShadow: variables.elevation,
|
||||
"&:hover": { boxShadow: variables.hoverElevation },
|
||||
"&:focus": { boxShadow: variables.elevation },
|
||||
}),
|
||||
},
|
||||
Flex: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
color: variables.color,
|
||||
backgroundColor: variables.backgroundColor,
|
||||
boxShadow: variables.elevation,
|
||||
}),
|
||||
},
|
||||
ToolbarItem: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
color: variables.color,
|
||||
fontWeight: variables.fontWeight,
|
||||
}),
|
||||
},
|
||||
PopupContent: {
|
||||
content: ({ variables }: ComponentVariablesObject) => ({
|
||||
boxShadow: variables.elevation,
|
||||
borderWidth: variables.borderWidth,
|
||||
}),
|
||||
},
|
||||
PopupButton: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
color: variables.color,
|
||||
}),
|
||||
},
|
||||
TableRow: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
height: variables.compactRow
|
||||
? variables.compactRowHeight
|
||||
: variables.defaultRowHeight,
|
||||
minHeight: variables.compactRow
|
||||
? variables.compactRowMinHeight
|
||||
: variables.defaultRowMinHeight,
|
||||
alignItems: variables.cellVerticalAlignment,
|
||||
}),
|
||||
},
|
||||
TableCell: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
paddingTop: variables.compactRow
|
||||
? variables.compactRowVerticalPadding
|
||||
: variables.defaultRowVerticalPadding,
|
||||
paddingBottom: variables.compactRow
|
||||
? variables.compactRowVerticalPadding
|
||||
: variables.defaultRowVerticalPadding,
|
||||
}),
|
||||
},
|
||||
TreeItem: {
|
||||
root: ({ variables }: ComponentVariablesObject) => ({
|
||||
color: variables.color,
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const getFluentUIThemeOrDefault = (theme?: IPartialTheme | ITheme): ITheme => {
|
||||
let currentTheme;
|
||||
|
||||
if (theme) {
|
||||
currentTheme = getVariant(theme, VariantThemeType.None);
|
||||
} else {
|
||||
const themeColorsFromWindow: Partial<IPalette> = window.__themeState__?.theme;
|
||||
if (themeColorsFromWindow) {
|
||||
currentTheme = createTheme({
|
||||
palette: themeColorsFromWindow
|
||||
});
|
||||
}
|
||||
else {
|
||||
currentTheme = getTheme();
|
||||
}
|
||||
}
|
||||
|
||||
return currentTheme;
|
||||
};
|
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 933 B |
@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-4.7/includes/tsconfig-web.json",
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-4.5/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
@ -13,6 +13,8 @@
|
||||
"outDir": "lib",
|
||||
"inlineSources": false,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": false,
|
||||
"noUnusedLocals": false,
|
||||
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
@ -31,5 +33,9 @@
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user