Aravind Jaimon
Aravind Jaimon

Reputation: 85

How to generate a Fluent UI theme with in the library?

I was creating a react application with Fluent UI - React, I want something like each user can pick a Primary Color, Text Color, and Background Color when they sign up and their app will be in that theme like the same way done in the Theming Designer

The theming designer gives me the following output.

const appTheme: PartialTheme = createTheme({
  palette: {
    themePrimary: "#ff5460",
    themeLighterAlt: "#0a0304",
    themeLighter: "#290d0f",
    themeLight: "#4d191d",
    themeTertiary: "#993239",
    themeSecondary: "#e04a54",
    themeDarkAlt: "#ff656f",
    themeDark: "#ff7d86",
    themeDarker: "#ff9fa6",
    neutralLighterAlt: "#000000",
    neutralLighter: "#000000",
    neutralLight: "#000000",
    neutralQuaternaryAlt: "#000000",
    neutralQuaternary: "#000000",
    neutralTertiaryAlt: "#000000",
    neutralTertiary: "#c8c8c8",
    neutralSecondary: "#d0d0d0",
    neutralPrimaryAlt: "#dadada",
    neutralPrimary: "#ffffff",
    neutralDark: "#f4f4f4",
    black: "#f8f8f8",
    white: "#000000",
  },
});

Is there a function that generates theme in Fluent UI in which I just want to provide Primary Color, Text Color, and Background Color and it gives the entire theme so that I can add it to the Theme Provider component.

Upvotes: 2

Views: 2626

Answers (2)

Majiy
Majiy

Reputation: 1920

The code given in the answer by Aravid Jaimon did produce incomplete results for me.

This is the solution I came up with for this purposes. It is mostly condensed from the ThemingDesigner.tsx source code:

import {
    BaseSlots,
    createTheme,
    getColorFromString,
    isDark,
    IThemeRules,
    ThemeGenerator,
    themeRulesStandardCreator,
} from '@fluentui/react';

function generateTheme(
    {
        primaryColor, textColor, backgroundColor,
    }: {
        primaryColor: string, textColor: string, backgroundColor: string,
    },
) {
    const themeRules = themeRulesStandardCreator();
    const colors = {
        primaryColor: getColorFromString(primaryColor)!,
        textColor: getColorFromString(textColor)!,
        backgroundColor: getColorFromString(backgroundColor)!,
    };

    const isCustomization = false;
    const overwriteCustomColor = true;

    ThemeGenerator.setSlot(
        themeRules[BaseSlots[BaseSlots.backgroundColor]],
        colors.backgroundColor,
        undefined,
        isCustomization,
        overwriteCustomColor,
    );

    const currentIsDark = isDark(themeRules[BaseSlots[BaseSlots.backgroundColor]].color!);

    ThemeGenerator.setSlot(
        themeRules[BaseSlots[BaseSlots.primaryColor]],
        colors.primaryColor,
        currentIsDark,
        isCustomization,
        overwriteCustomColor,
    );
    ThemeGenerator.setSlot(
        themeRules[BaseSlots[BaseSlots.foregroundColor]],
        colors.textColor,
        currentIsDark,
        isCustomization,
        overwriteCustomColor,
    );

    // strip out the unnecessary shade slots from the final output theme
    const abridgedTheme: IThemeRules = Object.entries(themeRules).reduce(
        (acc, [ruleName, ruleValue]) => (
            (
                ruleName.indexOf('ColorShade') === -1
                && ruleName !== 'primaryColor'
                && ruleName !== 'backgroundColor'
                && ruleName !== 'foregroundColor'
                && ruleName.indexOf('body') === -1
            )
                ? {
                    ...acc,
                    [ruleName]: ruleValue,
                }
                : acc
        ),
        {} as IThemeRules,
    );

    return createTheme({ palette: ThemeGenerator.getThemeAsJson(abridgedTheme) });
}

Upvotes: 1

Aravind Jaimon
Aravind Jaimon

Reputation: 85

Resolved it by creating a function,

import {
  BaseSlots,
  createTheme,
  getColorFromString,
  isDark,
  Theme,
  ThemeGenerator,
  themeRulesStandardCreator,
} from "@fluentui/react";

const generateTheme = (
  primaryColor: string,
  textColor: string,
  backgroundColor: string
): Theme => {
  const themeRules = themeRulesStandardCreator();
  const colors = {
    pColor: getColorFromString(primaryColor)!,
    tColor: getColorFromString(textColor)!,
    bColor: getColorFromString(backgroundColor)!,
  };

  const currentIsDark = isDark(
    themeRules[BaseSlots[BaseSlots.backgroundColor]].color!
  );

  ThemeGenerator.insureSlots(themeRules, currentIsDark);
  ThemeGenerator.setSlot(
    themeRules[BaseSlots[BaseSlots.primaryColor]],
    colors.pColor,
    currentIsDark,
    true,
    true
  );
  ThemeGenerator.setSlot(
    themeRules[BaseSlots[BaseSlots.foregroundColor]],
    colors.tColor,
    currentIsDark,
    true,
    true
  );
  ThemeGenerator.setSlot(
    themeRules[BaseSlots[BaseSlots.backgroundColor]],
    colors.bColor,
    currentIsDark,
    true,
    true
  );

  const themeAsJson: {
    [key: string]: string;
  } = ThemeGenerator.getThemeAsJson(themeRules);

  const finalTheme = createTheme({
    ...{ palette: themeAsJson },
    isInverted: currentIsDark,
  });

  return finalTheme;
};

export default generateTheme;

Actually, this must be part of Fluent UI

Upvotes: 3

Related Questions