@kerebron/extension-basic-editor 0.4.27 → 0.4.28

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 (146) hide show
  1. package/esm/ExtensionBaseKeymap.d.ts +7 -0
  2. package/esm/ExtensionBaseKeymap.d.ts.map +1 -0
  3. package/esm/ExtensionBaseKeymap.js +55 -0
  4. package/esm/ExtensionBasicCodeEditor.d.ts +11 -0
  5. package/esm/ExtensionBasicCodeEditor.d.ts.map +1 -0
  6. package/esm/ExtensionBasicCodeEditor.js +61 -0
  7. package/esm/ExtensionBasicEditor.d.ts +49 -0
  8. package/esm/ExtensionBasicEditor.d.ts.map +1 -0
  9. package/esm/ExtensionBasicEditor.js +94 -0
  10. package/esm/ExtensionDropcursor.d.ts +19 -0
  11. package/esm/ExtensionDropcursor.d.ts.map +1 -0
  12. package/esm/ExtensionDropcursor.js +186 -0
  13. package/esm/ExtensionGapcursor.d.ts +32 -0
  14. package/esm/ExtensionGapcursor.d.ts.map +1 -0
  15. package/esm/ExtensionGapcursor.js +249 -0
  16. package/esm/ExtensionHistory.d.ts +14 -0
  17. package/esm/ExtensionHistory.d.ts.map +1 -0
  18. package/esm/ExtensionHistory.js +34 -0
  19. package/esm/ExtensionHtml.d.ts +15 -0
  20. package/esm/ExtensionHtml.d.ts.map +1 -0
  21. package/esm/ExtensionHtml.js +99 -0
  22. package/esm/ExtensionMediaUpload.d.ts +24 -0
  23. package/esm/ExtensionMediaUpload.d.ts.map +1 -0
  24. package/esm/ExtensionMediaUpload.js +167 -0
  25. package/esm/ExtensionSelection.d.ts +11 -0
  26. package/esm/ExtensionSelection.d.ts.map +1 -0
  27. package/esm/ExtensionSelection.js +229 -0
  28. package/esm/ExtensionTextAlign.d.ts +11 -0
  29. package/esm/ExtensionTextAlign.d.ts.map +1 -0
  30. package/esm/ExtensionTextAlign.js +39 -0
  31. package/esm/MarkBookmark.d.ts +8 -0
  32. package/esm/MarkBookmark.d.ts.map +1 -0
  33. package/esm/MarkBookmark.js +16 -0
  34. package/esm/MarkChange.d.ts +8 -0
  35. package/esm/MarkChange.d.ts.map +1 -0
  36. package/esm/MarkChange.js +13 -0
  37. package/esm/MarkCode.d.ts +11 -0
  38. package/esm/MarkCode.d.ts.map +1 -0
  39. package/esm/MarkCode.js +23 -0
  40. package/esm/MarkHighlight.d.ts +8 -0
  41. package/esm/MarkHighlight.d.ts.map +1 -0
  42. package/esm/MarkHighlight.js +35 -0
  43. package/esm/MarkItalic.d.ts +11 -0
  44. package/esm/MarkItalic.d.ts.map +1 -0
  45. package/esm/MarkItalic.js +29 -0
  46. package/esm/MarkLink.d.ts +8 -0
  47. package/esm/MarkLink.d.ts.map +1 -0
  48. package/esm/MarkLink.js +29 -0
  49. package/esm/MarkStrike.d.ts +11 -0
  50. package/esm/MarkStrike.d.ts.map +1 -0
  51. package/esm/MarkStrike.js +26 -0
  52. package/esm/MarkStrong.d.ts +11 -0
  53. package/esm/MarkStrong.d.ts.map +1 -0
  54. package/esm/MarkStrong.js +38 -0
  55. package/esm/MarkSubscript.d.ts +11 -0
  56. package/esm/MarkSubscript.d.ts.map +1 -0
  57. package/esm/MarkSubscript.js +30 -0
  58. package/esm/MarkSuperscript.d.ts +11 -0
  59. package/esm/MarkSuperscript.d.ts.map +1 -0
  60. package/esm/MarkSuperscript.js +30 -0
  61. package/esm/MarkTextColor.d.ts +8 -0
  62. package/esm/MarkTextColor.d.ts.map +1 -0
  63. package/esm/MarkTextColor.js +27 -0
  64. package/esm/MarkUnderline.d.ts +11 -0
  65. package/esm/MarkUnderline.d.ts.map +1 -0
  66. package/esm/MarkUnderline.js +33 -0
  67. package/esm/NodeAside.d.ts +8 -0
  68. package/esm/NodeAside.d.ts.map +1 -0
  69. package/esm/NodeAside.js +16 -0
  70. package/esm/NodeBlockquote.d.ts +13 -0
  71. package/esm/NodeBlockquote.d.ts.map +1 -0
  72. package/esm/NodeBlockquote.js +34 -0
  73. package/esm/NodeBookmark.d.ts +8 -0
  74. package/esm/NodeBookmark.d.ts.map +1 -0
  75. package/esm/NodeBookmark.js +19 -0
  76. package/esm/NodeBulletList.d.ts +13 -0
  77. package/esm/NodeBulletList.d.ts.map +1 -0
  78. package/esm/NodeBulletList.js +34 -0
  79. package/esm/NodeCodeBlock.d.ts +9 -0
  80. package/esm/NodeCodeBlock.d.ts.map +1 -0
  81. package/esm/NodeCodeBlock.js +50 -0
  82. package/esm/NodeDefinitionDesc.d.ts +8 -0
  83. package/esm/NodeDefinitionDesc.d.ts.map +1 -0
  84. package/esm/NodeDefinitionDesc.js +16 -0
  85. package/esm/NodeDefinitionList.d.ts +13 -0
  86. package/esm/NodeDefinitionList.d.ts.map +1 -0
  87. package/esm/NodeDefinitionList.js +28 -0
  88. package/esm/NodeDefinitionTerm.d.ts +8 -0
  89. package/esm/NodeDefinitionTerm.d.ts.map +1 -0
  90. package/esm/NodeDefinitionTerm.js +16 -0
  91. package/esm/NodeDocument.d.ts +7 -0
  92. package/esm/NodeDocument.d.ts.map +1 -0
  93. package/esm/NodeDocument.js +19 -0
  94. package/esm/NodeDocumentCode.d.ts +7 -0
  95. package/esm/NodeDocumentCode.d.ts.map +1 -0
  96. package/esm/NodeDocumentCode.js +29 -0
  97. package/esm/NodeFrontmatter.d.ts +8 -0
  98. package/esm/NodeFrontmatter.d.ts.map +1 -0
  99. package/esm/NodeFrontmatter.js +16 -0
  100. package/esm/NodeHardBreak.d.ts +14 -0
  101. package/esm/NodeHardBreak.d.ts.map +1 -0
  102. package/esm/NodeHardBreak.js +67 -0
  103. package/esm/NodeHeading.d.ts +13 -0
  104. package/esm/NodeHeading.d.ts.map +1 -0
  105. package/esm/NodeHeading.js +49 -0
  106. package/esm/NodeHorizontalRule.d.ts +11 -0
  107. package/esm/NodeHorizontalRule.d.ts.map +1 -0
  108. package/esm/NodeHorizontalRule.js +29 -0
  109. package/esm/NodeImage.d.ts +8 -0
  110. package/esm/NodeImage.d.ts.map +1 -0
  111. package/esm/NodeImage.js +33 -0
  112. package/esm/NodeInlineShortCode.d.ts +11 -0
  113. package/esm/NodeInlineShortCode.d.ts.map +1 -0
  114. package/esm/NodeInlineShortCode.js +39 -0
  115. package/esm/NodeListItem.d.ts +14 -0
  116. package/esm/NodeListItem.d.ts.map +1 -0
  117. package/esm/NodeListItem.js +201 -0
  118. package/esm/NodeMath.d.ts +8 -0
  119. package/esm/NodeMath.d.ts.map +1 -0
  120. package/esm/NodeMath.js +99 -0
  121. package/esm/NodeOrderedList.d.ts +23 -0
  122. package/esm/NodeOrderedList.d.ts.map +1 -0
  123. package/esm/NodeOrderedList.js +52 -0
  124. package/esm/NodeParagraph.d.ts +11 -0
  125. package/esm/NodeParagraph.d.ts.map +1 -0
  126. package/esm/NodeParagraph.js +44 -0
  127. package/esm/NodeTaskItem.d.ts +24 -0
  128. package/esm/NodeTaskItem.d.ts.map +1 -0
  129. package/esm/NodeTaskItem.js +146 -0
  130. package/esm/NodeTaskList.d.ts +11 -0
  131. package/esm/NodeTaskList.d.ts.map +1 -0
  132. package/esm/NodeTaskList.js +25 -0
  133. package/esm/NodeText.d.ts +7 -0
  134. package/esm/NodeText.d.ts.map +1 -0
  135. package/esm/NodeText.js +9 -0
  136. package/esm/NodeVideo.d.ts +8 -0
  137. package/esm/NodeVideo.d.ts.map +1 -0
  138. package/esm/NodeVideo.js +45 -0
  139. package/esm/package.json +3 -0
  140. package/esm/remote-selection/ExtensionRemoteSelection.d.ts +24 -0
  141. package/esm/remote-selection/ExtensionRemoteSelection.d.ts.map +1 -0
  142. package/esm/remote-selection/ExtensionRemoteSelection.js +22 -0
  143. package/esm/remote-selection/remoteSelectionPlugin.d.ts +25 -0
  144. package/esm/remote-selection/remoteSelectionPlugin.d.ts.map +1 -0
  145. package/esm/remote-selection/remoteSelectionPlugin.js +96 -0
  146. package/package.json +2 -3
