-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ✨ custom emoji handler w/ reactnode n fallback supoort
- Loading branch information
1 parent
14721fc
commit 8edac58
Showing
20 changed files
with
241 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { useGlobalData } from "../../../store"; | ||
import { parseEmojis } from "../../emojis"; | ||
import { SlackEmojiSubElement } from "../types"; | ||
|
||
type Props = { | ||
element: SlackEmojiSubElement; | ||
}; | ||
|
||
export const SlackEmoji = (props: Props) => { | ||
const { element } = props; | ||
const { hooks } = useGlobalData(); | ||
|
||
if (hooks.emoji) { | ||
const custom_emoji = hooks.emoji(element.value); | ||
if (custom_emoji !== "fallback") return <>{custom_emoji}</>; | ||
} | ||
|
||
return <span className="slack_emoji">{parseEmojis(`:${element.value}:`)}</span>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./tokenizer"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import type { INodePoint } from "@yozora/character"; | ||
import { AsciiCodePoint } from "@yozora/character"; | ||
import type { | ||
IMatchInlineHookCreator, | ||
IResultOfFindDelimiters, | ||
IResultOfProcessSingleDelimiter, | ||
} from "@yozora/core-tokenizer"; | ||
import { SlackEmojiType, type IDelimiter, type IThis, type IToken, type T } from "./types"; | ||
|
||
export const match: IMatchInlineHookCreator<T, IDelimiter, IToken, IThis> = function (api) { | ||
return { findDelimiter, processSingleDelimiter }; | ||
|
||
function* findDelimiter(): IResultOfFindDelimiters<IDelimiter> { | ||
const nodePoints: ReadonlyArray<INodePoint> = api.getNodePoints(); | ||
const blockStartIndex: number = api.getBlockStartIndex(); | ||
const blockEndIndex: number = api.getBlockEndIndex(); | ||
|
||
const potentialDelimiters: IDelimiter[] = []; | ||
|
||
for (let i = blockStartIndex; i < blockEndIndex; ++i) { | ||
if (nodePoints[i]?.codePoint === AsciiCodePoint.COLON) { | ||
const endIndex = findEndDelimiter(nodePoints, i, blockEndIndex); | ||
if (endIndex !== -1) { | ||
potentialDelimiters.push({ | ||
type: "both", | ||
startIndex: i, | ||
endIndex: endIndex + 1, | ||
thickness: endIndex + 1 - i, | ||
}); | ||
i = endIndex; // Skip past the matched emoji | ||
} | ||
} | ||
} | ||
|
||
let pIndex = 0; | ||
let lastEndIndex = -1; | ||
let currentDelimiter: IDelimiter | null = null; | ||
while (pIndex < potentialDelimiters.length) { | ||
const [startIndex, endIndex] = yield currentDelimiter; | ||
|
||
if (lastEndIndex === endIndex) { | ||
if (currentDelimiter == null || currentDelimiter.startIndex >= startIndex) continue; | ||
} | ||
lastEndIndex = endIndex; | ||
|
||
for (; pIndex < potentialDelimiters.length; ++pIndex) { | ||
const delimiter = potentialDelimiters[pIndex]!; | ||
if (delimiter.startIndex >= startIndex) { | ||
currentDelimiter = { | ||
type: "full", | ||
startIndex: delimiter.startIndex, | ||
endIndex: delimiter.endIndex, | ||
thickness: delimiter.thickness, | ||
}; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
function findEndDelimiter( | ||
nodePoints: ReadonlyArray<INodePoint>, | ||
startIndex: number, | ||
blockEndIndex: number, | ||
): number { | ||
for (let i = startIndex + 1; i < blockEndIndex; ++i) { | ||
if (nodePoints[i]?.codePoint === AsciiCodePoint.COLON) { | ||
return i; | ||
} | ||
} | ||
return -1; // Not found | ||
} | ||
|
||
function processSingleDelimiter( | ||
delimiter: IDelimiter, | ||
): IResultOfProcessSingleDelimiter<T, IToken> { | ||
const token: IToken = { | ||
nodeType: SlackEmojiType, | ||
startIndex: delimiter.startIndex, | ||
endIndex: delimiter.endIndex, | ||
thickness: delimiter.thickness, | ||
}; | ||
return [token]; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type { INodePoint } from "@yozora/character"; | ||
import { calcStringFromNodePoints } from "@yozora/character"; | ||
import type { IParseInlineHookCreator } from "@yozora/core-tokenizer"; | ||
import { SlackEmojiType, type INode, type IThis, type IToken, type T } from "./types"; | ||
|
||
export const parse: IParseInlineHookCreator<T, IToken, INode, IThis> = function (api) { | ||
return { | ||
parse: (tokens) => | ||
tokens.map((token) => { | ||
const nodePoints: ReadonlyArray<INodePoint> = api.getNodePoints(); | ||
const fullString = calcStringFromNodePoints(nodePoints, token.startIndex, token.endIndex); | ||
|
||
const emojiPattern = /^:(\w+):$/; | ||
const match = emojiPattern.exec(fullString); | ||
|
||
let value = fullString; | ||
|
||
if (match) value = match[1] as string; | ||
|
||
const node: INode = api.shouldReservePosition | ||
? { type: SlackEmojiType, position: api.calcPosition(token), value } | ||
: { type: SlackEmojiType, value }; | ||
return node; | ||
}), | ||
}; | ||
}; |
32 changes: 32 additions & 0 deletions
32
src/utils/markdown_parser/tokenizers/slack_emoji/tokenizer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import type { | ||
IInlineTokenizer, | ||
IMatchInlineHookCreator, | ||
IParseInlineHookCreator, | ||
} from "@yozora/core-tokenizer"; | ||
import { BaseInlineTokenizer, TokenizerPriority } from "@yozora/core-tokenizer"; | ||
import { match } from "./match"; | ||
import { parse } from "./parse"; | ||
import { | ||
SlackEmojiType, | ||
type IDelimiter, | ||
type INode, | ||
type IThis, | ||
type IToken, | ||
type ITokenizerProps, | ||
type T, | ||
} from "./types"; | ||
|
||
export class SlackEmojiTokenizer | ||
extends BaseInlineTokenizer<T, IDelimiter, IToken, INode, IThis> | ||
implements IInlineTokenizer<T, IDelimiter, IToken, INode, IThis> | ||
{ | ||
constructor(props: ITokenizerProps = {}) { | ||
super({ | ||
name: SlackEmojiType, | ||
priority: props.priority || TokenizerPriority.ATOMIC, | ||
}); | ||
} | ||
|
||
public override readonly match: IMatchInlineHookCreator<T, IDelimiter, IToken, IThis> = match; | ||
public override readonly parse: IParseInlineHookCreator<T, IToken, INode, IThis> = parse; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Literal } from "@yozora/ast"; | ||
import type { | ||
IBaseInlineTokenizerProps, | ||
IPartialInlineToken, | ||
ITokenDelimiter, | ||
ITokenizer, | ||
} from "@yozora/core-tokenizer"; | ||
|
||
export const SlackEmojiType = "slack_emoji"; | ||
export type T = typeof SlackEmojiType; | ||
export type INode = Literal<typeof SlackEmojiType>; | ||
|
||
export interface IToken extends IPartialInlineToken<T> { | ||
thickness: number; | ||
} | ||
|
||
export interface IDelimiter extends ITokenDelimiter { | ||
type: "full" | "both"; | ||
thickness: number; | ||
} | ||
|
||
export type IThis = ITokenizer; | ||
export type ITokenizerProps = Partial<IBaseInlineTokenizerProps>; |
Oops, something went wrong.