1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-12-19 10:42:29 +03:00

Esbuild & Mentions: Updated interaction stability and build system

- Updated esbuild system to be module, and fixed build command.
- Reverted module use in package.json by default as this impacted test
  runs/files.
- Updated mention user select:
  - To look better in dark mode.
  - To not remove text after on select.
  - To properly revert/restore focus on enter or cancel.
This commit is contained in:
Dan Brown
2025-12-17 21:11:01 +00:00
parent 3d9aba7b1f
commit 90fc02c57f
7 changed files with 38 additions and 13 deletions

View File

@@ -5,7 +5,6 @@ import * as path from 'node:path';
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as process from "node:process"; import * as process from "node:process";
// Check if we're building for production // Check if we're building for production
// (Set via passing `production` as first argument) // (Set via passing `production` as first argument)
const mode = process.argv[2]; const mode = process.argv[2];
@@ -76,7 +75,13 @@ if (mode === 'watch') {
}); });
} else { } else {
// Build with meta output for analysis // Build with meta output for analysis
ctx.rebuild().then(result => { const result = await ctx.rebuild();
const outputs = result.metafile.outputs;
const files = Object.keys(outputs);
for (const file of files) {
const output = outputs[file];
console.log(`Written: ${file} @ ${Math.round(output.bytes / 1000)}kB`);
}
fs.writeFileSync('esbuild-meta.json', JSON.stringify(result.metafile)); fs.writeFileSync('esbuild-meta.json', JSON.stringify(result.metafile));
}).catch(() => process.exit(1)); process.exit(0);
} }

View File

@@ -1,13 +1,12 @@
{ {
"private": true, "private": true,
"type": "module",
"scripts": { "scripts": {
"build:css:dev": "sass ./resources/sass:./public/dist --embed-sources", "build:css:dev": "sass ./resources/sass:./public/dist --embed-sources",
"build:css:watch": "sass ./resources/sass:./public/dist --watch --embed-sources", "build:css:watch": "sass ./resources/sass:./public/dist --watch --embed-sources",
"build:css:production": "sass ./resources/sass:./public/dist -s compressed", "build:css:production": "sass ./resources/sass:./public/dist -s compressed",
"build:js:dev": "node dev/build/esbuild.js", "build:js:dev": "node dev/build/esbuild.mjs",
"build:js:watch": "node dev/build/esbuild.js watch", "build:js:watch": "node dev/build/esbuild.mjs watch",
"build:js:production": "node dev/build/esbuild.js production", "build:js:production": "node dev/build/esbuild.mjs production",
"build": "npm-run-all --parallel build:*:dev", "build": "npm-run-all --parallel build:*:dev",
"production": "npm-run-all --parallel build:*:production", "production": "npm-run-all --parallel build:*:production",
"dev": "npm-run-all --parallel build:*:watch", "dev": "npm-run-all --parallel build:*:watch",

View File

@@ -151,8 +151,6 @@ export function createCommentEditorInstance(container: HTMLElement, htmlContent:
theme: theme, theme: theme,
}); });
// TODO - Dedupe this with the basic editor instance
// Changed elements: namespace, registerMentions, toolbar, public event usage, mentioned decorator
const context: EditorUiContext = buildEditorUI(container, editor, options); const context: EditorUiContext = buildEditorUI(container, editor, options);
editor.setRootElement(context.editorDOM); editor.setRootElement(context.editorDOM);

View File

@@ -6,6 +6,7 @@ import {KEY_AT_COMMAND} from "lexical/LexicalCommands";
import {$createMentionNode, $isMentionNode, MentionNode} from "@lexical/link/LexicalMentionNode"; import {$createMentionNode, $isMentionNode, MentionNode} from "@lexical/link/LexicalMentionNode";
import {EditorUiContext} from "../ui/framework/core"; import {EditorUiContext} from "../ui/framework/core";
import {MentionDecorator} from "../ui/decorators/MentionDecorator"; import {MentionDecorator} from "../ui/decorators/MentionDecorator";
import {$selectSingleNode} from "../utils/selection";
function enterUserSelectMode(context: EditorUiContext, selection: RangeSelection) { function enterUserSelectMode(context: EditorUiContext, selection: RangeSelection) {
@@ -25,10 +26,13 @@ function enterUserSelectMode(context: EditorUiContext, selection: RangeSelection
} }
const split = textNode.splitText(offset); const split = textNode.splitText(offset);
const newNode = split[atStart ? 0 : 1]; const priorTextNode = split[0];
const afterTextNode = split[atStart ? 0 : 1];
const mention = $createMentionNode(0, '', ''); const mention = $createMentionNode(0, '', '');
newNode.replace(mention); priorTextNode.insertAfter(mention);
afterTextNode.spliceText(0, 1, '', false);
$selectSingleNode(mention);
requestAnimationFrame(() => { requestAnimationFrame(() => {
const mentionDecorator = context.manager.getDecoratorByNodeKey(mention.getKey()); const mentionDecorator = context.manager.getDecoratorByNodeKey(mention.getKey());

View File

@@ -170,14 +170,24 @@ export class MentionDecorator extends EditorDecorator {
this.dropdownContainer?.remove(); this.dropdownContainer?.remove();
this.abortController = null; this.abortController = null;
this.dropdownContainer = null; this.dropdownContainer = null;
this.context.manager.focus();
} }
revertMention() { revertMention() {
this.hideSelection(); this.hideSelection();
this.context.editor.update(() => { this.context.editor.update(() => {
const text = $createTextNode('@'); const text = $createTextNode('@');
const before = this.getNode().getPreviousSibling();
this.getNode().replace(text); this.getNode().replace(text);
requestAnimationFrame(() => {
this.context.editor.update(() => {
if (text.isAttached()) {
text.selectEnd(); text.selectEnd();
} else if (before?.isAttached()) {
before?.selectEnd();
}
});
});
}); });
} }

View File

@@ -206,6 +206,14 @@ export class EditorUIManager {
} }
} }
/**
* Set the UI focus to the editor.
*/
focus(): void {
this.getContext().editorDOM.focus();
this.getContext().editor.focus();
}
protected updateContextToolbars(update: EditorUiStateUpdate): void { protected updateContextToolbars(update: EditorUiStateUpdate): void {
for (let i = this.activeContextToolbars.length - 1; i >= 0; i--) { for (let i = this.activeContextToolbars.length - 1; i >= 0; i--) {
const toolbar = this.activeContextToolbars[i]; const toolbar = this.activeContextToolbars[i];

View File

@@ -985,6 +985,7 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
font-size: 0.8rem; font-size: 0.8rem;
&:hover,&:focus { &:hover,&:focus {
background-color: #F2F2F2; background-color: #F2F2F2;
@include mixins.lightDark(background-color, #F2F2F2, #444);
text-decoration: none; text-decoration: none;
} }
} }