Create a popover

Popovers are usually small components which will appear near a clicked element, button or icon. Popovers can contain additional information about an element or other object, and optionally provide buttons for any further actions, like edit or remove.
This guide describes how to create a custom popover yourself.

As an alternative to creating a custom popover yourself, the platform offers some complete, ready-to-use popovers.

Step 1: Create a new package for the popover

Create a folder called “recipe-popover” in your packages/ directory. Your folder structure might look like this:

Folder structure:

training-editor/
  packages/
    recipe-sx-module
    recipe-popover/

Step 2: Create a basic popover component

Create the file “packages/recipe-popover/src/ui/RecipePopover.jsx” and add the following code example to create the most basic ui of the popover.

RecipePopover.jsx
import React from 'react';
 
import { Button, Popover, PopoverBody, PopoverFooter } from 'fds/components';
 
const RecipePopover = ({ togglePopover }) => {
   return (
       <Popover maxWidth="300px" minWidth="220px">
           <PopoverBody> My first Fonto popover!</PopoverBody>
 
           <PopoverFooter>
               <Button type="primary" label="Close" onClick={togglePopover} />
           </PopoverFooter>
       </Popover>
   );
};
 
export default RecipePopover;

Step 3: Register the popover

Create “packages/recipe-popover/src/install.js” and add the following code to register the popover. This enables you to refer to the popover from your element configuration:

install.js
import uiManager from 'fontoxml-modular-ui/src/uiManager.js';
import RecipePopover from './ui/RecipePopover.jsx';

export default function install() {
    uiManager.registerReactComponent('RecipePopover', RecipePopover);
}

Step 4: Add the popover to the element configuration

Make a change to the location where the popover should be displayed by adjusting the element configuration in “packages/recipe-sx-module/configureSxModule.js”. In this guide the popover will only be displayed if the user clicks on <ingredient>.

configureSxModule.js
// <ingredient>
configureAsInlineFrame(sxModule, 'self::ingredient', 'ingredient', {
    popoverComponentName: 'RecipePopover'
});

Step 5: Add the dependency 

Add a reference to the “recipe-popover” package from config/fonto-manifest.json. At a minimum, it should contain the following code. This ensures that Fonto will find the install.js file that registers your popover.:

fonto-manifest.json
{
    "dependencies": {
        "recipe-popover": "packages/recipe-popover",
        "recipe-sx-module": "packages/recipe-sx-module"
    }
}

Step 6: Expand the popover component

For the training guide our purpose is to connect the text within the <ingredient> to the popover. With the following code we’re using XPath to extract a string (and uppercase the first letter) from the element that the popover was opened for.

The useXPath hook ensures that whenever the relevant XML changes, ingredientTitle is also updated.

RecipePopover.jsx
import React from 'react';

import evaluateXPath from 'fontoxml-selectors/src/evaluateXPath.js';
import documentsManager from 'fontoxml-documents/src/documentsManager.js';
import useXPath from 'fontoxml-fx/src/useXPath.js';
 
import { Button, Popover, PopoverBody, PopoverFooter, PopoverHeader } from 'fds/components';
 
const RecipePopover = ({ togglePopover, data }) => {
   const contextNode = documentsManager.getNodeById(data.contextNodeId);
   const ingredientTitle = useXPath(
       'concat(upper-case(substring(.,1,1)),substring(., 2))',
       contextNode,
       { expectedResultType: evaluateXPath.STRING_TYPE }
   );
 
   return (
       <Popover maxWidth="300px" minWidth="220px">
           <PopoverHeader title={ingredientTitle || 'Ingredient name...'} />

           <PopoverBody>
               Here comes ingredient information if you follow the dev-cms guide!
           </PopoverBody>
 
           <PopoverFooter>
               <Button type="primary" label="Close" onClick={togglePopover} />
           </PopoverFooter>
       </Popover>
   );
};
 
export default RecipePopover;

Final result

If the user will click on the other ingredient elements, such as “manioc root” the popover will show the corresponding popover title.

Available popovers

Apart from creating a custom popover, the platform offers multiple complete popovers for usage with reference-like elements.

Popovers in read-only context

Popovers will be rendered everywhere, including read-only contexts. These read-only contexts exist are previews and document history. Obviously, read-only contexts do not allow the user to edit the underlying XML document. This means that some popovers do not serve any purpose in read-only contexts or may need to only render additional information related to one or more elements.

Completely disable popover in a read-only context

By default, popovers are rendered in all contexts. This behavior can be changed per popover by setting the hidePopoverInReadOnlyViews static property on a popover component.

class MyPopover extends Component {
	static hidePopoverInReadOnlyViews = true;

	// Other popover content
}

For a function-style component the property can be set on the function itself:

function MyPopover (props) {
	// ...
}

MyPopover.hidePopoverInReadOnlyViews = true;


Note this does not apply when the popover is shown for content of an element in your XML document that is configuredAsReadOnly. See the table below.

Conditionally render parts of a popover in a read-only context

When a popover does provide useful information regarding an element, it is recommended to also render it in a read-only context. Popovers may, however, contain buttons which execute operation which edit the underlying XML document. These buttons should not be available to the user in a read-only context. To not render these buttons (or any other component) in a read-only context, there are several options available.
Something can be read-only for various reasons, which are reflected in different public APIs.

The table below shows a matrix of what read-only is in Fonto.

The columns are the 3 different read-only contexts in Fonto (i.e. why something is read-only).

The rows describe what happens visually to the content, and lists the values (or whether or not it applies) in each of the read-only contexts.


Using the CVK family
configureAsReadOnly

When the lock on the
document is unavailable

View is read-only (eg. on the review route
or in previews in the sidebar of browse modals)

Visually the content is:

greyed out

greyed out

unchanged





Static variable for a custom popover component
hidePopoverInReadOnlyViews (see section above)

does not apply

applies

applies





Prop for a custom popover component:
data.isReadOnly

true

true

true

Prop for a custom popover component:
data.isViewReadOnly

false false

true





XPath function to use anywhere inside your
custom popover (with useXPath):
fonto:is-node-read-only

true

true

false


Note that popovers could be opened from a read-only preview of an otherwise editable document (which is also loaded in the editor).
In such cases, operation-based components such as FxOperation would be enabled, and may need to be disabled manually based to prevent editing the document from a read-only view.

Use any (combination of) the APIs listed in the table above to disable the components manually as necessary and relevant for your popover and your documents.


Was this page helpful?