Skip to content

Commit

Permalink
finishing up direct upload stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
KonnorRogers committed Nov 22, 2024
1 parent e430331 commit 242b8da
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 132 deletions.
5 changes: 5 additions & 0 deletions .changeset/lemon-actors-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"rhino-editor": minor
---

Adding a "faux selection" for link insertions to give a visual indicator of insertion / replacement points
5 changes: 5 additions & 0 deletions .changeset/many-poems-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"rhino-editor": patch
---

Fixed a bug around "progress" finishing prematurely
5 changes: 5 additions & 0 deletions .changeset/witty-trainers-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"rhino-editor": patch
---

Fixed a bug with direct upload events not dispatching under the proper name
6 changes: 5 additions & 1 deletion esbuild.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,18 @@ function AppendCssStyles () {

const {
hostStyles,
toolbarButtonStyles
toolbarButtonStyles,
cursorStyles
} = await import(`./src/exports/styles/editor.js?cache=${date.toString()}`)

const finalString = `/* THIS FILE IS AUTO-GENERATED. DO NOT EDIT BY HAND! */
${styles.toString()}
/* src/exports/styles/editor.js:hostStyles */
${hostStyles.toString()}
/* src/exports/styles/editor.js:toolbarButtonStyles */
${cursorStyles.toString()}
/* src/exports/styles/editor.js:toolbarButtonStyles */
${toolbarButtonStyles.toString()}
`
Expand Down
20 changes: 13 additions & 7 deletions src/exports/attachment-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { LOADING_STATES } from "./elements/attachment-editor.js";

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

class AttachmentUploadStartEvent<
export class AttachmentUploadStartEvent<
T extends AttachmentUpload = AttachmentUpload,
> extends BaseEvent {
static eventName = "rhino-direct-upload:start" as const;
Expand All @@ -14,7 +14,7 @@ class AttachmentUploadStartEvent<
public attachmentUpload: T,
options?: EventInit | undefined,
) {
super(AttachmentUploadStartEvent.name, options);
super(AttachmentUploadStartEvent.eventName, options);
this.attachmentUpload = attachmentUpload;
}
}
Expand All @@ -28,7 +28,7 @@ export class AttachmentUploadProgressEvent<
public attachmentUpload: T,
options?: EventInit | undefined,
) {
super(AttachmentUploadProgressEvent.name, options);
super(AttachmentUploadProgressEvent.eventName, options);
this.attachmentUpload = attachmentUpload;
}
}
Expand All @@ -42,7 +42,7 @@ export class AttachmentUploadErrorEvent<
public attachmentUpload: T,
options?: EventInit | undefined,
) {
super(AttachmentUploadErrorEvent.name, options);
super(AttachmentUploadErrorEvent.eventName, options);
this.attachmentUpload = attachmentUpload;
}
}
Expand All @@ -56,7 +56,7 @@ export class AttachmentUploadSucceedEvent<
public attachmentUpload: T,
options?: EventInit | undefined,
) {
super(AttachmentUploadSucceedEvent.name, options);
super(AttachmentUploadSucceedEvent.eventName, options);
this.attachmentUpload = attachmentUpload;
}
}
Expand All @@ -69,7 +69,7 @@ export class AttachmentUploadCompleteEvent<
public attachmentUpload: T,
options?: EventInit | undefined,
) {
super(AttachmentUploadCompleteEvent.name, options);
super(AttachmentUploadCompleteEvent.eventName, options);
this.attachmentUpload = attachmentUpload;
}
}
Expand Down Expand Up @@ -159,21 +159,27 @@ export class AttachmentUpload implements DirectUploadDelegate {
});

// TODO: This may create problems for non-images, could use something like an `<object src="<url>">` instead.
const template = document.createElement("template")
const obj = document.createElement("object");
obj.toggleAttribute("hidden", true)
template.append(obj)

obj.onload = () => {
template.remove()
this.progress = 100;
this.setUploadProgress();
this.element.dispatchEvent(new AttachmentUploadSucceedEvent(this));
this.element.dispatchEvent(new AttachmentUploadCompleteEvent(this));
};

obj.onerror = () => {
template.remove()
this.handleError();
};

// obj.type = new MimeType()
obj.data = blobUrl;
// Needs to append to for onerror / onload to fire.
document.body.append(template)
}

setUploadProgress() {
Expand Down
28 changes: 27 additions & 1 deletion src/exports/elements/tip-tap-editor-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
TemplateResult,
} from "lit";

import { AttachmentUpload } from "../attachment-upload.js";
import { AttachmentUpload, AttachmentUploadCompleteEvent, AttachmentUploadStartEvent } from "../attachment-upload.js";
import { AttachmentManager } from "../attachment-manager.js";

