Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion __tests__/components/CreateDropWrapper.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ jest.mock('@/components/drops/create/full/CreateDropFull', () =>
))
);

jest.mock('@lexical/markdown', () => ({ $convertToMarkdownString: () => 'text', TRANSFORMERS: [] }));
jest.mock('@/components/waves/drops/normalizeDropMarkdown', () => ({
__esModule: true,
default: (value: string) => value,
normalizeDropMarkdown: (value: string) => value,
exportDropMarkdown: () => 'text',
}));
jest.mock('@/components/drops/create/lexical/transformers/MentionTransformer', () => ({}));
jest.mock('@/components/drops/create/lexical/transformers/HastagTransformer', () => ({}));
jest.mock('@/components/drops/create/lexical/transformers/ImageTransformer', () => ({}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ jest.mock('@/components/drops/create/utils/storm/CreateDropParts', () => () => <
jest.mock('@/components/drops/create/utils/CreateDropActionsRow', () => () => <div data-testid="actions" />);
jest.mock('@/components/drops/create/utils/storm/CreateDropContentMissingMediaWarning', () => () => <div />);
jest.mock('@/components/drops/create/utils/storm/CreateDropContentMissingMetadataWarning', () => () => <div />);
jest.mock('@/components/waves/drops/normalizeDropMarkdown', () => ({
__esModule: true,
default: (value: string) => value,
normalizeDropMarkdown: (value: string) => value,
exportDropMarkdown: () => '',
}));

let linkProps: any = null;
let mockClear: any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ jest.mock('react-use', () => ({
createBreakpoint: () => () => 'LG'
}));

// Mock lexical
jest.mock('@lexical/markdown', () => ({
$convertToMarkdownString: () => '',
TRANSFORMERS: []
// Mock markdown utilities
jest.mock('@/components/waves/drops/normalizeDropMarkdown', () => ({
__esModule: true,
default: (value: string) => value,
normalizeDropMarkdown: (value: string) => value,
exportDropMarkdown: () => '',
}));

// Mock transformers
Expand Down Expand Up @@ -265,4 +267,4 @@ describe('CreateDropWrapper Authentication Validation', () => {
expect(result.signer_address).toBe('0x1234567890123456789012345678901234567890');
});
});
});
});
28 changes: 20 additions & 8 deletions __tests__/components/waves/drops/EditDropLexical.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,25 @@ jest.mock('@lexical/react/LexicalComposerContext', () => ({
jest.mock('@lexical/markdown', () => ({
__esModule: true,
$convertFromMarkdownString: jest.fn(),
$convertToMarkdownString: jest.fn(() => 'mock markdown'),
}));
const {
$convertFromMarkdownString: convertFromMarkdownStringMock,
$convertToMarkdownString: convertToMarkdownStringMock,
} = jest.requireMock('@lexical/markdown') as {
$convertFromMarkdownString: jest.Mock;
$convertToMarkdownString: jest.Mock;
};

jest.mock('@/components/waves/drops/normalizeDropMarkdown', () => ({
__esModule: true,
default: jest.fn((value: string) => value),
normalizeDropMarkdown: jest.fn((value: string) => value),
exportDropMarkdown: jest.fn(() => 'mock markdown'),
}));
const {
normalizeDropMarkdown: normalizeDropMarkdownMock,
exportDropMarkdown: exportDropMarkdownMock,
} = jest.requireMock('@/components/waves/drops/normalizeDropMarkdown') as {
normalizeDropMarkdown: jest.Mock;
exportDropMarkdown: jest.Mock;
};
jest.mock('lexical', () => ({
$getRoot: getRootMock,
Expand Down Expand Up @@ -197,7 +208,8 @@ describe('EditDropLexical', () => {

beforeEach(() => {
jest.clearAllMocks();
convertToMarkdownStringMock.mockReturnValue('mock markdown');
exportDropMarkdownMock.mockReturnValue('mock markdown');
normalizeDropMarkdownMock.mockImplementation((value: string) => value);
convertFromMarkdownStringMock.mockReset();
rootMock.getChildren.mockReturnValue([]);
rootMock.getAllTextNodes.mockReturnValue([]);
Expand All @@ -214,7 +226,7 @@ describe('EditDropLexical', () => {
const user = userEvent.setup();
const onSave = jest.fn();
const onCancel = jest.fn();
convertToMarkdownStringMock.mockReturnValue('updated markdown');
exportDropMarkdownMock.mockReturnValue('updated markdown');

render(<EditDropLexical {...defaultProps} onSave={onSave} onCancel={onCancel} />);

Expand All @@ -239,7 +251,7 @@ describe('EditDropLexical', () => {
const user = userEvent.setup();
const onSave = jest.fn();
const onCancel = jest.fn();
convertToMarkdownStringMock.mockReturnValue('Initial content here');
exportDropMarkdownMock.mockReturnValue('Initial content here');

render(<EditDropLexical {...defaultProps} onSave={onSave} onCancel={onCancel} />);

Expand All @@ -253,7 +265,7 @@ describe('EditDropLexical', () => {
it('invokes keyboard command handlers', async () => {
const onSave = jest.fn();
const onCancel = jest.fn();
convertToMarkdownStringMock.mockReturnValue('changed content');
exportDropMarkdownMock.mockReturnValue('changed content');

render(<EditDropLexical {...defaultProps} onSave={onSave} onCancel={onCancel} />);

Expand Down Expand Up @@ -282,7 +294,7 @@ describe('EditDropLexical', () => {
handled = enterHandler?.({ shiftKey: false }) ?? false;
});
expect(handled).toBe(true);
expect(convertToMarkdownStringMock).toHaveBeenCalled();
expect(exportDropMarkdownMock).toHaveBeenCalled();
expect(onCancel).toHaveBeenCalledTimes(1);
});
});
72 changes: 72 additions & 0 deletions __tests__/components/waves/drops/normalizeDropMarkdown.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
jest.mock("@lexical/markdown", () => ({
__esModule: true,
$convertToMarkdownString: jest.fn(),
}));

import {
exportDropMarkdown,
normalizeDropMarkdown,
} from "@/components/waves/drops/normalizeDropMarkdown";
import type { EditorState } from "lexical";

const BLANK_PARAGRAPH_SENTINEL = "\u2063__BLANK_PARAGRAPH__\u2063";

const {
$convertToMarkdownString: convertToMarkdownStringMock,
} = jest.requireMock("@lexical/markdown") as {
$convertToMarkdownString: jest.Mock;
};

const createEditorStateStub = (): EditorState =>
({
read: (fn: () => string) => fn(),
} as unknown as EditorState);

describe("exportDropMarkdown", () => {
let editorState: EditorState;

beforeEach(() => {
editorState = createEditorStateStub();
convertToMarkdownStringMock.mockReset();
});

it("returns markdown unchanged when no blank markers are present", () => {
convertToMarkdownStringMock.mockReturnValue("First\n\nSecond");
expect(exportDropMarkdown(editorState, [])).toBe("First\n\nSecond");
});

it("collapses a single blank paragraph marker into one additional newline", () => {
convertToMarkdownStringMock.mockReturnValue(
`First\n\n${BLANK_PARAGRAPH_SENTINEL}\n\nSecond`
);
expect(exportDropMarkdown(editorState, [])).toBe("First\n\n\nSecond");
});

it("collapses multiple blank markers into the correct newline count", () => {
convertToMarkdownStringMock.mockReturnValue(
`First\n\n${BLANK_PARAGRAPH_SENTINEL}\n\n${BLANK_PARAGRAPH_SENTINEL}\n\nSecond`
);
expect(exportDropMarkdown(editorState, [])).toBe("First\n\n\n\nSecond");
});

it("preserves trailing blank paragraphs", () => {
convertToMarkdownStringMock.mockReturnValue(
`First\n\n${BLANK_PARAGRAPH_SENTINEL}`
);
expect(exportDropMarkdown(editorState, [])).toBe("First\n\n\n");
});

it("preserves multiple trailing blank paragraphs", () => {
convertToMarkdownStringMock.mockReturnValue(
`First\n\n${BLANK_PARAGRAPH_SENTINEL}\n\n${BLANK_PARAGRAPH_SENTINEL}`
);
expect(exportDropMarkdown(editorState, [])).toBe("First\n\n\n\n");
});

});

describe("normalizeDropMarkdown", () => {
it("normalizes CRLF to LF", () => {
expect(normalizeDropMarkdown("line1\r\nline2")).toBe("line1\nline2");
});
});
Comment thread
simo6529 marked this conversation as resolved.
25 changes: 14 additions & 11 deletions components/drops/create/utils/CreateDropContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
import { MaxLengthPlugin } from "../lexical/plugins/MaxLengthPlugin";
import ToggleViewButtonPlugin from "../lexical/plugins/ToggleViewButtonPlugin";
import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin";
import { $convertToMarkdownString } from "@lexical/markdown";

import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin";
import { ListNode, ListItemNode } from "@lexical/list";
Expand Down Expand Up @@ -70,6 +69,9 @@ import { EmojiNode } from "../lexical/nodes/EmojiNode";
import CreateDropEmojiPicker from "@/components/waves/CreateDropEmojiPicker";
import EmojiPlugin from "../lexical/plugins/emoji/EmojiPlugin";
import PlainTextPastePlugin from "../lexical/plugins/PlainTextPastePlugin";
import {
exportDropMarkdown,
} from "@/components/waves/drops/normalizeDropMarkdown";

export interface CreateDropContentHandles {
clearEditorState: () => void;
Expand Down Expand Up @@ -193,16 +195,17 @@ const CreateDropContent = forwardRef<
const currentPartCount = (drop?.parts.length ?? 0) + 1;
const [charsCount, setCharsCount] = useState(0);
useEffect(() => {
editorState?.read(() =>
setCharsCount(
$convertToMarkdownString([
...SAFE_MARKDOWN_TRANSFORMERS,
MENTION_TRANSFORMER,
HASHTAG_TRANSFORMER,
IMAGE_TRANSFORMER,
])?.length ?? 0
)
);
if (!editorState) {
setCharsCount(0);
return;
}
const markdown = exportDropMarkdown(editorState, [
...SAFE_MARKDOWN_TRANSFORMERS,
MENTION_TRANSFORMER,
HASHTAG_TRANSFORMER,
IMAGE_TRANSFORMER,
]);
setCharsCount(markdown.length);
}, [editorState]);

const [isStormMode, setIsStormMode] = useState(false);
Expand Down
20 changes: 11 additions & 9 deletions components/drops/create/utils/CreateDropWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
ReferencedNft,
} from "@/entities/IDrop";
import { createBreakpoint } from "react-use";
import { $convertToMarkdownString } from "@lexical/markdown";
import { CreateDropType, CreateDropViewType } from "../types";
import { MENTION_TRANSFORMER } from "../lexical/transformers/MentionTransformer";
import { HASHTAG_TRANSFORMER } from "../lexical/transformers/HastagTransformer";
Expand All @@ -38,6 +37,9 @@ import { SAFE_MARKDOWN_TRANSFORMERS } from "../lexical/transformers/markdownTran
import { QueryKey } from "@/components/react-query-wrapper/ReactQueryWrapper";
import { useSeizeConnectContext } from "@/components/auth/SeizeConnectContext";
import { WalletValidationError } from "@/src/errors/wallet";
import {
exportDropMarkdown,
} from "@/components/waves/drops/normalizeDropMarkdown";

export enum CreateDropScreenType {
DESKTOP = "DESKTOP",
Expand Down Expand Up @@ -194,14 +196,14 @@ const CreateDropWrapper = forwardRef<
]);
};
const getMarkdown = () =>
editorState?.read(() =>
$convertToMarkdownString([
...SAFE_MARKDOWN_TRANSFORMERS,
MENTION_TRANSFORMER,
HASHTAG_TRANSFORMER,
IMAGE_TRANSFORMER,
])
) ?? null;
editorState
? exportDropMarkdown(editorState, [
...SAFE_MARKDOWN_TRANSFORMERS,
MENTION_TRANSFORMER,
HASHTAG_TRANSFORMER,
IMAGE_TRANSFORMER,
])
: null;

const getMissingRequiredMetadata = (): ApiWaveRequiredMetadata[] => {
if (!waveProps?.id) {
Expand Down
10 changes: 6 additions & 4 deletions components/drops/view/part/dropPartMarkdown/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,12 @@ export const createMarkdownContentRenderers = ({
return content;
}

return content.replace(/\n{4,}/g, (match: string) => {
const numParagraphs = Math.floor(match.length / 2) - 1;
const emptyParagraphs = Array(numParagraphs).fill("\n\n&nbsp;").join("");
return "\n\n" + emptyParagraphs + "\n\n";
return content.replace(/\n{3,}/g, (match: string) => {
const extraBlankLines = match.length - 2;
const fillerParagraphs = Array(extraBlankLines)
.fill("&nbsp;")
.join("\n\n");
return `\n\n${fillerParagraphs}\n\n`;
});
};

Expand Down
20 changes: 10 additions & 10 deletions components/waves/CreateDropContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
MentionedUser,
ReferencedNft,
} from "@/entities/IDrop";
import { $convertToMarkdownString } from "@lexical/markdown";
import { MENTION_TRANSFORMER } from "../drops/create/lexical/transformers/MentionTransformer";
import { HASHTAG_TRANSFORMER } from "../drops/create/lexical/transformers/HastagTransformer";
import { IMAGE_TRANSFORMER } from "../drops/create/lexical/transformers/ImageTransformer";
Expand Down Expand Up @@ -59,6 +58,7 @@ import {
getMissingRequirements,
MissingRequirements,
} from "./utils/getMissingRequirements";
import { exportDropMarkdown } from "@/components/waves/drops/normalizeDropMarkdown";
import { EMOJI_TRANSFORMER } from "../drops/create/lexical/transformers/EmojiTransformer";
import { useDropSignature } from "@/hooks/drops/useDropSignature";
import { useWave } from "@/hooks/useWave";
Expand Down Expand Up @@ -488,15 +488,15 @@ const CreateDropContent: React.FC<CreateDropContentProps> = ({

const getMarkdown = useMemo(
() =>
editorState?.read(() =>
$convertToMarkdownString([
...SAFE_MARKDOWN_TRANSFORMERS,
MENTION_TRANSFORMER,
HASHTAG_TRANSFORMER,
IMAGE_TRANSFORMER,
EMOJI_TRANSFORMER,
])
) ?? null,
editorState
? exportDropMarkdown(editorState, [
...SAFE_MARKDOWN_TRANSFORMERS,
MENTION_TRANSFORMER,
HASHTAG_TRANSFORMER,
IMAGE_TRANSFORMER,
EMOJI_TRANSFORMER,
])
: null,
[editorState]
);

Expand Down
Loading