-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add popup plugin #3128
Draft
john-traas
wants to merge
9
commits into
main
Choose a base branch
from
add-popup-plugin
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Add popup plugin #3128
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
7506397
feat(text editor mentions): add new custom node spec for mentions
john-traas 65f7ffd
feat(text editor mentions): add basic item picker for mention items
john-traas 53a7dcf
feat(text editor mentions): render picker + add picker event listener…
john-traas 2a92cf8
feat(text editor mentions): add full stop key handler
john-traas 572d87c
feat(text editor mentions): add trigger plugin
john-traas e7b4f2e
feat(text editor mentions): add mention node to schema and trigger pl…
john-traas f7b03b1
feat(text editor mentions): add mention parser
john-traas b94a1a8
feat(text editor mentions): use mention parser in prosemirror adapter
john-traas 0c32b7c
feat(text editor mentions): serialize mention nodes in markdown
john-traas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
36 changes: 36 additions & 0 deletions
36
src/components/text-editor/prosemirror-adapter/mentions/node-schema-extender.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { NodeSpec } from 'prosemirror-model'; | ||
|
||
export const mention: NodeSpec = { | ||
inline: true, | ||
group: 'inline', | ||
selectable: true, | ||
atom: true, | ||
|
||
attrs: { | ||
type: {}, | ||
id: {}, | ||
name: {}, | ||
}, | ||
|
||
toDOM: (node) => [ | ||
'span', | ||
{ | ||
class: 'mention', | ||
style: 'color: blue', | ||
'data-mention-name': node.attrs.name, | ||
'data-mention-type': node.attrs.type, | ||
'data-mention-id': node.attrs.id, | ||
}, | ||
'@' + node.attrs.name, | ||
], | ||
parseDOM: [ | ||
{ | ||
tag: 'span[data-mention-type][data-mention-id][data-mention-name]', | ||
getAttrs: (dom) => ({ | ||
name: dom.getAttribute('data-mention-name'), | ||
type: dom.getAttribute('data-mention-type'), | ||
id: dom.getAttribute('data-mention-id'), | ||
}), | ||
}, | ||
], | ||
}; |
65 changes: 65 additions & 0 deletions
65
src/components/text-editor/prosemirror-adapter/mentions/parse-mentions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { Schema, Fragment, Slice } from 'prosemirror-model'; | ||
import { EditorState } from 'prosemirror-state'; | ||
|
||
/** | ||
* Processes text nodes to find mentions and creates a transaction to replace text with mention nodes. | ||
* @param state - The current editor state. | ||
* @param schema - The ProseMirror schema used to create mention nodes. | ||
* @returns - A transaction if changes are made, or null if no changes are needed. | ||
*/ | ||
export const createMentionParseTransaction = ( | ||
state: EditorState, | ||
schema: Schema, | ||
) => { | ||
const transaction = state.tr; | ||
const regex = /@([^:]+):(\w+):(\w+)/g; | ||
let madeChanges = false; | ||
|
||
state.doc.descendants((node, pos) => { | ||
if (!node.isText) { | ||
return; | ||
} | ||
|
||
const text = node.text; | ||
let lastMatchEnd = 0; | ||
const fragments = []; | ||
let match; | ||
|
||
while ((match = regex.exec(text)) !== null) { | ||
const [fullMatch, name, type, id] = match; | ||
const offset = match.index; | ||
|
||
// Add text before the match | ||
if (offset > lastMatchEnd) { | ||
fragments.push(node.cut(lastMatchEnd, offset)); | ||
} | ||
|
||
// Create and add the mention node | ||
const mentionNode = schema.nodes.mention.create({ | ||
name: name, | ||
type: type, | ||
id: id, | ||
}); | ||
fragments.push(mentionNode); | ||
|
||
lastMatchEnd = offset + fullMatch.length; | ||
} | ||
|
||
// Add any remaining text after the last match | ||
if (lastMatchEnd < text.length) { | ||
fragments.push(node.cut(lastMatchEnd)); | ||
} | ||
|
||
if (fragments.length) { | ||
const newFragments = Fragment.fromArray(fragments); | ||
transaction.replaceRange( | ||
pos, | ||
pos + node.nodeSize, | ||
new Slice(newFragments, 0, 0), | ||
); | ||
madeChanges = true; | ||
} | ||
}); | ||
|
||
return madeChanges ? transaction : null; | ||
}; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should call this thing "mention" already? Or if we should be more generic and design the feature in a way that the consumer can provide
limel-text-editor
with a list of items, which will be then shown if@
is entered as an input?Having "mentions" implemented in a text-editor is not an unusual feature. And probably approaching this feature as "mention" is an easy and straightforward way for going forward. But I'm just thinking about other forms of hotkeys (or short command triggers) such as
/
or#
or perhaps custom characters defined by the consumer like$
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many aspects of this will be agnostic and generic. However for NodeSpec's they will have to be unique and specific to what they hold.
If we're traversing the Editor State the current Node or group of Nodes needs to tell us exactly what it or they are. So for tags we would create a separate NodeSpec to specify tags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if I entirely understand the technical aspects that you mentioned. But what I was trying to say is, should this @-ing or #-ing be called "mentioning" and "tagging"? Or can we find more generic names and functionality-agnostic designs for them, such as
at-command
,hashtag-command
etc…If we call it "mention" and create an entire set of user interactions and components for handling mentions (picking a person from a searchable list while typing a piece of text), our work will be easy and straightforward. The consumer's expectations will also be straightforward. They will only use the
@
trigger to implement mentions, where they use the text editor component.However, in another context for other consumers, the @-ing may be used to link things together maybe… Or to add locations, or dates or whatever the 3rd-party consumers' use-case may be.
Maybe I'm over complicating… but this was just a question that poped in my head.