import { normalize } from "../styles/normalize.js";
Expand Down Expand Up @@ -95,6 +95,11 @@ export class TipTapEditorBase extends BaseElement {
*/
hasInitialized = false;

/**
* An array of "AttachmentUploads" added via direct upload. Check this for any attachment uploads that have not completed.
*/
pendingAttachments: AttachmentUpload[] = []

/**
* The hidden input to attach to
*/
Expand Down Expand Up @@ -387,11 +392,32 @@ export class TipTapEditorBase extends BaseElement {
this.registerDependencies();
this.addEventListener(AddAttachmentEvent.eventName, this.handleAttachment);

this.__addPendingAttachment = this.__addPendingAttachment.bind(this)
this.__removePendingAttachment = this.__removePendingAttachment.bind(this)

this.addEventListener(AttachmentUploadStartEvent.eventName, this.__addPendingAttachment)
this.addEventListener(AttachmentUploadCompleteEvent.eventName, this.__removePendingAttachment)

this.addEventListener("drop", this.handleNativeDrop);
this.addEventListener("rhino-paste", this.handlePaste);
this.addEventListener("rhino-file-accept", this.handleFileAccept);
}

__addPendingAttachment (e: { attachmentUpload: AttachmentUpload }) {
this.pendingAttachments.push(e.attachmentUpload)
}

__removePendingAttachment (e: { attachmentUpload: AttachmentUpload }) {
const index = this.pendingAttachments.findIndex((attachment) => {
return attachment === e.attachmentUpload
})

console.log("complete")
if (index > -1) {
this.pendingAttachments.splice(index, 1)
}
}

async connectedCallback(): Promise<void> {
super.connectedCallback();

Expand Down
2 changes: 1 addition & 1 deletion src/exports/extensions/attachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ export const Attachment = Node.create<AttachmentOptions>({
file-name=${fileName || ""}
file-size=${String(fileSize || 0)}
loading-state=${loadingState || LOADING_STATES.notStarted}
progress=${String(sgid || content || !fileSize ? 100 : progress)}
progress=${String(progress ? progress : (sgid || content || !fileSize ? 100 : progress))}
contenteditable="false"
?show-metadata=${isPreviewable}
.fileUploadErrorMessage=${this.options.fileUploadErrorMessage}
Expand Down
5 changes: 3 additions & 2 deletions src/exports/extensions/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ const selectionPlugin = (options: RhinoSelectionOptions) => {

set = set.remove(set.find());

// Whether selection was explicitly updated by this transaction.
// if (!tr.selectionSet) {
// return set
// }

// Whether selection was explicitly updated by this transaction.
const { doc, selection } = tr;

let deco: Decoration | null = null;
Expand All @@ -38,7 +38,8 @@ const selectionPlugin = (options: RhinoSelectionOptions) => {
} else {
// Show a fake cursor.
let widget = document.createElement("placeholder");
widget.setAttribute("class", "fake-cursor-selection");
// TODO: Make this configurable.
widget.setAttribute("class", "rhino-fake-cursor-selection");
widget.setAttribute("readonly", "");
widget.setAttribute("contenteditable", "false");
deco = Decoration.widget(selection.to, widget, {});
Expand Down
67 changes: 67 additions & 0 deletions src/exports/styles/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,73 @@ export const hostStyles = css`
}
`;

// TODO: Should these cursor styles be made a separate CSS files? I worry about having too many external stylesheets, but I know some users are not using `trix.css` and will miss out on these.
export const cursorStyles = css`
/**
* Cursor styles that are useful for providing a more "pleasant" editor experience.
*/
/**
* https://github.com/curvenote/editor/blob/main/packages/prosemirror-codemark/src/codemark.css
*/
@keyframes rhino-blink {
49% {
border-color: unset;
}
50% {
border-color: Canvas;
}
99% {
border-color: Canvas;
}
}
.rhino-editor .no-cursor {
caret-color: transparent;
}
:where(.rhino-editor) .fake-cursor {
margin: 0;
padding: 0;
margin-right: -1px;
border-left-width: 1px;
border-left-style: solid;
animation: rhino-blink 1s;
animation-iteration-count: infinite;
position: relative;
z-index: 1;
}
/** This is for actual "selection" which are highlighting more than 1 character. */
:where(.rhino-editor .ProseMirror):not(:focus-within) .rhino-selection {
background: var(--rhino-fake-selection-color);
}
/** .fake-cursor-selection is for link "insertions" without selected text. */
:where(.rhino-editor) .rhino-fake-cursor-selection {
display: none;
user-select: none;
}
/**
This is used for showing a fake cursor for selections like link insertions
*/
:where(.rhino-editor)[link-dialog-expanded] .rhino-fake-cursor-selection {
margin: 0;
padding: 0;
margin-right: -1px;
margin-left: -2px;
border-left-width: 4px;
border-left-style: solid;
border-color: Highlight;
position: relative;
z-index: 1;
display: inline;
}
.ProseMirror-separator {
display: none !important;
}
`

export const toolbarButtonStyles = css`
.rhino-toolbar-button {
appearance: none;
Expand Down
60 changes: 0 additions & 60 deletions src/exports/styles/trix-core.css
Original file line number Diff line number Diff line change
@@ -1,66 +1,6 @@
/* These all come from Trix / ActionText. This should probably be cleaned up into
a regular .css for users to include.
*/
/* @import "prosemirror-codemark/dist/codemark.css"; */

/**
* https://github.com/curvenote/editor/blob/main/packages/prosemirror-codemark/src/codemark.css
*/
@keyframes rhino-blink {
49% {
border-color: unset;
}
50% {
border-color: Canvas;
}
99% {
border-color: Canvas;
}
}
.rhino-editor .no-cursor {
caret-color: transparent;
}

.ProseMirror:not(:focus-within) .rhino-selection {
background: var(--rhino-fake-selection-color);
}

.rhino-editor .fake-cursor {
margin: 0;
padding: 0;
margin-right: -1px;
border-left-width: 1px;
border-left-style: solid;
animation: rhino-blink 1s;
animation-iteration-count: infinite;
position: relative;
z-index: 1;
}

.ProseMirror .fake-cursor-selection {
display: none;
user-select: none;
}

/**
This is used for showing a fake cursor for selections like link insertions
*/
.ProseMirror:not(:focus-within) .fake-cursor-selection {
margin: 0;
padding: 0;
margin-right: -2px;
margin-left: -2px;
border-left-width: 4px;
border-left-style: solid;
border-color: Highlight;
position: relative;
z-index: 1;
display: inline;
}

.ProseMirror-separator {
display: none !important;
}

.trix-content {
border: 1px solid var(--rhino-border-color);
Expand Down
Loading

0 comments on commit 242b8da

Please sign in to comment.