Skip to content

Commit

Permalink
Name refactorings
Browse files Browse the repository at this point in the history
  • Loading branch information
andrerpena committed May 1, 2022
1 parent 97257fc commit 8152dc9
Show file tree
Hide file tree
Showing 21 changed files with 190 additions and 230 deletions.
8 changes: 7 additions & 1 deletion demo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ import {
import { useTextAreaMarkdownEditor } from "../src/hooks/use-markdown-editor";
import { faBold, faItalic } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { bold, italic } from "../src";

export type DemoProps = {};

export const Demo: React.FunctionComponent<DemoProps> = props => {
const { ref, commandController } = useTextAreaMarkdownEditor();
const { ref, commandController } = useTextAreaMarkdownEditor({
commandMap: {
bold: bold,
italic: italic
}
});

return (
<ChakraProvider>
Expand Down
4 changes: 1 addition & 3 deletions src/commands/command-controller.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { extractKeyActivatedCommands } from "./command-utils";
import * as React from "react";
import { TextController } from "../types/CommandOptions";
import { Command, CommandContext, CommandMap } from "./command";
import { getDefaultCommandMap } from "./markdown-commands/defaults";

export class CommandController {
private readonly textController: TextController;
Expand All @@ -18,7 +16,7 @@ export class CommandController {

constructor(textController: TextController, commandMap: CommandMap) {
this.textController = textController;
this.commandMap = { ...getDefaultCommandMap(), ...(commandMap || {}) };
this.commandMap = commandMap;
this.keyActivatedCommands = extractKeyActivatedCommands(commandMap);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as React from "react";
import { Command } from "../command";
import { selectWord } from "../../util/MarkdownUtil";
import { markdownHelpers } from "../../helpers/markdown-helpers";

export const boldCommand: Command = {
export const bold: Command = {
execute: ({ initialState, textApi }) => {
// Adjust the selection to encompass the whole word if the caret is inside one
const newSelectionRange = selectWord({
const newSelectionRange = markdownHelpers.selectWord({
text: initialState.text,
selection: initialState.selection
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import * as React from "react";
import {
getBreaksNeededForEmptyLineAfter,
getBreaksNeededForEmptyLineBefore,
selectWord
} from "../../util/MarkdownUtil";
import { Command } from "../command";
import { markdownHelpers } from "../../helpers/markdown-helpers";

export const codeCommand: Command = {
export const code: Command = {
execute: async ({ textApi, initialState }) => {
// Adjust the selection to encompass the whole word if the caret is inside one
const newSelectionRange = selectWord({
const newSelectionRange = markdownHelpers.selectWord({
text: initialState.text,
selection: initialState.selection
});
Expand All @@ -30,13 +26,13 @@ export const codeCommand: Command = {
return;
}

const breaksBeforeCount = getBreaksNeededForEmptyLineBefore(
const breaksBeforeCount = markdownHelpers.getBreaksNeededForEmptyLineBefore(
state1.text,
state1.selection.start
);
const breaksBefore = Array(breaksBeforeCount + 1).join("\n");

const breaksAfterCount = getBreaksNeededForEmptyLineAfter(
const breaksAfterCount = markdownHelpers.getBreaksNeededForEmptyLineAfter(
state1.text,
state1.selection.end
);
Expand Down
30 changes: 0 additions & 30 deletions src/commands/markdown-commands/defaults.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from "react";
import { Command } from "../command";
import { selectWord } from "../../util/MarkdownUtil";
import { markdownHelpers } from "../../helpers/markdown-helpers";
import { TextController, TextState } from "../../types/CommandOptions";

function setHeader(
Expand All @@ -9,7 +9,7 @@ function setHeader(
prefix: string
) {
// Adjust the selection to encompass the whole word if the caret is inside one
const newSelectionRange = selectWord({
const newSelectionRange = markdownHelpers.selectWord({
text: initialState.text,
selection: initialState.selection
});
Expand All @@ -23,7 +23,7 @@ function setHeader(
});
}

export const headerCommand: Command = {
export const header: Command = {
execute: ({ initialState, textApi }) => {
setHeader(initialState, textApi, "### ");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as React from "react";
import { Command } from "../command";
import { selectWord } from "../../util/MarkdownUtil";
import { markdownHelpers } from "../../helpers/markdown-helpers";

export const imageCommand: Command = {
export const image: Command = {
execute: ({ initialState, textApi }) => {
// Replaces the current selection with the whole word selected
const state1 = textApi.setSelectionRange(
selectWord({
markdownHelpers.selectWord({
text: initialState.text,
selection: initialState.selection
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as React from "react";
import { selectWord } from "../../util/MarkdownUtil";
import { Command } from "../command";
import { markdownHelpers } from "../../helpers/markdown-helpers";

export const italicCommand: Command = {
export const italic: Command = {
execute: ({ initialState, textApi }) => {
// Adjust the selection to encompass the whole word if the caret is inside one
const newSelectionRange = selectWord({
const newSelectionRange = markdownHelpers.selectWord({
text: initialState.text,
selection: initialState.selection
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as React from "react";
import { selectWord } from "../../util/MarkdownUtil";
import { Command } from "../command";
import { markdownHelpers } from "../../helpers/markdown-helpers";

export const linkCommand: Command = {
export const link: Command = {
execute: ({ initialState, textApi }) => {
// Adjust the selection to encompass the whole word if the caret is inside one
const newSelectionRange = selectWord({
const newSelectionRange = markdownHelpers.selectWord({
text: initialState.text,
selection: initialState.selection
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import * as React from "react";
import {
getBreaksNeededForEmptyLineAfter,
getBreaksNeededForEmptyLineBefore,
selectWord
} from "../../util/MarkdownUtil";
import { TextController, TextState } from "../../types/CommandOptions";
import { Command } from "../command";
import { markdownHelpers } from "../../helpers/markdown-helpers";

export type AlterLineFunction = (line: string, index: number) => string;

Expand Down Expand Up @@ -42,19 +38,19 @@ export const makeList = (
insertBefore: string | AlterLineFunction
) => {
// Adjust the selection to encompass the whole word if the caret is inside one
const newSelectionRange = selectWord({
const newSelectionRange = markdownHelpers.selectWord({
text: state0.text,
selection: state0.selection
});
const state1 = api.setSelectionRange(newSelectionRange);

const breaksBeforeCount = getBreaksNeededForEmptyLineBefore(
const breaksBeforeCount = markdownHelpers.getBreaksNeededForEmptyLineBefore(
state1.text,
state1.selection.start
);
const breaksBefore = Array(breaksBeforeCount + 1).join("\n");

const breaksAfterCount = getBreaksNeededForEmptyLineAfter(
const breaksAfterCount = markdownHelpers.getBreaksNeededForEmptyLineAfter(
state1.text,
state1.selection.end
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import * as React from "react";
import {
getBreaksNeededForEmptyLineAfter,
getBreaksNeededForEmptyLineBefore,
selectWord
} from "../../util/MarkdownUtil";
import { Command } from "../command";
import { markdownHelpers } from "../../helpers/markdown-helpers";

export const quoteCommand: Command = {
export const quote: Command = {
execute: ({ initialState, textApi }) => {
// Adjust the selection to encompass the whole word if the caret is inside one
const newSelectionRange = selectWord({
const newSelectionRange = markdownHelpers.selectWord({
text: initialState.text,
selection: initialState.selection
});
const state1 = textApi.setSelectionRange(newSelectionRange);

const breaksBeforeCount = getBreaksNeededForEmptyLineBefore(
const breaksBeforeCount = markdownHelpers.getBreaksNeededForEmptyLineBefore(
state1.text,
state1.selection.start
);
const breaksBefore = Array(breaksBeforeCount + 1).join("\n");

const breaksAfterCount = getBreaksNeededForEmptyLineAfter(
const breaksAfterCount = markdownHelpers.getBreaksNeededForEmptyLineAfter(
state1.text,
state1.selection.end
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as React from "react";
import { selectWord } from "../../util/MarkdownUtil";
import { Command } from "../command";
import { markdownHelpers } from "../../helpers/markdown-helpers";

export const strikeThroughCommand: Command = {
export const strikethrough: Command = {
execute: ({ initialState, textApi }) => {
// Adjust the selection to encompass the whole word if the caret is inside one
const newSelectionRange = selectWord({
const newSelectionRange = markdownHelpers.selectWord({
text: initialState.text,
selection: initialState.selection
});
Expand Down
113 changes: 113 additions & 0 deletions src/helpers/markdown-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { TextSection } from "../types/TextSection";
import { SelectionRange } from "../types/SelectionRange";

/**
* A list of helpers for manipulating markdown text.
* These helpers do not interface with a textarea. For that, see
*/
export const markdownHelpers = {
getSurroundingWord: function(text: string, position: number): SelectionRange {
if (!text) throw Error("Argument 'text' should be truthy");

const isWordDelimiter = (c: string) => c === " " || c.charCodeAt(0) === 10;

// leftIndex is initialized to 0 because if selection is 0, it won't even enter the iteration
let start = 0;
// rightIndex is initialized to text.length because if selection is equal to text.length it won't even enter the interation
let end = text.length;

// iterate to the left
for (let i = position; i - 1 > -1; i--) {
if (isWordDelimiter(text[i - 1])) {
start = i;
break;
}
}

// iterate to the right
for (let i = position; i < text.length; i++) {
if (isWordDelimiter(text[i])) {
end = i;
break;
}
}

return { start, end };
},

/**
* If the cursor is inside a word and (selection.start === selection.end)
* returns a new Selection where the whole word is selected
* @param text
* @param selection
*/
selectWord: function({ text, selection }: TextSection): SelectionRange {
if (text && text.length && selection.start === selection.end) {
// the user is pointing to a word
return this.getSurroundingWord(text, selection.start);
}
return selection;
},

/**
* Gets the number of line-breaks that would have to be inserted before the given 'startPosition'
* to make sure there's an empty line between 'startPosition' and the previous text
*/
getBreaksNeededForEmptyLineBefore: function(
text = "",
startPosition: number
): number {
if (startPosition === 0) return 0;

// rules:
// - If we're in the first line, no breaks are needed
// - Otherwise there must be 2 breaks before the previous character. Depending on how many breaks exist already, we
// may need to insert 0, 1 or 2 breaks

let neededBreaks = 2;
let isInFirstLine = true;
for (let i = startPosition - 1; i >= 0 && neededBreaks >= 0; i--) {
switch (text.charCodeAt(i)) {
case 32: // blank space
continue;
case 10: // line break
neededBreaks--;
isInFirstLine = false;
break;
default:
return neededBreaks;
}
}
return isInFirstLine ? 0 : neededBreaks;
},

/**
* Gets the number of line-breaks that would have to be inserted after the given 'startPosition'
* to make sure there's an empty line between 'startPosition' and the next text
*/
getBreaksNeededForEmptyLineAfter(text = "", startPosition: number): number {
if (startPosition === text.length - 1) return 0;

// rules:
// - If we're in the first line, no breaks are needed
// - Otherwise there must be 2 breaks before the previous character. Depending on how many breaks exist already, we
// may need to insert 0, 1 or 2 breaks

let neededBreaks = 2;
let isInLastLine = true;
for (let i = startPosition; i < text.length && neededBreaks >= 0; i++) {
switch (text.charCodeAt(i)) {
case 32:
continue;
case 10: {
neededBreaks--;
isInLastLine = false;
break;
}
default:
return neededBreaks;
}
}
return isInLastLine ? 0 : neededBreaks;
}
};
Loading

0 comments on commit 8152dc9

Please sign in to comment.