Skip to content

Commit

Permalink
Merge dark mode into master!!!! (microsoft#326)
Browse files Browse the repository at this point in the history
For more information, please view the roosterjs-darkmode-alpha branch.
  • Loading branch information
William Saulnier authored Jul 30, 2019
1 parent edf2355 commit 6049453
Show file tree
Hide file tree
Showing 24 changed files with 1,534 additions and 1,108 deletions.
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
registry=https://registry.npmjs.com/
12 changes: 10 additions & 2 deletions packages/roosterjs-editor-api/lib/format/clearFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,18 @@ export default function clearFormat(editor: Editor) {
setFontSize(editor, defaultFormat.fontSize);
}
if (defaultFormat.textColor) {
setTextColor(editor, defaultFormat.textColor);
if (defaultFormat.textColors) {
setTextColor(editor, defaultFormat.textColors);
} else {
setTextColor(editor, defaultFormat.textColor);
}
}
if (defaultFormat.backgroundColor) {
setBackgroundColor(editor, defaultFormat.backgroundColor);
if (defaultFormat.backgroundColors) {
setBackgroundColor(editor, defaultFormat.backgroundColors);
} else {
setBackgroundColor(editor, defaultFormat.backgroundColor);
}
}
if (defaultFormat.bold) {
toggleBold(editor);
Expand Down
164 changes: 82 additions & 82 deletions packages/roosterjs-editor-api/lib/format/replaceWithNode.ts
Original file line number Diff line number Diff line change
@@ -1,82 +1,82 @@
import { Editor } from 'roosterjs-editor-core';
import { PositionContentSearcher } from 'roosterjs-editor-dom';
import { ContentPosition } from 'roosterjs-editor-types';

/**
* Replace text before current selection with a node, current selection will be kept if possible
* @param editor The editor instance
* @param text The text for matching. We will try to match the text with the text before cursor
* @param node The node to replace the text with
* @param exactMatch True if the text must appear exactly before selection,
* otherwise there can be some text between the tearget text and selection
* @param searcher Optional PositionContentSearcher of current selection to help search text
*/
export default function replaceWithNode(
editor: Editor,
text: string,
node: Node,
exactMatch: boolean,
searcher?: PositionContentSearcher
): boolean;

/**
* Replace a given range with a node, current selection will be kept if possible
* @param editor The editor instance
* @param range The range to replace from
* @param node The node to replace the text with
* @param exactMatch True if the text must appear exactly before selection,
* otherwise there can be some text between the tearget text and selection
*/
export default function replaceWithNode(
editor: Editor,
range: Range,
node: Node,
exactMatch: boolean
): boolean;

export default function replaceWithNode(
editor: Editor,
textOrRange: string | Range,
node: Node,
exactMatch: boolean,
searcher?: PositionContentSearcher
): boolean {
// Make sure the text and node is valid
if (!textOrRange || !node) {
return false;
}

let range: Range;

if (typeof textOrRange == 'string') {
searcher = searcher || editor.getContentSearcherOfCursor();
range = searcher && searcher.getRangeFromText(textOrRange, exactMatch);
} else {
range = textOrRange;
}

if (range) {
const backupRange = editor.getSelectionRange();

// If the range to replace is right before current cursor, it is actually an exact match
if (
backupRange.collapsed &&
range.endContainer == backupRange.startContainer &&
range.endOffset == backupRange.startOffset
) {
exactMatch = true;
}

editor.insertNode(node, {
position: ContentPosition.Range,
updateCursor: exactMatch,
replaceSelection: true,
insertOnNewLine: false,
range: range,
});

return true;
}

return false;
}
import { ContentPosition } from 'roosterjs-editor-types';
import { Editor } from 'roosterjs-editor-core';
import { PositionContentSearcher } from 'roosterjs-editor-dom';

/**
* Replace text before current selection with a node, current selection will be kept if possible
* @param editor The editor instance
* @param text The text for matching. We will try to match the text with the text before cursor
* @param node The node to replace the text with
* @param exactMatch True if the text must appear exactly before selection,
* otherwise there can be some text between the tearget text and selection
* @param searcher Optional PositionContentSearcher of current selection to help search text
*/
export default function replaceWithNode(
editor: Editor,
text: string,
node: Node,
exactMatch: boolean,
searcher?: PositionContentSearcher
): boolean;

/**
* Replace a given range with a node, current selection will be kept if possible
* @param editor The editor instance
* @param range The range to replace from
* @param node The node to replace the text with
* @param exactMatch True if the text must appear exactly before selection,
* otherwise there can be some text between the tearget text and selection
*/
export default function replaceWithNode(
editor: Editor,
range: Range,
node: Node,
exactMatch: boolean
): boolean;

export default function replaceWithNode(
editor: Editor,
textOrRange: string | Range,
node: Node,
exactMatch: boolean,
searcher?: PositionContentSearcher
): boolean {
// Make sure the text and node is valid
if (!textOrRange || !node) {
return false;
}

let range: Range;

if (typeof textOrRange == 'string') {
searcher = searcher || editor.getContentSearcherOfCursor();
range = searcher && searcher.getRangeFromText(textOrRange, exactMatch);
} else {
range = textOrRange;
}

if (range) {
const backupRange = editor.getSelectionRange();

// If the range to replace is right before current cursor, it is actually an exact match
if (
backupRange.collapsed &&
range.endContainer == backupRange.startContainer &&
range.endOffset == backupRange.startOffset
) {
exactMatch = true;
}

editor.insertNode(node, {
position: ContentPosition.Range,
updateCursor: exactMatch,
replaceSelection: true,
insertOnNewLine: false,
range: range,
});

return true;
}

return false;
}
29 changes: 22 additions & 7 deletions packages/roosterjs-editor-api/lib/format/setBackgroundColor.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import applyInlineStyle from '../utils/applyInlineStyle';
import { Editor } from 'roosterjs-editor-core';
import { ModeIndependentColor } from 'roosterjs-editor-types';

/**
* Set background color at current selection
* @param editor The editor instance
* @param color The color string, can be any of the predefined color names (e.g, 'red')
* @param color One of two options:
* The color string, can be any of the predefined color names (e.g, 'red')
* or hexadecimal color string (e.g, '#FF0000') or rgb value (e.g, 'rgb(255, 0, 0)') supported by browser.
* Currently there's no validation to the string, if the passed string is invalid, it won't take affect
*/
export default function setBackgroundColor(editor: Editor, color: string) {
color = color.trim();
applyInlineStyle(editor, (element, isInnerNode) => {
element.style.backgroundColor = isInnerNode ? '' : color;
});
* Alternatively, you can pass a @typedef ModeIndepenentColor. If in light mode, the lightModeColor property will be used.
* If in dark mode, the darkModeColor will be used and the lightModeColor will be used when converting back to light mode.
**/
export default function setBackgroundColor(editor: Editor, color: string | ModeIndependentColor) {
if (typeof color === 'string') {
const trimmedColor = color.trim();
applyInlineStyle(editor, (element, isInnerNode) => {
element.style.backgroundColor = isInnerNode ? '' : trimmedColor;
});
} else {
const darkMode = editor.isDarkMode();
const appliedColor = darkMode ? color.darkModeColor : color.lightModeColor;
applyInlineStyle(editor, (element, isInnerNode) => {
element.style.backgroundColor = isInnerNode ? '' : appliedColor;
if (darkMode) {
element.dataset.ogsb = color.lightModeColor;
}
});
}
}
27 changes: 21 additions & 6 deletions packages/roosterjs-editor-api/lib/format/setTextColor.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import applyInlineStyle from '../utils/applyInlineStyle';
import { Editor } from 'roosterjs-editor-core';
import { ModeIndependentColor } from 'roosterjs-editor-types';

/**
* Set text color at selection
* @param editor The editor instance
* @param color The color string, can be any of the predefined color names (e.g, 'red')
* @param color One of two options:
* The color string, can be any of the predefined color names (e.g, 'red')
* or hexadecimal color string (e.g, '#FF0000') or rgb value (e.g, 'rgb(255, 0, 0)') supported by browser.
* Currently there's no validation to the string, if the passed string is invalid, it won't take affect
* Alternatively, you can pass a @typedef ModeIndepenentColor. If in light mode, the lightModeColor property will be used.
* If in dark mode, the darkModeColor will be used and the lightModeColor will be used when converting back to light mode.
*/
export default function setTextColor(editor: Editor, color: string) {
color = color.trim();
applyInlineStyle(editor, (element, isInnerNode) => {
element.style.color = isInnerNode ? '' : color;
});
export default function setTextColor(editor: Editor, color: string | ModeIndependentColor) {
if (typeof color === 'string') {
const trimmedColor = color.trim();
applyInlineStyle(editor, (element, isInnerNode) => {
element.style.color = isInnerNode ? '' : trimmedColor;
});
} else {
const darkMode = editor.isDarkMode();
const appliedColor = darkMode ? color.darkModeColor : color.lightModeColor;
applyInlineStyle(editor, (element, isInnerNode) => {
element.style.color = isInnerNode ? '' : appliedColor;
if (darkMode) {
element.dataset.ogsc = color.lightModeColor;
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { DefaultFormat } from 'roosterjs-editor-types';
import { getComputedStyles } from 'roosterjs-editor-dom';

const DARK_MODE_DEFAULT_FORMAT = {
backgroundColors: {
darkModeColor: 'rgb(51,51,51)',
lightModeColor: 'rgb(255,255,255)',
},
textColors: {
darkModeColor: 'rgb(255,255,255)',
lightModeColor: 'rgb(0,0,0)',
}
}

export function calculateDefaultFormat(
node: Node,
baseFormat: DefaultFormat,
inDarkMode: boolean
): DefaultFormat {
if (inDarkMode) {
if (!baseFormat.backgroundColors) {
baseFormat.backgroundColors = DARK_MODE_DEFAULT_FORMAT.backgroundColors;
}
if (!baseFormat.textColors) {
baseFormat.textColors = DARK_MODE_DEFAULT_FORMAT.textColors;
}
}

if (baseFormat && Object.keys(baseFormat).length === 0) {
return {};
}

baseFormat = baseFormat || <DefaultFormat>{};
let {
fontFamily,
fontSize,
textColor,
textColors,
backgroundColor,
backgroundColors,
bold,
italic,
underline,
} = baseFormat;
let currentStyles =
fontFamily && fontSize && (textColor || textColors) ? null : getComputedStyles(node);
return {
fontFamily: fontFamily || currentStyles[0],
fontSize: fontSize || currentStyles[1],
get textColor() {
return textColors
? inDarkMode
? textColors.darkModeColor
: textColors.lightModeColor
: textColor || currentStyles[2];
},
textColors: textColors,
get backgroundColor() {
return backgroundColors
? inDarkMode
? backgroundColors.darkModeColor
: backgroundColors.lightModeColor
: backgroundColor || '';
},
backgroundColors: backgroundColors,
bold: bold,
italic: italic,
underline: underline,
};
}
Loading

0 comments on commit 6049453

Please sign in to comment.