Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions plugins/emojis/src/emojis.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,3 @@
width: auto;
display: inline-block;
}


.astrolabe-editor [contenteditable="false"]
span[data-type="inline-spoilers"][data-visible="false"] {
background-color: black;
}

.astrolabe-editor [contenteditable="false"]
span[data-type="inline-spoilers"][data-visible="true"] {
border: 1px dashed black;
}
45 changes: 28 additions & 17 deletions plugins/inline-spoilers/src/Mark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import {
markPasteRule,
mergeAttributes,
} from "@tiptap/core";
import {ReactMarkViewRenderer } from '@tiptap/react';

import { PluginKey } from "@tiptap/pm/state";
import { toggleAttributeOnClick } from "./utils";
import {
toggleAttributeOnClick,
toggleAttributeOnFocusKey
} from "./utils";
import "./inline-spoilers.css";

export interface Options {
visible?: boolean;
focusable?: boolean;
}

export const Key = new PluginKey("InlineSpoilersPlugin");
Expand Down Expand Up @@ -41,43 +45,46 @@ export const Plugin = Mark.create<Options>({
return {
visible: {
default: false,
parseHTML: (element) => (element.getAttribute("data-visible") === 'true'),
parseHTML: (element) => (element.getAttribute("aria-expanded") === 'true'),
renderHTML: (attributes) => {
return {
"data-visible": attributes.visible,
"aria-expanded": attributes.visible,
};
},
},
};
},

addOptions() {
return {
// Editing functions break if you add tabindex=0,
// which we want in the view only state to allow revealing spoilers via keyboard navigation,
// but we can't directly access this.editor in renderHTML so it needs to be set via configuration based on the editor props.
focusable: false,
};
return { };
},

parseHTML() {
return [
{
tag: `span[data-type=${this.name}]`,
tag: `button[data-type=${this.name}]`,
},
];
},

renderHTML({ HTMLAttributes }) {
return [
"span",
"button",
mergeAttributes(HTMLAttributes, {
"data-type": this.name,
"aria-label": "text spoilers",
tabindex: this.options.focusable ? 0 : undefined,
// "title" is used instead of "aria-label" because this way, when the
// spoiler is revealed, it just says it outright instead of repeating
// the "aria-label" value
"title": "Text Spoilers",
"tabindex": this.editor.options.editable ? undefined : 0,
"disabled": this.editor.options.editable ? 0 : undefined,
}),
// This 0 is used to mark where the content is to be inserted (https://tiptap.dev/guide/custom-extensions#render-html)
0,
[
"span",
{},
// This 0 is used to mark where the content is to be inserted (https://tiptap.dev/guide/custom-extensions#render-html)
0,
]
];
},

Expand Down Expand Up @@ -129,7 +136,11 @@ export const Plugin = Mark.create<Options>({
return [
toggleAttributeOnClick({
name: this.name,
attribute: "data-visible",
attribute: "aria-expanded",
}),
toggleAttributeOnFocusKey({
name: this.name,
attribute: "aria-expanded",
}),
];
},
Expand Down
29 changes: 18 additions & 11 deletions plugins/inline-spoilers/src/inline-spoilers.css
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
.astrolabe-editor [contenteditable="true"] span[data-type="inline-spoilers"] {
background-color: lightgray;
border: 1px dashed black;
.astrolabe-editor [contenteditable="true"]
button[data-type="inline-spoilers"] {
all: unset;
background-color: lightgray;
border: 1px dashed black;
}

.astrolabe-editor [contenteditable="false"]
span[data-type="inline-spoilers"][data-visible="false"] {
background-color: black;
color: transparent;
button[data-type="inline-spoilers"] {
all: unset;
outline: revert;
outline-offset: 2px;
}

.astrolabe-editor [contenteditable="false"]
span[data-type="inline-spoilers"][data-visible="false"]::selection {
color:transparent
button[data-type="inline-spoilers"][aria-expanded="false"] {
background-color: oklch(0 0 0);
}
.astrolabe-editor [contenteditable="false"]
button[data-type="inline-spoilers"][aria-expanded="false"] span {
visibility: hidden;
}

.astrolabe-editor [contenteditable="false"]
span[data-type="inline-spoilers"][data-visible="true"] {
border: 1px dashed black;
button[data-type="inline-spoilers"][aria-expanded="true"] {
border: 1px dashed black;
}
52 changes: 52 additions & 0 deletions plugins/inline-spoilers/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,55 @@ export const toggleAttributeOnClick = ({
},
});
};

export const toggleAttributeOnFocusKey = ({
name,
attribute,
}: {
name: string;
attribute: string;
}) => {
return new Plugin({
key: new PluginKey(`update${name}AttributeOnFocusKey`),
props: {
handleDOMEvents: {
keydown(view, event) {
if (view.editable) {
return false;
}

const keyName = event.key
if (keyName !== "Enter" && keyName !== " ") {
return false;
}
console.log(event)
console.log(keyName)

const element = event.target as HTMLElement;
const elementOrParent = getElementOrAncestorWithAttribute(
element,
attribute
);
if (!elementOrParent) {
console.log(
"neither target nor parent has html attribute",
attribute
);
return false;
}
const currentValue = elementOrParent.getAttribute(attribute);
if (!currentValue) {
console.log("elementOrParent attribute has no currentValue");
return false;
}
const newValue = currentValue === "false" ? "true" : "false";
console.log(
`toggling ${name} attribute ${attribute} from ${currentValue} to ${newValue}`
);
elementOrParent.setAttribute(attribute, newValue);
return true;
}
}
},
});
};
Loading