import * as React from 'react';
import { AccessibilityChecker } from './AccessibilityChecker';
import {
BaseSlots,
IThemeRules,
FabricSlots,
ThemeGenerator,
themeRulesStandardCreator,
} from 'office-ui-fabric-react/lib/ThemeGenerator';
import { Async } from 'office-ui-fabric-react/lib/Utilities';
import { createTheme, ITheme } from 'office-ui-fabric-react/lib/Styling';
import { ThemeSlots } from './ThemeSlots';
import { getColorFromString, IColor } from 'office-ui-fabric-react/lib/Color';
import { Header } from './Header';
import { IconButton } from 'office-ui-fabric-react/lib/Button';
import { isDark } from 'office-ui-fabric-react/lib/utilities/color/shades';
import { mergeStyles } from '@uifabric/merge-styles';
import { Samples } from './Samples/index';
import { Stack, IStackProps } from 'office-ui-fabric-react/lib/Stack';
import { ThemeDesignerColorPicker } from './ThemeDesignerColorPicker';
import { Text } from 'office-ui-fabric-react';
import { ThemeProvider } from 'office-ui-fabric-react/lib/Foundation';
import { MainPanelWidth } from '../shared/MainPanelStyles';
export interface IThemingDesignerState {
primaryColor: IColor;
textColor: IColor;
backgroundColor: IColor;
theme?: ITheme;
themeRules?: IThemeRules;
}
const Page = (props: IStackProps) => (
);
const Content = (props: IStackProps) => (
);
const Sidebar = (props: IStackProps) => (
);
const Main = (props: IStackProps) => (
);
export class ThemingDesigner extends React.Component<{}, IThemingDesignerState> {
private _colorChangeTimeout: number;
private _fabricPaletteColorChangeTimeout: number;
private _async: Async;
constructor(props: {}) {
super(props);
this._async = new Async(this);
this.state = this._buildInitialState();
}
public componentWillUnmount(): void {
this._async.dispose();
}
public render() {
return (
Color
{/* the three base slots, prominently displayed at the top of the page */}
);
}
private _onFabricPaletteColorChange = (newColor: IColor | undefined, fabricSlot: FabricSlots) => {
if (this._fabricPaletteColorChangeTimeout) {
this._async.clearTimeout(this._fabricPaletteColorChangeTimeout);
}
if (!this.state.themeRules) {
return;
}
this._fabricPaletteColorChangeTimeout = this._async.setTimeout(() => {
const { themeRules } = this.state;
if (themeRules) {
const currentIsDark = isDark(themeRules[FabricSlots[fabricSlot]].color!);
ThemeGenerator.setSlot(themeRules[FabricSlots[fabricSlot]], newColor, currentIsDark, true, true);
if (currentIsDark !== isDark(themeRules[FabricSlots[fabricSlot]].color!)) {
// isInverted got swapped, so need to refresh slots with new shading rules
ThemeGenerator.insureSlots(themeRules, currentIsDark);
}
}
this.setState({ themeRules: themeRules }, this._makeNewTheme);
}, 20);
};
private _onPrimaryColorPickerChange = (newColor: IColor | undefined) => {
this._onColorChange(this.state.primaryColor, BaseSlots.primaryColor, newColor);
};
private _onTextColorPickerChange = (newColor: IColor | undefined) => {
this._onColorChange(this.state.textColor, BaseSlots.foregroundColor, newColor);
};
private _onBkgColorPickerChange = (newColor: IColor | undefined) => {
this._onColorChange(this.state.backgroundColor, BaseSlots.backgroundColor, newColor);
};
private _makeNewTheme = (): void => {
if (this.state.themeRules) {
const themeAsJson: {
[key: string]: string;
} = ThemeGenerator.getThemeAsJson(this.state.themeRules);
const finalTheme = createTheme({
...{ palette: themeAsJson },
isInverted: isDark(this.state.themeRules[BaseSlots[BaseSlots.backgroundColor]].color!),
});
this.setState({ theme: finalTheme });
}
};
private _onColorChange = (colorToChange: IColor, baseSlot: BaseSlots, newColor: IColor | undefined) => {
if (this._colorChangeTimeout) {
this._async.clearTimeout(this._colorChangeTimeout);
}
if (newColor) {
if (colorToChange === this.state.primaryColor) {
this.setState({ primaryColor: newColor });
} else if (colorToChange === this.state.textColor) {
this.setState({ textColor: newColor });
} else if (colorToChange === this.state.backgroundColor) {
this.setState({ backgroundColor: newColor });
} else {
return;
}
this._colorChangeTimeout = this._async.setTimeout(() => {
const themeRules = this.state.themeRules;
if (themeRules) {
const currentIsDark = isDark(themeRules[BaseSlots[BaseSlots.backgroundColor]].color!);
ThemeGenerator.setSlot(themeRules[BaseSlots[baseSlot]], newColor, currentIsDark, true, true);
if (currentIsDark !== isDark(themeRules[BaseSlots[BaseSlots.backgroundColor]].color!)) {
// isInverted got swapped, so need to refresh slots with new shading rules
ThemeGenerator.insureSlots(themeRules, currentIsDark);
}
}
this.setState({ themeRules: themeRules }, this._makeNewTheme);
}, 20);
// 20ms is low enough that you can slowly drag to change color and see that theme,
// but high enough that quick changes don't get bogged down by a million changes inbetween
}
};
private _buildInitialState = (): IThemingDesignerState => {
const themeRules = themeRulesStandardCreator();
const colors = {
primaryColor: getColorFromString('#0078d4')!,
textColor: getColorFromString('#323130')!,
backgroundColor: getColorFromString('#ffffff')!,
};
ThemeGenerator.insureSlots(themeRules, isDark(themeRules[BaseSlots[BaseSlots.backgroundColor]].color!));
ThemeGenerator.setSlot(themeRules[BaseSlots[BaseSlots.primaryColor]], colors.primaryColor, undefined, false, false);
ThemeGenerator.setSlot(themeRules[BaseSlots[BaseSlots.foregroundColor]], colors.textColor, undefined, false, false);
ThemeGenerator.setSlot(
themeRules[BaseSlots[BaseSlots.backgroundColor]],
colors.backgroundColor,
undefined,
false,
false,
);
const themeAsJson: {
[key: string]: string;
} = ThemeGenerator.getThemeAsJson(themeRules);
const finalTheme = createTheme({
...{ palette: themeAsJson },
isInverted: isDark(themeRules[BaseSlots[BaseSlots.backgroundColor]].color!),
});
const state = {
...colors,
theme: finalTheme,
themeRules: themeRules,
};
return state;
};
}