office-ui-fabric-react
Version:
Reusable React components for building experiences for Microsoft 365.
219 lines • 9.97 kB
JavaScript
import { getColorFromString } from '../../utilities/color/getColorFromString';
import { isValidShade, getShade, getBackgroundShade } from '../../utilities/color/shades';
import { format } from '../../Utilities';
var ThemeGenerator = /** @class */ (function () {
function ThemeGenerator() {
}
/**
* Sets an IThemeSlotRule to the given color and cascades it to the rest of the theme, updating other IThemeSlotRules
* in the theme that inherit from that color.
* @param isInverted - whether it's a dark theme or not, which affects the algorithm used to generate shades
* @param isCustomization - should be true only if it's a user action, and indicates overwriting the slot's
* inheritance (if any)
* @param overwriteCustomColor - A slot could have a generated color based on its inheritance rules (isCustomized
* is false), or a custom color based on user input (isCustomized is true). This bool tells us whether to override
* existing customized colors.
*/
ThemeGenerator.setSlot = function (rule, color, isInverted, isCustomization, overwriteCustomColor) {
if (isInverted === void 0) { isInverted = false; }
if (isCustomization === void 0) { isCustomization = false; }
if (overwriteCustomColor === void 0) { overwriteCustomColor = true; }
if (!rule.color && rule.value) {
// not a color rule
return;
}
if (overwriteCustomColor) {
var colorAsIColor = void 0;
if (typeof color === 'string') {
colorAsIColor = getColorFromString(color); // the ! is a lie here but we'll verify it in the next line
if (!colorAsIColor) {
throw new Error('color is invalid in setSlot(): ' + color);
}
}
else {
colorAsIColor = color;
}
ThemeGenerator._setSlot(rule, colorAsIColor, isInverted, isCustomization, overwriteCustomColor);
}
else if (rule.color) {
ThemeGenerator._setSlot(rule, rule.color, isInverted, isCustomization, overwriteCustomColor);
}
};
/**
* Sets the color of each slot based on its rule. Slots that don't inherit must have a color already.
* If this completes without error, then the theme is ready to use. (All slots will have a color.)
* setSlot() can be called before this, but this must be called before getThemeAs*().
* Does not override colors of rules where isCustomized is true (i.e. doesn't override existing customizations).
*/
ThemeGenerator.insureSlots = function (slotRules, isInverted) {
// Get all the "root" rules, the ones which don't inherit. Then "set" them to trigger updating dependent slots.
for (var ruleName in slotRules) {
if (slotRules.hasOwnProperty(ruleName)) {
var rule = slotRules[ruleName];
if (!rule.inherits && !rule.value) {
if (!rule.color) {
throw new Error('A color slot rule that does not inherit must provide its own color.');
}
ThemeGenerator._setSlot(rule, rule.color, isInverted, false, false);
}
}
}
};
/**
* Gets the JSON-formatted blob that describes the theme, usable with the REST request endpoints:
* ```
* { [theme slot name as string] : [color as string],
* "tokenName": "#f00f00",
* "tokenName2": "#ba2ba2",
* ... }
* ```
*/
ThemeGenerator.getThemeAsJson = function (slotRules) {
var theme = {};
for (var ruleName in slotRules) {
if (slotRules.hasOwnProperty(ruleName)) {
var rule = slotRules[ruleName];
theme[rule.name] = rule.color ? rule.color.str : rule.value || '';
}
}
return theme;
};
/**
* Gets code-formatted load theme blob that can be copy and pasted.
* Only used for the old theme designer, where loadTheme usage is acceptable,
* unlike in the new theme designer.
*/
ThemeGenerator.getThemeAsCode = function (slotRules) {
var output = 'loadTheme({\n palette: {\n';
return ThemeGenerator._makeRemainingCode(output, slotRules);
};
/**
* Gets code-formatted load theme blob, specifically for the new theme designer,
* aka.ms/themedesigner. Shouldn't use loadTheme like the old theme designer since it's deprecated.
* We want to use the theme object from createTheme and use the Customizations.applySettings API instead.
*/
ThemeGenerator.getThemeAsCodeWithCreateTheme = function (slotRules) {
var output = 'const myTheme = createTheme({\n palette: {\n';
return ThemeGenerator._makeRemainingCode(output, slotRules);
};
/**
* Gets the theme as a list of SASS variables that can be used in code
* ```
* $tokenName: "[theme:tokenName, default:#f00f00]";
* $tokenName2: "[theme:tokenName2, default:#ba2ba2]";
* ...
* ```
*/
ThemeGenerator.getThemeAsSass = function (slotRules) {
var sassVarTemplate = '${0}Color: "[theme: {1}, default: {2}]";\n';
var output = '';
for (var ruleName in slotRules) {
if (slotRules.hasOwnProperty(ruleName)) {
var rule = slotRules[ruleName];
var camelCasedName = rule.name.charAt(0).toLowerCase() + rule.name.slice(1);
output += format(sassVarTemplate, camelCasedName, camelCasedName, rule.color ? rule.color.str : rule.value || '');
}
}
return output;
};
/**
* Gets the theme formatted for PowerShell scripts
* ```
* @{
* "tokenName" = "#f00f00";
* "tokenName2" = "#ba2ba2";
* ...
* }
* ```
*/
ThemeGenerator.getThemeForPowerShell = function (slotRules) {
var psVarTemplate = '"{0}" = "{1}";\n';
var output = '';
for (var ruleName in slotRules) {
if (slotRules.hasOwnProperty(ruleName)) {
var rule = slotRules[ruleName];
if (rule.value) {
// skip this one, it's not a color
continue;
}
var camelCasedName = rule.name.charAt(0).toLowerCase() + rule.name.slice(1);
var outputColor = rule.color ? '#' + rule.color.hex : rule.value || '';
// powershell endpoint uses the RGBA format
if (rule.color && rule.color.a && rule.color.a !== 100) {
outputColor += String(rule.color.a.toString(16));
}
output += format(psVarTemplate, camelCasedName, outputColor);
}
}
return '@{\n' + output + '}';
};
/**
* Sets the given slot's color to the appropriate color, shading it if necessary.
* Then, iterates through all other rules (that are this rule's dependents) to update them accordingly.
* @param isCustomization - If true, it's a user-provided color, which should be to that raw color.
* If false, the rule it's inheriting from changed, so updated using asShade.
*/
ThemeGenerator._setSlot = function (rule, color, isInverted, isCustomization, overwriteCustomColor) {
if (overwriteCustomColor === void 0) { overwriteCustomColor = true; }
if (!rule.color && rule.value) {
// not a color rule
return;
}
if (overwriteCustomColor || !rule.color || !rule.isCustomized || !rule.inherits) {
// set the rule's color under these conditions
if ((overwriteCustomColor || !rule.isCustomized) &&
!isCustomization &&
rule.inherits &&
isValidShade(rule.asShade)) {
// it's inheriting by shade
if (rule.isBackgroundShade) {
rule.color = getBackgroundShade(color, rule.asShade, isInverted);
}
else {
rule.color = getShade(color, rule.asShade, isInverted);
}
rule.isCustomized = false;
}
else {
rule.color = color;
rule.isCustomized = true;
}
// then update dependent colors
for (var _i = 0, _a = rule.dependentRules; _i < _a.length; _i++) {
var ruleToUpdate = _a[_i];
ThemeGenerator._setSlot(ruleToUpdate, rule.color, isInverted, false, overwriteCustomColor);
}
}
};
/**
* Makes the rest of the code that's used for the load theme blob in the exported codepens of
* both the older sharepoint-specific theme designer and the new theme designer. Takes in
* theme rules and converts them to format fitting a list of palette colors and their values.
* Resulting output looks like:
* ```
* const _theme = createTheme({
* palette: {
* themePrimary: '#0078d4',
* themeLighterAlt: '#f3f9fd',
* ...
* }});
* ```
* The first line is loadTheme instead of createTheme for the old sharepoint theme designer.
*/
ThemeGenerator._makeRemainingCode = function (output, slotRules) {
var attributeTemplate = " {0}: '{1}',\n";
for (var ruleName in slotRules) {
if (slotRules.hasOwnProperty(ruleName)) {
var rule = slotRules[ruleName];
var camelCasedName = rule.name.charAt(0).toLowerCase() + rule.name.slice(1);
var outputColor = rule.color ? '#' + rule.color.hex : rule.value || '';
output += format(attributeTemplate, camelCasedName, outputColor);
}
}
output += ' }});';
return output;
};
return ThemeGenerator;
}());
export { ThemeGenerator };
//# sourceMappingURL=ThemeGenerator.js.map