Skip to content

Commit

Permalink
add events
Browse files Browse the repository at this point in the history
  • Loading branch information
KonnorRogers committed Sep 9, 2024
1 parent d06012b commit c20def6
Show file tree
Hide file tree
Showing 19 changed files with 290 additions and 90 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilly-knives-explode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"rhino-editor": patch
---

Feature: Added the `rhino-update` event for tracking updates to the editor
5 changes: 5 additions & 0 deletions .changeset/cyan-items-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"rhino-editor": minor
---

Feature: Added some CSS fallbacks for dark color schemes
5 changes: 5 additions & 0 deletions .changeset/friendly-steaks-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"rhino-editor": minor
---

Feature: added events for direct upload in the form of `rhino-direct-upload:*`, you can read more in the editor events section.
5 changes: 5 additions & 0 deletions .changeset/wicked-mayflies-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"rhino-editor": minor
---

Feature: added the `rhino-update` event. Useful for tracking when the component has updated.
4 changes: 3 additions & 1 deletion docs/esbuild.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ const esbuildOptions = {
from: [path.resolve(__dirname, '../exports/styles/trix.css')],
to: [path.resolve(__dirname, 'src/rhino-editor/exports/styles/trix.css')],
},
verbose: false
verbose: false,
watch: true,

}),
]
}
Expand Down
5 changes: 5 additions & 0 deletions docs/frontend/styles/overrides/light-pen.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
light-preview {
}
light-preview::before {
content: "Preview";
background: var(--sl-color-neutral-600);
border: 1px solid var(--sl-color-neutral-700);
border-bottom: none;
color: var(--sl-color-neutral-0);
padding: 4px;
padding-inline-start: 16px;
display: block;
}

