Project: Inline references to all entities (aka "mentions")

type: #Project
status: ready to review
owner: @horacio


In the Hypermedia protocol, references are defined in a way that they can be either at block-level or inline level. this means that technically we can add references to other entities along side normal content.
This project started as the need to add "mentions" to people, but the underlying mechanism can me applied not only to account mentions but to references to any entity in the whole system.
The result of this project means that we will be able to add inline references to any entity the same way a normal mention system works in other platforms: Documents, groups, blocks and accounts.


Currently the only entity that is aware of any link reference are Documents. In order for this project to get its full potential we need all entities to be aware of all its references and build a way to access them (accounts and groups). Eventhough this is crucial for the whole system, is not a real stopper for enabling the reference system to users.
The real scope of the project is to enable users add inline references to any entity. This means that we need to define a new Inline element inside the editor, Add a new editor command and make our Publication renderer aware of this new elements.

Non-editable inline references

We need to think of inline references as links. Links have anchor and a reference (href). A non-editable inline references does not have anchor because it's anchor is defined by the reference you are pointing to. In Hypermedia, everything inside a block is modelled as an annotation. Here's the link annotation type definition:
// current link contract
type LinkAnnotation = {
  starts: number[]
  ends: number[]
  type: 'link'
  ref: string
Currently every block reference has the type embed. I believe it make sense we call inline references the same way:
type InlineEmbedAnnotation = {
  type: 'embed'
  starts: number[]
  ends: number[]
  ref: string // 'hm://... with #BlockRef
  attributes: {}
The main difference between a link annotation and a inline embed annotation is its length. because we don't want inline references to be edited but we want them to be considered, this references will have a fixed length of one code point. This will give us the flexibility of rendering anything we want inside of it and also makes it possible to select them and make the editor aware of them.
Let's look at the differences with practical examples: account mention, a document mention and a group mention.

Account mentions

Here's the result of an account mention in code:
let mention = {
  type: 'embed'
  ref: 'hm://a/ACCOUNT_ID',
  starts: [0],
  ends: [1],
  attributes: {}
The way to add a new mention will be by typing the character @ and this will open a list menu similar to the current Slash command:
example of the mentions menu from Notion
When you start typing, it will use the characters typed to "filter" the options on the list by the alias comparing with the text the user typed after the special character (@). The text we will render inside this account mentions will be the current account's alias for the account mentioned.

Document & Group Mentions

Here's the result of a document/group mention in code:
let document_mention = {
  type: 'embed'
  ref: 'hm://d/DOC_ID?v=DOC_VERSION',
  starts: [0],
  ends: [1],
  attributes: {}
This should work the same way as Account mentions. We can either use the same special character and have a list separated by two headers inside the menu (subgroups) or we can use a different special character: # for example. The problem of using # is that is the same character we use to create Headings. I believe having a list with subgroups is the best option. The text we will render inside this document mentions will be the current document's title for the account mentioned. for the group will be the group title.
There's a particular difference between account references and Document/Group references: Documents and Groups can have versions, which means that for the inline embed renderer we need to let users point to the exact version or "latest". (Similar to Project: enable latest versions in embeds)
Like I mentioned above, inline embeds are non-editable. this means that the content of this embeds will be empty. we need to make sure the editor understand them and we need to add special characters in the text we store in the backend to make sure we have code points to position them properly.

List Citations for Inline references

For documents, adding an inline reference to it will work the same was as a normal link work right now (it will be respected). Currently we don't have a way to list citations for any other entity, but this does not mean we cannot do inline references to accounts and groups.
I believe we can leave this backend support (list citations for any entity) out of the scope of this project. But I'm sure users will find this extra necessary quite soon.

Make Publication renderer aware of Inline references

The code we use to render publications currently is not the same code we use for the editor part. This means we need to include inline reference renderers to it.
This is not a huge difference because we have mechanisms to render block embeds now.

Add an option to add a mention/inline embed from the link menu when pasting a link

Mentions/Inline embeds should work only for entities, not blocks. (for now)

Nice to have

the ability to create a link from a mention/inline embed (to change the alias)


2 weeks. there's a lot involved both in the editor part and in the renderer part.

Rabbit Holes

This is OUT OF SCOPE, but something interesting to do in the future is when creating a new Document reference, we can use the same UI to create documents from the draft. This will create a new draft, add the content as the title, publish it and then add the inline reference. we can do the same for groups too.