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; }; }