feat: Add option to 'Create new child doc' from link editor

This commit is contained in:
Tom Moor
2023-12-27 22:40:21 -05:00
parent 7be71fda61
commit bd7d5c338d
8 changed files with 56 additions and 28 deletions

View File

@ -35,7 +35,7 @@ type Props = {
to: number;
dictionary: Dictionary;
onRemoveLink?: () => void;
onCreateLink?: (title: string) => Promise<void>;
onCreateLink?: (title: string, nested?: boolean) => Promise<void>;
onSearchLink?: (term: string) => Promise<SearchResult[]>;
onSelectLink: (options: {
href: string;
@ -186,7 +186,7 @@ class LinkEditor extends React.Component<Props, State> {
event.preventDefault();
event.stopPropagation();
const { selectedIndex } = this.state;
const total = results.length;
const total = results.length + 1;
const nextIndex = selectedIndex + 1;
this.setState({
@ -243,17 +243,17 @@ class LinkEditor extends React.Component<Props, State> {
}
};
handleCreateLink = async (value: string) => {
handleCreateLink = async (title: string, nested?: boolean) => {
this.discardInputValue = true;
const { onCreateLink } = this.props;
value = value.trim();
if (value.length === 0) {
title = title.trim();
if (title.length === 0) {
return;
}
if (onCreateLink) {
return onCreateLink(value);
return onCreateLink(title, nested);
}
};
@ -368,22 +368,42 @@ class LinkEditor extends React.Component<Props, State> {
))}
{showCreateLink && (
<LinkSearchResult
key="create"
containerRef={this.resultsRef}
title={suggestedLinkTitle}
subtitle={dictionary.createNewDoc}
icon={<PlusIcon />}
onPointerMove={() => this.handleFocusLink(results.length)}
onClick={async () => {
await this.handleCreateLink(suggestedLinkTitle);
<>
<LinkSearchResult
key="create"
containerRef={this.resultsRef}
title={suggestedLinkTitle}
subtitle={dictionary.createNewDoc}
icon={<PlusIcon />}
onPointerMove={() => this.handleFocusLink(results.length)}
onClick={async () => {
await this.handleCreateLink(suggestedLinkTitle);
if (this.initialSelectionLength) {
this.moveSelectionToEnd();
if (this.initialSelectionLength) {
this.moveSelectionToEnd();
}
}}
selected={results.length === selectedIndex}
/>
<LinkSearchResult
key="create-nested"
containerRef={this.resultsRef}
title={suggestedLinkTitle}
subtitle={dictionary.createNewChildDoc}
icon={<PlusIcon />}
onPointerMove={() =>
this.handleFocusLink(results.length + 1)
}
}}
selected={results.length === selectedIndex}
/>
onClick={async () => {
await this.handleCreateLink(suggestedLinkTitle, true);
if (this.initialSelectionLength) {
this.moveSelectionToEnd();
}
}}
selected={results.length + 1 === selectedIndex}
/>
</>
)}
</>
)}

View File

@ -52,7 +52,7 @@ export default function LinkToolbar({
});
const handleOnCreateLink = React.useCallback(
async (title: string) => {
async (title: string, nested?: boolean) => {
onClose();
view.focus();
@ -81,6 +81,7 @@ export default function LinkToolbar({
);
return createAndInsertLink(view, title, href, {
nested,
onCreateLink,
dictionary,
});

View File

@ -148,7 +148,10 @@ export default function SelectionToolbar(props: Props) {
};
}, [isActive, previousIsActive, readOnly, view]);
const handleOnCreateLink = async (title: string): Promise<void> => {
const handleOnCreateLink = async (
title: string,
nested?: boolean
): Promise<void> => {
const { onCreateLink } = props;
if (!onCreateLink) {
@ -173,6 +176,7 @@ export default function SelectionToolbar(props: Props) {
);
return createAndInsertLink(view, title, href, {
nested,
onCreateLink,
dictionary,
});

View File

@ -24,6 +24,7 @@ export default function useDictionary() {
createLink: t("Create link"),
createLinkError: t("Sorry, an error occurred creating the link"),
createNewDoc: t("Create a new doc"),
createNewChildDoc: t("Create a new child doc"),
deleteColumn: t("Delete column"),
deleteRow: t("Delete row"),
deleteTable: t("Delete table"),

View File

@ -43,7 +43,7 @@ type Children = (options: {
revision: Revision | undefined;
abilities: Record<string, boolean>;
readOnly: boolean;
onCreateLink: (title: string) => Promise<string>;
onCreateLink: (title: string, nested?: boolean) => Promise<string>;
sharedTree: NavigationNode | undefined;
}) => React.ReactNode;
@ -152,14 +152,14 @@ function DataLoader({ match, children }: Props) {
}, [document?.id, document?.isDeleted, revisionId, views]);
const onCreateLink = React.useCallback(
async (title: string) => {
async (title: string, nested?: boolean) => {
if (!document) {
throw new Error("Document not loaded yet");
}
const newDocument = await documents.create({
collectionId: document.collectionId,
parentDocumentId: document.parentDocumentId,
parentDocumentId: nested ? document.id : document.parentDocumentId,
title,
text: "",
});

View File

@ -78,7 +78,7 @@ type Props = WithTranslation &
revision?: Revision;
readOnly: boolean;
shareId?: string;
onCreateLink?: (title: string) => Promise<string>;
onCreateLink?: (title: string, nested?: boolean) => Promise<string>;
onSearchLink?: (term: string) => any;
};

View File

@ -38,14 +38,15 @@ const createAndInsertLink = async function (
href: string,
options: {
dictionary: any;
onCreateLink: (title: string) => Promise<string>;
nested?: boolean;
onCreateLink: (title: string, nested?: boolean) => Promise<string>;
}
) {
const { dispatch, state } = view;
const { onCreateLink } = options;
try {
const url = await onCreateLink(title);
const url = await onCreateLink(title, options.nested);
const result = findPlaceholderLink(view.state.doc, href);
if (!result) {

View File

@ -302,6 +302,7 @@
"Create link": "Create link",
"Sorry, an error occurred creating the link": "Sorry, an error occurred creating the link",
"Create a new doc": "Create a new doc",
"Create a new child doc": "Create a new child doc",
"Delete column": "Delete column",
"Delete row": "Delete row",
"Delete table": "Delete table",