GithubHelp home page GithubHelp logo

joelewis / prosemirror-mentions Goto Github PK

View Code? Open in Web Editor NEW
110.0 7.0 32.0 1.65 MB

ProseMirror plugin to enable @mentions and #hashtags

License: MIT License

JavaScript 100.00%
prosemirror javascript-library

prosemirror-mentions's Introduction

ProseMirror Mentions

A ProseMirror plugin that enables @mentions and #hashtags in a prosemirror view.

Demo: https://star-drug.glitch.me/

Alternative: https://github.com/quartzy/prosemirror-suggestions

What's different then?

prosemirror-suggestions is a lighter alternative that comes with the bare minimum. It is upto you to implement the dropdown & related logic.

prosemirror-mentions is a fully packed plugin. It comes with all batteries included: default dropdown UI, behavior handling, support for async fetching of suggestions, etc. Configure options to suit your needs.

Installation

npm install prosemirror-mentions

Usage

import {addMentionNodes, addTagNodes, getMentionsPlugin} from 'prosemirror-mentions'

...
...

var schema = new Schema({
    nodes: addTagNodes(addMentionNodes(schema.spec.nodes)),
    marks: schema.spec.marks
});

...
...


/**
 * IMPORTANT: outer div's "suggestion-item-list" class is mandatory. The plugin uses this class for querying.
 * IMPORTANT: inner div's "suggestion-item" class is mandatory too for the same reasons
 */
var getMentionSuggestionsHTML = items => '<div class="suggestion-item-list">'+
  items.map(i => '<div class="suggestion-item">'+i.name+'</div>').join('')+
'</div>';

/**
 * IMPORTANT: outer div's "suggestion-item-list" class is mandatory. The plugin uses this class for querying.
 * IMPORTANT: inner div's "suggestion-item" class is mandatory too for the same reasons
 */
var getTagSuggestionsHTML = items => '<div class="suggestion-item-list">'+
  items.map(i => '<div class="suggestion-item">'+i.tag+'</div>').join('')+
'</div>';

var plugins = [/* A list of other plugins */]

var mentionPlugin = getMentionsPlugin({
    getSuggestions: (type, text, done) => {
      setTimeout(() => {
        if (type === 'mention') {
            // pass dummy mention suggestions
            done([{name: 'John Doe', id: '101', email: '[email protected]'}, {name: 'Joe Lewis', id: '102', email: '[email protected]'}])
        } else {
            // pass dummy tag suggestions
            done([{tag: 'WikiLeaks'}, {tag: 'NetNeutrality'}])
        }
      }, 0);
    },
    getSuggestionsHTML: (items, type) =>  {
      if (type === 'mention') {
        return getMentionSuggestionsHTML(items)
      } else if (type === 'tag') {
        return getTagSuggestionsHTML(items)
      }
    }
});

plugins.unshift(mentionPlugin); // push it before keymap plugin to override keydown handlers
...
...
window.view = new EditorView(document.querySelector("#my-editor-div"), {
  state: EditorState.create({
    schema: schema,
    plugins: plugins
  })
});

Refer example application for clarifications.

Complete List of Options

// default options
var defaultOpts = {
  // char for triggering @mention
  mentionTrigger: "@",

  // char for triggering #tag
  hashtagTrigger: "#",

  // if true: allows you to type @FirstName LastName with a space in between.
  allowSpace: true,

  /**
   * callback to fetch suggestions and return a list of suggestions
   * @param {String} type - 'mention' or 'tag'
   * @param {String} text - query text. For e.g @Joh -> text = 'Joh'
   * @param {Function} done - callback to execute after fetching suggestions (ideally from ajax requests)
   */
  getSuggestions: (type, text, done) => {
    done([]);
  },

  /**
   * callback to construct and return a HTML string for a set of suggestions
   * @param {Array} items - a list of suggestions returned from getSuggestions()
   * @param {String} type - 'mention' or 'tag'
   */
  getSuggestionsHTML: (items, type) =>
    '<div class="suggestion-item-list">' +
    items
      .map(i =>
        '<div class="suggestion-item">' + type === "mention"
          ? i.name
          : i.tag + "</div>"
      )
      .join("") +
    "</div>",

  // css class to add when a .suggestion-item element is active / selected.
  activeClass: "suggestion-item-active",

  // css class to add to "@Mentioned Text" in editor. Can be used to style, the current active @mention content.
  suggestionTextClass: "prosemirror-suggestion",

  // Max number of suggestions to show in dropdown UI.
  // The response from getSuggestions() will be truncated based on this value.
  maxNoOfSuggestions: 10,

  // debounce timeout for getSuggestions() call when user types continuously
  delay: 500
};

Development

npm run build
npm run watch

Authors

Pending Tasks

grep the repository for "TODO:"

ISSUES & FEEDBACK

Use Github Issues to file requests and bugs.

License

MIT License

prosemirror-mentions's People

Contributors

icellan avatar joelewis avatar ravi7mech avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

prosemirror-mentions's Issues

dispatchTransaction not called when selection a mention

Hi, I noticed that selecting a mention doesn't call dispatchTransaction, which breaks react-prosemirror since it relies on this to update the state.

As a result as long no other input is done (press a key like space or use a command), the state of the document is invalid. In our case saving the text saved the text without the mention (plain text typed for the search)

I think this line should be a view.dispatch instead of view.updateState, which does trigger the updateState eventually according to the doc, but also will call dispatchTransation which is important for many plugins.

