@jvs-milkdown/components 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/lib/__internal__/components/icon.d.ts +24 -0
  4. package/lib/__internal__/components/icon.d.ts.map +1 -0
  5. package/lib/__internal__/components/image-input.d.ts +17 -0
  6. package/lib/__internal__/components/image-input.d.ts.map +1 -0
  7. package/lib/__internal__/keep-alive.d.ts +2 -0
  8. package/lib/__internal__/keep-alive.d.ts.map +1 -0
  9. package/lib/__internal__/meta.d.ts +3 -0
  10. package/lib/__internal__/meta.d.ts.map +1 -0
  11. package/lib/__tests__/setup.d.ts +2 -0
  12. package/lib/__tests__/setup.d.ts.map +1 -0
  13. package/lib/code-block/config.d.ts +23 -0
  14. package/lib/code-block/config.d.ts.map +1 -0
  15. package/lib/code-block/index.d.ts +5 -0
  16. package/lib/code-block/index.d.ts.map +1 -0
  17. package/lib/code-block/index.js +4160 -0
  18. package/lib/code-block/index.js.map +1 -0
  19. package/lib/code-block/view/components/code-block.d.ts +16 -0
  20. package/lib/code-block/view/components/code-block.d.ts.map +1 -0
  21. package/lib/code-block/view/components/copy-button.d.ts +9 -0
  22. package/lib/code-block/view/components/copy-button.d.ts.map +1 -0
  23. package/lib/code-block/view/components/language-picker.d.ts +5 -0
  24. package/lib/code-block/view/components/language-picker.d.ts.map +1 -0
  25. package/lib/code-block/view/components/preview-panel.d.ts +9 -0
  26. package/lib/code-block/view/components/preview-panel.d.ts.map +1 -0
  27. package/lib/code-block/view/index.d.ts +3 -0
  28. package/lib/code-block/view/index.d.ts.map +1 -0
  29. package/lib/code-block/view/loader.d.ts +13 -0
  30. package/lib/code-block/view/loader.d.ts.map +1 -0
  31. package/lib/code-block/view/node-view.d.ts +40 -0
  32. package/lib/code-block/view/node-view.d.ts.map +1 -0
  33. package/lib/image-block/config.d.ts +16 -0
  34. package/lib/image-block/config.d.ts.map +1 -0
  35. package/lib/image-block/index.d.ts +7 -0
  36. package/lib/image-block/index.d.ts.map +1 -0
  37. package/lib/image-block/index.js +660 -0
  38. package/lib/image-block/index.js.map +1 -0
  39. package/lib/image-block/remark-plugin.d.ts +2 -0
  40. package/lib/image-block/remark-plugin.d.ts.map +1 -0
  41. package/lib/image-block/schema.d.ts +3 -0
  42. package/lib/image-block/schema.d.ts.map +1 -0
  43. package/lib/image-block/view/components/__tests__/image-viewer.onImageLoadError.spec.d.ts +2 -0
  44. package/lib/image-block/view/components/__tests__/image-viewer.onImageLoadError.spec.d.ts.map +1 -0
  45. package/lib/image-block/view/components/image-block.d.ts +18 -0
  46. package/lib/image-block/view/components/image-block.d.ts.map +1 -0
  47. package/lib/image-block/view/components/image-viewer.d.ts +3 -0
  48. package/lib/image-block/view/components/image-viewer.d.ts.map +1 -0
  49. package/lib/image-block/view/index.d.ts +3 -0
  50. package/lib/image-block/view/index.d.ts.map +1 -0
  51. package/lib/image-inline/components/image-inline.d.ts +18 -0
  52. package/lib/image-inline/components/image-inline.d.ts.map +1 -0
  53. package/lib/image-inline/config.d.ts +11 -0
  54. package/lib/image-inline/config.d.ts.map +1 -0
  55. package/lib/image-inline/index.d.ts +5 -0
  56. package/lib/image-inline/index.d.ts.map +1 -0
  57. package/lib/image-inline/index.js +377 -0
  58. package/lib/image-inline/index.js.map +1 -0
  59. package/lib/image-inline/view.d.ts +3 -0
  60. package/lib/image-inline/view.d.ts.map +1 -0
  61. package/lib/index.d.ts +2 -0
  62. package/lib/index.d.ts.map +1 -0
  63. package/lib/index.js +35 -0
  64. package/lib/index.js.map +1 -0
  65. package/lib/link-tooltip/command.d.ts +2 -0
  66. package/lib/link-tooltip/command.d.ts.map +1 -0
  67. package/lib/link-tooltip/configure.d.ts +3 -0
  68. package/lib/link-tooltip/configure.d.ts.map +1 -0
  69. package/lib/link-tooltip/edit/component.d.ts +11 -0
  70. package/lib/link-tooltip/edit/component.d.ts.map +1 -0
  71. package/lib/link-tooltip/edit/edit-configure.d.ts +3 -0
  72. package/lib/link-tooltip/edit/edit-configure.d.ts.map +1 -0
  73. package/lib/link-tooltip/edit/edit-view.d.ts +15 -0
  74. package/lib/link-tooltip/edit/edit-view.d.ts.map +1 -0
  75. package/lib/link-tooltip/index.d.ts +7 -0
  76. package/lib/link-tooltip/index.d.ts.map +1 -0
  77. package/lib/link-tooltip/index.js +2526 -0
  78. package/lib/link-tooltip/index.js.map +1 -0
  79. package/lib/link-tooltip/preview/component.d.ts +11 -0
  80. package/lib/link-tooltip/preview/component.d.ts.map +1 -0
  81. package/lib/link-tooltip/preview/preview-configure.d.ts +3 -0
  82. package/lib/link-tooltip/preview/preview-configure.d.ts.map +1 -0
  83. package/lib/link-tooltip/preview/preview-view.d.ts +14 -0
  84. package/lib/link-tooltip/preview/preview-view.d.ts.map +1 -0
  85. package/lib/link-tooltip/slices.d.ts +34 -0
  86. package/lib/link-tooltip/slices.d.ts.map +1 -0
  87. package/lib/link-tooltip/tooltips.d.ts +3 -0
  88. package/lib/link-tooltip/tooltips.d.ts.map +1 -0
  89. package/lib/link-tooltip/utils.d.ts +14 -0
  90. package/lib/link-tooltip/utils.d.ts.map +1 -0
  91. package/lib/list-item-block/component.d.ts +19 -0
  92. package/lib/list-item-block/component.d.ts.map +1 -0
  93. package/lib/list-item-block/config.d.ts +13 -0
  94. package/lib/list-item-block/config.d.ts.map +1 -0
  95. package/lib/list-item-block/index.d.ts +6 -0
  96. package/lib/list-item-block/index.d.ts.map +1 -0
  97. package/lib/list-item-block/index.js +2149 -0
  98. package/lib/list-item-block/index.js.map +1 -0
  99. package/lib/list-item-block/view.d.ts +3 -0
  100. package/lib/list-item-block/view.d.ts.map +1 -0
  101. package/lib/table-block/config.d.ts +8 -0
  102. package/lib/table-block/config.d.ts.map +1 -0
  103. package/lib/table-block/dnd/calc-drag-over.d.ts +3 -0
  104. package/lib/table-block/dnd/calc-drag-over.d.ts.map +1 -0
  105. package/lib/table-block/dnd/create-drag-handler.d.ts +5 -0
  106. package/lib/table-block/dnd/create-drag-handler.d.ts.map +1 -0
  107. package/lib/table-block/dnd/drag-over-handler.d.ts +3 -0
  108. package/lib/table-block/dnd/drag-over-handler.d.ts.map +1 -0
  109. package/lib/table-block/dnd/prepare-dnd-context.d.ts +3 -0
  110. package/lib/table-block/dnd/prepare-dnd-context.d.ts.map +1 -0
  111. package/lib/table-block/dnd/preview.d.ts +3 -0
  112. package/lib/table-block/dnd/preview.d.ts.map +1 -0
  113. package/lib/table-block/index.d.ts +5 -0
  114. package/lib/table-block/index.d.ts.map +1 -0
  115. package/lib/table-block/index.js +3961 -0
  116. package/lib/table-block/index.js.map +1 -0
  117. package/lib/table-block/view/component.d.ts +16 -0
  118. package/lib/table-block/view/component.d.ts.map +1 -0
  119. package/lib/table-block/view/drag.d.ts +7 -0
  120. package/lib/table-block/view/drag.d.ts.map +1 -0
  121. package/lib/table-block/view/index.d.ts +2 -0
  122. package/lib/table-block/view/index.d.ts.map +1 -0
  123. package/lib/table-block/view/operation.d.ts +11 -0
  124. package/lib/table-block/view/operation.d.ts.map +1 -0
  125. package/lib/table-block/view/pointer.d.ts +7 -0
  126. package/lib/table-block/view/pointer.d.ts.map +1 -0
  127. package/lib/table-block/view/types.d.ts +32 -0
  128. package/lib/table-block/view/types.d.ts.map +1 -0
  129. package/lib/table-block/view/utils.d.ts +21 -0
  130. package/lib/table-block/view/utils.d.ts.map +1 -0
  131. package/lib/table-block/view/view.d.ts +22 -0
  132. package/lib/table-block/view/view.d.ts.map +1 -0
  133. package/lib/tsconfig.tsbuildinfo +1 -0
  134. package/package.json +110 -0
  135. package/src/__internal__/components/icon.tsx +38 -0
  136. package/src/__internal__/components/image-input.tsx +182 -0
  137. package/src/__internal__/keep-alive.ts +3 -0
  138. package/src/__internal__/meta.ts +15 -0
  139. package/src/__tests__/setup.ts +6 -0
  140. package/src/code-block/config.ts +54 -0
  141. package/src/code-block/index.ts +12 -0
  142. package/src/code-block/view/components/code-block.tsx +170 -0
  143. package/src/code-block/view/components/copy-button.tsx +96 -0
  144. package/src/code-block/view/components/language-picker.tsx +239 -0
  145. package/src/code-block/view/components/preview-panel.tsx +79 -0
  146. package/src/code-block/view/index.ts +24 -0
  147. package/src/code-block/view/loader.ts +40 -0
  148. package/src/code-block/view/node-view.ts +310 -0
  149. package/src/image-block/config.ts +37 -0
  150. package/src/image-block/index.ts +18 -0
  151. package/src/image-block/remark-plugin.ts +51 -0
  152. package/src/image-block/schema.ts +71 -0
  153. package/src/image-block/view/components/__tests__/image-viewer.onImageLoadError.spec.tsx +42 -0
  154. package/src/image-block/view/components/image-block.tsx +80 -0
  155. package/src/image-block/view/components/image-viewer.tsx +186 -0
  156. package/src/image-block/view/index.ts +111 -0
  157. package/src/image-inline/components/image-inline.tsx +85 -0
  158. package/src/image-inline/config.ts +30 -0
  159. package/src/image-inline/index.ts +12 -0
  160. package/src/image-inline/view.ts +109 -0
  161. package/src/index.ts +1 -0
  162. package/src/link-tooltip/command.ts +19 -0
  163. package/src/link-tooltip/configure.ts +9 -0
  164. package/src/link-tooltip/edit/component.tsx +82 -0
  165. package/src/link-tooltip/edit/edit-configure.ts +29 -0
  166. package/src/link-tooltip/edit/edit-view.ts +165 -0
  167. package/src/link-tooltip/index.ts +19 -0
  168. package/src/link-tooltip/preview/component.tsx +87 -0
  169. package/src/link-tooltip/preview/preview-configure.ts +65 -0
  170. package/src/link-tooltip/preview/preview-view.ts +101 -0
  171. package/src/link-tooltip/slices.ts +69 -0
  172. package/src/link-tooltip/tooltips.ts +22 -0
  173. package/src/link-tooltip/utils.ts +56 -0
  174. package/src/list-item-block/component.tsx +133 -0
  175. package/src/list-item-block/config.ts +39 -0
  176. package/src/list-item-block/index.ts +13 -0
  177. package/src/list-item-block/view.ts +130 -0
  178. package/src/table-block/config.ts +53 -0
  179. package/src/table-block/dnd/calc-drag-over.ts +46 -0
  180. package/src/table-block/dnd/create-drag-handler.ts +99 -0
  181. package/src/table-block/dnd/drag-over-handler.ts +113 -0
  182. package/src/table-block/dnd/prepare-dnd-context.ts +46 -0
  183. package/src/table-block/dnd/preview.ts +58 -0
  184. package/src/table-block/index.ts +9 -0
  185. package/src/table-block/view/component.tsx +219 -0
  186. package/src/table-block/view/drag.ts +121 -0
  187. package/src/table-block/view/index.ts +1 -0
  188. package/src/table-block/view/operation.ts +148 -0
  189. package/src/table-block/view/pointer.ts +165 -0
  190. package/src/table-block/view/types.ts +35 -0
  191. package/src/table-block/view/utils.ts +192 -0
  192. package/src/table-block/view/view.ts +165 -0
