UBER-1249 Make document Todos work with Heap (#4886)

This commit is contained in:
Alexander Onnikov 2024-03-06 14:39:25 +07:00 committed by GitHub
parent 4a85b0ad13
commit e003fb29fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 62 additions and 15 deletions

View File

@ -89,7 +89,9 @@ class SvelteNodeView extends NodeView<SvelteNodeViewComponent, Editor, SvelteNod
})
this.renderer = new SvelteRenderer(this.component, { element: target, props, context })
this.editor.on('update', this.handleEditorUpdate.bind(this))
this.editor.on('selectionUpdate', this.handleSelectionUpdate.bind(this))
}
override get dom (): HTMLElement {
@ -131,10 +133,12 @@ class SvelteNodeView extends NodeView<SvelteNodeViewComponent, Editor, SvelteNod
selectNode (): void {
this.renderer.updateProps({ selected: true })
this.renderer.element.classList.add('ProseMirror-selectednode')
}
deselectNode (): void {
this.renderer.updateProps({ selected: false })
this.renderer.element.classList.remove('ProseMirror-selectednode')
}
handleEditorUpdate (): void {
@ -144,10 +148,29 @@ class SvelteNodeView extends NodeView<SvelteNodeViewComponent, Editor, SvelteNod
}
}
handleSelectionUpdate (): void {
const { from, to } = this.editor.state.selection
if (from <= this.getPos() && to >= this.getPos() + this.node.nodeSize) {
if (this.renderer.props.selected === true) {
return
}
this.selectNode()
} else {
if (this.renderer.props.selected !== true) {
return
}
this.deselectNode()
}
}
destroy (): void {
this.renderer.destroy()
this.contentDOMElement = null
this.editor.off('update', this.handleEditorUpdate.bind(this))
this.editor.off('selectionUpdate', this.handleSelectionUpdate.bind(this))
this.contentDOMElement = null
}
}

View File

@ -20,17 +20,19 @@ export type SvelteRendererComponent = typeof SvelteComponent | ComponentType
export interface SvelteRendererOptions {
element: HTMLElement
props?: any
props?: Record<string, any>
context?: any
}
export class SvelteRenderer {
private readonly component: SvelteComponent
element: HTMLElement
props: Record<string, any>
constructor (component: SvelteRendererComponent, { element, props, context }: SvelteRendererOptions) {
this.element = element
this.element.classList.add('svelte-renderer')
this.props = props ?? {}
const options = { target: element, props, context }
const Component = component

View File

@ -29,7 +29,8 @@
} from '@hcengineering/text-editor'
import { createEventDispatcher } from 'svelte'
import ToDoNodeView from './node-view/ToDoNodeView.svelte'
import ToDoItemNodeView from './node-view/ToDoItemNodeView.svelte'
import ToDoListNodeView from './node-view/ToDoListNodeView.svelte'
export let object: Document
export let readonly = false
@ -55,14 +56,23 @@
}),
TodoItemExtension.extend({
addNodeView () {
return SvelteNodeViewRenderer(ToDoNodeView, { contentAs: 'li', componentProps: { object } })
return SvelteNodeViewRenderer(ToDoItemNodeView, {
contentAs: 'li',
contentClass: 'todo-item',
componentProps: { object },
ignoreMutation: () => true
})
}
}).configure({
HTMLAttributes: {
class: 'todo-item'
}
}),
TodoListExtension.configure({
TodoListExtension.extend({
addNodeView () {
return SvelteNodeViewRenderer(ToDoListNodeView, { ignoreMutation: () => true })
}
}).configure({
HTMLAttributes: {
class: 'todo-list'
}

View File

@ -18,6 +18,11 @@
const client = getClient()
const query = createQuery()
$: todoId = node.attrs.todoid as Ref<ToDo>
$: userId = node.attrs.userid as Ref<Person>
$: checked = node.attrs.checked ?? false
$: readonly = !editor.isEditable || object === undefined
let todo: ToDo | undefined = undefined
$: query.query(
time.class.ToDo,
@ -26,15 +31,10 @@
},
(res) => {
;[todo] = res
syncTodo(todo)
void syncTodo(todo)
}
)
$: todoId = node.attrs.todoid as Ref<ToDo>
$: userId = node.attrs.userid as Ref<Person>
$: checked = node.attrs.checked ?? false
$: readonly = !editor.isEditable || object === undefined
async function syncTodo (todo: ToDo | undefined): Promise<void> {
if (todo !== undefined) {
const todoChecked = todo.doneOn != null
@ -59,7 +59,7 @@
if (todo !== undefined) {
await client.update(todo, { doneOn: todo.doneOn == null ? Date.now() : null })
} else {
updateAttributes({ checked: !node.attrs.checked })
updateAttributes({ checked: node.attrs.checked !== true })
}
}
@ -72,7 +72,7 @@
const ops = client.apply('todo')
if (todo !== undefined) {
await ops.removeDoc(todo._class, todo.space, todo._id)
await ops.remove(todo)
}
const id = await ops.addCollection(time.class.ProjectToDo, time.space.ToDos, object._id, object._class, 'todos', {
@ -101,7 +101,7 @@
})
if (todo !== undefined) {
await client.removeDoc(todo._class, todo.space, todo._id)
await client.remove(todo)
}
}
@ -164,12 +164,13 @@
await changeAssignee(result?._id)
}
hovered = false
editor.commands.focus()
}
)
}
</script>
<NodeViewWrapper data-drag-handle="">
<NodeViewWrapper data-drag-handle="" data-type="todoItem">
<div
class="todo-item flex-row-top flex-gap-3"
class:empty={node.textContent.length === 0}
@ -197,6 +198,10 @@
<style lang="scss">
.todo-item {
.assignee {
cursor: pointer;
}
&.unassigned {
.assignee {
opacity: 0;

View File

@ -0,0 +1,7 @@
<script lang="ts">
import { NodeViewContent, NodeViewWrapper } from '@hcengineering/text-editor'
</script>
<NodeViewWrapper data-drag-handle="">
<NodeViewContent as="ul" class="todo-list" data-type="todoList" />
</NodeViewWrapper>