Skip to content

Commit

Permalink
Merge pull request #2682 from microsoft/u/jisong/colorkey
Browse files Browse the repository at this point in the history
Allow customization of color key generation
  • Loading branch information
haven2world committed Jun 7, 2024
2 parents 48855d1 + 1b67dd6 commit 3cab230
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { defaultGenerateColorKey } from 'roosterjs-content-model-dom';
import type {
DarkColorHandler,
ColorTransformFunction,
Expand All @@ -8,7 +9,8 @@ class DarkColorHandlerImpl implements DarkColorHandler {
constructor(
private readonly root: HTMLElement,
public getDarkColor: ColorTransformFunction,
public readonly knownColors: Record<string, Colors>
public readonly knownColors: Record<string, Colors>,
public generateColorKey: ColorTransformFunction
) {}

updateKnownColor(isDarkMode: boolean, key?: string, colorPair?: Colors): void {
Expand Down Expand Up @@ -48,7 +50,8 @@ class DarkColorHandlerImpl implements DarkColorHandler {
export function createDarkColorHandler(
root: HTMLElement,
getDarkColor: ColorTransformFunction,
knownColors: Record<string, Colors> = {}
knownColors: Record<string, Colors> = {},
generateColorKey: ColorTransformFunction = defaultGenerateColorKey
): DarkColorHandler {
return new DarkColorHandlerImpl(root, getDarkColor, knownColors);
return new DarkColorHandlerImpl(root, getDarkColor, knownColors, generateColorKey);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export function createEditorCore(contentDiv: HTMLDivElement, options: EditorOpti
darkColorHandler: createDarkColorHandler(
contentDiv,
options.getDarkColor ?? getDarkColorFallback,
options.knownColors
options.knownColors,
options.generateColorKey
),
trustedHTMLHandler: options.trustedHTMLHandler || defaultTrustHtmlHandler,
domHelper: createDOMHelper(contentDiv),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,21 @@ describe('DarkColorHandlerImpl.ctor', () => {
);
});

it('with knownColors', () => {
it('with knownColors and generateColorKey', () => {
const div = document.createElement('div');
const mockedGetDarkColor = jasmine.createSpy('getDarkColor');
const mockedKnownColors = 'KNOWN' as any;
const handler = createDarkColorHandler(div, mockedGetDarkColor, mockedKnownColors);
const mockedGenerateColorKey = 'KEY' as any;
const handler = createDarkColorHandler(
div,
mockedGetDarkColor,
mockedKnownColors,
mockedGenerateColorKey
);

expect(handler.knownColors).toEqual(mockedKnownColors);
expect(handler.getDarkColor).toBe(mockedGetDarkColor);
expect(handler.generateColorKey).toBe(mockedGenerateColorKey);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ describe('createEditorCore', () => {
expect(DarkColorHandlerImpl.createDarkColorHandler).toHaveBeenCalledWith(
mockedDiv,
getDarkColorFallback,
undefined,
undefined
);
});
Expand All @@ -146,6 +147,8 @@ describe('createEditorCore', () => {
const mockedGetDarkColor = 'DARK' as any;
const mockedTrustHtmlHandler = 'TRUST' as any;
const mockedDisposeErrorHandler = 'DISPOSE' as any;
const mockedGenerateColorKey = 'KEY' as any;
const mockedKnownColors = 'COLORS' as any;
const mockedOptions = {
coreApiOverride: {
a: 'b',
Expand All @@ -154,6 +157,8 @@ describe('createEditorCore', () => {
getDarkColor: mockedGetDarkColor,
trustedHTMLHandler: mockedTrustHtmlHandler,
disposeErrorHandler: mockedDisposeErrorHandler,
generateColorKey: mockedGenerateColorKey,
knownColors: mockedKnownColors,
} as any;

runTest(mockedDiv, mockedOptions, {
Expand Down Expand Up @@ -181,7 +186,8 @@ describe('createEditorCore', () => {
expect(DarkColorHandlerImpl.createDarkColorHandler).toHaveBeenCalledWith(
mockedDiv,
mockedGetDarkColor,
undefined
mockedKnownColors,
mockedGenerateColorKey
);
});

Expand Down Expand Up @@ -214,6 +220,7 @@ describe('createEditorCore', () => {
expect(DarkColorHandlerImpl.createDarkColorHandler).toHaveBeenCalledWith(
mockedDiv,
getDarkColorFallback,
undefined,
undefined
);
});
Expand Down Expand Up @@ -247,6 +254,7 @@ describe('createEditorCore', () => {
expect(DarkColorHandlerImpl.createDarkColorHandler).toHaveBeenCalledWith(
mockedDiv,
getDarkColorFallback,
undefined,
undefined
);
});
Expand Down Expand Up @@ -280,6 +288,7 @@ describe('createEditorCore', () => {
expect(DarkColorHandlerImpl.createDarkColorHandler).toHaveBeenCalledWith(
mockedDiv,
getDarkColorFallback,
undefined,
undefined
);
});
Expand Down Expand Up @@ -313,6 +322,7 @@ describe('createEditorCore', () => {
expect(DarkColorHandlerImpl.createDarkColorHandler).toHaveBeenCalledWith(
mockedDiv,
getDarkColorFallback,
undefined,
undefined
);
});
Expand Down Expand Up @@ -346,6 +356,7 @@ describe('createEditorCore', () => {
expect(DarkColorHandlerImpl.createDarkColorHandler).toHaveBeenCalledWith(
mockedDiv,
getDarkColorFallback,
undefined,
undefined
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { getObjectKeys } from '../../domUtils/getObjectKeys';
import type { DarkColorHandler, Colors } from 'roosterjs-content-model-types';
import type {
DarkColorHandler,
Colors,
ColorTransformFunction,
} from 'roosterjs-content-model-types';

/**
* List of deprecated colors
Expand Down Expand Up @@ -97,15 +101,13 @@ export function setColor(
color = fallbackColor ?? color;

if (darkColorHandler && color) {
const key = existingKey || `${COLOR_VAR_PREFIX}_${color.replace(/[^\d\w]/g, '_')}`;
const colorType = isBackground ? 'background' : 'text';
const key =
existingKey ||
darkColorHandler.generateColorKey(color, undefined /*baseLValue*/, colorType, element);
const darkModeColor =
darkColorHandler.knownColors?.[key]?.darkModeColor ||
darkColorHandler.getDarkColor(
color,
undefined /*baseLAValue*/,
isBackground ? 'background' : 'text',
element
);
darkColorHandler.getDarkColor(color, undefined /*baseLValue*/, colorType, element);

darkColorHandler.updateKnownColor(isDarkMode, key, {
lightModeColor: color,
Expand All @@ -119,6 +121,15 @@ export function setColor(
element.style.setProperty(isBackground ? 'background-color' : 'color', color || null);
}

/**
* Generate color key for dark color
* @param lightColor The input light color
* @returns Key of the color
*/
export const defaultGenerateColorKey: ColorTransformFunction = lightColor => {
return `${COLOR_VAR_PREFIX}_${lightColor.replace(/[^\d\w]/g, '_')}`;
};

/**
* Parse color string to r/g/b value.
* If the given color is not in a recognized format, return null
Expand Down
8 changes: 7 additions & 1 deletion packages/roosterjs-content-model-dom/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,13 @@ export { getAutoListStyleType } from './modelApi/list/getAutoListStyleType';

export { parseValueWithUnit } from './formatHandlers/utils/parseValueWithUnit';
export { BorderKeys } from './formatHandlers/common/borderFormatHandler';
export { DeprecatedColors, getColor, setColor, parseColor } from './formatHandlers/utils/color';
export {
DeprecatedColors,
getColor,
setColor,
parseColor,
defaultGenerateColorKey,
} from './formatHandlers/utils/color';

export {
createDomToModelContext,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { backgroundColorFormatHandler } from '../../../lib/formatHandlers/common/backgroundColorFormatHandler';
import { createDomToModelContext } from '../../../lib/domToModel/context/createDomToModelContext';
import { createModelToDomContext } from '../../../lib/modelToDom/context/createModelToDomContext';
import { DeprecatedColors } from '../../../lib/formatHandlers/utils/color';
import { defaultGenerateColorKey, DeprecatedColors } from '../../../lib/formatHandlers/utils/color';
import { expectHtml } from '../../testUtils';
import {
BackgroundColorFormat,
Expand Down Expand Up @@ -113,6 +113,7 @@ describe('backgroundColorFormatHandler.apply', () => {
context.darkColorHandler = {
updateKnownColor: () => {},
getDarkColor: (lightColor: string) => `var(--darkColor_${lightColor}, ${lightColor})`,
generateColorKey: defaultGenerateColorKey,
} as any;

backgroundColorFormatHandler.apply(format, div, context);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createDomToModelContext } from '../../../lib/domToModel/context/createDomToModelContext';
import { createModelToDomContext } from '../../../lib/modelToDom/context/createModelToDomContext';
import { defaultGenerateColorKey, DeprecatedColors } from '../../../lib';
import { defaultHTMLStyleMap } from '../../../lib/config/defaultHTMLStyleMap';
import { DeprecatedColors } from '../../../lib';
import { expectHtml } from '../../testUtils';
import { textColorFormatHandler } from '../../../lib/formatHandlers/segment/textColorFormatHandler';
import {
Expand Down Expand Up @@ -110,6 +110,7 @@ describe('textColorFormatHandler.apply', () => {
context.darkColorHandler = {
updateKnownColor: () => {},
getDarkColor: (lightColor: string) => `var(--darkColor_${lightColor}, ${lightColor})`,
generateColorKey: defaultGenerateColorKey,
} as any;

format = {};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Colors, DarkColorHandler } from 'roosterjs-content-model-types';
import { getColor, parseColor, setColor } from '../../../lib/formatHandlers/utils/color';
import {
defaultGenerateColorKey,
getColor,
parseColor,
setColor,
} from '../../../lib/formatHandlers/utils/color';

describe('getColor without darkColorHandler', () => {
it('no color', () => {
Expand Down Expand Up @@ -122,6 +127,7 @@ describe('getColor with darkColorHandler', () => {
getDarkColor: getDarkColorSpy,
updateKnownColor: updateKnownColorSpy,
reset: null!,
generateColorKey: defaultGenerateColorKey,
};
});

Expand Down Expand Up @@ -351,6 +357,7 @@ describe('setColor with darkColorHandler', () => {
getDarkColor: getDarkColorSpy,
updateKnownColor: updateKnownColorSpy,
reset: null!,
generateColorKey: defaultGenerateColorKey,
};
});

Expand Down Expand Up @@ -489,6 +496,49 @@ describe('setColor with darkColorHandler', () => {
darkModeColor: '--dark_green',
});
});

it('with customized generateColorKey', () => {
const generateColorKeySpy = jasmine
.createSpy('generateColorKey')
.and.callFake((color: string) => '--' + color + '_key');

const lightDiv = document.createElement('div');
const darkDiv = document.createElement('div');

darkColorHandler.generateColorKey = generateColorKeySpy;

setColor(lightDiv, 'red', true, false, darkColorHandler);
setColor(lightDiv, 'green', false, false, darkColorHandler);
setColor(darkDiv, 'red', true, true, darkColorHandler);
setColor(darkDiv, 'green', false, true, darkColorHandler);

expect(lightDiv.outerHTML).toBe('<div style="background-color: red; color: green;"></div>');
expect(darkDiv.outerHTML).toBe(
'<div style="background-color: var(--red_key, red); color: var(--green_key, green);"></div>'
);
expect(getDarkColorSpy).toHaveBeenCalledTimes(4);
expect(getDarkColorSpy).toHaveBeenCalledWith('green', undefined, 'text', lightDiv);
expect(getDarkColorSpy).toHaveBeenCalledWith('red', undefined, 'background', lightDiv);
expect(getDarkColorSpy).toHaveBeenCalledWith('green', undefined, 'text', darkDiv);
expect(getDarkColorSpy).toHaveBeenCalledWith('red', undefined, 'background', darkDiv);
expect(updateKnownColorSpy).toHaveBeenCalledTimes(4);
expect(updateKnownColorSpy).toHaveBeenCalledWith(false, '--red_key', {
lightModeColor: 'red',
darkModeColor: '--dark_red',
});
expect(updateKnownColorSpy).toHaveBeenCalledWith(false, '--green_key', {
lightModeColor: 'green',
darkModeColor: '--dark_green',
});
expect(updateKnownColorSpy).toHaveBeenCalledWith(true, '--red_key', {
lightModeColor: 'red',
darkModeColor: '--dark_red',
});
expect(updateKnownColorSpy).toHaveBeenCalledWith(true, '--green_key', {
lightModeColor: 'green',
darkModeColor: '--dark_green',
});
});
});

describe('parseColor', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,9 @@ export interface DarkColorHandler {
* A util function to transform light mode color to dark mode color
*/
getDarkColor: ColorTransformFunction;

/**
* Generate color key for dark mode color.
*/
generateColorKey: ColorTransformFunction;
}
Loading

0 comments on commit 3cab230

Please sign in to comment.