diff --git a/.changeset/gentle-goats-hang.md b/.changeset/gentle-goats-hang.md new file mode 100644 index 000000000..ff7843b72 --- /dev/null +++ b/.changeset/gentle-goats-hang.md @@ -0,0 +1,14 @@ +--- +'@wangeditor-next/upload-image-module': patch +'@wangeditor-next/code-highlight': patch +'@wangeditor-next/basic-modules': patch +'@wangeditor-next/yjs-for-react': patch +'@wangeditor-next/table-module': patch +'@wangeditor-next/video-module': patch +'@wangeditor-next/list-module': patch +'@wangeditor-next/editor': patch +'@wangeditor-next/core': patch +'@wangeditor-next/yjs': patch +--- + +254 在windows上搭建webview2或者electron客户端使用wangeditor和搜狗输入法执行特定步骤会出现异常 diff --git a/docs/contribution-CN.md b/docs/contribution-CN.md index 9c38ab256..a53f52403 100644 --- a/docs/contribution-CN.md +++ b/docs/contribution-CN.md @@ -17,7 +17,7 @@ 我们非常欢迎Pull Request! - **克隆仓库**:Fork并克隆项目到本地。 -- **创建分支**:基于开发分支`develop`创建一个新的分支。 +- **创建分支**:基于开发分支`master`创建一个新的分支。 - **编写代码**:确保您的代码遵循项目中的编码规范。 - **提交更改**:提交您的更改,并确保提交信息清晰明了。 - **Pull Request**:将您的分支推送到远程仓库,并在GitHub上发起Pull Request。 @@ -62,4 +62,4 @@ ## 感谢 -我们非常感激您的贡献,无论是大是小。您的努力帮助我们构建了一个更好的`wangEditor-next`。 \ No newline at end of file +我们非常感激您的贡献,无论是大是小。您的努力帮助我们构建了一个更好的`wangEditor-next`。 diff --git a/docs/contribution-EN.md b/docs/contribution-EN.md index 6b7f4faa7..489e5f00b 100644 --- a/docs/contribution-EN.md +++ b/docs/contribution-EN.md @@ -17,7 +17,7 @@ If you find a bug or have an idea for a new feature, please create a new issue i We warmly welcome Pull Requests! - **Fork the Repository**: Fork and clone the project to your local machine. -- **Create a Branch**: Create a new branch based on the `develop` branch. +- **Create a Branch**: Create a new branch based on the `master` branch. - **Write Code**: Ensure your code follows the project's coding standards. - **Commit Changes**: Commit your changes, and make sure the commit messages are clear and descriptive. - **Pull Request**: Push your branch to the remote repository and initiate a Pull Request on GitHub. @@ -62,4 +62,4 @@ Help answer questions, participate in discussions, or promote the project on soc ## Thanks -We greatly appreciate your contributions, big or small. Your efforts help us build a better `wangEditor-next`. \ No newline at end of file +We greatly appreciate your contributions, big or small. Your efforts help us build a better `wangEditor-next`. diff --git a/docs/dev.md b/docs/dev.md index 08795e46b..14b226fbe 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -4,7 +4,7 @@ - 了解 slate.js - 了解 vdom 和 snabbdom.js -- 了解 lerna +- 了解 turbo 和 changeset - 已安装 yarn ## 本地启动 diff --git a/docs/publish.md b/docs/publish.md index b9e9cea91..46a693198 100644 --- a/docs/publish.md +++ b/docs/publish.md @@ -1,40 +1,14 @@ # 发布到 NPM -因为我们的项目是使用 `independent` 的方式组织 `muti-packgae`,所以每个包都有单独的版本号,默认使用 `lerna publish` 发布包,我们需要根据包的修改内容选择合适的版本号。**对于没有变动的 `package`,lerna 发布的时候不会算在本次发布的内容里面**。 +## 发布一个正式版本 -发布的流程分两步: +1. 添加 `changeset`:`npx changeset` +2. 提交代码合并 master,线上会自动发版到 `npm`。 -第一步:将所有要发版的代码合并到 `master` 分支后,先在本地执行 `yarn release:version` 生成各个本次变动的 `package` 的版本后,自动生成 `changelog`,接着 lerna 会生成 `git tag` 并 `push` 到远程。 - -第二步:上面步骤完成后, `lerna` push `git tag` 到远程的时候会触发我们配置的 `git action`,走完正常的发版 `action`,具体看 [`action` 配置]('./../.github/workflows/release.yml') 。 - -因为目前我们还在开发当中,所以为了更加方便发版到 `npm` 进行测试,目前,项目中集成了以下 `release` 的 `script command`: - -## 正常发布一个版本 - -```bash -yarn release:publish -``` - -## 发布指定的 dist-tag 版本 - -发布一个 `experimental` [dist-tag](https://docs.npmjs.com/cli/v7/commands/npm-dist-tag) 的版本: - -```bash -yarn release:publish:experimental -``` - -发布一个 `next` [dist-tag](https://docs.npmjs.com/cli/v7/commands/npm-dist-tag) 的版本: - -```bash -yarn release:next -``` - -## 发布 canary 版本 - -发布一个 `canary` 版本: -```bash -# 1.0.0 => 1.0.1-alpha.0+${SHA} of packages changed since the previous commit -lerna publish --canary -``` +## 发布一个测试版本 +1. 进入预发布模式:`npx changeset pre enter beta` +2. 添加 `changeset`:`npx changeset` +3. 更新版本号:`npx changeset version` +4. 发布测试包:`npx changeset publish` +5. 退出预发布模式(可选):`npx changeset pre exit` diff --git a/packages/core/src/text-area/event-handlers/composition.ts b/packages/core/src/text-area/event-handlers/composition.ts index 58ce6224e..4216d9b82 100644 --- a/packages/core/src/text-area/event-handlers/composition.ts +++ b/packages/core/src/text-area/event-handlers/composition.ts @@ -3,19 +3,47 @@ * @author wangfupeng */ -import { Editor, Range, Element, Text } from 'slate' -import { IDomEditor } from '../../editor/interface' +import { + Editor, Element, Range, Text, +} from 'slate' + import { DomEditor } from '../../editor/dom-editor' -import TextArea from '../TextArea' -import { hasEditableTarget } from '../helpers' -import { IS_SAFARI, IS_CHROME, IS_FIREFOX } from '../../utils/ua' +import { IDomEditor } from '../../editor/interface' import { DOMNode } from '../../utils/dom' +import { IS_CHROME, IS_FIREFOX, IS_SAFARI } from '../../utils/ua' +import { hasEditableTarget } from '../helpers' import { hidePlaceholder } from '../place-holder' import { editorSelectionToDOM } from '../syncSelection' +import TextArea from '../TextArea' const EDITOR_TO_TEXT: WeakMap = new WeakMap() const EDITOR_TO_START_CONTAINER: WeakMap = new WeakMap() +function areBothTextNodes(editor, selection) { + if (Range.isCollapsed(selection)) { + const { anchor, focus } = selection + + if ( + anchor.path.length === 2 + && focus.path.length === 2 + && (anchor.offset === 0 || focus.offset === 0) + ) { + const nowEntry = Editor.node(editor, anchor.path) + const nowPath = anchor.offset === 0 ? anchor.path : focus.path + const prePath = [nowPath[0], nowPath[1] - 1] + + if (nowPath[1] === 0) { + return false + } + const preEntry = Editor.node(editor, prePath) + + if (Text.isText(preEntry[0]) && Text.isText(nowEntry[0])) { + return true + } + } + } +} + /** * composition start 事件 * @param e event @@ -25,9 +53,10 @@ const EDITOR_TO_START_CONTAINER: WeakMap = new WeakMap() export function handleCompositionStart(e: Event, textarea: TextArea, editor: IDomEditor) { const event = e as CompositionEvent - if (!hasEditableTarget(editor, event.target)) return + if (!hasEditableTarget(editor, event.target)) { return } const { selection } = editor + if (selection && Range.isExpanded(selection)) { Editor.deleteFragment(editor) @@ -40,11 +69,12 @@ export function handleCompositionStart(e: Event, textarea: TextArea, editor: IDo }) } - if (selection && (Range.isExpanded(selection) || Range.isCollapsed(selection))) { + if (editor.selection) { // 记录下 dom text ,以便触发 maxLength 时使用 - const domRange = DomEditor.toDOMRange(editor, selection) + const domRange = DomEditor.toDOMRange(editor, editor.selection) const startContainer = domRange.startContainer const curText = startContainer.textContent || '' + EDITOR_TO_TEXT.set(editor, curText) // 记录下 dom range startContainer @@ -63,7 +93,7 @@ export function handleCompositionStart(e: Event, textarea: TextArea, editor: IDo * @param editor editor */ export function handleCompositionUpdate(event: Event, textarea: TextArea, editor: IDomEditor) { - if (!hasEditableTarget(editor, event.target)) return + if (!hasEditableTarget(editor, event.target)) { return } textarea.isComposing = true } @@ -77,11 +107,12 @@ export function handleCompositionUpdate(event: Event, textarea: TextArea, editor export function handleCompositionEnd(e: Event, textarea: TextArea, editor: IDomEditor) { const event = e as CompositionEvent - if (!hasEditableTarget(editor, event.target)) return + if (!hasEditableTarget(editor, event.target)) { return } textarea.isComposing = false const { selection } = editor - if (selection == null) return + + if (selection == null) { return } // 清理可能暴露的 text 节点 // 例如 chrome 在链接后面,输入拼音,就会出现有暴露出来的 text node @@ -96,8 +127,9 @@ export function handleCompositionEnd(e: Event, textarea: TextArea, editor: IDomE const start = Range.isBackward(selection) ? selection.focus : selection.anchor const [paragraph] = Editor.node(editor, [start.path[0]]) - for (let i = 0; i < start.path.length; i++) { + for (let i = 0; i < start.path.length; i += 1) { const [node] = Editor.node(editor, start.path.slice(0, i + 1)) + if (Element.isElement(node)) { if (((IS_SAFARI || IS_FIREFOX) && node.type === 'link') || node.type === 'code') { DomEditor.setNewKey(paragraph) @@ -107,15 +139,21 @@ export function handleCompositionEnd(e: Event, textarea: TextArea, editor: IDomE } const { data } = event - if (!data) return + + if (!data) { return } // 检查 maxLength -【注意】这里只处理拼音输入的 maxLength 限制。其他限制,在插件 with-max-length.ts 中处理 const { maxLength } = editor.getConfig() + if (maxLength) { const leftLengthOfMaxLength = DomEditor.getLeftLengthOfMaxLength(editor) + if (leftLengthOfMaxLength < data.length) { const domRange = DomEditor.toDOMRange(editor, selection) - domRange.startContainer.textContent = EDITOR_TO_TEXT.get(editor) || '' + + if (domRange.startContainer.nodeType === Node.TEXT_NODE) { + domRange.startContainer.textContent = EDITOR_TO_TEXT.get(editor) || '' + } if (leftLengthOfMaxLength > 0) { // 剩余长度 >0 ,但小于 data 长度,截取一部分插入 Editor.insertText(editor, data.slice(0, leftLengthOfMaxLength)) @@ -128,6 +166,7 @@ export function handleCompositionEnd(e: Event, textarea: TextArea, editor: IDomE // 拼音输入,当选区的边缘在两个 text node 之间时 需要重置为 domselction 的 选区 const root = DomEditor.findDocumentOrShadowRoot(editor) const domSelection = root.getSelection() + if (domSelection && areBothTextNodes(editor, selection)) { editor.selection = DomEditor.toSlateRange(editor, domSelection, { exactMatch: false, @@ -140,11 +179,14 @@ export function handleCompositionEnd(e: Event, textarea: TextArea, editor: IDomE // 检查拼音输入是否夸 DOM 节点了,解决 wangEditor-v5/issues/47 if (!IS_SAFARI) { setTimeout(() => { - const { selection } = editor - if (selection == null) return + const { selection: setTimeoutSelection } = editor + + if (setTimeoutSelection == null) { return } const oldStartContainer = EDITOR_TO_START_CONTAINER.get(editor) // 拼音输入开始时的 text node - if (oldStartContainer == null) return - const curStartContainer = DomEditor.toDOMRange(editor, selection).startContainer // 拼音输入结束时的 text node + + if (oldStartContainer == null) { return } + const curStartContainer = DomEditor.toDOMRange(editor, setTimeoutSelection).startContainer // 拼音输入结束时的 text node + if (curStartContainer === oldStartContainer) { // 拼音输入的开始和结束,都在同一个 text node ,则不做处理 return @@ -154,25 +196,3 @@ export function handleCompositionEnd(e: Event, textarea: TextArea, editor: IDomE }) } } -function areBothTextNodes(editor, selection) { - if (Range.isCollapsed(selection)) { - const { anchor, focus } = selection - if ( - anchor.path.length === 2 && - focus.path.length === 2 && - (anchor.offset === 0 || focus.path.offset === 0) - ) { - const nowEntry = Editor.node(editor, anchor.path) - const nowPath = anchor.offset === 0 ? anchor.path : focus.path - const prePath = [nowPath[0], nowPath[1] - 1] - if (nowPath[1] === 0) { - return false - } - const preEntry = Editor.node(editor, prePath) - - if (Text.isText(preEntry[0]) && Text.isText(nowEntry[0])) { - return true - } - } - } -}