@@ -0,0 +1,52 @@
1
+ import { Node } from '@kerebron/editor';
2
+ import { getHtmlAttributes, setHtmlAttributes, } from '@kerebron/editor/utilities';
3
+ import { wrappingInputRule, } from '@kerebron/editor/plugins/input-rules';
4
+ export class NodeOrderedList extends Node {
5
+ name = 'ordered_list';
6
+ requires = ['doc'];
7
+ attributes = {
8
+ type: {
9
+ default: '1',
10
+ fromDom(element) {
11
+ return element.hasAttribute('type')
12
+ ? element.getAttribute('type')
13
+ : '1';
14
+ },
15
+ },
16
+ start: {
17
+ default: 1,
18
+ fromDom(element) {
19
+ return element.hasAttribute('start')
20
+ ? +element.getAttribute('start')
21
+ : 1;
22
+ },
23
+ },
24
+ };
25
+ getNodeSpec() {
26
+ return {
27
+ group: 'block',
28
+ content: 'list_item+',
29
+ parseDOM: [
30
+ { tag: 'ol', getAttrs: (element) => setHtmlAttributes(this, element) },
31
+ ],
32
+ toDOM: (node) => ['ol', getHtmlAttributes(this, node), 0],
33
+ };
34
+ }
35
+ getInputRules(type) {
36
+ return [
37
+ /// Given a list node type, returns an input rule that turns a number
38
+ /// followed by a dot at the start of a textblock into an ordered list.
39
+ wrappingInputRule(/^(\d+)\.\s$/, type, (match) => ({ order: +match[1] }), (match, node) => node.childCount + node.attrs.order == +match[1]),
40
+ ];
41
+ }
42
+ getCommandFactories(editor, type) {
43
+ return {
44
+ 'toggleOrderedList': () => editor.commandFactories.wrapInList(type),
45
+ };
46
+ }
47
+ getKeyboardShortcuts() {
48
+ return {
49
+ 'Shift-Ctrl-7': 'toggleOrderedList',
50
+ };
51
+ }
52
+ }
@@ -0,0 +1,11 @@
1
+ import { type NodeSpec, type NodeType } from 'prosemirror-model';
2
+ import { type CoreEditor, Node } from '@kerebron/editor';
3
+ import { type CommandFactories, type CommandShortcuts } from '@kerebron/editor/commands';
4
+ export declare class NodeParagraph extends Node {
5
+ name: string;
6
+ requires: string[];
7
+ getNodeSpec(): NodeSpec;
8
+ getCommandFactories(editor: CoreEditor, type: NodeType): Partial<CommandFactories>;
9
+ getKeyboardShortcuts(): Partial<CommandShortcuts>;
10
+ }
11
+ //# sourceMappingURL=NodeParagraph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeParagraph.d.ts","sourceRoot":"","sources":["../src/NodeParagraph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAInC,qBAAa,aAAc,SAAQ,IAAI;IAC5B,IAAI,SAAe;IAC5B,QAAQ,WAAW;IAEV,WAAW,IAAI,QAAQ;IAgCvB,mBAAmB,CAC1B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,gBAAgB,CAAC;IAMnB,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAK3D"}
@@ -0,0 +1,44 @@
1
+ import { Node } from '@kerebron/editor';
2
+ export class NodeParagraph extends Node {
3
+ name = 'paragraph';
4
+ requires = ['doc'];
5
+ getNodeSpec() {
6
+ return {
7
+ content: 'inline*',
8
+ group: 'block',
9
+ attrs: {
10
+ textAlign: { default: null },
11
+ },
12
+ parseDOM: [
13
+ {
14
+ tag: 'p',
15
+ getAttrs(dom) {
16
+ const element = dom;
17
+ const style = element.style.textAlign;
18
+ if (style === 'center' || style === 'right' || style === 'justify') {
19
+ return { textAlign: style };
20
+ }
21
+ return { textAlign: null };
22
+ },
23
+ },
24
+ ],
25
+ toDOM(node) {
26
+ const align = node.attrs.textAlign;
27
+ if (align && align !== 'left') {
28
+ return ['p', { style: `text-align: ${align}` }, 0];
29
+ }
30
+ return ['p', 0];
31
+ },
32
+ };
33
+ }
34
+ getCommandFactories(editor, type) {
35
+ return {
36
+ 'setParagraph': () => editor.commandFactories.setBlockType(type),
37
+ };
38
+ }
39
+ getKeyboardShortcuts() {
40
+ return {
41
+ 'Shift-Ctrl-0': 'setParagraph',
42
+ };
43
+ }
44
+ }
@@ -0,0 +1,24 @@
1
+ import { Node as PmNode, NodeSpec, type NodeType } from 'prosemirror-model';
2
+ import { type CoreEditor, Node } from '@kerebron/editor';
3
+ import { type CommandFactories, type CommandShortcuts } from '@kerebron/editor/commands';
4
+ import { NodeViewConstructor } from '@kerebron/editor/DummyEditorView';
5
+ /**
6
+ * Matches a task item to a - [ ] on input.
7
+ */
8
+ export declare const inputRegex: RegExp;
9
+ export interface TaskItemOptions {
10
+ onReadOnlyChecked?: (node: PmNode, checked: boolean) => boolean;
11
+ nested: boolean;
12
+ }
13
+ export declare class NodeTaskItem extends Node {
14
+ protected config: Partial<TaskItemOptions>;
15
+ name: string;
16
+ requires: string[];
17
+ constructor(config?: Partial<TaskItemOptions>);
18
+ getNodeSpec(): NodeSpec;
19
+ getCommandFactories(editor: CoreEditor, type: NodeType): Partial<CommandFactories>;
20
+ getNodeView(editor: CoreEditor): NodeViewConstructor;
21
+ getKeyboardShortcuts(): Partial<CommandShortcuts>;
22
+ getInputRules(type: NodeType): any[];
23
+ }
24
+ //# sourceMappingURL=NodeTaskItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeTaskItem.d.ts","sourceRoot":"","sources":["../src/NodeTaskItem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,KAAK,UAAU,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAOnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAIvE;;GAEG;AACH,eAAO,MAAM,UAAU,QAA2B,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC;IAChE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,YAAa,SAAQ,IAAI;cAIE,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC;IAH7D,IAAI,SAAe;IAC5B,QAAQ,WAAW;gBAEmB,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM;IAIlE,WAAW,IAAI,QAAQ;IAyCvB,mBAAmB,CAC1B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,gBAAgB,CAAC;IAQnB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,mBAAmB;IAoFpD,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAQjD,aAAa,CAAC,IAAI,EAAE,QAAQ;CAWtC"}
@@ -0,0 +1,146 @@
1
+ import { Node } from '@kerebron/editor';
2
+ import { wrappingInputRule } from '@kerebron/editor/plugins/input-rules';
3
+ import { liftListItem, sinkListItem, splitListItem, } from './NodeListItem.js';
4
+ /**
5
+ * Matches a task item to a - [ ] on input.
6
+ */
7
+ export const inputRegex = /^\s*(\[([( |x])?\])\s$/;
8
+ export class NodeTaskItem extends Node {
9
+ config;
10
+ name = 'task_item';
11
+ requires = ['doc'];
12
+ constructor(config = {}) {
13
+ super(config);
14
+ this.config = config;
15
+ }
16
+ getNodeSpec() {
17
+ return {
18
+ attrs: {
19
+ checked: {
20
+ default: false,
21
+ },
22
+ },
23
+ content: this.config.nested ? 'paragraph block*' : 'paragraph+',
24
+ parseDOM: [{
25
+ tag: 'li[data-checked]',
26
+ getAttrs(node) {
27
+ return {
28
+ checked: node.getAttribute('data-checked') === 'true',
29
+ };
30
+ },
31
+ }],
32
+ defining: true,
33
+ toDOM(node) {
34
+ return [
35
+ 'li',
36
+ {
37
+ 'data-type': this.name,
38
+ 'data-checked': node.attrs.checked,
39
+ },
40
+ [
41
+ 'label',
42
+ [
43
+ 'input',
44
+ {
45
+ type: 'checkbox',
46
+ checked: node.attrs.checked ? 'checked' : null,
47
+ },
48
+ ],
49
+ ['span'],
50
+ ],
51
+ ['div', 0],
52
+ ];
53
+ },
54
+ };
55
+ }
56
+ getCommandFactories(editor, type) {
57
+ return {
58
+ 'splitListItem': () => splitListItem(type),
59
+ 'liftListItem': () => liftListItem(type),
60
+ 'sinkListItem': () => sinkListItem(type),
61
+ };
62
+ }
63
+ getNodeView(editor) {
64
+ return (node, view, getPos) => {
65
+ const listItem = document.createElement('li');
66
+ const checkboxWrapper = document.createElement('label');
67
+ const checkboxStyler = document.createElement('span');
68
+ const checkbox = document.createElement('input');
69
+ const content = document.createElement('div');
70
+ // Style for inline checkbox and text
71
+ listItem.style.display = 'flex';
72
+ listItem.style.alignItems = 'flex-start';
73
+ listItem.style.gap = '0.5em';
74
+ checkboxWrapper.style.flexShrink = '0';
75
+ checkboxWrapper.style.marginTop = '0.25em';
76
+ content.style.flex = '1';
77
+ checkboxWrapper.contentEditable = 'false';
78
+ checkbox.type = 'checkbox';
79
+ checkbox.addEventListener('mousedown', (event) => event.preventDefault());
80
+ checkbox.addEventListener('change', (event) => {
81
+ const isEditable = true; // TODO editor.isEditable
82
+ // if the editor isn’t editable and we don't have a handler for
83
+ // readonly checks we have to undo the latest change
84
+ if (!isEditable && !this.config.onReadOnlyChecked) {
85
+ checkbox.checked = !checkbox.checked;
86
+ return;
87
+ }
88
+ const { checked } = event.target;
89
+ if (isEditable && typeof getPos === 'function') {
90
+ editor
91
+ .chain()
92
+ .focus(undefined, { scrollIntoView: false })
93
+ .command(({ tr }) => {
94
+ const position = getPos();
95
+ if (typeof position !== 'number') {
96
+ return false;
97
+ }
98
+ const currentNode = tr.doc.nodeAt(position);
99
+ tr.setNodeMarkup(position, undefined, {
100
+ ...currentNode?.attrs,
101
+ checked,
102
+ });
103
+ return true;
104
+ })
105
+ .run();
106
+ }
107
+ if (!isEditable && this.config.onReadOnlyChecked) {
108
+ // Reset state if onReadOnlyChecked returns false
109
+ if (!this.config.onReadOnlyChecked(node, checked)) {
110
+ checkbox.checked = !checkbox.checked;
111
+ }
112
+ }
113
+ });
114
+ listItem.dataset.checked = node.attrs.checked;
115
+ checkbox.checked = node.attrs.checked;
116
+ checkboxWrapper.append(checkbox, checkboxStyler);
117
+ listItem.append(checkboxWrapper, content);
118
+ return {
119
+ dom: listItem,
120
+ contentDOM: content,
121
+ update: (updatedNode) => {
122
+ if (updatedNode.type.name !== this.type) {
123
+ return false;
124
+ }
125
+ listItem.dataset.checked = updatedNode.attrs.checked;
126
+ checkbox.checked = updatedNode.attrs.checked;
127
+ return true;
128
+ },
129
+ };
130
+ };
131
+ }
132
+ getKeyboardShortcuts() {
133
+ return {
134
+ 'Enter': 'splitListItem',
135
+ 'Tab': 'sinkListItem',
136
+ 'Shift-Tab': 'liftListItem',
137
+ };
138
+ }
139
+ getInputRules(type) {
140
+ return [
141
+ wrappingInputRule(inputRegex, type, (match) => ({
142
+ checked: match[match.length - 1] === 'x',
143
+ })),
144
+ ];
145
+ }
146
+ }
@@ -0,0 +1,11 @@
1
+ import type { NodeSpec, NodeType } from 'prosemirror-model';
2
+ import { type CoreEditor, Node } from '@kerebron/editor';
3
+ import { type CommandFactories, type CommandShortcuts } from '@kerebron/editor/commands';
4
+ export declare class NodeTaskList extends Node {
5
+ name: string;
6
+ requires: string[];
7
+ getNodeSpec(): NodeSpec;
8
+ getCommandFactories(editor: CoreEditor, type: NodeType): Partial<CommandFactories>;
9
+ getKeyboardShortcuts(): Partial<CommandShortcuts>;
10
+ }
11
+ //# sourceMappingURL=NodeTaskList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeTaskList.d.ts","sourceRoot":"","sources":["../src/NodeTaskList.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EAAE,KAAK,UAAU,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAEnC,qBAAa,YAAa,SAAQ,IAAI;IAC3B,IAAI,SAAe;IAC5B,QAAQ,WAAW;IAEV,WAAW,IAAI,QAAQ;IAWvB,mBAAmB,CAC1B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,gBAAgB,CAAC;IAMnB,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAK3D"}
@@ -0,0 +1,25 @@
1
+ import { Node } from '@kerebron/editor';
2
+ export class NodeTaskList extends Node {
3
+ name = 'task_list';
4
+ requires = ['doc'];
5
+ getNodeSpec() {
6
+ return {
7
+ content: 'task_item+',
8
+ group: 'block',
9
+ parseDOM: [{ tag: `ul[data-type="${this.name}"]` }],
10
+ toDOM() {
11
+ return ['ul', { 'data-type': this.name }, 0];
12
+ },
13
+ };
14
+ }
15
+ getCommandFactories(editor, type) {
16
+ return {
17
+ 'toggleTaskList': () => editor.commandFactories.wrapInList(type),
18
+ };
19
+ }
20
+ getKeyboardShortcuts() {
21
+ return {
22
+ 'Shift-Ctrl-9': 'toggleTaskList',
23
+ };
24
+ }
25
+ }
@@ -0,0 +1,7 @@
1
+ import { NodeSpec } from 'prosemirror-model';
2
+ import { Node } from '@kerebron/editor';
3
+ export declare class NodeText extends Node {
4
+ name: string;
5
+ getNodeSpec(): NodeSpec;
6
+ }
7
+ //# sourceMappingURL=NodeText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeText.d.ts","sourceRoot":"","sources":["../src/NodeText.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,qBAAa,QAAS,SAAQ,IAAI;IACvB,IAAI,SAAU;IAEd,WAAW,IAAI,QAAQ;CAKjC"}
@@ -0,0 +1,9 @@
1
+ import { Node } from '@kerebron/editor';
2
+ export class NodeText extends Node {
3
+ name = 'text';
4
+ getNodeSpec() {
5
+ return {
6
+ group: 'inline',
7
+ };
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ import { type NodeSpec } from 'prosemirror-model';
2
+ import { Node } from '@kerebron/editor';
3
+ export declare class NodeVideo extends Node {
4
+ name: string;
5
+ requires: string[];
6
+ getNodeSpec(): NodeSpec;
7
+ }
8
+ //# sourceMappingURL=NodeVideo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeVideo.d.ts","sourceRoot":"","sources":["../src/NodeVideo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,qBAAa,SAAU,SAAQ,IAAI;IACxB,IAAI,SAAW;IACxB,QAAQ,WAAW;IAEV,WAAW,IAAI,QAAQ;CAoCjC"}
@@ -0,0 +1,45 @@
1
+ import { Node } from '@kerebron/editor';
2
+ export class NodeVideo extends Node {
3
+ name = 'video';
4
+ requires = ['doc'];
5
+ getNodeSpec() {
6
+ return {
7
+ attrs: {
8
+ src: {},
9
+ title: { default: null },
10
+ controls: { default: true },
11
+ width: { default: null },
12
+ height: { default: null },
13
+ },
14
+ group: 'block',
15
+ draggable: true,
16
+ parseDOM: [
17
+ {
18
+ tag: 'video[src]',
19
+ getAttrs(dom) {
20
+ return {
21
+ src: dom.getAttribute('src'),
22
+ title: dom.getAttribute('title'),
23
+ controls: dom.hasAttribute('controls'),
24
+ width: dom.getAttribute('width'),
25
+ height: dom.getAttribute('height'),
26
+ };
27
+ },
28
+ },
29
+ ],
30
+ toDOM(node) {
31
+ const { src, title, controls, width, height } = node.attrs;
32
+ const attrs = { src };
33
+ if (title)
34
+ attrs.title = title;
35
+ if (controls)
36
+ attrs.controls = ''; // Boolean attribute - just needs to be present
37
+ if (width)
38
+ attrs.width = width;
39
+ if (height)
40
+ attrs.height = height;
41
+ return ['video', attrs];
42
+ },
43
+ };
44
+ }
45
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,24 @@
1
+ import { Plugin } from 'prosemirror-state';
2
+ import { Extension } from '@kerebron/editor';
3
+ type Color = string;
4
+ export interface SelectionState {
5
+ clientId: number;
6
+ user: {
7
+ name: string;
8
+ color: Color;
9
+ colorLight: Color;
10
+ };
11
+ cursor?: {
12
+ anchor: number;
13
+ head: number;
14
+ };
15
+ }
16
+ export { remoteSelectionPluginKey } from './remoteSelectionPlugin.js';
17
+ export declare class ExtensionRemoteSelection extends Extension {
18
+ name: string;
19
+ private remoteStates;
20
+ getProseMirrorPlugins(): Plugin[];
21
+ getRemoteStates(): SelectionState[];
22
+ setRemoteStates(states: SelectionState[]): void;
23
+ }
24
+ //# sourceMappingURL=ExtensionRemoteSelection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExtensionRemoteSelection.d.ts","sourceRoot":"","sources":["../../src/remote-selection/ExtensionRemoteSelection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAmB,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI9D,KAAK,KAAK,GAAG,MAAM,CAAC;AAEpB,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,KAAK,CAAC;QACb,UAAU,EAAE,KAAK,CAAC;KACnB,CAAC;IACF,MAAM,CAAC,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,qBAAa,wBAAyB,SAAQ,SAAS;IAC5C,IAAI,SAAsB;IAEnC,OAAO,CAAC,YAAY,CAAwB;IAEnC,qBAAqB,IAAI,MAAM,EAAE;IAM1C,eAAe,IAAI,cAAc,EAAE;IAInC,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE;CAOzC"}
@@ -0,0 +1,22 @@
1
+ import { Extension } from '@kerebron/editor';
2
+ import { remoteSelectionPlugin } from './remoteSelectionPlugin.js';
3
+ export { remoteSelectionPluginKey } from './remoteSelectionPlugin.js';
4
+ export class ExtensionRemoteSelection extends Extension {
5
+ name = 'remote-selection';
6
+ remoteStates = [];
7
+ getProseMirrorPlugins() {
8
+ return [
9
+ remoteSelectionPlugin(this, this.editor),
10
+ ];
11
+ }
12
+ getRemoteStates() {
13
+ return this.remoteStates;
14
+ }
15
+ setRemoteStates(states) {
16
+ this.remoteStates = states;
17
+ const event = new CustomEvent('remoteSelectionChange', {
18
+ detail: {},
19
+ });
20
+ this.editor.dispatchEvent(event);
21
+ }
22
+ }
@@ -0,0 +1,25 @@
1
+ import { Plugin, PluginKey } from 'prosemirror-state';
2
+ import { type DecorationAttrs } from 'prosemirror-view';
3
+ import type { CoreEditor } from '@kerebron/editor';
4
+ import type { ExtensionRemoteSelection } from './ExtensionRemoteSelection.js';
5
+ export declare const remoteSelectionPluginKey: PluginKey<any>;
6
+ /**
7
+ * Default generator for a cursor element
8
+ */
9
+ export declare const defaultCursorBuilder: (user: any) => HTMLElement;
10
+ /**
11
+ * Default generator for the selection attributes
12
+ */
13
+ export declare const defaultSelectionBuilder: (user: any) => DecorationAttrs;
14
+ export declare const createDecorations: (state: any, extension: ExtensionRemoteSelection, createCursor: (user: {
15
+ name: string;
16
+ color: string;
17
+ }, clientId: number) => Element, createSelection: (user: {
18
+ name: string;
19
+ color: string;
20
+ }, clientId: number) => DecorationAttrs) => any;
21
+ export declare const remoteSelectionPlugin: (extension: ExtensionRemoteSelection, editor: CoreEditor, { cursorBuilder, selectionBuilder, }?: {
22
+ cursorBuilder?: (user: any, clientId: number) => HTMLElement;
23
+ selectionBuilder?: (user: any, clientId: number) => DecorationAttrs;
24
+ }) => Plugin<any>;
25
+ //# sourceMappingURL=remoteSelectionPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remoteSelectionPlugin.d.ts","sourceRoot":"","sources":["../../src/remote-selection/remoteSelectionPlugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAE9E,eAAO,MAAM,wBAAwB,gBAAoC,CAAC;AAE1E;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,GAAG,KAAG,WAahD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,MAAM,GAAG,KAAG,eAKnD,CAAC;AAIF,eAAO,MAAM,iBAAiB,GAC5B,OAAO,GAAG,EACV,WAAW,wBAAwB,EACnC,cAAc,CACZ,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EACrC,QAAQ,EAAE,MAAM,KACb,OAAO,EACZ,iBAAiB,CACf,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EACrC,QAAQ,EAAE,MAAM,KACb,eAAe,KACnB,GAwDF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,WAAW,wBAAwB,EACnC,QAAQ,UAAU,EAClB,uCAGG;IACD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,KAAK,WAAW,CAAC;IAC7D,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,KAAK,eAAe,CAAC;CAChE,gBAsCP,CAAC"}
@@ -0,0 +1,96 @@
1
+ import { Decoration, DecorationSet } from 'prosemirror-view';
2
+ import { Plugin, PluginKey } from 'prosemirror-state';
3
+ export const remoteSelectionPluginKey = new PluginKey('remote-selection');
4
+ /**
5
+ * Default generator for a cursor element
6
+ */
7
+ export const defaultCursorBuilder = (user) => {
8
+ const cursor = document.createElement('span');
9
+ cursor.classList.add('kb-yjs__cursor');
10
+ cursor.setAttribute('style', `border-color: ${user.color};`);
11
+ const userDiv = document.createElement('div');
12
+ userDiv.setAttribute('style', `background-color: ${user.color}`);
13
+ userDiv.insertBefore(document.createTextNode(user.name), null);
14
+ const nonbreakingSpace1 = document.createTextNode('\u2060');
15
+ const nonbreakingSpace2 = document.createTextNode('\u2060');
16
+ cursor.insertBefore(nonbreakingSpace1, null);
17
+ cursor.insertBefore(userDiv, null);
18
+ cursor.insertBefore(nonbreakingSpace2, null);
19
+ return cursor;
20
+ };
21
+ /**
22
+ * Default generator for the selection attributes
23
+ */
24
+ export const defaultSelectionBuilder = (user) => {
25
+ return {
26
+ style: `background-color: ${user.color}70`,
27
+ class: 'kb-yjs__selection',
28
+ };
29
+ };
30
+ const rxValidColor = /^#[0-9a-fA-F]{6}$/;
31
+ export const createDecorations = (state, extension, createCursor, createSelection) => {
32
+ const decorations = [];
33
+ const remoteStates = extension.getRemoteStates();
34
+ if (remoteStates.length === 0) {
35
+ return DecorationSet.create(state.doc, []);
36
+ }
37
+ for (const remoteState of remoteStates) {
38
+ if (remoteState.cursor != null) {
39
+ const user = remoteState.user || {};
40
+ if (user.color == null) {
41
+ user.color = '#ffa500';
42
+ }
43
+ else if (!rxValidColor.test(user.color)) {
44
+ // We only support 6-digit RGB colors in y-prosemirror
45
+ console.warn('A user uses an unsupported color format', user);
46
+ }
47
+ if (user.name == null) {
48
+ user.name = `User: ${remoteState.clientId}`;
49
+ }
50
+ const cursor = remoteState.cursor;
51
+ let anchor = cursor.anchor || null;
52
+ let head = cursor.head || null;
53
+ if (anchor !== null && head !== null) {
54
+ const maxsize = Math.max(state.doc.content.size - 1, 0);
55
+ anchor = Math.min(anchor, maxsize);
56
+ head = Math.min(head, maxsize);
57
+ decorations.push(Decoration.widget(head, () => createCursor(user, remoteState.clientId), {
58
+ key: remoteState.clientId + '',
59
+ side: 10,
60
+ }));
61
+ const from = Math.min(anchor, head);
62
+ const to = Math.max(anchor, head);
63
+ decorations.push(Decoration.inline(from, to, createSelection(user, remoteState.clientId), {
64
+ inclusiveEnd: true,
65
+ inclusiveStart: false,
66
+ }));
67
+ }
68
+ }
69
+ }
70
+ return DecorationSet.create(state.doc, decorations);
71
+ };
72
+ export const remoteSelectionPlugin = (extension, editor, { cursorBuilder = defaultCursorBuilder, selectionBuilder = defaultSelectionBuilder, } = {}) => {
73
+ return new Plugin({
74
+ key: remoteSelectionPluginKey,
75
+ state: {
76
+ init(_, state) {
77
+ return createDecorations(state, extension, cursorBuilder, selectionBuilder);
78
+ },
79
+ apply(tr, prevState, _oldState, newState) {
80
+ const remoteCursorState = tr.getMeta(remoteSelectionPluginKey);
81
+ // TODO validate: isChangeOrigin
82
+ // const state = remoteSelectionPluginKey.getState(newState);
83
+ if ((remoteCursorState?.isChangeOrigin) ||
84
+ (remoteCursorState?.remotePositionUpdated)) {
85
+ return createDecorations(newState, extension, cursorBuilder, selectionBuilder);
86
+ }
87
+ return prevState.map(tr.mapping, tr.doc);
88
+ },
89
+ },
90
+ props: {
91
+ decorations: (state) => {
92
+ return remoteSelectionPluginKey.getState(state);
93
+ },
94
+ },
95
+ });
96
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerebron/extension-basic-editor",
3
- "version": "0.4.27",
3
+ "version": "0.4.28",
4
4
  "license": "MIT",
5
5
  "module": "./esm/ExtensionBasicEditor.js",
6
6
  "exports": {
@@ -111,9 +111,8 @@
111
111
  }
112
112
  },
113
113
  "scripts": {},
114
- "files": [],
115
114
  "dependencies": {
116
- "@kerebron/editor": "0.4.27",
115
+ "@kerebron/editor": "0.4.28",
117
116
  "prosemirror-history": "1.4.1",
118
117
  "prosemirror-model": "1.25.3",
119
118
  "prosemirror-state": "1.4.3",