Skip to content

Commit

Permalink
Merge branch 'main' into fix/copy-paste-font-size-consistency
Browse files Browse the repository at this point in the history
  • Loading branch information
citruscai authored Oct 25, 2024
2 parents e9feb84 + d64d395 commit a7326c4
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 30 deletions.
3 changes: 2 additions & 1 deletion .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ untyped-type-import=error
[options]
server.max_workers=4
exact_by_default=true
component_syntax=true

;; [generated-start update-flowconfig]
module.name_mapper='^lexical$' -> '<PROJECT_ROOT>/packages/lexical/flow/Lexical.js.flow'
Expand Down Expand Up @@ -105,4 +106,4 @@ nonstrict-import
unclear-type

[version]
^0.226.0
^0.250.0
1 change: 1 addition & 0 deletions libdefs/yjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ declare module 'yjs' {
};

declare type StackItem = {
// $FlowFixMe: perhaps add generic typing instead of mixed
meta: Map<mixed, mixed>,
type: 'undo' | 'redo',
};
Expand Down
15 changes: 8 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-simple-import-sort": "^12.1.0",
"eslint-plugin-sort-keys-fix": "^1.1.2",
"flow-bin": "^0.226.0",
"flow-bin": "^0.250.0",
"fs-extra": "^10.0.0",
"glob": "^10.4.1",
"google-closure-compiler": "^20220202.0.0",
Expand Down
43 changes: 43 additions & 0 deletions packages/lexical-playground/__tests__/e2e/Links.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
moveRight,
moveToLineBeginning,
moveToLineEnd,
paste,
selectAll,
selectCharacters,
STANDARD_KEYPRESS_DELAY_MS,
Expand Down Expand Up @@ -2076,6 +2077,48 @@ test.describe.parallel('Links', () => {
});
});

test.describe('Link attributes', () => {
test.use({hasLinkAttributes: true});
test.beforeEach(({isCollab, hasLinkAttributes, page}) =>
initialize({hasLinkAttributes, isCollab, page}),
);
test('Can add attributes with paste', async ({
page,
context,
hasLinkAttributes,
browserName,
}) => {
if (browserName === 'chromium') {
await focusEditor(page);
await page.keyboard.type('Hello awesome');
await focusEditor(page);
await selectAll(page);
await context.grantPermissions(['clipboard-read', 'clipboard-write']);
await page.evaluate(() =>
navigator.clipboard.writeText('https://facebook.com'),
);
await paste(page);
await assertHTML(
page,
html`
<p
class="PlaygroundEditorTheme__paragraph PlaygroundEditorTheme__ltr"
dir="ltr">
<a
class="PlaygroundEditorTheme__link PlaygroundEditorTheme__ltr"
dir="ltr"
href="https://facebook.com"
rel="noopener noreferrer"
target="_blank">
<span data-lexical-text="true">Hello awesome</span>
</a>
</p>
`,
);
}
});
});

