chore: merge editor-dev to dev (#403)

* feat(rich-text-editor): add new component rich-text-editor (#346)

* feat(rich-text-editor): add new components rich-text-editor

---------

Co-authored-by: 常浩-BJS21325 <changhao01@youdao>

* style(rich-text-editor): adjust style, fit Highlight, Default, Disabled (#357)

* style(rich-text-editor): adjust style, fit Highlight, Default, Disabled

* fix(rich-text-editor): Space format changed from four to two

* fix(rich-text-editor): add svg file and support high light and disabled and default

---------

Co-authored-by: 常浩-BJS21325 <changhao01@youdao>

* feat(rich-text-editor): add text alignment, task list, table interaction (#372)

* feat(rich-text-editor): add text alignment, task list, table interaction

---------

Co-authored-by: 常浩-BJS21325 <changhao01@youdao>

* perf(rich-text-editor): split pure function from vue.ts to index.ts (#395)

Co-authored-by: 常浩-BJS21325 <changhao01@youdao>

* fix(rich-text-editor): fix conflict

---------

Co-authored-by: Caesar-ch <74941512+Caesar-ch@users.noreply.github.com>
Co-authored-by: 常浩-BJS21325 <changhao01@youdao>
This commit is contained in:
Kagol 2023-08-17 16:23:38 +08:00 committed by GitHub
parent 59c73952bd
commit c0cd7cdb4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 81 deletions

View File

@ -0,0 +1,81 @@
export const handleChange = (editor) => {
return (event) => {
const file = event.target.files[0]
if (!file.type.match("image.*")) {
console.log("请选择图片文件!")
return
}
const reader = new FileReader()
reader.onload = function (e) {
editor.value.chain().focus().setImage({ src: e.target?.result }).run()
}
reader.readAsDataURL(file)
}
}
export const setLink = (editor) => {
return () => {
const previousUrl = editor.value.getAttributes('link').href
const url = window.prompt('URL', previousUrl)
if (url === null) {
return
}
if (url === '') {
editor.value
.chain()
.focus()
.extendMarkRange('link')
.unsetLink()
.run()
return
}
editor.value
.chain()
.focus()
.extendMarkRange('link')
.setLink({ href: url })
.run()
}
}
// table 处理逻辑
export const handleMove = (state, box) => {
return (e) => {
let { x, y } = box.value.getBoundingClientRect()
state.flagX = Math.ceil((e.x - x) / 30) // 后期改变30就可以
state.flagY = Math.ceil((e.y - y) / 30)
}
}
export const handleClickOutside = (state, box) => {
return (e) => {
if (!box.value?.contains(e.target)) {
state.isShow = false
removeClickOutside(state, box)()
}
}
}
export const removeClickOutside = (state, box) => {
return () => {
window.removeEventListener('click', handleClickOutside(state, box))
}
}
export const handleClick = (state, box) => {
return (e) => {
e.stopPropagation();
if (state.isShow) {
if (state.flagX && state.flagY) {
state.editor.chain().focus().insertTable({ rows: state.flagX, cols: state.flagY, withHeaderRow: true }).run()
}
state.flagX = 0
state.flagY = 0
removeClickOutside(state, box)()
} else {
window.addEventListener('click', handleClickOutside(state, box))
}
state.isShow = !state.isShow
}
}
// bubble菜单
export const shouldShow = ({ editor, view, state, oldState, from, to }) => {
// 仅在无序列表选中的时候才显示 气泡菜单
return editor.isActive("table");
};

View File

@ -1,3 +1,4 @@
import { handleChange, setLink, handleMove, handleClickOutside, removeClickOutside, handleClick, shouldShow } from './index'
export const api = ['state', 'setLink', 'handleChange', 'box', 'handleMove', 'handleClickOutside', 'removeClickOutside', 'handleClick', 'shouldShow']
export const renderless = (
props,
@ -47,74 +48,6 @@ export const renderless = (
editable: true,
injectCSS: false,
})
const handleChange = (event) => {
const file = event.target.files[0]
if (!file.type.match("image.*")) {
console.log("请选择图片文件!")
return
}
const reader = new FileReader()
reader.onload = function (e) {
editor.value.chain().focus().setImage({ src: e.target?.result }).run()
}
reader.readAsDataURL(file)
}
const setLink = () => {
const previousUrl = editor.value.getAttributes('link').href
const url = window.prompt('URL', previousUrl)
if (url === null) {
return
}
if (url === '') {
editor.value
.chain()
.focus()
.extendMarkRange('link')
.unsetLink()
.run()
return
}
editor.value
.chain()
.focus()
.extendMarkRange('link')
.setLink({ href: url })
.run()
}
// table 处理逻辑
const handleMove = (e) => {
let { x, y } = box.value.getBoundingClientRect()
state.flagX = Math.ceil((e.x - x) / 30) // 后期改变30就可以
state.flagY = Math.ceil((e.y - y) / 30)
}
const handleClickOutside = (e) => {
if (!box.value?.contains(e.target)) {
state.isShow = false
removeClickOutside()
}
}
const removeClickOutside = () => {
window.removeEventListener('click', handleClickOutside)
}
const handleClick = (e) => {
e.stopPropagation();
if (state.isShow) {
if (state.flagX && state.flagY) {
state.editor.chain().focus().insertTable({ rows: state.flagX, cols: state.flagY, withHeaderRow: true }).run()
}
state.flagX = 0
state.flagY = 0
removeClickOutside()
} else {
window.addEventListener('click', handleClickOutside)
}
state.isShow = !state.isShow
}
// bubble菜单
const shouldShow = ({ editor, view, state, oldState, from, to }) => {
// 仅在无序列表选中的时候才显示 气泡菜单
return editor.isActive("table");
};
const box = ref(null)
const state = reactive({
editor: null,
@ -126,16 +59,16 @@ export const renderless = (
state.editor = editor
const api = {
state,
setLink,
handleChange,
setLink: setLink(editor),
handleChange: handleChange(editor),
// table处理函数
box,
handleMove,
handleClickOutside,
removeClickOutside,
handleClick,
handleMove: handleMove(state, box),
handleClickOutside: handleClickOutside(state, box),
removeClickOutside: removeClickOutside(state, box),
handleClick: handleClick(state, box),
// bubble 菜单
shouldShow,
shouldShow: shouldShow,
}
onBeforeUnmount(() => {
state.editor.destroy()

View File

@ -1,12 +1,16 @@
@import './vars.less';
.tiny-rich-text-editor {
.component-css-vars-rich-text-editor();
width: 500px;
height: 350px;
margin: 0 auto;
outline: 3px solid rgb(203, 203, 203);
outline: 3px solid var(--ti-rich-text-editor-box-outline-color);
border-radius: 8px 8px 0 0;
&:hover {
outline: 3px solid black;
outline: 3px solid var(--ti-rich-text-editor-box-outline-hover-color);
}
.button-area {
@ -26,18 +30,18 @@
cursor: pointer;
&:hover {
background-color: #d2e4ff;
background-color: var(--ti-rich-text-editor-button-hover);
}
}
button:disabled {
// color: rgba(34, 47, 62, .5);
background-color: rgba(203, 203, 203, .3);
background-color: var(--ti-rich-text-editor-button-disabled);
cursor: not-allowed;
}
button.is-active {
background-color: #d2e4ff;
background-color: var(--ti-rich-text-editor-button-active);
}
.tiny-svg {

View File

@ -1 +1,9 @@
.component-css-vars-roles() {}
.component-css-vars-rich-text-editor() {
--ti-rich-text-editor-box-outline-color: var(--ti-common-color-line-normal);
--ti-rich-text-editor-box-outline-hover-color: var(--ti-common-color-line-hover);
--ti-rich-text-editor-button-hover: var(--ti-base-color-brand-8);
--ti-rich-text-editor-button-disabled: var(--ti-common-color-primary-disabled-bgcolor);
--ti-rich-text-editor-button-active: var(--ti-base-color-brand-8);
--ti-rich-text-editor-poplist-item-selected-bg-color: var(--ti-common-color-selected-background);
--ti-rich-text-editor-poplist-item-selected-text-color: var(--ti-common-color-selected-text-color);
}