Skip to content

Commit

Permalink
SITES-20344: Documentation for Universal Editor Extensibility in UIX …
Browse files Browse the repository at this point in the history
…Docs
  • Loading branch information
irenelagno committed Apr 23, 2024
1 parent 5a08af3 commit 6917397
Show file tree
Hide file tree
Showing 13 changed files with 715 additions and 1 deletion.
28 changes: 27 additions & 1 deletion gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ module.exports = {
title: "AEM Content Fragments Editor",
path: "/services/aem-cf-editor/"
},
{
title: "Universal Editor",
path: "/services/aem-universal-editor/"
},
{
title: "Adobe Commerce Admin",
path: "https://developer.adobe.com/commerce/extensibility/admin-ui-sdk/"
Expand Down Expand Up @@ -214,7 +218,29 @@ module.exports = {
path: "/extension-manager/extension-developed-by-adobe/content-fragments-workflows"
}
]
}
},
{
title: "Extension Points",
path: "/services/aem-universal-editor/api/",
pages: [
{
title: "Common Concepts",
path: "/services/aem-universal-editor/api/commons/"
},
{
title: "Header Menu",
path: "/services/aem-universal-editor/api/header-menu/"
},
{
title: "Modal Dialogs",
path: "/services/aem-universal-editor/api/modal/"
},
{
title: "Overriding Default Rendering of Item Types ",
path: "/services/aem-universal-editor/api/item-types-renderers/"
}
]
},
]
},
plugins: [
Expand Down
4 changes: 4 additions & 0 deletions src/pages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ Start building extensions for AEM Content Fragments console

Start building extensions for AEM Content Fragments editor

[Universal Editor](services/aem-universal-editor/)

Start building extensions for the Universal Editor

<DiscoverBlock slots="link, text"/>

[Adobe Commerce Admin](https://developer.adobe.com/commerce/extensibility/admin-ui-sdk/)
Expand Down
180 changes: 180 additions & 0 deletions src/pages/services/aem-universal-editor/api/commons/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
---
title: Universal Editor Extensibility
description: Learn how to customize Universal Editor
contributors:
- https://github.com/AdobeDocs/uix
---

# Common Concepts in Creating Extensions

Learn about common approaches and methods that can be used in any extension for the universal editor.

## Extension Registration

Interaction between UI Extension and Universal Editor starts with the initialization process that includes extension's
capabilities registration so Universal Editor knows when to invoke the extension. Registration is done by `register`
method provided by `@adobe/uix-guest` library. This asynchronous method takes single object that describes extension
and returns object representing connection to the Universal Editor.

Method `register` should be invoked after extension initialization page is loaded.

Extension registration data must include:

- `id` - string with random extension identifier. This identifier useful for debugging of interaction between Universal
Editor and extension and needed if extension provides custom UI.
- `methods` - objects with extension code exposed to the Universal Editor console. All methods are grouped into
namespaces that represents extension points provided by the Universal Editor.
Currently, the following **namespaces** are available:
- _headerMenu_, that allows to add buttons to the header of the Universal Editor;
- _rightPanel_, that allows to add custom content under the rails to the right panel of the Universal Editor;
- _canvas_, that allows to add custom renderer for data types

```js
import { register } from "@adobe/uix-guest";

// ...

const guestConnection = await register({
id: "extension-id",
methods: {
headerMenu: {
getButtons() {
// ..
}
},
rightPanel: {
getPanels() {
// ..
}
},
canvas: {
getRenderers() {
// ..
}
}
}
});
// ...
```
## Extension UI

For use-cases when UI Extension provides any data handling or send data to remote service `register` is the only method
that is expected to be invoked. If UI Extension implements own UI it should be provided as separate page.
If this UI requires data from Universal Editor or need to invoke any logic it should establish connection with `attach`
method.

```js
import { attach } from "@adobe/uix-guest";

const guestConnection = await attach({ id: "extension-id" });
```

## Connection Object

Both `register` and `attach` function of `@adobe/uix-guest` returns same connection object that has `host` property and
expose API of Universal Editor exposed for UI Extensions.


### Shared Context

The shared context is a dataset that Universal Editor shares with UI Extensions. It's used to understand the context of
the user who is running Universal Editor. You can access the shared context through the `sharedContext` property of the
connection object.

```js
import { attach } from "@adobe/uix-guest";

useEffect(() => {
(async () => {
const guestConnection = await attach({ id: extensionId });

setGuestConnection(guestConnection);
})();
}, []);

...

const context = guestConnection.sharedContext;
const hostAppLocale = context.get("locale");
```

Available data in the shared context:

| Key | Type | Description |
|--------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| locale | `string` | Locale string for globalization of current user |
| theme | `string` | Available [options](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/overview/aem-cloud-service-on-unified-shell#changing-to-dark-theme): "light" or "dark". The theme selected by current user |
| orgId | `string` | IMS org ID |
| token | `string` | User token |
| authScheme | `string` | Auth schema that should be used during communication with host application |


### Editor State

The editor state is a dataset that Universal Editor shares with UI Extensions. It's used to understand the current state
of the editor. You can access the editor state through the `editorState` property of the host object.

Below is an example of how you can access editor state properties, e.g., connections.

```js
import { attach } from "@adobe/uix-guest";

...

useEffect(() => {
(async () => {
const guestConnection = await attach({ id: extensionId });

setGuestConnection(guestConnection);
})();
}, []);
...

const editorState = await guestConnection.host.editorState.get();
const {connections} = editorState;

...

```
Available data in the editor state:

| Key | Type | Sample | Description |
|-----|---------------------------|-----------------------------------------------------------------------|-------------|
| connections | `obj` | { "aemconnection": "aem:%auth_instance_url%" } | [Connections](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/implementing/developing/universal-editor/getting-started#connections) which are used in the app are stored as `<meta>` tags in the page’s `<head>`. |
| selected | `obj<string, boolean>` | {fcb38012-c4c7-51a8-896c-79e76kjk: true} | Element that is currently edited. |
| editables | `[objects]` | Array[{id: '33661..", type: 'reference', resource: "urn:..., ..}, {}] | List of elements that might be edited. The editable element object includes [proper metadata](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/implementing/developing/universal-editor/attributes-types). |
| location | `string` | "%locationString%" | The current page location |
| customTokens | `obj<string, string>` | {"aemconnection":""} | Custom tokens available for connections |

### Working with Events

The Universal Editor offers a list of events that extensions can subscribe to in order to respond to changes in content or the user interface.
Refer to this [document](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/implementing/developing/universal-editor/events) for the available event list.

For instance, here's an example of how to subscribe to the "aue:ui-select" event:

```js

useEffect(() => {
(async () => {
const guestConnection = await attach({id: extensionId});
...
await guestConnection.host.remoteApp.addEventListener('aue:ui-select', console.log('event recieved!'));
...
})();
}, []);
```

If your business logic requires sending an event to the Universal Editor, you can use the `dispatchEvent` method.
Here's an example of how to dispatch the "aue:ui-select" event:

```js
useEffect(() => {
(async () => {
const guestConnection = await attach({id: extensionId});
...
await guestConnection.host.remoteApp.dispatchEvent('aue:ui-select', {data: 'some data'});
...
})();
}, []);
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
115 changes: 115 additions & 0 deletions src/pages/services/aem-universal-editor/api/header-menu/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
title: Universal Editor Extensibility
description: Learn how to customize Universal Editor
contributors:
- https://github.com/AdobeDocs/uix
---

# Header Menu

Header menu can be customized via methods defined in `headerMenu` namespace.

You have the ability to:

- create multiple buttons from single extension;
- implement drop-down menu buttons;
- use different [variations](https://spectrum.adobe.com/page/button/#Options) of buttons from React Spectrum;
- use any [icon](https://react-spectrum.adobe.com/react-spectrum/workflow-icons.html#available-icons) from React Spectrum;

## Custom button with callback

```js
import { register } from "@adobe/uix-guest";

// ...

const guestConnection = await register({
id: "my.company.extension-with-header-menu-button",
methods: {
headerMenu: {
getButtons() {
return [
{
id: "my.company.export-button",
label: "Export",
icon: 'Export',
onClick: () => {
console.log('Export button has been pressed.');
},
},
];
},
},
},
});
```

The `onClick` callback is invoked when a user clicks on the button. It does not receive any arguments.

![Header menu item](./header-menu-item.png)

## Custom button with sub menu

```js
import { register } from "@adobe/uix-guest";

// ...

const guestConnection = await register({
id: "my.company.extension-with-header-menu-button",
methods: {
headerMenu: {
async getButtons() {
return [
{
id: "my.company.export-button",
label: "Export",
icon: 'Export',
subItems: [
{
id: 'xml',
label: 'XML',
onClick: async () => {
// ...
},
},
{
id: 'csv',
label: 'CSV',
onClick: async () => {
// ...
},
},
],
},
];
},
},
},
});
```

![Header menu item with submenu](./header-menu-item-with-submenu.png)

## API Reference

### Button API

| Field | Type | Required | Description |
|----------|-----------------------------------------------------------------------------| ------ |-------------------------------------------------------------------------------------------------------------------------------|
| id | `string` | ✔️ | **Must be unique** across all extensions. Consider adding a vendor prefix to this field |
| label | `string` | ✔️ | Button label that will be visible on UI |
| icon | `string` | | Name of a [React-Spectrum workflow icon](https://react-spectrum.adobe.com/react-spectrum/workflow-icons.html#available-icons) |
| variant | `cta` <br /> `primary` <br /> `secondary` <br /> `negative` <br /> `action` | | The [visual style](https://spectrum.adobe.com/page/button/#Options) of the button |
| subItems | `array` | | A list with sub menu items. |
| onClick | `callback(): void` | ✔️ | A callback for a button `onClick` event |

### Sub menu item API

| Field | Type | Required | Description |
|----------|-------------------------------------------------------------------------| ------ |--------------------------------------------------------------------------------------------------------------|
| id | `string` | ✔️ | **Must be unique** across the current button sub menu |
| label | `string` | ✔️ | Button label that will be visible on UI |
| icon | `string` | | Name of a [React-Spectrum workflow icon](https://react-spectrum.adobe.com/react-spectrum/workflow-icons.html#available-icons) |
| onClick | `callback(): void` | ✔️ | A callback for a button `onClick` event |

32 changes: 32 additions & 0 deletions src/pages/services/aem-universal-editor/api/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: Universal Editor Extensibility
description: Learn how to customize Universal Editor
contributors:
- https://github.com/AdobeDocs/uix
---

# The Universal Editor Extension Points

This section covers the utilization of existing extension points, extension registration, and common methods that can be used in any application that leverages extension points for service customization.

<DiscoverBlock slots="link, text"/>

[Common Concepts in Creating Extensions](commons)

Learn about common concepts, extension registration, and methods that can be used in any extension

<DiscoverBlock slots="link, text"/>

[Header Menu](header-menu)

Explore the ways to extend and customize Header Menu

<DiscoverBlock slots="link, text"/>

[Modal Dialogs](modal)

Learn about modal host API methods that can be used in any extension

[Custom data types renderers for properties rail](item-types-renderers)

Learn how to customize the user interface of a data type field within the properties rail of Universal Editor.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 6917397

Please sign in to comment.