mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-24 09:16:43 +00:00
Support tables and minor fixes (#2365)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
6cc79a0fcd
commit
88a9037545
common/config/rush
packages
plugins/document-resources/src/components
@ -656,6 +656,16 @@ dependencies:
|
||||
|
||||
packages:
|
||||
|
||||
/@_ueberdosis/prosemirror-tables/1.1.3:
|
||||
resolution: {integrity: sha512-su3pbFi1DT89g6Cuh72TE0MWWKHmWgHcQJ3ODRkm6XfIppWaGpU49t02ur3sgJc7hUhfQXjB93aSkDgOmIii2w==}
|
||||
dependencies:
|
||||
prosemirror-keymap: 1.2.0
|
||||
prosemirror-model: 1.18.1
|
||||
prosemirror-state: 1.4.1
|
||||
prosemirror-transform: 1.7.0
|
||||
prosemirror-view: 1.29.0
|
||||
dev: false
|
||||
|
||||
/@ampproject/remapping/2.2.0:
|
||||
resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
@ -1861,6 +1871,42 @@ packages:
|
||||
'@tiptap/core': 2.0.0-beta.199
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-table-cell/2.0.0-beta.202_@tiptap+core@2.0.0-beta.199:
|
||||
resolution: {integrity: sha512-Ypmcq7zaMSZ0VNKwDPINOsSzyuH+gSIw+FrXy6O1dzVHAo1gNFJ2pEG/ZhQ2RqpDTpGfJFD8tNDx8wjCCAVlxA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0-beta.193
|
||||
dependencies:
|
||||
'@tiptap/core': 2.0.0-beta.199
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-table-header/2.0.0-beta.202_@tiptap+core@2.0.0-beta.199:
|
||||
resolution: {integrity: sha512-/l0lz3Hmc+hikj+RfSW7F6B/jYV2dROGQnK1/EYjgbvOK0158ml1mB6/Dhm+BhldV73MI7eU8+3YLB9uhsPR4w==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0-beta.193
|
||||
dependencies:
|
||||
'@tiptap/core': 2.0.0-beta.199
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-table-row/2.0.0-beta.202_@tiptap+core@2.0.0-beta.199:
|
||||
resolution: {integrity: sha512-IsHBT3lp//XSqcAWPIGWjPIKQ4okVaDJbwcElehlOo/rcRBeK0orT+c10T08PoOsozi4BeMYRo0nfA5tvrJMEw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0-beta.193
|
||||
dependencies:
|
||||
'@tiptap/core': 2.0.0-beta.199
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-table/2.0.0-beta.202_@tiptap+core@2.0.0-beta.199:
|
||||
resolution: {integrity: sha512-WMfXtDfx45FgU81WnfxGOSJbVoaDpe8hjuBJSGbwJj+Qj4HGhbK7/RbTtDrM8oqseHRzHuGWgNX+EfOUQppjdA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0-beta.193
|
||||
dependencies:
|
||||
'@_ueberdosis/prosemirror-tables': 1.1.3
|
||||
'@tiptap/core': 2.0.0-beta.199
|
||||
prosemirror-model: 1.18.1
|
||||
prosemirror-state: 1.4.1
|
||||
prosemirror-view: 1.29.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-task-item/2.0.0-beta.199_@tiptap+core@2.0.0-beta.199:
|
||||
resolution: {integrity: sha512-dvMgXr4B/V8dYvksLtbby3R2wM9zk3xdkOBuohTLQuRq73dK12Bh/h5xrl4cey8i/2tQBWgUfFiGVPsEUJjQCQ==}
|
||||
peerDependencies:
|
||||
@ -14540,7 +14586,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/text-editor.tgz_13653a9d42656433759444fbd2afc848:
|
||||
resolution: {integrity: sha512-fTQmayD5wtd7FqRklhl13kDS5Y9tyBXfC5FAoJP+xUHbNk61+FzgKnmHFOjbsJVvgFVkag98AJA9xb9nHfjFzw==, tarball: file:projects/text-editor.tgz}
|
||||
resolution: {integrity: sha512-CUuJVSwdoBUNvSy7GIaxemhr6fLCaU1BrbzzEpecP4HuRfQviyQQ2ME6gj4PWhcYVweFmUa1g3gRrCECtWIU8g==, tarball: file:projects/text-editor.tgz}
|
||||
id: file:projects/text-editor.tgz
|
||||
name: '@rush-temp/text-editor'
|
||||
version: 0.0.0
|
||||
@ -14555,6 +14601,10 @@ packages:
|
||||
'@tiptap/extension-link': 2.0.0-beta.199_@tiptap+core@2.0.0-beta.199
|
||||
'@tiptap/extension-mention': 2.0.0-beta.199_c8f353cb3abc70247a8f6c56ebb87d62
|
||||
'@tiptap/extension-placeholder': 2.0.0-beta.199_@tiptap+core@2.0.0-beta.199
|
||||
'@tiptap/extension-table': 2.0.0-beta.202_@tiptap+core@2.0.0-beta.199
|
||||
'@tiptap/extension-table-cell': 2.0.0-beta.202_@tiptap+core@2.0.0-beta.199
|
||||
'@tiptap/extension-table-header': 2.0.0-beta.202_@tiptap+core@2.0.0-beta.199
|
||||
'@tiptap/extension-table-row': 2.0.0-beta.202_@tiptap+core@2.0.0-beta.199
|
||||
'@tiptap/extension-task-item': 2.0.0-beta.199_ec97b388f910dbe754a14ff2f0072b88
|
||||
'@tiptap/extension-task-list': 2.0.0-beta.199_@tiptap+core@2.0.0-beta.199
|
||||
'@tiptap/extension-typography': 2.0.0-beta.199_@tiptap+core@2.0.0-beta.199
|
||||
|
@ -23,6 +23,20 @@
|
||||
"Food": "Food",
|
||||
"FullDescription": "Full description",
|
||||
"NoFullDescription": "There are no detailed description",
|
||||
"EnableDiffMode": "Diff mode"
|
||||
"EnableDiffMode": "Diff mode",
|
||||
|
||||
"AddColumnBefore": "Add before",
|
||||
"AddColumnAfter": "Add after",
|
||||
"DeleteColumn": "Delete",
|
||||
"AddRowBefore": "Add before",
|
||||
"AddRowAfter": "Add after",
|
||||
"DeleteRow": "Delete",
|
||||
"DeleteTable": "Delete",
|
||||
|
||||
"CategoryRow": "Rows",
|
||||
"CategoryColumn": "Columns",
|
||||
"Table": "Table",
|
||||
"InsertTable": "Insert table",
|
||||
"TableOptions": "Customize table"
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,20 @@
|
||||
"Food": "Еда",
|
||||
"FullDescription": "Детальное описание",
|
||||
"NoFullDescription": "Нет детального описания",
|
||||
"EnableDiffMode": "Режим сравнения"
|
||||
"EnableDiffMode": "Режим сравнения",
|
||||
|
||||
"AddColumnBefore": "Добавить до",
|
||||
"AddColumnAfter": "Добавить после",
|
||||
"DeleteColumn": "Удалить",
|
||||
"AddRowBefore": "Добавить до",
|
||||
"AddRowAfter": "Добавить после",
|
||||
"DeleteRow": "Удалить",
|
||||
"DeleteTable": "Удалить",
|
||||
|
||||
"CategoryRow": "Строки",
|
||||
"CategoryColumn": "Колонки",
|
||||
"Table": "Таблица",
|
||||
"InsertTable": "Добавить таблицу",
|
||||
"TableOptions": "Настроить таблицу"
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,10 @@
|
||||
"diff": "~5.1.0",
|
||||
"@tiptap/extension-code-block": "~2.0.0-beta.200",
|
||||
"@tiptap/extension-gapcursor": "~2.0.0-beta.200",
|
||||
"@tiptap/extension-heading": "~2.0.0-beta.200"
|
||||
"@tiptap/extension-heading": "~2.0.0-beta.200",
|
||||
"@tiptap/extension-table": "~2.0.0-beta.202",
|
||||
"@tiptap/extension-table-cell": "~2.0.0-beta.202",
|
||||
"@tiptap/extension-table-header": "~2.0.0-beta.202",
|
||||
"@tiptap/extension-table-row": "~2.0.0-beta.202"
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Editor, Extension } from '@tiptap/core'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import Link from '@tiptap/extension-link'
|
||||
import Heading, { Level } from '@tiptap/extension-heading'
|
||||
import TaskItem from '@tiptap/extension-task-item'
|
||||
import TaskList from '@tiptap/extension-task-list'
|
||||
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import { Plugin, PluginKey } from 'prosemirror-state'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
|
||||
@ -30,18 +24,16 @@
|
||||
import { IconSize } from '@hcengineering/ui'
|
||||
import StyleButton from './StyleButton.svelte'
|
||||
|
||||
import TipTapCodeBlock from '@tiptap/extension-code-block'
|
||||
import Gapcursor from '@tiptap/extension-gapcursor'
|
||||
import { DecorationSet } from 'prosemirror-view'
|
||||
import textEditorPlugin from '../plugin'
|
||||
|
||||
import { calculateDecorations } from './diff/decorations'
|
||||
import { defaultExtensions } from './extensions'
|
||||
import Objects from './icons/Objects.svelte'
|
||||
|
||||
export let content: Markup
|
||||
export let buttonSize: IconSize = 'small'
|
||||
export let comparedVersion: Markup | undefined = undefined
|
||||
export let headingLevels: Level[] = [1, 2, 3, 4]
|
||||
|
||||
let element: HTMLElement
|
||||
let editor: Editor
|
||||
@ -89,34 +81,7 @@
|
||||
element,
|
||||
content,
|
||||
editable: true,
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Highlight.configure({
|
||||
multicolor: false
|
||||
}),
|
||||
TipTapCodeBlock.configure({
|
||||
languageClassPrefix: 'language-',
|
||||
exitOnArrowDown: true,
|
||||
exitOnTripleEnter: true,
|
||||
HTMLAttributes: {
|
||||
class: 'code-block'
|
||||
}
|
||||
}),
|
||||
Gapcursor,
|
||||
Heading.configure({
|
||||
levels: headingLevels
|
||||
}),
|
||||
Link.configure({ openOnClick: false }),
|
||||
TaskList,
|
||||
TaskItem.configure({
|
||||
nested: true,
|
||||
HTMLAttributes: {
|
||||
class: 'flex flex-grow gap-1 checkbox_style'
|
||||
}
|
||||
}),
|
||||
DecorationExtension
|
||||
// ...extensions
|
||||
],
|
||||
extensions: [...defaultExtensions, DecorationExtension],
|
||||
onTransaction: () => {
|
||||
// force re-render so `editor.isActive` works as expected
|
||||
editor = editor
|
||||
|
@ -18,16 +18,11 @@
|
||||
import { getEmbeddedLabel, IntlString, translate } from '@hcengineering/platform'
|
||||
|
||||
import { Editor, Extension, HTMLContent } from '@tiptap/core'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import Link from '@tiptap/extension-link'
|
||||
import Placeholder from '@tiptap/extension-placeholder'
|
||||
import Collaboration from '@tiptap/extension-collaboration'
|
||||
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
|
||||
import Heading, { Level } from '@tiptap/extension-heading'
|
||||
import TaskItem from '@tiptap/extension-task-item'
|
||||
import TaskList from '@tiptap/extension-task-list'
|
||||
import { Level } from '@tiptap/extension-heading'
|
||||
import Placeholder from '@tiptap/extension-placeholder'
|
||||
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import { Plugin, PluginKey, Transaction } from 'prosemirror-state'
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||
|
||||
@ -38,8 +33,8 @@
|
||||
import * as Y from 'yjs'
|
||||
import StyleButton from './StyleButton.svelte'
|
||||
|
||||
import TipTapCodeBlock from '@tiptap/extension-code-block'
|
||||
import Gapcursor from '@tiptap/extension-gapcursor'
|
||||
import presentation from '@hcengineering/presentation'
|
||||
|
||||
import { DecorationSet } from 'prosemirror-view'
|
||||
import textEditorPlugin from '../plugin'
|
||||
import { FormatMode, FORMAT_MODES } from '../types'
|
||||
@ -48,7 +43,9 @@
|
||||
import CodeBlock from './icons/CodeBlock.svelte'
|
||||
|
||||
import { calculateDecorations } from './diff/decorations'
|
||||
import { defaultExtensions, headingLevels } from './extensions'
|
||||
import Header from './icons/Header.svelte'
|
||||
import IconTable from './icons/IconTable.svelte'
|
||||
import Italic from './icons/Italic.svelte'
|
||||
import LinkEl from './icons/Link.svelte'
|
||||
import ListBullet from './icons/ListBullet.svelte'
|
||||
@ -71,8 +68,6 @@
|
||||
export let suggestMode = false
|
||||
export let comparedVersion: Markup | undefined = undefined
|
||||
|
||||
export let headingLevels: Level[] = [1, 2, 3, 4]
|
||||
|
||||
const ydoc = new Y.Doc()
|
||||
const wsProvider = new WebsocketProvider(collaboratorURL, documentId, ydoc, {
|
||||
params: {
|
||||
@ -213,37 +208,9 @@
|
||||
// content: 'Hello world<br/> This is simple text<br/>Some more text<br/>Yahoo <br/>Cool <br/><br/> Done',
|
||||
editable: true,
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Highlight.configure({
|
||||
multicolor: false
|
||||
}),
|
||||
TipTapCodeBlock.configure({
|
||||
languageClassPrefix: 'language-',
|
||||
exitOnArrowDown: true,
|
||||
exitOnTripleEnter: true,
|
||||
HTMLAttributes: {
|
||||
class: 'code-block'
|
||||
}
|
||||
}),
|
||||
Gapcursor,
|
||||
Heading.configure({
|
||||
levels: headingLevels
|
||||
}),
|
||||
// ChangeHighlight,
|
||||
// ChangesetExtension.configure({
|
||||
// isSuggestMode
|
||||
// }),
|
||||
Link.configure({ openOnClick: false }),
|
||||
// ...(supportSubmit ? [Handle] : []), // order important
|
||||
// Typography, // we need to disable 1/2 -> ½ rule (https://github.com/hcengineering/anticrm/issues/345)
|
||||
...defaultExtensions,
|
||||
Placeholder.configure({ placeholder: placeHolderStr }),
|
||||
TaskList,
|
||||
TaskItem.configure({
|
||||
nested: true,
|
||||
HTMLAttributes: {
|
||||
class: 'flex flex-grow gap-1 checkbox_style'
|
||||
}
|
||||
}),
|
||||
|
||||
Collaboration.configure({
|
||||
document: ydoc
|
||||
}),
|
||||
@ -269,7 +236,6 @@
|
||||
focused = true
|
||||
},
|
||||
onUpdate: (op: { editor: Editor; transaction: Transaction }) => {
|
||||
// _decoration = DecorationSet.empty
|
||||
dispatch('content', editor.getHTML())
|
||||
updateFormattingState()
|
||||
},
|
||||
@ -328,7 +294,7 @@
|
||||
showPopup(
|
||||
SelectPopup,
|
||||
{
|
||||
value: Array.from(headingLevels).map((it) => ({ id: it.toString(), label: it.toString() }))
|
||||
value: Array.from(headingLevels).map((it) => ({ id: it.toString(), text: it.toString() }))
|
||||
},
|
||||
getEventPositionElement(event),
|
||||
(val) => {
|
||||
@ -342,6 +308,182 @@
|
||||
}
|
||||
}
|
||||
|
||||
function insertTable (event: MouseEvent) {
|
||||
const tables = [
|
||||
{
|
||||
label: '2x2',
|
||||
rows: 2,
|
||||
cols: 2,
|
||||
header: false
|
||||
},
|
||||
{
|
||||
label: '3x3',
|
||||
rows: 3,
|
||||
cols: 3,
|
||||
header: false
|
||||
},
|
||||
{
|
||||
label: '2x1',
|
||||
rows: 2,
|
||||
cols: 1,
|
||||
header: false
|
||||
},
|
||||
{
|
||||
label: '5x5',
|
||||
rows: 5,
|
||||
cols: 5,
|
||||
header: false
|
||||
},
|
||||
{
|
||||
label: '1x2',
|
||||
rows: 1,
|
||||
cols: 2,
|
||||
header: false
|
||||
},
|
||||
{
|
||||
label: 'Headed 2x2',
|
||||
rows: 2,
|
||||
cols: 2,
|
||||
header: true
|
||||
},
|
||||
{
|
||||
label: 'Headed 3x3',
|
||||
rows: 3,
|
||||
cols: 3,
|
||||
header: true
|
||||
},
|
||||
{
|
||||
label: 'Headed 2x1',
|
||||
rows: 2,
|
||||
cols: 1,
|
||||
header: true
|
||||
},
|
||||
{
|
||||
label: 'Headed 5x5',
|
||||
rows: 5,
|
||||
cols: 5,
|
||||
header: true
|
||||
},
|
||||
{
|
||||
label: 'Headed 1x2',
|
||||
rows: 1,
|
||||
cols: 2,
|
||||
header: true
|
||||
}
|
||||
]
|
||||
showPopup(
|
||||
SelectPopup,
|
||||
{
|
||||
value: [
|
||||
{ id: '#delete', label: presentation.string.Remove },
|
||||
...tables.map((it) => ({ id: it.label, text: it.label }))
|
||||
]
|
||||
},
|
||||
getEventPositionElement(event),
|
||||
(val) => {
|
||||
if (val !== undefined) {
|
||||
if (val === '#delete') {
|
||||
editor.commands.deleteTable()
|
||||
needFocus = true
|
||||
updateFormattingState()
|
||||
return
|
||||
}
|
||||
const tab = tables.find((it) => it.label === val)
|
||||
if (tab) {
|
||||
editor.commands.insertTable({
|
||||
cols: tab.cols,
|
||||
rows: tab.rows,
|
||||
withHeaderRow: tab.header
|
||||
})
|
||||
|
||||
needFocus = true
|
||||
updateFormattingState()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function tableOptions (event: MouseEvent) {
|
||||
const ops = [
|
||||
{
|
||||
id: '#addColumnBefore',
|
||||
label: textEditorPlugin.string.AddColumnBefore,
|
||||
action: () => editor.commands.addColumnBefore(),
|
||||
category: {
|
||||
label: textEditorPlugin.string.CategoryColumn
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '#addColumnAfter',
|
||||
label: textEditorPlugin.string.AddColumnAfter,
|
||||
action: () => editor.commands.addColumnAfter(),
|
||||
category: {
|
||||
label: textEditorPlugin.string.CategoryColumn
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
id: '#deleteColumn',
|
||||
label: textEditorPlugin.string.DeleteColumn,
|
||||
action: () => editor.commands.deleteColumn(),
|
||||
category: {
|
||||
label: textEditorPlugin.string.CategoryColumn
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '#addRowBefore',
|
||||
label: textEditorPlugin.string.AddRowBefore,
|
||||
action: () => editor.commands.addRowBefore(),
|
||||
category: {
|
||||
label: textEditorPlugin.string.CategoryRow
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '#addRowAfter',
|
||||
label: textEditorPlugin.string.AddRowAfter,
|
||||
action: () => editor.commands.addRowAfter(),
|
||||
category: {
|
||||
label: textEditorPlugin.string.CategoryRow
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '#deleteRow',
|
||||
label: textEditorPlugin.string.DeleteRow,
|
||||
action: () => editor.commands.deleteRow(),
|
||||
category: {
|
||||
label: textEditorPlugin.string.CategoryRow
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '#deleteTable',
|
||||
label: textEditorPlugin.string.DeleteTable,
|
||||
action: () => editor.commands.deleteTable(),
|
||||
category: {
|
||||
label: textEditorPlugin.string.Table
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
showPopup(
|
||||
SelectPopup,
|
||||
{
|
||||
value: ops
|
||||
},
|
||||
getEventPositionElement(event),
|
||||
(val) => {
|
||||
if (val !== undefined) {
|
||||
const op = ops.find((it) => it.id === val)
|
||||
if (op) {
|
||||
op.action()
|
||||
needFocus = true
|
||||
updateFormattingState()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function formatLink (): Promise<void> {
|
||||
const link = editor.getAttributes('link').href
|
||||
|
||||
@ -435,6 +577,24 @@
|
||||
showTooltip={{ label: textEditorPlugin.string.CodeBlock }}
|
||||
on:click={getToggler(toggleCodeBlock)}
|
||||
/>
|
||||
|
||||
<StyleButton
|
||||
icon={IconTable}
|
||||
iconProps={{ style: 'table' }}
|
||||
size={buttonSize}
|
||||
selected={activeModes.has('table')}
|
||||
on:click={insertTable}
|
||||
showTooltip={{ label: textEditorPlugin.string.InsertTable }}
|
||||
/>
|
||||
{#if activeModes.has('table')}
|
||||
<StyleButton
|
||||
icon={IconTable}
|
||||
iconProps={{ style: 'grid' }}
|
||||
size={buttonSize}
|
||||
on:click={tableOptions}
|
||||
showTooltip={{ label: textEditorPlugin.string.TableOptions }}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex-grow" />
|
||||
|
@ -17,6 +17,7 @@
|
||||
import { AnySvelteComponent, Icon, IconSize, LabelAndProps, tooltip } from '@hcengineering/ui'
|
||||
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let iconProps: any = undefined
|
||||
export let size: IconSize
|
||||
export let selected: boolean = false
|
||||
export let showTooltip: LabelAndProps | undefined = undefined
|
||||
@ -32,7 +33,7 @@
|
||||
on:click|preventDefault|stopPropagation
|
||||
>
|
||||
<div class="icon {size} flex">
|
||||
<Icon {icon} {size} />
|
||||
<Icon {icon} {size} {iconProps} />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
@ -17,16 +17,12 @@
|
||||
import { IntlString, translate } from '@hcengineering/platform'
|
||||
|
||||
import { AnyExtension, Editor, Extension, HTMLContent } from '@tiptap/core'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import Link from '@tiptap/extension-link'
|
||||
// import Typography from '@tiptap/extension-typography'
|
||||
import Placeholder from '@tiptap/extension-placeholder'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import TaskList from '@tiptap/extension-task-list'
|
||||
import TaskItem from '@tiptap/extension-task-item'
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||
import textEditorPlugin from '../plugin'
|
||||
import { FormatMode } from '../types'
|
||||
import { defaultExtensions } from './extensions'
|
||||
|
||||
export let content: string = ''
|
||||
export let placeholder: IntlString = textEditorPlugin.string.EditorPlaceholder
|
||||
@ -144,19 +140,9 @@
|
||||
element,
|
||||
content,
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Highlight,
|
||||
Link.configure({ openOnClick: false }),
|
||||
...defaultExtensions,
|
||||
...(supportSubmit ? [Handle] : []), // order important
|
||||
// Typography, // we need to disable 1/2 -> ½ rule (https://github.com/hcengineering/anticrm/issues/345)
|
||||
Placeholder.configure({ placeholder: placeHolderStr }),
|
||||
TaskList,
|
||||
TaskItem.configure({
|
||||
nested: true,
|
||||
HTMLAttributes: {
|
||||
class: 'flex flex-grow gap-1 checkbox_style'
|
||||
}
|
||||
}),
|
||||
...extensions
|
||||
],
|
||||
onTransaction: () => {
|
||||
|
66
packages/text-editor/src/components/extensions.ts
Normal file
66
packages/text-editor/src/components/extensions.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import Table from '@tiptap/extension-table'
|
||||
import TableCell from '@tiptap/extension-table-cell'
|
||||
import TableHeader from '@tiptap/extension-table-header'
|
||||
import TableRow from '@tiptap/extension-table-row'
|
||||
|
||||
import TaskItem from '@tiptap/extension-task-item'
|
||||
import TaskList from '@tiptap/extension-task-list'
|
||||
|
||||
import Heading, { Level } from '@tiptap/extension-heading'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
|
||||
import TipTapCodeBlock from '@tiptap/extension-code-block'
|
||||
import Gapcursor from '@tiptap/extension-gapcursor'
|
||||
|
||||
import Link from '@tiptap/extension-link'
|
||||
|
||||
export const tableExtensions = [
|
||||
Table.configure({
|
||||
resizable: false,
|
||||
HTMLAttributes: {
|
||||
class: 'antiTable editable '
|
||||
}
|
||||
}),
|
||||
TableRow.configure({
|
||||
HTMLAttributes: {
|
||||
class: 'antiTable-body__row'
|
||||
}
|
||||
}),
|
||||
TableHeader.configure({}),
|
||||
TableCell.configure({})
|
||||
]
|
||||
|
||||
export const taskListExtensions = [
|
||||
TaskList,
|
||||
TaskItem.configure({
|
||||
nested: true,
|
||||
HTMLAttributes: {
|
||||
class: 'flex flex-grow gap-1 checkbox_style'
|
||||
}
|
||||
})
|
||||
]
|
||||
|
||||
export const headingLevels: Level[] = [1, 2, 3, 4, 5, 6]
|
||||
|
||||
export const defaultExtensions = [
|
||||
StarterKit,
|
||||
Highlight.configure({
|
||||
multicolor: false
|
||||
}),
|
||||
TipTapCodeBlock.configure({
|
||||
languageClassPrefix: 'language-',
|
||||
exitOnArrowDown: true,
|
||||
exitOnTripleEnter: true,
|
||||
HTMLAttributes: {
|
||||
class: 'code-block'
|
||||
}
|
||||
}),
|
||||
Gapcursor,
|
||||
Heading.configure({
|
||||
levels: headingLevels
|
||||
}),
|
||||
Link.configure({ openOnClick: false }),
|
||||
...tableExtensions,
|
||||
...taskListExtensions
|
||||
]
|
25
packages/text-editor/src/components/icons/IconTable.svelte
Normal file
25
packages/text-editor/src/components/icons/IconTable.svelte
Normal file
@ -0,0 +1,25 @@
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
export let style: 'table' | 'grid' = 'table'
|
||||
const fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
{#if style === 'table'}
|
||||
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M2 8C2 6.34315 3.34315 5 5 5H19C20.6569 5 22 6.34315 22 8V16C22 17.6569 20.6569 19 19 19H5C3.34315 19 2 17.6569 2 16V8ZM5 7H19C19.5523 7 20 7.44771 20 8V11H4V8C4 7.44772 4.44772 7 5 7ZM4 13V16C4 16.5523 4.44772 17 5 17H8V13H4ZM10 17H19C19.5523 17 20 16.5523 20 16V13H10V17Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
{:else if style === 'grid'}
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"
|
||||
><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M5 5C3.34315 5 2 6.34315 2 8V16C2 17.6569 3.34315 19 5 19H19C20.6569 19 22 17.6569 22 16V8C22 6.34315 20.6569 5 19 5H5ZM8 7H5C4.44772 7 4 7.44772 4 8V9H8V7ZM10 7V9H14V7H10ZM16 7V9H20V8C20 7.44771 19.5523 7 19 7H16ZM14 11H10V13H14V11ZM16 13V11H20V13H16ZM14 15H10V17H14V15ZM16 17V15H20V16C20 16.5523 19.5523 17 19 17H16ZM8 17V15H4V16C4 16.5523 4.44772 17 5 17H8ZM8 13V11H4V13H8Z"
|
||||
fill="currentColor"
|
||||
/></svg
|
||||
>
|
||||
{/if}
|
@ -55,6 +55,19 @@ export default plugin(textEditorId, {
|
||||
Objects: '' as IntlString,
|
||||
FullDescription: '' as IntlString,
|
||||
NoFullDescription: '' as IntlString,
|
||||
EnableDiffMode: '' as IntlString
|
||||
EnableDiffMode: '' as IntlString,
|
||||
|
||||
InsertTable: '' as IntlString,
|
||||
AddColumnBefore: '' as IntlString,
|
||||
AddColumnAfter: '' as IntlString,
|
||||
DeleteColumn: '' as IntlString,
|
||||
AddRowBefore: '' as IntlString,
|
||||
AddRowAfter: '' as IntlString,
|
||||
DeleteRow: '' as IntlString,
|
||||
DeleteTable: '' as IntlString,
|
||||
CategoryRow: '' as IntlString,
|
||||
CategoryColumn: '' as IntlString,
|
||||
Table: '' as IntlString,
|
||||
TableOptions: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
@ -35,7 +35,8 @@ export const FORMAT_MODES = [
|
||||
'blockquote',
|
||||
'code',
|
||||
'codeBlock',
|
||||
'heading'
|
||||
'heading',
|
||||
'table'
|
||||
] as const
|
||||
|
||||
export type FormatMode = typeof FORMAT_MODES[number]
|
||||
|
@ -372,6 +372,13 @@
|
||||
.checkall { visibility: visible; }
|
||||
}
|
||||
|
||||
&.editable {
|
||||
th, td, tr {
|
||||
border: 1px dashed var(--divider-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.metaColumn {
|
||||
th, td {
|
||||
&:first-child {
|
||||
|
@ -234,8 +234,8 @@
|
||||
let mode: ModelType = 'view'
|
||||
const modeLabels = {
|
||||
view: document.string.ViewMode,
|
||||
edit: document.string.EditMode,
|
||||
suggest: document.string.SuggestMode
|
||||
edit: document.string.EditMode
|
||||
// suggest: document.string.SuggestMode
|
||||
}
|
||||
|
||||
function selectMode (event: MouseEvent): void {
|
||||
@ -534,7 +534,7 @@
|
||||
<DocumentEditor
|
||||
object={version}
|
||||
initialContentId={version.initialContentId}
|
||||
comparedVersion={compareTo?.content ?? versions[versions.length - 1].content}
|
||||
comparedVersion={compareTo?.content ?? versions[versions.length - 2]?.content}
|
||||
readonly={mode === 'view'}
|
||||
bind:this={editor}
|
||||
/>
|
||||
|
Loading…
Reference in New Issue
Block a user