Skip to content

Commit f4c64a7

Browse files
authored
fix bubble menu, add extensions, fix default styles (#205)
* fix bubble menu, add extensions, fix default styles * prettier * add changelog notE * add defer-initialize attribute * changelog * changelog * implement retry * get greedy, try additional test with retry * get greedy, try additional test with retry
1 parent 07efbb8 commit f4c64a7

File tree

17 files changed

+345
-116
lines changed

17 files changed

+345
-116
lines changed

.changeset/long-snails-hunt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"rhino-editor": patch
3+
---
4+
5+
Bug fix: bubble menu will now anchor the `<figcaption>` or an attachment.

.changeset/nine-deers-accept.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"rhino-editor": patch
3+
---
4+
5+
Style fix: attachments without previews no longer have weird empty border lines

.changeset/nine-turtles-teach.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"rhino-editor": minor
3+
---
4+
5+
Feature: Added the `determineNodeViewAnchor` to the bubble menu extension

.changeset/serious-hairs-knock.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"rhino-editor": patch
3+
---
4+
5+
Bug Fix: no longer generate an empty `<img>` for non-previewable attachments.

.changeset/tricky-years-wave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"rhino-editor": minor
3+
---
4+
5+
Feature: Add the `defer-initialize` attribute for more reliable initialization events.

docs/src/_documentation/references/04-modifying-the-editor.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ There are 3 general ways to wait for RhinoEditor to connect to the DOM and then
99
- `rhino-initialize` - `<rhino-editor>` after the TipTap instance is created
1010
- `customElements.whenDefined("rhino-editor").then(() => { document.querySelectorAll("rhino-editor") })` This is a general purpose callback you can use. The TipTap instance more or may not created when this is called.
1111

12+
<%= render Alert.new(type: :info) do %>
13+
If you are having trouble catching the `rhino-initialize` or the `rhino-before-initialize` events read the section on [Delaying Initialization](#delaying-initialization)
14+
<% end %>
15+
1216
You can use any of these events to modify the editor options. Heres an example for each one to add
1317
additional heading levels.
1418

@@ -42,3 +46,22 @@ customElements.whenDefined("rhino-editor").then(() => {
4246
})
4347
```
4448

49+
## Delaying Initialization
50+
51+
Sometimes it can be quite challenging to catch either the `rhino-initialize` or `rhino-before-initialize` events due to load order of your JavaScript.
52+
53+
If you add the `defer-initialization` attribute to your editor, the editor will not start until you remove that attribute.
54+
55+
Like so:
56+
57+
```html
58+
<rhino-editor defer-initialize></rhino-editor>
59+
60+
<script type="module">
61+
// Setup your event listeners to modify the editor *before* removing the `defer-initialize` attribute.
62+
document.addEventListener("rhino-before-initialize", () => {})
63+
64+
// The editor will initialize and start the TipTap instance.
65+
document.querySelectorAll("rhino-editor").forEach((el) => el.removeAttribute("defer-initialize"))
66+
</script>
67+
```

docs/src/rhino-editor/exports/styles/trix.css

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"@esm-bundle/chai": "4.3.4-fix.0",
4545
"@open-wc/testing": "^3.2.2",
4646
"@playwright/test": "^1.48.0",
47+
"@types/mocha": "^10.0.9",
4748
"@types/rails__activestorage": "^7.1.1",
4849
"@typescript-eslint/parser": "^6.21.0",
4950
"@web/dev-server": "^0.3.7",

pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/exports/elements/tip-tap-editor-base.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ export class TipTapEditorBase extends BaseElement {
6666
class: { reflect: true },
6767
accept: { reflect: true },
6868
serializer: { reflect: true },
69+
deferInitialize: {
70+
type: Boolean,
71+
attribute: "defer-initialize",
72+
reflect: true,
73+
},
6974

7075
// Properties
7176
editor: { state: true },
@@ -126,6 +131,11 @@ export class TipTapEditorBase extends BaseElement {
126131
*/
127132
extensions: EditorOptions["extensions"] = [];
128133

134+
/**
135+
* When the `defer-initialize` attribute is present, it will wait to start the TipTap editor until the attribute has been removed.
136+
*/
137+
deferInitialize = false;
138+
129139
/**
130140
* @internal
131141
*/
@@ -315,6 +325,10 @@ export class TipTapEditorBase extends BaseElement {
315325
protected willUpdate(
316326
changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>,
317327
): void {
328+
if (changedProperties.has("deferInitialize") && !this.deferInitialize) {
329+
this.startEditor();
330+
}
331+
318332
if (changedProperties.has("class")) {
319333
this.classList.add("rhino-editor");
320334
}
@@ -387,6 +401,12 @@ export class TipTapEditorBase extends BaseElement {
387401

388402
this.classList.add("rhino-editor");
389403

404+
if (!this.deferInitialize) {
405+
this.startEditor();
406+
}
407+
}
408+
409+
async startEditor() {
390410
await this.updateComplete;
391411

392412
setTimeout(() => {

src/exports/elements/tip-tap-editor.ts

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,18 @@ export class TipTapEditor extends TipTapEditorBase {
191191
},
192192
}) as typeof this.starterKitOptions;
193193

194+
document.addEventListener("click", this.__handleLinkDialogClick);
195+
}
196+
197+
/**
198+
* @override
199+
*/
200+
async startEditor() {
201+
await super.startEditor();
202+
194203
if (this.editor) {
195204
this.editor.on("focus", this.closeLinkDialog);
196205
}
197-
198-
document.addEventListener("click", this.__handleLinkDialogClick);
199206
}
200207

201208
disconnectedCallback() {
@@ -256,8 +263,6 @@ export class TipTapEditor extends TipTapEditorBase {
256263
setTimeout(() => {
257264
if (inputElement != null) inputElement.focus();
258265
});
259-
260-
console.log("showing");
261266
}
262267

263268
get linkDialog(): Maybe<HTMLDivElement> {
@@ -332,7 +337,9 @@ export class TipTapEditor extends TipTapEditorBase {
332337
}
333338

334339
renderBoldButton(prefix = "") {
335-
const boldEnabled = Boolean(this.editor?.commands.toggleBold);
340+
const boldEnabled =
341+
this.starterKitOptions.bold !== false ||
342+
Boolean(this.editor?.commands.toggleBold);
336343

337344
if (!boldEnabled) return html``;
338345

@@ -384,7 +391,9 @@ export class TipTapEditor extends TipTapEditorBase {
384391
}
385392

386393
renderItalicButton(prefix = "") {
387-
const italicEnabled = Boolean(this.editor?.commands.toggleItalic);
394+
const italicEnabled =
395+
this.starterKitOptions.italic !== false ||
396+
Boolean(this.editor?.commands.toggleItalic);
388397

389398
if (!italicEnabled) return html``;
390399

@@ -440,7 +449,9 @@ export class TipTapEditor extends TipTapEditorBase {
440449
}
441450

442451
renderStrikeButton(prefix = "") {
443-
const strikeEnabled = Boolean(this.editor?.commands.toggleStrike);
452+
const strikeEnabled =
453+
this.starterKitOptions.rhinoStrike !== false ||
454+
Boolean(this.editor?.commands.toggleStrike);
444455

445456
if (!strikeEnabled) return html``;
446457

@@ -495,7 +506,9 @@ export class TipTapEditor extends TipTapEditorBase {
495506
}
496507

497508
renderLinkButton(prefix = "") {
498-
const linkEnabled = Boolean(this.editor?.commands.setLink);
509+
const linkEnabled =
510+
this.starterKitOptions.rhinoLink !== false ||
511+
Boolean(this.editor?.commands.setLink);
499512

500513
if (!linkEnabled) return html``;
501514

@@ -553,7 +566,9 @@ export class TipTapEditor extends TipTapEditorBase {
553566
}
554567

555568
renderHeadingButton(prefix = "") {
556-
const headingEnabled = Boolean(this.editor?.commands.toggleHeading);
569+
const headingEnabled =
570+
this.starterKitOptions.heading !== false ||
571+
Boolean(this.editor?.commands.toggleHeading);
557572

558573
if (!headingEnabled) return html``;
559574

@@ -610,7 +625,9 @@ export class TipTapEditor extends TipTapEditorBase {
610625
}
611626

612627
renderBlockquoteButton(prefix = "") {
613-
const blockQuoteEnabled = Boolean(this.editor?.commands.toggleBlockquote);
628+
const blockQuoteEnabled =
629+
this.starterKitOptions.blockquote !== false ||
630+
Boolean(this.editor?.commands.toggleBlockquote);
614631

615632
if (!blockQuoteEnabled) return html``;
616633

@@ -667,7 +684,9 @@ export class TipTapEditor extends TipTapEditorBase {
667684
}
668685

669686
renderCodeBlockButton(prefix = "") {
670-
const codeBlockEnabled = Boolean(this.editor?.commands.toggleCodeBlock);
687+
const codeBlockEnabled =
688+
this.starterKitOptions.codeBlock !== false ||
689+
Boolean(this.editor?.commands.toggleCodeBlock);
671690

672691
if (!codeBlockEnabled) return html``;
673692

@@ -723,7 +742,9 @@ export class TipTapEditor extends TipTapEditorBase {
723742
}
724743

725744
renderBulletListButton(prefix = "") {
726-
const bulletListEnabled = Boolean(this.editor?.commands.toggleBulletList);
745+
const bulletListEnabled =
746+
this.starterKitOptions.bulletList !== false ||
747+
Boolean(this.editor?.commands.toggleBulletList);
727748

728749
if (!bulletListEnabled) return html``;
729750

@@ -786,7 +807,9 @@ export class TipTapEditor extends TipTapEditorBase {
786807
}
787808

788809
renderOrderedListButton(prefix = "") {
789-
const orderedListEnabled = Boolean(this.editor?.commands.toggleOrderedList);
810+
const orderedListEnabled =
811+
this.starterKitOptions.orderedList !== false ||
812+
Boolean(this.editor?.commands.toggleOrderedList);
790813

791814
if (!orderedListEnabled) return html``;
792815

@@ -851,7 +874,9 @@ export class TipTapEditor extends TipTapEditorBase {
851874
}
852875

853876
renderAttachmentButton(prefix = "") {
854-
const attachmentEnabled = Boolean(this.editor?.commands.setAttachment);
877+
const attachmentEnabled =
878+
this.starterKitOptions.rhinoAttachment !== false ||
879+
Boolean(this.editor?.commands.setAttachment);
855880

856881
if (!attachmentEnabled) return html``;
857882

@@ -912,7 +937,9 @@ export class TipTapEditor extends TipTapEditorBase {
912937
}
913938

914939
renderUndoButton(prefix = "") {
915-
const undoEnabled = Boolean(this.editor?.commands.undo);
940+
const undoEnabled =
941+
this.starterKitOptions.history !== false ||
942+
Boolean(this.editor?.commands.undo);
916943

917944
if (!undoEnabled) return html``;
918945

@@ -966,10 +993,10 @@ export class TipTapEditor extends TipTapEditorBase {
966993
renderDecreaseIndentation(prefix = "") {
967994
// Decrease / increase indentation are special cases in that they rely on built-in editor
968995
// commands and not commands added by extensions.
969-
const decreaseIndentationNotEnabled =
970-
this.starterKitOptions.decreaseIndentation == false;
996+
const decreaseIndentationEnabled =
997+
this.starterKitOptions.decreaseIndentation !== false; // || Boolean(this.editor?.commands.liftListItem);
971998

972-
if (decreaseIndentationNotEnabled) return html``;
999+
if (!decreaseIndentationEnabled) return html``;
9731000

9741001
const isDisabled =
9751002
this.editor == null || !this.editor.can().liftListItem("listItem");
@@ -1021,10 +1048,12 @@ export class TipTapEditor extends TipTapEditorBase {
10211048
}
10221049

10231050
renderIncreaseIndentation(prefix = "") {
1024-
const increaseIndentationNotEnabled =
1025-
this.starterKitOptions.increaseIndentation == false;
1051+
// Decrease / increase indentation are special cases in that they rely on built-in editor
1052+
// commands and not commands added by extensions.
1053+
const increaseIndentationEnabled =
1054+
this.starterKitOptions.increaseIndentation !== false; // || Boolean(this.editor?.commands.sinkListItem);
10261055

1027-
if (increaseIndentationNotEnabled) return html``;
1056+
if (!increaseIndentationEnabled) return html``;
10281057

10291058
const isDisabled =
10301059
this.editor == null || !this.editor.can().sinkListItem("listItem");
@@ -1076,7 +1105,9 @@ export class TipTapEditor extends TipTapEditorBase {
10761105
}
10771106

10781107
renderRedoButton(prefix = "") {
1079-
const redoEnabled = Boolean(this.editor?.commands.redo);
1108+
const redoEnabled =
1109+
this.starterKitOptions.history !== false ||
1110+
Boolean(this.editor?.commands.redo);
10801111

10811112
if (!redoEnabled) return html``;
10821113

src/exports/extensions/attachment.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -756,22 +756,26 @@ export const Attachment = Node.create<AttachmentOptions>({
756756
</rhino-attachment-editor>
757757
758758
${when(
759-
content && !isPreviewable,
759+
content,
760760
/* This is really not great. This is how Trix does it, but it feels very unsafe.
761761
https://github.com/basecamp/trix/blob/fda14c5ae88a0821cf8999a53dcb3572b4172cf0/src/trix/views/attachment_view.js#L36
762762
*/
763763
() => html`${unsafeHTML(content)}`,
764-
() => html`
765-
<img
764+
() => html``,
765+
)}
766+
${when(
767+
isPreviewable && !content,
768+
() =>
769+
html` <img
766770
class=${loadingState === LOADING_STATES.error
767771
? "rhino-upload-error"
768772
: ""}
769773
width=${String(width)}
770774
height=${String(height)}
771775
src=${ifDefined(imgSrc)}
772776
contenteditable="false"
773-
/>
774-
`,
777+
/>`,
778+
() => html``,
775779
)}
776780
777781
<figcaption

0 commit comments

Comments
 (0)