@@ -0,0 +1,99 @@
1
+ import type { Ctx } from '@jvs-milkdown/ctx'
2
+
3
+ import { editorViewCtx } from '@jvs-milkdown/core'
4
+
5
+ import type { DragContext, Refs } from '../view/types'
6
+
7
+ import { prepareDndContext } from './prepare-dnd-context'
8
+ import { clearPreview, renderPreview } from './preview'
9
+
10
+ export function createDragRowHandler(refs: Refs, ctx?: Ctx) {
11
+ return (event: DragEvent) => {
12
+ handleDrag(refs, event, ctx, (context) => {
13
+ updateDragInfo('y', event, context, refs)
14
+
15
+ const { preview, content, previewRoot } = context
16
+
17
+ clearPreview(previewRoot)
18
+
19
+ const { hoverIndex } = refs
20
+ const [rowIndex] = hoverIndex.value
21
+ renderPreview('y', preview, previewRoot, content, rowIndex)
22
+ })
23
+ }
24
+ }
25
+
26
+ export function createDragColHandler(refs: Refs, ctx?: Ctx) {
27
+ return (event: DragEvent) => {
28
+ handleDrag(refs, event, ctx, (context) => {
29
+ updateDragInfo('x', event, context, refs)
30
+
31
+ const { preview, content, previewRoot } = context
32
+
33
+ const { hoverIndex } = refs
34
+ const [_, colIndex] = hoverIndex.value
35
+
36
+ clearPreview(previewRoot)
37
+
38
+ renderPreview('x', preview, previewRoot, content, colIndex)
39
+ })
40
+ }
41
+ }
42
+
43
+ function updateDragInfo(
44
+ axis: 'x' | 'y',
45
+ event: DragEvent,
46
+ context: DragContext,
47
+ refs: Refs
48
+ ) {
49
+ const { xHandle, yHandle, colHandle, rowHandle, preview } = context
50
+ xHandle.dataset.displayType = axis === 'y' ? 'indicator' : 'none'
51
+ yHandle.dataset.displayType = axis === 'x' ? 'indicator' : 'none'
52
+
53
+ if (axis === 'y') {
54
+ colHandle.dataset.show = 'false'
55
+ hideButtonGroup(rowHandle)
56
+ } else {
57
+ rowHandle.dataset.show = 'false'
58
+ hideButtonGroup(colHandle)
59
+ }
60
+
61
+ const { hoverIndex, dragInfo } = refs
62
+ const [rowIndex, colIndex] = hoverIndex.value
63
+
64
+ dragInfo.value = {
65
+ startCoords: [event.clientX, event.clientY],
66
+ startIndex: axis === 'y' ? rowIndex : colIndex,
67
+ endIndex: axis === 'y' ? rowIndex : colIndex,
68
+ type: axis === 'y' ? 'row' : 'col',
69
+ }
70
+
71
+ preview.dataset.direction = axis === 'y' ? 'vertical' : 'horizontal'
72
+ }
73
+
74
+ function handleDrag(
75
+ refs: Refs,
76
+ event: DragEvent,
77
+ ctx: Ctx | undefined,
78
+ fn: (context: DragContext) => void
79
+ ) {
80
+ const view = ctx?.get(editorViewCtx)
81
+ if (!view?.editable) return
82
+
83
+ event.stopPropagation()
84
+ if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'
85
+
86
+ const context = prepareDndContext(refs)
87
+
88
+ if (!context) return
89
+
90
+ // This is to avoid a chrome bug:
91
+ // https://stackoverflow.com/questions/14203734/dragend-dragenter-and-dragleave-firing-off-immediately-when-i-drag
92
+ requestAnimationFrame(() => {
93
+ fn(context)
94
+ })
95
+ }
96
+
97
+ function hideButtonGroup(handle: HTMLElement) {
98
+ handle.querySelector('.button-group')?.setAttribute('data-show', 'false')
99
+ }
@@ -0,0 +1,113 @@
1
+ import { computePosition, offset } from '@floating-ui/dom'
2
+ import { throttle } from 'lodash-es'
3
+
4
+ import type { Refs } from '../view/types'
5
+
6
+ import { getRelatedDOM } from '../view/utils'
7
+ import { getDragOverColumn, getDragOverRow } from './calc-drag-over'
8
+ import { prepareDndContext } from './prepare-dnd-context'
9
+
10
+ export function createDragOverHandler(refs: Refs): (e: DragEvent) => void {
11
+ return throttle((e: DragEvent) => {
12
+ const context = prepareDndContext(refs)
13
+ if (!context) return
14
+ const { preview, content, contentRoot, xHandle, yHandle } = context
15
+ const { dragInfo, hoverIndex } = refs
16
+
17
+ if (preview.dataset.show === 'false') return
18
+ const dom = getRelatedDOM(refs.contentWrapperRef, hoverIndex.value!)
19
+ if (!dom) return
20
+ const firstRow = contentRoot.querySelector('tr')
21
+ if (!firstRow) return
22
+ const info = dragInfo.value
23
+ if (!info) return
24
+
25
+ if (!contentRoot.offsetParent) return
26
+
27
+ const wrapperOffsetTop = (contentRoot.offsetParent as HTMLElement).offsetTop
28
+ const wrapperOffsetLeft = (contentRoot.offsetParent as HTMLElement)
29
+ .offsetLeft
30
+
31
+ if (info.type === 'col') {
32
+ const width = dom.col.getBoundingClientRect().width
33
+ const { left, width: fullWidth } = contentRoot.getBoundingClientRect()
34
+ const leftGap = wrapperOffsetLeft - left
35
+ const previewLeft = e.clientX + leftGap - width / 2
36
+
37
+ const [startX] = info.startCoords
38
+ const direction = startX < e.clientX ? 'right' : 'left'
39
+
40
+ preview.style.top = `${wrapperOffsetTop}px`
41
+ const previewLeftOffset =
42
+ previewLeft < left + leftGap - 20
43
+ ? left + leftGap - 20
44
+ : previewLeft > left + fullWidth + leftGap - width + 20
45
+ ? left + fullWidth + leftGap - width + 20
46
+ : previewLeft
47
+
48
+ preview.style.left = `${previewLeftOffset}px`
49
+
50
+ const dragOverColumn = getDragOverColumn(contentRoot, e.clientX)
51
+ if (dragOverColumn) {
52
+ const [col, index] = dragOverColumn
53
+ const yHandleWidth = yHandle.getBoundingClientRect().width
54
+ const contentBoundary = content.getBoundingClientRect()
55
+ info.endIndex = index
56
+
57
+ computePosition(col, yHandle, {
58
+ placement: direction === 'left' ? 'left' : 'right',
59
+ middleware: [offset(direction === 'left' ? -1 * yHandleWidth : 0)],
60
+ })
61
+ .then(({ x }) => {
62
+ yHandle.dataset.show = 'true'
63
+ Object.assign(yHandle.style, {
64
+ height: `${contentBoundary.height}px`,
65
+ left: `${x}px`,
66
+ top: `${wrapperOffsetTop}px`,
67
+ })
68
+ })
69
+ .catch(console.error)
70
+ }
71
+ } else if (info.type === 'row') {
72
+ const height = dom.row.getBoundingClientRect().height
73
+ const { top, height: fullHeight } = contentRoot.getBoundingClientRect()
74
+
75
+ const topGap = wrapperOffsetTop - top
76
+ const previewTop = e.clientY + topGap - height / 2
77
+
78
+ const [_, startY] = info.startCoords
79
+ const direction = startY < e.clientY ? 'down' : 'up'
80
+
81
+ const previewTopOffset =
82
+ previewTop < top + topGap - 20
83
+ ? top + topGap - 20
84
+ : previewTop > top + fullHeight + topGap - height + 20
85
+ ? top + fullHeight + topGap - height + 20
86
+ : previewTop
87
+
88
+ preview.style.top = `${previewTopOffset}px`
89
+ preview.style.left = `${wrapperOffsetLeft}px`
90
+
91
+ const dragOverRow = getDragOverRow(contentRoot, e.clientY)
92
+ if (dragOverRow) {
93
+ const [row, index] = dragOverRow
94
+ const xHandleHeight = xHandle.getBoundingClientRect().height
95
+ const contentBoundary = content.getBoundingClientRect()
96
+ info.endIndex = index
97
+
98
+ computePosition(row, xHandle, {
99
+ placement: direction === 'up' ? 'top' : 'bottom',
100
+ middleware: [offset(direction === 'up' ? -1 * xHandleHeight : 0)],
101
+ })
102
+ .then(({ y }) => {
103
+ xHandle.dataset.show = 'true'
104
+ Object.assign(xHandle.style, {
105
+ width: `${contentBoundary.width}px`,
106
+ top: `${y}px`,
107
+ })
108
+ })
109
+ .catch(console.error)
110
+ }
111
+ }
112
+ }, 20)
113
+ }
@@ -0,0 +1,46 @@
1
+ import type { DragContext, Refs } from '../view/types'
2
+
3
+ export function prepareDndContext(refs: Refs): DragContext | undefined {
4
+ const {
5
+ dragPreviewRef,
6
+ tableWrapperRef,
7
+ contentWrapperRef,
8
+ yLineHandleRef,
9
+ xLineHandleRef,
10
+ colHandleRef,
11
+ rowHandleRef,
12
+ } = refs
13
+
14
+ const preview = dragPreviewRef.value
15
+ if (!preview) return
16
+ const wrapper = tableWrapperRef.value
17
+ if (!wrapper) return
18
+ const content = contentWrapperRef.value
19
+ if (!content) return
20
+ const contentRoot = content.querySelector('tbody')
21
+ if (!contentRoot) return
22
+ const previewRoot = preview.querySelector('tbody')
23
+ if (!previewRoot) return
24
+ const yHandle = yLineHandleRef.value
25
+ if (!yHandle) return
26
+ const xHandle = xLineHandleRef.value
27
+ if (!xHandle) return
28
+ const colHandle = colHandleRef.value
29
+ if (!colHandle) return
30
+ const rowHandle = rowHandleRef.value
31
+ if (!rowHandle) return
32
+
33
+ const context = {
34
+ preview,
35
+ wrapper,
36
+ content,
37
+ contentRoot,
38
+ previewRoot,
39
+ yHandle,
40
+ xHandle,
41
+ colHandle,
42
+ rowHandle,
43
+ }
44
+
45
+ return context
46
+ }
@@ -0,0 +1,58 @@
1
+ export function clearPreview(previewRoot: HTMLElement) {
2
+ while (previewRoot.firstChild) previewRoot.removeChild(previewRoot.firstChild)
3
+ }
4
+
5
+ export function renderPreview(
6
+ axis: 'x' | 'y',
7
+ preview: HTMLElement,
8
+ previewRoot: HTMLElement,
9
+ tableContent: HTMLElement,
10
+ index: number
11
+ ) {
12
+ const { width: tableWidth, height: tableHeight } = tableContent
13
+ .querySelector('tbody')!
14
+ .getBoundingClientRect()
15
+ if (axis === 'y') {
16
+ const rows = tableContent.querySelectorAll('tr')
17
+ const row = rows[index]
18
+ if (!row) return
19
+
20
+ previewRoot.appendChild(row.cloneNode(true))
21
+ const height = row.getBoundingClientRect().height
22
+
23
+ Object.assign(preview.style, {
24
+ width: `${tableWidth}px`,
25
+ height: `${height}px`,
26
+ })
27
+
28
+ preview.dataset.show = 'true'
29
+
30
+ return
31
+ }
32
+
33
+ if (axis === 'x') {
34
+ const rows = tableContent.querySelectorAll('tr')
35
+ let width: number | undefined
36
+
37
+ Array.from(rows).forEach((row) => {
38
+ const col = row.children[index]
39
+ if (!col) return
40
+
41
+ if (width === undefined) width = col.getBoundingClientRect().width
42
+
43
+ const tr = col.parentElement!.cloneNode(false)
44
+ const clone = col.cloneNode(true)
45
+ tr.appendChild(clone)
46
+ previewRoot.appendChild(tr)
47
+ })
48
+
49
+ Object.assign(preview.style, {
50
+ width: `${width}px`,
51
+ height: `${tableHeight}px`,
52
+ })
53
+
54
+ preview.dataset.show = 'true'
55
+
56
+ return
57
+ }
58
+ }
@@ -0,0 +1,9 @@
1
+ import type { MilkdownPlugin } from '@jvs-milkdown/ctx'
2
+
3
+ import { tableBlockConfig } from './config'
4
+ import { tableBlockView } from './view'
5
+
6
+ export * from './view'
7
+ export * from './config'
8
+
9
+ export const tableBlock: MilkdownPlugin[] = [tableBlockConfig, tableBlockView]
@@ -0,0 +1,219 @@
1
+ import type { Ctx } from '@jvs-milkdown/ctx'
2
+ import type { Node } from '@jvs-milkdown/prose/model'
3
+ import type { EditorView } from '@jvs-milkdown/prose/view'
4
+
5
+ import {
6
+ defineComponent,
7
+ ref,
8
+ type VNodeRef,
9
+ h,
10
+ onMounted,
11
+ type Ref,
12
+ } from 'vue'
13
+
14
+ import type { TableBlockConfig } from '../config'
15
+ import type { CellIndex, DragInfo, Refs } from './types'
16
+
17
+ import { Icon } from '../../__internal__/components/icon'
18
+ import { keepAlive } from '../../__internal__/keep-alive'
19
+ import { useDragHandlers } from './drag'
20
+ import { useOperation } from './operation'
21
+ import { usePointerHandlers } from './pointer'
22
+ import { recoveryStateBetweenUpdate } from './utils'
23
+
24
+ keepAlive(h)
25
+
26
+ type TableBlockProps = {
27
+ view: EditorView
28
+ ctx: Ctx
29
+ getPos: () => number | undefined
30
+ config: TableBlockConfig
31
+ onMount: (div: Element) => void
32
+ node: Ref<Node>
33
+ }
34
+
35
+ export const TableBlock = defineComponent<TableBlockProps>({
36
+ props: {
37
+ view: {
38
+ type: Object,
39
+ required: true,
40
+ },
41
+ ctx: {
42
+ type: Object,
43
+ required: true,
44
+ },
45
+ getPos: {
46
+ type: Function,
47
+ required: true,
48
+ },
49
+ config: {
50
+ type: Object,
51
+ required: true,
52
+ },
53
+ onMount: {
54
+ type: Function,
55
+ required: true,
56
+ },
57
+ node: {
58
+ type: Object,
59
+ required: true,
60
+ },
61
+ },
62
+ setup({ view, node, ctx, getPos, config, onMount }) {
63
+ const contentWrapperRef = ref<HTMLElement>()
64
+ const contentWrapperFunctionRef: VNodeRef = (div) => {
65
+ if (div == null) return
66
+ if (div instanceof HTMLElement) {
67
+ contentWrapperRef.value = div
68
+ onMount(div)
69
+ } else {
70
+ contentWrapperRef.value = undefined
71
+ }
72
+ }
73
+ const colHandleRef = ref<HTMLDivElement>()
74
+ const rowHandleRef = ref<HTMLDivElement>()
75
+ const xLineHandleRef = ref<HTMLDivElement>()
76
+ const yLineHandleRef = ref<HTMLDivElement>()
77
+ const tableWrapperRef = ref<HTMLDivElement>()
78
+ const dragPreviewRef = ref<HTMLDivElement>()
79
+ const hoverIndex = ref<CellIndex>([0, 0])
80
+ const lineHoverIndex = ref<CellIndex>([-1, -1])
81
+ const dragInfo = ref<DragInfo>()
82
+
83
+ const refs: Refs = {
84
+ dragPreviewRef,
85
+ tableWrapperRef,
86
+ contentWrapperRef,
87
+ yLineHandleRef,
88
+ xLineHandleRef,
89
+ colHandleRef,
90
+ rowHandleRef,
91
+ hoverIndex,
92
+ lineHoverIndex,
93
+ dragInfo,
94
+ }
95
+
96
+ const { pointerLeave, pointerMove } = usePointerHandlers(refs, view)
97
+ const { dragRow, dragCol } = useDragHandlers(refs, ctx, getPos)
98
+ const {
99
+ onAddRow,
100
+ onAddCol,
101
+ selectCol,
102
+ selectRow,
103
+ deleteSelected,
104
+ onAlign,
105
+ } = useOperation(refs, ctx, getPos)
106
+
107
+ onMounted(() => {
108
+ requestAnimationFrame(() => {
109
+ // This is a wordaround to keep the popover open when click the select col/row button
110
+ if (view.editable) recoveryStateBetweenUpdate(refs, view, node.value)
111
+ })
112
+ })
113
+
114
+ return () => {
115
+ return (
116
+ <div
117
+ onDragstart={(e) => e.preventDefault()}
118
+ onDragover={(e) => e.preventDefault()}
119
+ onDragleave={(e) => e.preventDefault()}
120
+ onPointermove={pointerMove}
121
+ onPointerleave={pointerLeave}
122
+ >
123
+ <div
124
+ data-show="false"
125
+ contenteditable="false"
126
+ draggable="true"
127
+ data-role="col-drag-handle"
128
+ class="handle cell-handle"
129
+ onDragstart={dragCol}
130
+ onClick={selectCol}
131
+ onPointerdown={(e: PointerEvent) => e.stopPropagation()}
132
+ onPointermove={(e: PointerEvent) => e.stopPropagation()}
133
+ ref={colHandleRef}
134
+ >
135
+ <Icon icon={config.renderButton('col_drag_handle')} />
136
+ <div
137
+ data-show="false"
138
+ class="button-group"
139
+ onPointermove={(e: PointerEvent) => e.stopPropagation()}
140
+ >
141
+ <button type="button" onPointerdown={onAlign('left')}>
142
+ <Icon icon={config.renderButton('align_col_left')} />
143
+ </button>
144
+ <button type="button" onPointerdown={onAlign('center')}>
145
+ <Icon icon={config.renderButton('align_col_center')} />
146
+ </button>
147
+ <button type="button" onPointerdown={onAlign('right')}>
148
+ <Icon icon={config.renderButton('align_col_right')} />
149
+ </button>
150
+ <button type="button" onPointerdown={deleteSelected}>
151
+ <Icon icon={config.renderButton('delete_col')} />
152
+ </button>
153
+ </div>
154
+ </div>
155
+ <div
156
+ data-show="false"
157
+ contenteditable="false"
158
+ draggable="true"
159
+ data-role="row-drag-handle"
160
+ class="handle cell-handle"
161
+ onDragstart={dragRow}
162
+ onClick={selectRow}
163
+ onPointerdown={(e: PointerEvent) => e.stopPropagation()}
164
+ onPointermove={(e: PointerEvent) => e.stopPropagation()}
165
+ ref={rowHandleRef}
166
+ >
167
+ <Icon icon={config.renderButton('row_drag_handle')} />
168
+ <div
169
+ data-show="false"
170
+ class="button-group"
171
+ onPointermove={(e: PointerEvent) => e.stopPropagation()}
172
+ >
173
+ <button type="button" onPointerdown={deleteSelected}>
174
+ <Icon icon={config.renderButton('delete_row')} />
175
+ </button>
176
+ </div>
177
+ </div>
178
+ <div class="table-wrapper" ref={tableWrapperRef}>
179
+ <div
180
+ data-show="false"
181
+ class="drag-preview"
182
+ data-direction="vertical"
183
+ ref={dragPreviewRef}
184
+ >
185
+ <table>
186
+ <tbody></tbody>
187
+ </table>
188
+ </div>
189
+ <div
190
+ data-show="false"
191
+ contenteditable="false"
192
+ data-display-type="tool"
193
+ data-role="x-line-drag-handle"
194
+ class="handle line-handle"
195
+ ref={xLineHandleRef}
196
+ >
197
+ <button type="button" onClick={onAddRow} class="add-button">
198
+ <Icon icon={config.renderButton('add_row')} />
199
+ </button>
200
+ </div>
201
+ <div
202
+ data-show="false"
203
+ contenteditable="false"
204
+ data-display-type="tool"
205
+ data-role="y-line-drag-handle"
206
+ class="handle line-handle"
207
+ ref={yLineHandleRef}
208
+ >
209
+ <button type="button" onClick={onAddCol} class="add-button">
210
+ <Icon icon={config.renderButton('add_col')} />
211
+ </button>
212
+ </div>
213
+ <table ref={contentWrapperFunctionRef} class="children"></table>
214
+ </div>
215
+ </div>
216
+ )
217
+ }
218
+ },
219
+ })
@@ -0,0 +1,121 @@
1
+ import type { Ctx } from '@jvs-milkdown/ctx'
2
+
3
+ import { commandsCtx, editorViewCtx } from '@jvs-milkdown/core'
4
+ import {
5
+ moveColCommand,
6
+ moveRowCommand,
7
+ selectColCommand,
8
+ selectRowCommand,
9
+ } from '@jvs-milkdown/preset-gfm'
10
+ import { onMounted, onUnmounted } from 'vue'
11
+
12
+ import type { CellIndex, Refs } from './types'
13
+
14
+ import {
15
+ createDragColHandler,
16
+ createDragRowHandler,
17
+ } from '../dnd/create-drag-handler'
18
+ import { createDragOverHandler } from '../dnd/drag-over-handler'
19
+ import {
20
+ computeColHandlePositionByIndex,
21
+ computeRowHandlePositionByIndex,
22
+ } from './utils'
23
+
24
+ export function useDragHandlers(
25
+ refs: Refs,
26
+ ctx?: Ctx,
27
+ getPos?: () => number | undefined
28
+ ) {
29
+ const { dragPreviewRef, yLineHandleRef, xLineHandleRef, dragInfo } = refs
30
+
31
+ const dragRow = createDragRowHandler(refs, ctx)
32
+ const dragCol = createDragColHandler(refs, ctx)
33
+
34
+ const onDragEnd = () => {
35
+ const preview = dragPreviewRef.value
36
+ if (!preview) return
37
+
38
+ if (preview.dataset.show === 'false') return
39
+
40
+ const previewRoot = preview?.querySelector('tbody')
41
+
42
+ while (previewRoot?.firstChild)
43
+ previewRoot?.removeChild(previewRoot.firstChild)
44
+
45
+ if (preview) preview.dataset.show = 'false'
46
+ }
47
+
48
+ const onDrop = () => {
49
+ const preview = dragPreviewRef.value
50
+ if (!preview) return
51
+ const yHandle = yLineHandleRef.value
52
+ if (!yHandle) return
53
+ const xHandle = xLineHandleRef.value
54
+ if (!xHandle) return
55
+ const info = dragInfo.value
56
+ if (!info) return
57
+ if (!ctx) return
58
+ if (preview.dataset.show === 'false') return
59
+ const colHandle = refs.colHandleRef.value
60
+ if (!colHandle) return
61
+ const rowHandle = refs.rowHandleRef.value
62
+ if (!rowHandle) return
63
+
64
+ yHandle.dataset.show = 'false'
65
+ xHandle.dataset.show = 'false'
66
+
67
+ if (info.startIndex === info.endIndex) return
68
+
69
+ const commands = ctx.get(commandsCtx)
70
+ const payload = {
71
+ from: info.startIndex,
72
+ to: info.endIndex,
73
+ pos: (getPos?.() ?? 0) + 1,
74
+ }
75
+ if (info.type === 'col') {
76
+ commands.call(selectColCommand.key, {
77
+ pos: payload.pos,
78
+ index: info.startIndex,
79
+ })
80
+ commands.call(moveColCommand.key, payload)
81
+ const index: CellIndex = [0, info.endIndex]
82
+ computeColHandlePositionByIndex({
83
+ refs,
84
+ index,
85
+ })
86
+ } else {
87
+ commands.call(selectRowCommand.key, {
88
+ pos: payload.pos,
89
+ index: info.startIndex,
90
+ })
91
+ commands.call(moveRowCommand.key, payload)
92
+ const index: CellIndex = [info.endIndex, 0]
93
+ computeRowHandlePositionByIndex({
94
+ refs,
95
+ index,
96
+ })
97
+ }
98
+
99
+ requestAnimationFrame(() => {
100
+ ctx.get(editorViewCtx).focus()
101
+ })
102
+ }
103
+ const onDragOver = createDragOverHandler(refs)
104
+
105
+ onMounted(() => {
106
+ window.addEventListener('dragover', onDragOver)
107
+ window.addEventListener('dragend', onDragEnd)
108
+ window.addEventListener('drop', onDrop)
109
+ })
110
+
111
+ onUnmounted(() => {
112
+ window.removeEventListener('dragover', onDragOver)
113
+ window.removeEventListener('dragend', onDragEnd)
114
+ window.removeEventListener('drop', onDrop)
115
+ })
116
+
117
+ return {
118
+ dragRow,
119
+ dragCol,
120
+ }
121
+ }
@@ -0,0 +1 @@
1
+ export * from './view'