light-preview {
display: grid;
align-items: start;
Expand Down
10 changes: 6 additions & 4 deletions docs/src/_documentation/references/02-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ Equivalent Trix Events: <https://github.com/basecamp/trix/blob/main/README.md#ob

Direct Uploads now have the following events you can listen to in the editor. All of the events have the `event.attachmentManager` property which should have all the information you need to react appropriately.

- [ ] - `direct-upload:start` - called when the upload starts.
- [ ] - `direct-upload:progress` - Called periodically as the editor progesses.
- [ ] - `direct-upload:error` - Called when the upload errors.
- [ ] - `direct-upload:end` - Called when the upload has finished. This will not get called if there is an error.
- [x] - `rhino-direct-upload:start` - called when the upload starts.
- [x] - `rhino-direct-upload:progress` - Called periodically as the editor progesses.
- [x] - `rhino-direct-upload:error` - Called when the upload errors.
- [x] - `rhino-direct-upload:success` - Called when the upload has finished. This will get **NOT** get called if there is an error.
- [x] - `rhino-direct-upload:complete` - Called when the upload has finished. This will get called even if there is an error.

All of the above have a `event.directUploadInstance` which will contain various properties you need. Such as `.progress`, `.attachment`, etc.
50 changes: 45 additions & 5 deletions docs/src/_documentation/references/06-bubble-menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,29 @@ Notice the slot name is `bubble-menu__strike-icon`, and the regular toolbar is j

## Multiple bubble menus

It is possible to have multiple bubble menus, and display certain buttons / elements depending on what bubble menu is being shown. The easiest way to do this is to re-use the existing bubble menu and hook into the `bubble-menu-show` event from the editor. Then, you can find the current active node and decide what to display.
It is possible to have multiple bubble menus, and display certain buttons / elements depending on what bubble menu is being shown. The easiest way to do this is to re-use the existing bubble menu and hook into the `rhino-bubble-menu-show` event from the editor. Then, you can find the current active node and decide what to display.

<% multiple_bubble_menus = capture do %>
const rhinoEditor = document.querySelector("rhino-editor")
function handleBubbleMenuShow () {
const listToolbar = rhinoEditor.querySelector("#list-toolbar")
const defaultToolbar = rhinoEditor.defaultBubbleMenuToolbar

const indentButton = rhinoEditor.querySelector(".indent-button")
const dedentButton = rhinoEditor.querySelector(".dedent-button")

indentButton.addEventListener("click", (e) => {
if (rhinoEditor.editor.can().sinkListItem("listItem")) {
rhinoEditor.editor.chain().focus().sinkListItem("listItem").run();
}
})

dedentButton.addEventListener("click", (e) => {
if (rhinoEditor.editor.can().liftListItem("listItem")) {
rhinoEditor.editor.chain().focus().liftListItem("listItem").run();
}
})

// When the current active node, or a parent of the current active node is a list element, then
if (rhinoEditor.editor.isActive("bulletList") || rhinoEditor.editor.isActive("orderedList")) {
// We're on a list. Show the list bubble menu.
Expand All @@ -95,22 +110,47 @@ function handleBubbleMenuShow () {
}
}

rhinoEditor.addEventListener("bubble-menu-show", handleBubbleMenuShow)
// Tracks changes to the editor and updates the button.
function handleRhinoUpdate (e) {
const indentButton = rhinoEditor.querySelector(".indent-button")
indentButton.toggleAttribute("disabled", !rhinoEditor.editor.can().sinkListItem("listItem"))

const dedentButton = rhinoEditor.querySelector(".dedent-button")
dedentButton.toggleAttribute("disabled", !rhinoEditor.editor.can().liftListItem("listItem"))
}

rhinoEditor.addEventListener("rhino-update", handleRhinoUpdate)
rhinoEditor.addEventListener("rhino-bubble-menu-show", handleBubbleMenuShow)
<%- end -%>


```js
<%= multiple_bubble_menus %>
```

<% content = "<ul><li><p>Select me and I can indent</p></li></ul><p></p><p>Select me and I'm the default bubble menu.</p>".html_safe %>
<% content = "<ul><li><p>I have a different bubble menu.</p></li></ul><p></p><p>Select me and I'm the default bubble menu.</p>".html_safe %>

<% html = capture do %>
<style>
role-toolbar::part(base) {
border-color: gray;
}
</style>
<input id="input" type="hidden" value="<%= content %>">
<rhino-editor input="input">
<role-toolbar id="list-toolbar" slot="additional-bubble-menu-toolbar">
<button>Indent</button>
<button>Dedent</button>
<button
type="button"
class="indent-button rhino-toolbar-button"
data-role="toolbar-item"
tabindex="-1"
>Indent</button>
<button
type="button"
class="dedent-button rhino-toolbar-button"
data-role="toolbar-item"
tabindex="-1"
>Dedent</button>
</role-toolbar>
</rhino-editor>
<script type="module">
Expand Down
1 change: 1 addition & 0 deletions docs/src/_partials/_head.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<% resource_title = strip_html(strip_newlines(title)) || site.metadata.title %>
<title><%= resource_title %></title>

<meta name="env" content="<%= Bridgetown.env %>">
<meta name="description" content="<%= metadata.description %>" />
<link rel="modulepreload" href="<%= asset_path "javascript/index.js" %>">
<link rel="modulepreload" href="<%= asset_path "javascript/defer.js" %>">
Expand Down
17 changes: 16 additions & 1 deletion docs/src/rhino-editor/exports/styles/trix.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions esbuild.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ function AppendCssStyles () {
const finalString = `/* THIS FILE IS AUTO-GENERATED. DO NOT EDIT BY HAND! */
${styles.toString()}
/* src/exports/styles/editor.js:hostStyles */
.trix-content {
${hostStyles.toString()}
}
${hostStyles.toString()}
/* src/exports/styles/editor.js:toolbarButtonStyles */
${toolbarButtonStyles.toString()}
Expand Down
64 changes: 64 additions & 0 deletions src/exports/attachment-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,63 @@ import type { Blob, DirectUploadDelegate } from "@rails/activestorage";
import { AttachmentManager } from "./attachment-manager.js";
import { LOADING_STATES } from "./elements/attachment-editor.js";

import { BaseEvent } from "./events/base-event.js";


class DirectUploadStartEvent<T extends DirectUpload = DirectUpload> extends BaseEvent {
static eventName = "rhino-direct-upload:start" as const;

constructor(public directUploadInstance: T, options?: EventInit | undefined) {
super(DirectUploadStartEvent.name, options)
this.directUploadInstance = directUploadInstance
}
}

export class DirectUploadProgressEvent<T extends DirectUpload = DirectUpload> extends BaseEvent {
static eventName = "rhino-direct-upload:progress" as const;

constructor(public directUploadInstance: T, options?: EventInit | undefined) {
super(DirectUploadProgressEvent.name, options)
this.directUploadInstance = directUploadInstance
}
}

export class DirectUploadErrorEvent<T extends DirectUpload = DirectUpload> extends BaseEvent {
static eventName = "rhino-direct-upload:error" as const;

constructor(public directUploadInstance: T, options?: EventInit | undefined) {
super(DirectUploadErrorEvent.name, options)
this.directUploadInstance = directUploadInstance
}
}

export class DirectUploadSucceedEvent<T extends DirectUpload = DirectUpload> extends BaseEvent {
static eventName = "rhino-direct-upload:succeed" as const;

constructor(public directUploadInstance: T, options?: EventInit | undefined) {
super(DirectUploadSucceedEvent.name, options)
this.directUploadInstance = directUploadInstance
}
}
export class DirectUploadCompleteEvent<T extends DirectUpload = DirectUpload> extends BaseEvent {
static eventName = "rhino-direct-upload:complete" as const;

constructor(public directUploadInstance: T, options?: EventInit | undefined) {
super(DirectUploadCompleteEvent.name, options)
this.directUploadInstance = directUploadInstance
}
}

declare global {
interface GlobalEventHandlersEventMap {
[DirectUploadStartEvent.eventName]: DirectUploadStartEvent;
[DirectUploadProgressEvent.eventName]: DirectUploadProgressEvent;
[DirectUploadErrorEvent.eventName]: DirectUploadErrorEvent;
[DirectUploadSucceedEvent.eventName]: DirectUploadSucceedEvent;
[DirectUploadCompleteEvent.eventName]: DirectUploadCompleteEvent;
}
}

/**
* An extension of DirectUpload. This is what handles uploading to remote sources
* for attachments.
Expand All @@ -28,13 +85,15 @@ export class AttachmentUpload implements DirectUploadDelegate {

start() {
this.directUpload.create(this.directUploadDidComplete.bind(this));
this.element.dispatchEvent(new DirectUploadStartEvent(this.directUpload))
}

directUploadWillStoreFileWithXHR(xhr: XMLHttpRequest) {
xhr.upload.addEventListener("progress", (event) => {
const progress = (event.loaded / event.total) * 100;
this.currentProgress = progress;
this.setUploadProgress();
this.element.dispatchEvent(new DirectUploadProgressEvent(this.directUpload))
});
}

Expand All @@ -51,6 +110,8 @@ export class AttachmentUpload implements DirectUploadDelegate {
});
}

this.element.dispatchEvent(new DirectUploadErrorEvent(this.directUpload))
this.element.dispatchEvent(new DirectUploadCompleteEvent(this.directUpload))
throw Error(`Direct upload failed: ${error}`);
}

Expand All @@ -61,6 +122,9 @@ export class AttachmentUpload implements DirectUploadDelegate {

this.currentProgress = 100;
this.setUploadProgress();

this.element.dispatchEvent(new DirectUploadSucceedEvent(this.directUpload))
this.element.dispatchEvent(new DirectUploadCompleteEvent(this.directUpload))
}

setUploadProgress() {
Expand Down
1 change: 1 addition & 0 deletions src/exports/elements/tip-tap-editor-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ export class TipTapEditorBase extends BaseElement {
}

super.updated(changedProperties);
this.dispatchEvent(new Event("rhino-update", { bubbles: true, composed: true, cancelable: false }))
}

/** Used for registering things like <role-toolbar>, <role-tooltip>, <rhino-attachment-editor> */
Expand Down
8 changes: 4 additions & 4 deletions src/exports/elements/tip-tap-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ import RoleAnchoredRegion from "role-components/exports/components/anchored-regi
* @slot toolbar-end
*
* ## Events
* @bubble-menu-show
* @bubble-menu-hide
* @rhino-bubble-menu-show
* @rhino-bubble-menu-hide
*/
export class TipTapEditor extends TipTapEditorBase {
static get styles() {
Expand Down Expand Up @@ -1353,12 +1353,12 @@ export class TipTapEditor extends TipTapEditorBase {
return html`
<role-anchored-region
part="bubble-menu__anchored-region"
@bubble-menu-show=${(e: Event & { clientRect: () => DOMRect }) => {
@rhino-bubble-menu-show=${(e: Event & { clientRect: () => DOMRect }) => {
const self = e.currentTarget as RoleAnchoredRegion;
self.anchor = { getBoundingClientRect: e.clientRect };
self.active = true;
}}
@bubble-menu-hide=${(e: Event) => {
@rhino-bubble-menu-hide=${(e: Event) => {
const self = e.currentTarget as RoleAnchoredRegion;
self.anchor = null;
self.active = false;
Expand Down
18 changes: 18 additions & 0 deletions src/exports/events/rhino-update-event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { BaseEvent } from "./base-event.js";

/**
* Fires any time LitElement calls the "updated" function. This is a good event for tracking changes to the editor as it includes both the host Web Component and the underlying TipTap instance.
*/
export class RhinoUpdateEvent extends BaseEvent {
static eventName = "rhino-update" as const;

constructor(options?: EventInit | undefined) {
super(RhinoUpdateEvent.eventName, options);
}
}

declare global {
interface GlobalEventHandlersEventMap {
[RhinoUpdateEvent.eventName]: RhinoUpdateEvent;
}
}
Loading

0 comments on commit c20def6

Please sign in to comment.