I'm not a prosemirror expert so I hope this wouldn't break anything.

Backspace on Android phones adds characters instead of deleting the @mention

Hello. Using the example at https://star-drug.glitch.me/ on Android phones (with Google Chrome or Opera) results in adding characters instead of deleting the @mention code. (Backspace does work as expected on a desktop PC running Linux or Windows.)

For example, if I add @johndoe as a mention, using the Backspace key to delete it results in adding more characters like "Do" or "oe" or "DDo" ... and each attempt to use the Backspace key keeps adding more of these.

React element suggestions

What is required to return a React element for suggestions? I can't get anything to appear. Is this against ProseMirror norms for decorations perhaps?

Why?

  • Avoid DOM creation
  • Stay within React
  • Avoid class names

Running build causes error

When trying to build via npm run build, the /dist folder is created, but you get the following error...

[!] Error: Invalid format: esm - valid options are amd, cjs, es, iife, umd

I tried to solve this by installing esm via npm i esm, but it still results in the same error.

Workaround for caret position (or disappear) bug when @ is at the end of a line

Symptom : When @mention is the only element on a line (or when you start typing at the beginning of the line), the caret disappears on Firefox, and is moved to the end of the line of Chrome.

Firefox: (caret is gone)

image

Chrome: (caret is after </p>)

image

The html looks like this:

<div contenteditable="true" class="ProseMirror" role="textbox">
  <p class="">
    <span data-mention-id="1" data-mention-name="mension" data-mention-email="" class="prosemirror-mention-node" contenteditable="false">
      @mension x
    </span>
  </p>
</div>

On Firefox and Chrome, inside a contenteditable=true div, when the line contains single child, the above bug happens. This is a bug on the browsers. They are unlikely to be resolved, because when there's a single child, the it's ambiguous where the caret should be placed.

One workaround for this is to make it so that the inserted @mension node is not the single child in <p></p>, by automatically inserting spaces around the mention tag. You can modify the source code, and add .insertText(" ", ...) around the Transaction:

  let select = function (view, state, opts) {
    let item = state.suggestions[state.index];
    let attrs;
    if (state.type === "mention") {
      attrs = {
        name: item.name,
        id: item.id,
        email: item.email,
      };
    } else {
      attrs = {
        tag: item.tag,
      };
    }
    let node = view.state.schema.nodes[state.type].create(attrs);
    let tr = view.state.tr
        .insertText(" ", state.range.to)  // ADD THIS
        .replaceWith(state.range.from, state.range.to, node)
        .insertText(" ", state.range.from); // ADD THIS

    //let newState = view.state.apply(tr);
    //view.updateState(newState);
    view.dispatch(tr);
  };

Prosemirror-view + prosemirror-mentions for Android Google Chrome, show mentions without delay, on key input

Hi guys, my current solution working fine for ios and desktops, I input “@s” and I immediately see mentions block, but when I input “@something” on Android device it activating mentions container just on “space” click or after 5000ms inactivity delay. Also if I continue input after 5000ms it duplicates input section from Android keyboard suggestions. I tried to delete android exception for 5000ms delay in prosemirror-view

" // Drop active composition after 5 seconds of inactivity on Android var timeoutComposition = result.android ? 5000 : -1;"

It fixed my first issue “Show mentions list on input”, but duplication bug became reproducing

Could you please help me to resolve “show mentions on input” issue or could you told me more about Android suggestions input specify if you already had an opportunity to discover this issue?

Error when using horizontal rule

When I insert a horizontal rule in an empty editor, and then click the line after/before the rule, I get this error:

image

star-drug.glitch.me.-.Google.Chrome.2023-12-11.13-22-18.mp4

Better click-away behavior

If the user clicks away from the ProseMirror editor with @mention suggestions open... they can get stuck open. This is particularly bad once the user scrolls and the suggestions remain fixed.

Is it possible to react to ProseMirror losing focus?

It may be the repressibility of the wrapping application to provide a listener canvas.

Here's a thread with similar goals... https://discuss.prosemirror.net/t/handling-focus-in-plugins/1981

Install over prosemirror-markdown

Can I install the component over prosemirror-markdown?
Right now I'm having difficulties to expand markdown schema with nodes form prosemirror-mentions package. Did somebody do it or similar things?
The point is that the markdown has predefined schema with nodes and all my attempts to expand it with nodes of this library failed.
Right now there is only one solution that worked for me: download the markdown package and do manual schema adjustments to add nodes from here.

Uncaught TypeError: Cannot read property 'create' of undefined

Getting this error after selecting from the dropdown list

node_modules/prosemirror-mentions/dist/index.js:237 
Uncaught TypeError: Cannot read property 'create' of undefined
    at select (/node_modules/prosemirror-mentions/dist/index.js:237)
    at HTMLDivElement.eval (/node_modules/prosemirror-mentions/dist/index.js:151)

Calling mention suggestions callback with empty list causes crash (patch included)

In my Mentions plugin (created using getMentionsPlugin), when getting suggestions, my code calls the done callback with an empty list to indicate no matching suggestions, but this causes a crash in mentionPlugin.js:addClassAtIndex ("prevItem is undefined" due to there being no matching element).

The patch below adds a simple check to addClassAtIndex to fix this issue, and also in related function removeClassAtIndex.

prosemirror.patch.txt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.