async function setURL(page, url) {
await click(page, '.link-edit');
await focus(page, '.link-input');
Expand Down
3 changes: 3 additions & 0 deletions packages/lexical-playground/__tests__/utils/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export async function initialize({
isCharLimit,
isCharLimitUtf8,
isMaxLength,
hasLinkAttributes,
showNestedEditorTreeView,
tableCellMerge,
tableCellBackgroundColor,
Expand Down Expand Up @@ -85,6 +86,7 @@ export async function initialize({
appSettings.isCharLimit = !!isCharLimit;
appSettings.isCharLimitUtf8 = !!isCharLimitUtf8;
appSettings.isMaxLength = !!isMaxLength;
appSettings.hasLinkAttributes = !!hasLinkAttributes;
if (tableCellMerge !== undefined) {
appSettings.tableCellMerge = tableCellMerge;
}
Expand Down Expand Up @@ -140,6 +142,7 @@ async function exposeLexicalEditor(page) {
}

export const test = base.extend({
hasLinkAttributes: false,
isCharLimit: false,
isCharLimitUtf8: false,
isCollab: IS_COLLAB,
Expand Down
3 changes: 2 additions & 1 deletion packages/lexical-playground/src/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export default function Editor(): JSX.Element {
isAutocomplete,
isMaxLength,
isCharLimit,
hasLinkAttributes,
isCharLimitUtf8,
isRichText,
showTreeView,
Expand Down Expand Up @@ -185,7 +186,7 @@ export default function Editor(): JSX.Element {
<TableCellResizer />
<ImagesPlugin />
<InlineImagePlugin />
<LinkPlugin />
<LinkPlugin hasLinkAttributes={hasLinkAttributes} />
<PollPlugin />
<TwitterPlugin />
<YouTubePlugin />
Expand Down
6 changes: 6 additions & 0 deletions packages/lexical-playground/src/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default function Settings(): JSX.Element {
isCollab,
isRichText,
isMaxLength,
hasLinkAttributes,
isCharLimit,
isCharLimitUtf8,
isAutocomplete,
Expand Down Expand Up @@ -116,6 +117,11 @@ export default function Settings(): JSX.Element {
checked={isCharLimitUtf8}
text="Char Limit (UTF-8)"
/>
<Switch
onClick={() => setOption('hasLinkAttributes', !hasLinkAttributes)}
checked={hasLinkAttributes}
text="Link Attributes"
/>
<Switch
onClick={() => setOption('isMaxLength', !isMaxLength)}
checked={isMaxLength}
Expand Down
1 change: 1 addition & 0 deletions packages/lexical-playground/src/appSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const isDevPlayground: boolean =
export const DEFAULT_SETTINGS = {
disableBeforeInput: false,
emptyEditor: isDevPlayground,
hasLinkAttributes: false,
isAutocomplete: false,
isCharLimit: false,
isCharLimitUtf8: false,
Expand Down
22 changes: 20 additions & 2 deletions packages/lexical-playground/src/plugins/LinkPlugin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ import * as React from 'react';

import {validateUrl} from '../../utils/url';

export default function LinkPlugin(): JSX.Element {
return <LexicalLinkPlugin validateUrl={validateUrl} />;
type Props = {
hasLinkAttributes?: boolean;
};

export default function LinkPlugin({
hasLinkAttributes = false,
}: Props): JSX.Element {
return (
<LexicalLinkPlugin
validateUrl={validateUrl}
attributes={
hasLinkAttributes
? {
rel: 'noopener noreferrer',
target: '_blank',
}
: undefined
}
/>
);
}
20 changes: 9 additions & 11 deletions packages/lexical-react/flow/LexicalContentEditable.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ import type { LexicalEditor } from 'lexical';
import type {TRefFor} from 'CoreTypes.flow';

import * as React from 'react';
import type { AbstractComponent } from "react";

type InlineStyle = {
[key: string]: mixed;
}
[key: string]: mixed,
};

// Due to Flow limitations, we prefer fixed types over the built-in inexact HTMLElement
type HTMLDivElementDOMProps = $ReadOnly<{
Expand All @@ -29,7 +28,7 @@ type HTMLDivElementDOMProps = $ReadOnly<{
'aria-invalid'?: void | boolean,
'aria-owns'?: void | string,
'title'?: void | string,
onClick?: void | (e: SyntheticEvent<HTMLDivElement>) => mixed,
onClick?: void | ((e: SyntheticEvent<HTMLDivElement>) => mixed),
autoCapitalize?: void | boolean,
autoComplete?: void | boolean,
autoCorrect?: void | boolean,
Expand Down Expand Up @@ -72,11 +71,10 @@ export type Props = $ReadOnly<{
ariaOwns?: string,
ariaRequired?: string,
autoCapitalize?: boolean,
ref?: TRefFor<HTMLDivElement>,
...PlaceholderProps
}>
...PlaceholderProps,
}>;

declare export var ContentEditable: AbstractComponent<
Props,
HTMLDivElement,
>;
declare export var ContentEditable: component(
ref: React.RefSetter<HTMLDivElement>,
...Props
);
28 changes: 21 additions & 7 deletions packages/lexical-react/src/LexicalLinkPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
*
*/

import {$toggleLink, LinkNode, TOGGLE_LINK_COMMAND} from '@lexical/link';
import {
$toggleLink,
LinkAttributes,
LinkNode,
TOGGLE_LINK_COMMAND,
} from '@lexical/link';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {mergeRegister, objectKlassEquals} from '@lexical/utils';
import {
Expand All @@ -20,9 +25,10 @@ import {useEffect} from 'react';

type Props = {
validateUrl?: (url: string) => boolean;
attributes?: LinkAttributes;
};

export function LinkPlugin({validateUrl}: Props): null {
export function LinkPlugin({validateUrl, attributes}: Props): null {
const [editor] = useLexicalComposerContext();

useEffect(() => {
Expand All @@ -38,13 +44,18 @@ export function LinkPlugin({validateUrl}: Props): null {
return true;
} else if (typeof payload === 'string') {
if (validateUrl === undefined || validateUrl(payload)) {
$toggleLink(payload);
$toggleLink(payload, attributes);
return true;
}
return false;
} else {
const {url, target, rel, title} = payload;
$toggleLink(url, {rel, target, title});
$toggleLink(url, {
...attributes,
rel,
target,
title,
});
return true;
}
},
Expand Down Expand Up @@ -73,7 +84,10 @@ export function LinkPlugin({validateUrl}: Props): null {
}
// If we select nodes that are elements then avoid applying the link.
if (!selection.getNodes().some((node) => $isElementNode(node))) {
editor.dispatchCommand(TOGGLE_LINK_COMMAND, clipboardText);
editor.dispatchCommand(TOGGLE_LINK_COMMAND, {
...attributes,
url: clipboardText,
});
event.preventDefault();
return true;
}
Expand All @@ -82,10 +96,10 @@ export function LinkPlugin({validateUrl}: Props): null {
COMMAND_PRIORITY_LOW,
)
: () => {
// Don't paste arbritrary text as a link when there's no validate function
// Don't paste arbitrary text as a link when there's no validate function
},
);
}, [editor, validateUrl]);
}, [editor, validateUrl, attributes]);

return null;
}

0 comments on commit a7326c4

Please sign in to comment.