mirror of
https://github.com/zadam/trilium.git
synced 2026-07-28 04:30:55 +02:00
refactor: show only modified lines
This commit is contained in:
@@ -1,39 +1,19 @@
|
||||
import {
|
||||
AttributeEditor as CKEditorAttributeEditor,
|
||||
MentionFeed,
|
||||
ModelElement,
|
||||
ModelNode,
|
||||
ModelPosition,
|
||||
} from "@triliumnext/ckeditor5";
|
||||
import { AttributeEditor as CKEditorAttributeEditor, MentionFeed, ModelElement, ModelNode, ModelPosition } from "@triliumnext/ckeditor5";
|
||||
import { AttributeType } from "@triliumnext/commons";
|
||||
import { createPortal } from "preact/compat";
|
||||
import {
|
||||
MutableRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "preact/hooks";
|
||||
import { MutableRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from "preact/hooks";
|
||||
|
||||
import type {
|
||||
CommandData,
|
||||
FilteredCommandNames,
|
||||
} from "../../../components/app_context";
|
||||
import type { CommandData, FilteredCommandNames } from "../../../components/app_context";
|
||||
import FAttribute from "../../../entities/fattribute";
|
||||
import FNote from "../../../entities/fnote";
|
||||
import contextMenu from "../../../menus/context_menu";
|
||||
import attribute_parser, {
|
||||
Attribute,
|
||||
} from "../../../services/attribute_parser";
|
||||
import attribute_parser, { Attribute } from "../../../services/attribute_parser";
|
||||
import attribute_renderer from "../../../services/attribute_renderer";
|
||||
import attributes from "../../../services/attributes";
|
||||
import froca from "../../../services/froca";
|
||||
import { t } from "../../../services/i18n";
|
||||
import link from "../../../services/link";
|
||||
import note_autocomplete, {
|
||||
Suggestion,
|
||||
} from "../../../services/note_autocomplete";
|
||||
import note_autocomplete, { Suggestion } from "../../../services/note_autocomplete";
|
||||
import note_create from "../../../services/note_create";
|
||||
import server from "../../../services/server";
|
||||
import { isIMEComposing } from "../../../services/shortcuts";
|
||||
@@ -41,13 +21,7 @@ import { escapeQuotes, getErrorMessage } from "../../../services/utils";
|
||||
import AttributeDetailWidget from "../../attribute_widgets/attribute_detail";
|
||||
import ActionButton from "../../react/ActionButton";
|
||||
import CKEditor, { CKEditorApi } from "../../react/CKEditor";
|
||||
import {
|
||||
useLegacyImperativeHandlers,
|
||||
useLegacyWidget,
|
||||
useTooltip,
|
||||
useTriliumEvent,
|
||||
useTriliumOption,
|
||||
} from "../../react/hooks";
|
||||
import { useLegacyImperativeHandlers, useLegacyWidget, useTooltip, useTriliumEvent, useTriliumOption } from "../../react/hooks";
|
||||
|
||||
type AttributeCommandNames = FilteredCommandNames<CommandData>;
|
||||
|
||||
@@ -61,8 +35,7 @@ const HELP_TEXT = `
|
||||
const mentionSetup: MentionFeed[] = [
|
||||
{
|
||||
marker: "@",
|
||||
feed: (queryText) =>
|
||||
note_autocomplete.autocompleteSourceForCKEditor(queryText),
|
||||
feed: (queryText) => note_autocomplete.autocompleteSourceForCKEditor(queryText),
|
||||
itemRenderer: (_item) => {
|
||||
const item = _item as Suggestion;
|
||||
const itemElement = document.createElement("button");
|
||||
@@ -71,42 +44,39 @@ const mentionSetup: MentionFeed[] = [
|
||||
|
||||
return itemElement;
|
||||
},
|
||||
minimumCharacters: 0,
|
||||
minimumCharacters: 0
|
||||
},
|
||||
{
|
||||
marker: "#",
|
||||
feed: async (queryText) => {
|
||||
const names = await server.get<string[]>(
|
||||
`attribute-names/?type=label&query=${encodeURIComponent(queryText)}`,
|
||||
);
|
||||
const names = await server.get<string[]>(`attribute-names/?type=label&query=${encodeURIComponent(queryText)}`);
|
||||
|
||||
return names.map((name) => {
|
||||
return {
|
||||
id: `#${name}`,
|
||||
name,
|
||||
name
|
||||
};
|
||||
});
|
||||
},
|
||||
minimumCharacters: 0,
|
||||
minimumCharacters: 0
|
||||
},
|
||||
{
|
||||
marker: "~",
|
||||
feed: async (queryText) => {
|
||||
const names = await server.get<string[]>(
|
||||
`attribute-names/?type=relation&query=${encodeURIComponent(queryText)}`,
|
||||
);
|
||||
const names = await server.get<string[]>(`attribute-names/?type=relation&query=${encodeURIComponent(queryText)}`);
|
||||
|
||||
return names.map((name) => {
|
||||
return {
|
||||
id: `~${name}`,
|
||||
name,
|
||||
name
|
||||
};
|
||||
});
|
||||
},
|
||||
minimumCharacters: 0,
|
||||
},
|
||||
minimumCharacters: 0
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
interface AttributeEditorProps {
|
||||
api: MutableRef<AttributeEditorImperativeHandlers | null>;
|
||||
note: FNote;
|
||||
@@ -123,39 +93,29 @@ export interface AttributeEditorImperativeHandlers {
|
||||
renderOwnedAttributes(ownedAttributes: FAttribute[]): Promise<void>;
|
||||
}
|
||||
|
||||
export default function AttributeEditor({
|
||||
api,
|
||||
note,
|
||||
componentId,
|
||||
notePath,
|
||||
ntxId,
|
||||
hidden,
|
||||
}: AttributeEditorProps) {
|
||||
const [currentValue, setCurrentValue] = useState("");
|
||||
const [state, setState] = useState<
|
||||
"normal" | "showHelpTooltip" | "showAttributeDetail"
|
||||
>();
|
||||
const [error, setError] = useState<unknown>();
|
||||
const [needsSaving, setNeedsSaving] = useState(false);
|
||||
export default function AttributeEditor({ api, note, componentId, notePath, ntxId, hidden }: AttributeEditorProps) {
|
||||
const [ currentValue, setCurrentValue ] = useState("");
|
||||
const [ state, setState ] = useState<"normal" | "showHelpTooltip" | "showAttributeDetail">();
|
||||
const [ error, setError ] = useState<unknown>();
|
||||
const [ needsSaving, setNeedsSaving ] = useState(false);
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const suppressNextOnHide = useRef(false);
|
||||
|
||||
const lastSavedContent = useRef<string>();
|
||||
const currentValueRef = useRef(currentValue);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
const editorRef = useRef<CKEditorApi>();
|
||||
const [locale] = useTriliumOption("locale");
|
||||
const [ locale ] = useTriliumOption("locale");
|
||||
|
||||
const { showTooltip, hideTooltip } = useTooltip(wrapperRef, {
|
||||
trigger: "focus",
|
||||
html: true,
|
||||
title: HELP_TEXT,
|
||||
placement: "bottom",
|
||||
offset: "0,30",
|
||||
offset: "0,30"
|
||||
});
|
||||
|
||||
const [attributeDetailWidgetEl, attributeDetailWidget] = useLegacyWidget(
|
||||
() => new AttributeDetailWidget(),
|
||||
);
|
||||
const [ attributeDetailWidgetEl, attributeDetailWidget ] = useLegacyWidget(() => new AttributeDetailWidget());
|
||||
|
||||
useEffect(() => {
|
||||
if (state === "showHelpTooltip") {
|
||||
@@ -163,16 +123,13 @@ export default function AttributeEditor({
|
||||
} else {
|
||||
hideTooltip();
|
||||
}
|
||||
}, [state]);
|
||||
}, [ state ]);
|
||||
|
||||
async function renderOwnedAttributes(
|
||||
ownedAttributes: FAttribute[],
|
||||
saved: boolean,
|
||||
) {
|
||||
async function renderOwnedAttributes(ownedAttributes: FAttribute[], saved: boolean) {
|
||||
// attrs are not resorted if position changes after the initial load
|
||||
ownedAttributes.sort((a, b) => a.position - b.position);
|
||||
|
||||
let htmlAttrs = `<p>${(await attribute_renderer.renderAttributes(ownedAttributes, true)).html()}</p>`;
|
||||
let htmlAttrs = (`<p>${(await attribute_renderer.renderAttributes(ownedAttributes, true)).html()}</p>`);
|
||||
|
||||
if (saved) {
|
||||
lastSavedContent.current = htmlAttrs;
|
||||
@@ -189,9 +146,7 @@ export default function AttributeEditor({
|
||||
|
||||
function parseAttributes() {
|
||||
try {
|
||||
return attribute_parser.lexAndParse(
|
||||
getPreprocessedData(currentValueRef.current),
|
||||
);
|
||||
return attribute_parser.lexAndParse(getPreprocessedData(currentValueRef.current));
|
||||
} catch (e: unknown) {
|
||||
setError(e);
|
||||
}
|
||||
@@ -204,11 +159,7 @@ export default function AttributeEditor({
|
||||
return;
|
||||
}
|
||||
|
||||
await server.put(
|
||||
`notes/${note.noteId}/attributes`,
|
||||
attributes,
|
||||
componentId,
|
||||
);
|
||||
await server.put(`notes/${note.noteId}/attributes`, attributes, componentId);
|
||||
setNeedsSaving(false);
|
||||
|
||||
// blink the attribute text to give a visual hint that save has been executed
|
||||
@@ -222,9 +173,7 @@ export default function AttributeEditor({
|
||||
}
|
||||
}
|
||||
|
||||
async function handleAddNewAttributeCommand(
|
||||
command: AttributeCommandNames | undefined,
|
||||
) {
|
||||
async function handleAddNewAttributeCommand(command: AttributeCommandNames | undefined) {
|
||||
// TODO: Not sure what the relation between FAttribute[] and Attribute[] is.
|
||||
const attrs = parseAttributes() as FAttribute[];
|
||||
|
||||
@@ -261,7 +210,7 @@ export default function AttributeEditor({
|
||||
type,
|
||||
name,
|
||||
value,
|
||||
isInheritable: false,
|
||||
isInheritable: false
|
||||
});
|
||||
|
||||
await renderOwnedAttributes(attrs, false);
|
||||
@@ -277,7 +226,7 @@ export default function AttributeEditor({
|
||||
isOwned: true,
|
||||
x: rect ? (rect.left + rect.right) / 2 : 0,
|
||||
y: rect?.bottom ?? 0,
|
||||
focus: "name",
|
||||
focus: "name"
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
@@ -287,51 +236,34 @@ export default function AttributeEditor({
|
||||
renderOwnedAttributes(note.getOwnedAttributes(), true);
|
||||
}
|
||||
|
||||
useEffect(() => refresh(), [note]);
|
||||
useEffect(() => refresh(), [ note ]);
|
||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||
if (
|
||||
loadResults
|
||||
.getAttributeRows(componentId)
|
||||
.find((attr) => attributes.isAffecting(attr, note))
|
||||
) {
|
||||
if (loadResults.getAttributeRows(componentId).find((attr) => attributes.isAffecting(attr, note))) {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
|
||||
// Interaction with CKEditor.
|
||||
useLegacyImperativeHandlers(
|
||||
useMemo(
|
||||
() => ({
|
||||
loadReferenceLinkTitle: async (
|
||||
$el: JQuery<HTMLElement>,
|
||||
href: string,
|
||||
) => {
|
||||
const { noteId } = link.parseNavigationStateFromUrl(href);
|
||||
const note = noteId
|
||||
? await froca.getNote(noteId, true)
|
||||
: null;
|
||||
const title = note ? note.title : "[missing]";
|
||||
useLegacyImperativeHandlers(useMemo(() => ({
|
||||
loadReferenceLinkTitle: async ($el: JQuery<HTMLElement>, href: string) => {
|
||||
const { noteId } = link.parseNavigationStateFromUrl(href);
|
||||
const note = noteId ? await froca.getNote(noteId, true) : null;
|
||||
const title = note ? note.title : "[missing]";
|
||||
|
||||
$el.text(title);
|
||||
},
|
||||
createNoteForReferenceLink: async (title: string) => {
|
||||
let result;
|
||||
if (notePath) {
|
||||
result = await note_create.createNoteWithTypePrompt(
|
||||
notePath,
|
||||
{
|
||||
activate: false,
|
||||
title,
|
||||
},
|
||||
);
|
||||
}
|
||||
$el.text(title);
|
||||
},
|
||||
createNoteForReferenceLink: async (title: string) => {
|
||||
let result;
|
||||
if (notePath) {
|
||||
result = await note_create.createNoteWithTypePrompt(notePath, {
|
||||
activate: false,
|
||||
title
|
||||
});
|
||||
}
|
||||
|
||||
return result?.note?.getBestNotePathString();
|
||||
},
|
||||
}),
|
||||
[notePath],
|
||||
),
|
||||
);
|
||||
return result?.note?.getBestNotePathString();
|
||||
}
|
||||
}), [ notePath ]));
|
||||
|
||||
// Keyboard shortcuts
|
||||
useTriliumEvent("addNewLabel", ({ ntxId: eventNtxId }) => {
|
||||
@@ -344,217 +276,135 @@ export default function AttributeEditor({
|
||||
});
|
||||
|
||||
// Imperative API
|
||||
useImperativeHandle(
|
||||
api,
|
||||
() => ({
|
||||
save,
|
||||
refresh,
|
||||
renderOwnedAttributes: (attributes) =>
|
||||
renderOwnedAttributes(attributes as FAttribute[], false),
|
||||
focus: () => editorRef.current?.focus(),
|
||||
}),
|
||||
[save, refresh, renderOwnedAttributes],
|
||||
);
|
||||
useImperativeHandle(api, () => ({
|
||||
save,
|
||||
refresh,
|
||||
renderOwnedAttributes: (attributes) => renderOwnedAttributes(attributes as FAttribute[], false),
|
||||
focus: () => editorRef.current?.focus()
|
||||
}), [ save, refresh, renderOwnedAttributes ]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{!hidden && (
|
||||
<div
|
||||
className="attribute-list-editor-wrapper"
|
||||
ref={wrapperRef}
|
||||
style="position: relative; padding-top: 10px; padding-bottom: 10px"
|
||||
onKeyDown={(e) => {
|
||||
// Skip processing during IME composition
|
||||
if (isIMEComposing(e)) {
|
||||
return;
|
||||
}
|
||||
{!hidden && <div
|
||||
className="attribute-list-editor-wrapper"
|
||||
ref={wrapperRef}
|
||||
style="position: relative; padding-top: 10px; padding-bottom: 10px"
|
||||
onKeyDown={(e) => {
|
||||
// Skip processing during IME composition
|
||||
if (isIMEComposing(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.key === "Enter") {
|
||||
// allow autocomplete to fill the result textarea
|
||||
setTimeout(() => save(), 100);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
<div style="position: relative;">
|
||||
<CKEditor
|
||||
apiRef={editorRef}
|
||||
className="attribute-list-editor"
|
||||
tabIndex={200}
|
||||
editor={CKEditorAttributeEditor}
|
||||
currentValue={currentValue}
|
||||
config={{
|
||||
toolbar: { items: [] },
|
||||
placeholder: t("attribute_editor.placeholder"),
|
||||
mention: { feeds: mentionSetup },
|
||||
licenseKey: "GPL",
|
||||
language: "en",
|
||||
}}
|
||||
onChange={(currentValue) => {
|
||||
currentValueRef.current = currentValue ?? "";
|
||||
if (e.key === "Enter") {
|
||||
// allow autocomplete to fill the result textarea
|
||||
setTimeout(() => save(), 100);
|
||||
}
|
||||
}}
|
||||
> <div style="position: relative;">
|
||||
<CKEditor
|
||||
apiRef={editorRef}
|
||||
className="attribute-list-editor"
|
||||
tabIndex={200}
|
||||
editor={CKEditorAttributeEditor}
|
||||
currentValue={currentValue}
|
||||
config={{
|
||||
toolbar: { items: [] },
|
||||
placeholder: t("attribute_editor.placeholder"),
|
||||
mention: { feeds: mentionSetup },
|
||||
licenseKey: "GPL",
|
||||
language: "en"
|
||||
}}
|
||||
onChange={(currentValue) => {
|
||||
currentValueRef.current = currentValue ?? "";
|
||||
|
||||
const oldValue = getPreprocessedData(
|
||||
lastSavedContent.current ?? "",
|
||||
).trimEnd();
|
||||
const newValue = getPreprocessedData(
|
||||
currentValue ?? "",
|
||||
).trimEnd();
|
||||
setNeedsSaving(oldValue !== newValue);
|
||||
setError(undefined);
|
||||
}}
|
||||
onClick={(e, pos) => {
|
||||
if (pos && pos.textNode && pos.textNode.data) {
|
||||
const clickIndex = getClickIndex(pos);
|
||||
const oldValue = getPreprocessedData(lastSavedContent.current ?? "").trimEnd();
|
||||
const newValue = getPreprocessedData(currentValue ?? "").trimEnd();
|
||||
setNeedsSaving(oldValue !== newValue);
|
||||
setError(undefined);
|
||||
}}
|
||||
// onClick={(e, pos) => {
|
||||
// if (pos && pos.textNode && pos.textNode.data) {
|
||||
// const clickIndex = getClickIndex(pos);
|
||||
|
||||
let parsedAttrs: Attribute[];
|
||||
// let parsedAttrs: Attribute[];
|
||||
|
||||
try {
|
||||
parsedAttrs =
|
||||
attribute_parser.lexAndParse(
|
||||
getPreprocessedData(
|
||||
currentValueRef.current,
|
||||
),
|
||||
true,
|
||||
);
|
||||
} catch (e: unknown) {
|
||||
// the input is incorrect because the user messed up with it and now needs to fix it manually
|
||||
console.log(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
let matchedAttr: Attribute | null = null;
|
||||
|
||||
for (const attr of parsedAttrs) {
|
||||
if (
|
||||
attr.startIndex !== undefined &&
|
||||
clickIndex > attr.startIndex &&
|
||||
attr.endIndex !== undefined &&
|
||||
clickIndex <= attr.endIndex
|
||||
) {
|
||||
matchedAttr = attr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (matchedAttr) {
|
||||
attributeDetailWidget.showAttributeDetail(
|
||||
{
|
||||
allAttributes: parsedAttrs,
|
||||
attribute: matchedAttr,
|
||||
isOwned: true,
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
},
|
||||
);
|
||||
setState("showAttributeDetail");
|
||||
} else {
|
||||
setState("showHelpTooltip");
|
||||
}
|
||||
}, 100);
|
||||
} else {
|
||||
setState("showHelpTooltip");
|
||||
}
|
||||
}}
|
||||
onKeyDown={() => attributeDetailWidget.hide()}
|
||||
onBlur={() => save()}
|
||||
onInitialized={() => editorRef.current?.focus()}
|
||||
disableNewlines
|
||||
disableSpellcheck
|
||||
/>
|
||||
|
||||
<div className="attribute-editor-buttons">
|
||||
{needsSaving && (
|
||||
<ActionButton
|
||||
icon="bx bx-save"
|
||||
className="save-attributes-button tn-tool-button"
|
||||
text={escapeQuotes(
|
||||
t("attribute_editor.save_attributes"),
|
||||
)}
|
||||
onClick={save}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ActionButton
|
||||
icon="bx bx-plus"
|
||||
className="add-new-attribute-button tn-tool-button"
|
||||
text={
|
||||
isMenuOpen
|
||||
? ""
|
||||
: escapeQuotes(t("attribute_editor.add_a_new_attribute"))
|
||||
}
|
||||
|
||||
onClick={(e) => {
|
||||
// Prevent automatic hiding of the context menu due to the button being clicked.
|
||||
e.stopPropagation();
|
||||
if (isMenuOpen) {
|
||||
// If we re-show the menu, ContextMenu.show() will call hide()
|
||||
// and immediately trigger onHide. Suppress that transient hide.
|
||||
suppressNextOnHide.current = true;
|
||||
}
|
||||
setIsMenuOpen(true);
|
||||
// try {
|
||||
// parsedAttrs = attribute_parser.lexAndParse(getPreprocessedData(currentValueRef.current), true);
|
||||
// } catch (e: unknown) {
|
||||
// // the input is incorrect because the user messed up with it and now needs to fix it manually
|
||||
// console.log(e);
|
||||
// return null;
|
||||
// }
|
||||
onClick={(e) => {
|
||||
// Prevent automatic hiding of the context menu due to the button being clicked.
|
||||
e.stopPropagation();
|
||||
if (isMenuOpen) {
|
||||
// If we re-show the menu, ContextMenu.show() will call hide()
|
||||
// and immediately trigger onHide. Suppress that transient hide.
|
||||
suppressNextOnHide.current = true;
|
||||
}
|
||||
setIsMenuOpen(true);
|
||||
|
||||
contextMenu.show<AttributeCommandNames>({
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
orientation: "left",
|
||||
contextMenu.show<AttributeCommandNames>({
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
orientation: "left",
|
||||
|
||||
items: [
|
||||
{
|
||||
title: t(
|
||||
"attribute_editor.add_new_label",
|
||||
),
|
||||
command: "addNewLabel",
|
||||
uiIcon: "bx bx-hash",
|
||||
},
|
||||
{
|
||||
title: t(
|
||||
"attribute_editor.add_new_relation",
|
||||
),
|
||||
command: "addNewRelation",
|
||||
uiIcon: "bx bx-transfer",
|
||||
},
|
||||
{ kind: "separator" },
|
||||
{
|
||||
title: t(
|
||||
"attribute_editor.add_new_label_definition",
|
||||
),
|
||||
command:
|
||||
items: [
|
||||
{
|
||||
title: t(
|
||||
"attribute_editor.add_new_label",
|
||||
),
|
||||
command: "addNewLabel",
|
||||
uiIcon: "bx bx-hash",
|
||||
},
|
||||
{
|
||||
title: t(
|
||||
"attribute_editor.add_new_relation",
|
||||
),
|
||||
command: "addNewRelation",
|
||||
uiIcon: "bx bx-transfer",
|
||||
},
|
||||
{ kind: "separator" },
|
||||
{
|
||||
title: t(
|
||||
"attribute_editor.add_new_label_definition",
|
||||
),
|
||||
command:
|
||||
"addNewLabelDefinition",
|
||||
uiIcon: "bx bx-empty",
|
||||
},
|
||||
{
|
||||
title: t(
|
||||
"attribute_editor.add_new_relation_definition",
|
||||
),
|
||||
command:
|
||||
uiIcon: "bx bx-empty",
|
||||
},
|
||||
{
|
||||
title: t(
|
||||
"attribute_editor.add_new_relation_definition",
|
||||
),
|
||||
command:
|
||||
"addNewRelationDefinition",
|
||||
uiIcon: "bx bx-empty",
|
||||
},
|
||||
],
|
||||
selectMenuItemHandler: (item) =>
|
||||
handleAddNewAttributeCommand(
|
||||
item.command,
|
||||
),
|
||||
onHide: () => {
|
||||
if (suppressNextOnHide.current) {
|
||||
suppressNextOnHide.current = false;
|
||||
return;
|
||||
}
|
||||
setIsMenuOpen(false);
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{error && (
|
||||
<div className="attribute-errors">
|
||||
{getErrorMessage(error)}
|
||||
</div>
|
||||
)}
|
||||
uiIcon: "bx bx-empty",
|
||||
},
|
||||
],
|
||||
selectMenuItemHandler: (item) =>
|
||||
handleAddNewAttributeCommand(
|
||||
item.command,
|
||||
),
|
||||
onHide: () => {
|
||||
if (suppressNextOnHide.current) {
|
||||
suppressNextOnHide.current = false;
|
||||
return;
|
||||
}
|
||||
setIsMenuOpen(false);
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{ error && (
|
||||
<div className="attribute-errors">
|
||||
{getErrorMessage(error)}
|
||||
</div>
|
||||
)}
|
||||
</div>}
|
||||
|
||||
{createPortal(attributeDetailWidgetEl, document.body)}
|
||||
</>
|
||||
@@ -585,4 +435,4 @@ function getClickIndex(pos: ModelPosition) {
|
||||
}
|
||||
|
||||
return clickIndex;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user