From e36a4a88fbb6590a4acbd78822ab5b6e7d203e36 Mon Sep 17 00:00:00 2001 From: Jeremy Valentine <38669521+valentine195@users.noreply.github.com> Date: Wed, 22 May 2024 20:09:35 -0400 Subject: [PATCH] fix: Improves appearance of suggesters (close #338) --- package-lock.json | 130 +++++++++----- package.json | 3 +- src/modal/index.ts | 423 +++++---------------------------------------- 3 files changed, 140 insertions(+), 416 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d95141..4c3d7fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/free-regular-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.15.1", + "@javalent/utilities": "file:../obsidian-utilities", "@popperjs/core": "^2.9.2", "@primer/octicons": "^16.3.1", "@types/node": "^14.14.2", @@ -26,11 +27,38 @@ "esbuild-sass-plugin": "^2.2.4", "monkey-around": "^2.3.0", "object.fromentries": "^2.0.4", - "obsidian": "^1.1.1", + "obsidian": "^1.5.7-1", "tslib": "^2.0.3", "typescript": "^4.0.3" } }, + "../obsidian-utilities": { + "name": "@javalent/utilities", + "version": "1.1.5-a", + "dev": true, + "dependencies": { + "svelte": "^4.2.15" + }, + "devDependencies": { + "@sveltejs/package": "^2.3.1", + "@tsconfig/svelte": "^5.0.2", + "@types/css-modules": "^1.0.5", + "@types/node": "^20.11.20", + "builtin-modules": "^3.3.0", + "concurrently": "^8.2.2", + "dotenv": "^16.4.5", + "esbuild": "^0.20.1", + "esbuild-svelte": "^0.8.0", + "globby": "^14.0.1", + "obsidian": "^1.5.7-1", + "svelte-preprocess": "^5.1.4", + "typescript": "^5.4.5", + "vitest": "^1.3.1" + }, + "funding": { + "url": "https://www.buymeacoffee.com/valentine195" + } + }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -182,6 +210,10 @@ "node": ">=6.9.0" } }, + "node_modules/@javalent/utilities": { + "resolved": "../obsidian-utilities", + "link": true + }, "node_modules/@popperjs/core": { "version": "2.11.6", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", @@ -202,18 +234,18 @@ } }, "node_modules/@types/codemirror": { - "version": "0.0.108", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz", - "integrity": "sha512-3FGFcus0P7C2UOGCNUVENqObEb4SFk+S8Dnxq7K6aIsLVs/vDtlangl3PEO0ykaKXyK56swVF6Nho7VsA44uhw==", + "version": "5.60.8", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz", + "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==", "dev": true, "dependencies": { "@types/tern": "*" } }, "node_modules/@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/minimist": { @@ -239,9 +271,9 @@ "dev": true }, "node_modules/@types/tern": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", - "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", "dev": true, "dependencies": { "@types/estree": "*" @@ -2797,12 +2829,12 @@ } }, "node_modules/obsidian": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.1.1.tgz", - "integrity": "sha512-GcxhsHNkPEkwHEjeyitfYNBcQuYGeAHFs1pEpZIv0CnzSfui8p8bPLm2YKLgcg20B764770B1sYGtxCvk9ptxg==", + "version": "1.5.7-1", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.5.7-1.tgz", + "integrity": "sha512-T5ZRuQ1FnfXqEoakTTHVDYvzUEEoT8zSPnQCW31PVgYwG4D4tZCQfKHN2hTz1ifnCe8upvwa6mBTAP2WUA5Vng==", "dev": true, "dependencies": { - "@types/codemirror": "0.0.108", + "@types/codemirror": "5.60.8", "moment": "2.29.4" }, "peerDependencies": { @@ -3375,9 +3407,9 @@ } }, "node_modules/style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", "dev": true, "peer": true }, @@ -3535,9 +3567,9 @@ } }, "node_modules/w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", "dev": true, "peer": true }, @@ -3788,6 +3820,26 @@ "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==" }, + "@javalent/utilities": { + "version": "file:../obsidian-utilities", + "requires": { + "@sveltejs/package": "^2.3.1", + "@tsconfig/svelte": "^5.0.2", + "@types/css-modules": "^1.0.5", + "@types/node": "^20.11.20", + "builtin-modules": "^3.3.0", + "concurrently": "^8.2.2", + "dotenv": "^16.4.5", + "esbuild": "^0.20.1", + "esbuild-svelte": "^0.8.0", + "globby": "^14.0.1", + "obsidian": "^1.5.7-1", + "svelte": "^4.2.15", + "svelte-preprocess": "^5.1.4", + "typescript": "^5.4.5", + "vitest": "^1.3.1" + } + }, "@popperjs/core": { "version": "2.11.6", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", @@ -3804,18 +3856,18 @@ } }, "@types/codemirror": { - "version": "0.0.108", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz", - "integrity": "sha512-3FGFcus0P7C2UOGCNUVENqObEb4SFk+S8Dnxq7K6aIsLVs/vDtlangl3PEO0ykaKXyK56swVF6Nho7VsA44uhw==", + "version": "5.60.8", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz", + "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==", "dev": true, "requires": { "@types/tern": "*" } }, "@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "@types/minimist": { @@ -3841,9 +3893,9 @@ "dev": true }, "@types/tern": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", - "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", "dev": true, "requires": { "@types/estree": "*" @@ -5586,12 +5638,12 @@ } }, "obsidian": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.1.1.tgz", - "integrity": "sha512-GcxhsHNkPEkwHEjeyitfYNBcQuYGeAHFs1pEpZIv0CnzSfui8p8bPLm2YKLgcg20B764770B1sYGtxCvk9ptxg==", + "version": "1.5.7-1", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.5.7-1.tgz", + "integrity": "sha512-T5ZRuQ1FnfXqEoakTTHVDYvzUEEoT8zSPnQCW31PVgYwG4D4tZCQfKHN2hTz1ifnCe8upvwa6mBTAP2WUA5Vng==", "dev": true, "requires": { - "@types/codemirror": "0.0.108", + "@types/codemirror": "5.60.8", "moment": "2.29.4" } }, @@ -6004,9 +6056,9 @@ } }, "style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", "dev": true, "peer": true }, @@ -6121,9 +6173,9 @@ } }, "w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", "dev": true, "peer": true }, diff --git a/package.json b/package.json index 1a1832b..6131cb5 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/free-regular-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.15.1", + "@javalent/utilities": "file:../obsidian-utilities", "@popperjs/core": "^2.9.2", "@primer/octicons": "^16.3.1", "@types/node": "^14.14.2", @@ -30,7 +31,7 @@ "esbuild-sass-plugin": "^2.2.4", "monkey-around": "^2.3.0", "object.fromentries": "^2.0.4", - "obsidian": "^1.1.1", + "obsidian": "^1.5.7-1", "tslib": "^2.0.3", "typescript": "^4.0.3" }, diff --git a/src/modal/index.ts b/src/modal/index.ts index 8444d15..0f03108 100644 --- a/src/modal/index.ts +++ b/src/modal/index.ts @@ -1,404 +1,75 @@ import { - App, - Editor, FuzzyMatch, - FuzzySuggestModal, Modal, Notice, - Platform, - Scope, + SearchComponent, Setting, - SuggestModal, - TextComponent + TextComponent, + renderMatches, + setIcon } from "obsidian"; -import { createPopper, Instance as PopperInstance } from "@popperjs/core"; + +import { FuzzyInputSuggest } from "@javalent/utilities"; import { Admonition, AdmonitionIconDefinition } from "src/@types"; import ObsidianAdmonition from "src/main"; -class Suggester { - owner: SuggestModal; - items: T[]; - suggestions: HTMLDivElement[]; - selectedItem: number; - containerEl: HTMLElement; +export class IconSuggestionModal extends FuzzyInputSuggest { constructor( - owner: SuggestModal, - containerEl: HTMLElement, - scope: Scope + public plugin: ObsidianAdmonition, + input: TextComponent | SearchComponent, + items: AdmonitionIconDefinition[] ) { - this.containerEl = containerEl; - this.owner = owner; - containerEl.on( - "click", - ".suggestion-item", - this.onSuggestionClick.bind(this) - ); - containerEl.on( - "mousemove", - ".suggestion-item", - this.onSuggestionMouseover.bind(this) - ); - - scope.register([], "ArrowUp", () => { - this.setSelectedItem(this.selectedItem - 1, true); - return false; - }); - - scope.register([], "ArrowDown", () => { - this.setSelectedItem(this.selectedItem + 1, true); - return false; - }); - - scope.register([], "Enter", (evt) => { - this.useSelectedItem(evt); - return false; - }); - - scope.register([], "Tab", (evt) => { - this.useSelectedItem(evt); - return false; - }); - } - chooseSuggestion(evt: KeyboardEvent | MouseEvent) { - if (!this.items || !this.items.length) return; - const currentValue = this.items[this.selectedItem]; - if (currentValue) { - this.owner.selectSuggestion(currentValue, evt); - } - } - onSuggestionClick(event: MouseEvent, el: HTMLDivElement): void { - event.preventDefault(); - if (!this.suggestions || !this.suggestions.length) return; - - const item = this.suggestions.indexOf(el); - this.setSelectedItem(item, false); - this.useSelectedItem(event); - } - - onSuggestionMouseover(event: MouseEvent, el: HTMLDivElement): void { - if (!this.suggestions || !this.suggestions.length) return; - const item = this.suggestions.indexOf(el); - this.setSelectedItem(item, false); - } - empty() { - this.containerEl.empty(); - } - setSuggestions(items: T[]) { - this.containerEl.empty(); - const els: HTMLDivElement[] = []; - - items.forEach((item) => { - const suggestionEl = this.containerEl.createDiv("suggestion-item"); - this.owner.renderSuggestion(item, suggestionEl); - els.push(suggestionEl); - }); - this.items = items; - this.suggestions = els; - this.setSelectedItem(0, false); - } - useSelectedItem(event: MouseEvent | KeyboardEvent) { - if (!this.items || !this.items.length) return; - const currentValue = this.items[this.selectedItem]; - if (currentValue) { - this.owner.selectSuggestion(currentValue, event); - } - if (Platform.isMobile) { - this.chooseSuggestion(event); - } - } - wrap(value: number, size: number): number { - return ((value % size) + size) % size; - } - setSelectedItem(index: number, scroll: boolean) { - const nIndex = this.wrap(index, this.suggestions.length); - const prev = this.suggestions[this.selectedItem]; - const next = this.suggestions[nIndex]; - - if (prev) prev.removeClass("is-selected"); - if (next) next.addClass("is-selected"); - - this.selectedItem = nIndex; - - if (scroll) { - next.scrollIntoView(false); - } - } -} - -export abstract class SuggestionModal extends FuzzySuggestModal { - items: T[] = []; - suggestions: HTMLDivElement[]; - popper: PopperInstance; - scope: Scope = new Scope(); - suggester: Suggester>; - suggestEl: HTMLDivElement; - promptEl: HTMLDivElement; - emptyStateText: string = "No match found"; - limit: number = 100; - constructor(app: App, inputEl: HTMLInputElement, items: T[]) { - super(app); - this.inputEl = inputEl; - this.items = items; - - this.suggestEl = createDiv("suggestion-container"); - - this.suggestEl.style.width = `${inputEl.clientWidth}px`; - - this.contentEl = this.suggestEl.createDiv("suggestion"); - - this.suggester = new Suggester(this, this.contentEl, this.scope); - - this.scope.register([], "Escape", this.close.bind(this)); - - this.inputEl.addEventListener("input", this.onInputChanged.bind(this)); - this.inputEl.addEventListener("focus", this.onInputChanged.bind(this)); - this.inputEl.addEventListener("blur", this.close.bind(this)); - this.suggestEl.on( - "mousedown", - ".suggestion-container", - (event: MouseEvent) => { - event.preventDefault(); - } - ); - } - empty() { - this.suggester.empty(); - } - onInputChanged(): void { - const inputStr = this.modifyInput(this.inputEl.value); - const suggestions = this.getSuggestions(inputStr); - if (suggestions.length > 0) { - this.suggester.setSuggestions(suggestions.slice(0, this.limit)); - } else { - this.onNoSuggestion(); - } - this.open(); - } - - modifyInput(input: string): string { - return input; - } - onNoSuggestion() { - this.empty(); - this.renderSuggestion( - null, - this.contentEl.createDiv("suggestion-item") + super(plugin.app, input, items); + } + renderNote( + noteEL: HTMLElement, + result: FuzzyMatch + ): void { + noteEL.setText(this.plugin.iconManager.getIconModuleName(result.item)); + } + renderTitle( + titleEl: HTMLElement, + result: FuzzyMatch + ): void { + renderMatches(titleEl, result.item.name, result.match.matches); + } + renderFlair( + flairEl: HTMLElement, + result: FuzzyMatch + ): void { + const { item } = result; + + flairEl.appendChild( + this.plugin.iconManager.getIconNode(item) ?? createDiv() ); } - open(): void { - // TODO: Figure out a better way to do this. Idea from Periodic Notes plugin - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this.app).keymap.pushScope(this.scope); - - document.body.appendChild(this.suggestEl); - this.popper = createPopper(this.inputEl, this.suggestEl, { - placement: "bottom-start", - modifiers: [ - { - name: "offset", - options: { - offset: [0, 10] - } - }, - { - name: "flip", - options: { - fallbackPlacements: ["top"] - } - } - ] - }); - } - - close(): void { - // TODO: Figure out a better way to do this. Idea from Periodic Notes plugin - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (this.app).keymap.popScope(this.scope); - - this.suggester.setSuggestions([]); - if (this.popper) { - this.popper.destroy(); - } - - this.suggestEl.detach(); - } - createPrompt(prompts: HTMLSpanElement[]) { - if (!this.promptEl) - this.promptEl = this.suggestEl.createDiv("prompt-instructions"); - let prompt = this.promptEl.createDiv("prompt-instruction"); - for (let p of prompts) { - prompt.appendChild(p); - } - } - abstract onChooseItem(item: T, evt: MouseEvent | KeyboardEvent): void; - abstract getItemText(arg: T): string; - abstract getItems(): T[]; -} - -export class IconSuggestionModal extends SuggestionModal { - icons: AdmonitionIconDefinition[]; - icon: AdmonitionIconDefinition; - text: TextComponent; - constructor(public plugin: ObsidianAdmonition, input: TextComponent) { - super( - plugin.app, - input.inputEl, - plugin.iconManager.iconDefinitions - ); - this.icons = plugin.iconManager.iconDefinitions; - this.text = input; - - this.createPrompts(); - this.inputEl.addEventListener("input", this.getItem.bind(this)); - } - createPrompts() {} - getItem() { - const v = this.inputEl.value, - icon = this.icons.find((iconName) => iconName.name === v.trim()); - if (icon == this.icon) return; - this.icon = icon; - if (this.icons) this.onInputChanged(); - } getItemText(item: AdmonitionIconDefinition) { return item.name; } - onChooseItem(item: AdmonitionIconDefinition) { - this.text.setValue(item.name); - this.icon = item; - } - selectSuggestion({ item }: FuzzyMatch) { - this.text.setValue(item.name); - this.icon = item; - this.onClose(); - - this.close(); - } - renderSuggestion( - result: FuzzyMatch, - el: HTMLElement - ) { - let { item, match: matches } = result || {}; - let content = el.createDiv({ - cls: "suggestion-content icon" - }); - - if (!item) { - content.setText(this.emptyStateText); - content.parentElement.addClass("is-selected"); - return; - } - - const matchElements = matches.matches.map((m) => { - return createSpan("suggestion-highlight"); - }); - for (let i = 0; i < item.name.length; i++) { - let match = matches.matches.find((m) => m[0] === i); - if (match) { - let element = matchElements[matches.matches.indexOf(match)]; - content.appendChild(element); - element.appendText(item.name.substring(match[0], match[1])); - - i += match[1] - match[0] - 1; - continue; - } - - content.appendText(item.name[i]); - } - - const iconDiv = createDiv("suggestion-flair admonition-suggester-icon"); - iconDiv.appendChild( - this.plugin.iconManager.getIconNode(item) ?? createDiv() - ); - content.prepend(iconDiv); - content.createDiv({ - cls: "suggestion-note", - text: this.plugin.iconManager.getIconModuleName(item) - }); - } - getItems() { - return this.icons; - } } -class AdmonitionSuggestionModal extends SuggestionModal { - admonitions: Admonition[]; - admonition: Admonition; - text: TextComponent; +class AdmonitionSuggestionModal extends FuzzyInputSuggest { constructor( public plugin: ObsidianAdmonition, - input: TextComponent, + input: TextComponent | SearchComponent, items: Admonition[] ) { - super(plugin.app, input.inputEl, items); - this.admonitions = [...items]; - this.text = input; - - this.createPrompts(); - - this.inputEl.addEventListener("input", this.getItem.bind(this)); - } - createPrompts() {} - getItem() { - const v = this.inputEl.value, - admonition = this.admonitions.find( - (admonition) => admonition.type === v.trim() - ); - if (admonition == this.admonition) return; - this.admonition = admonition; - if (this.admonitions) this.onInputChanged(); - } - getItemText(item: Admonition) { - return item.type; + super(plugin.app, input, items); } - onChooseItem(item: Admonition) { - this.text.setValue(item.type); - this.admonition = item; + renderTitle(titleEl: HTMLElement, result: FuzzyMatch): void { + renderMatches(titleEl, result.item.type, result.match.matches); } - selectSuggestion({ item }: FuzzyMatch) { - this.text.setValue(item.type); - this.onClose(); - this.close(); - } - renderSuggestion(result: FuzzyMatch, el: HTMLElement) { - let { item, match: matches } = result || {}; - let content = el.createDiv({ - cls: "suggestion-content icon" - }); - if (!item) { - content.setText(this.emptyStateText); - content.parentElement.addClass("is-selected"); - return; - } - - const matchElements = matches.matches.map((m) => { - return createSpan("suggestion-highlight"); - }); - for (let i = 0; i < item.type.length; i++) { - let match = matches.matches.find((m) => m[0] === i); - if (match) { - let element = matchElements[matches.matches.indexOf(match)]; - content.appendChild(element); - element.appendText(item.type.substring(match[0], match[1])); - - i += match[1] - match[0] - 1; - continue; - } - - content.appendText(item.type[i]); - } - - const iconDiv = createDiv("suggestion-flair admonition-suggester-icon"); - iconDiv + renderFlair(flairEl: HTMLElement, result: FuzzyMatch): void { + const { item } = result; + flairEl .appendChild( this.plugin.iconManager.getIconNode(item.icon) ?? createDiv() ) .setAttribute("color", `rgb(${item.color})`); - - content.prepend(iconDiv); } - getItems() { - return this.admonitions; + getItemText(item: Admonition) { + return item.type; } } @@ -456,11 +127,11 @@ export class InsertAdmonitionModal extends Modal { t.inputEl.onblur = build; - modal.onClose = build; - if (focus) { - modal.open(); - t.inputEl.focus(); - } + modal.onSelect((item) => { + t.inputEl.value = item.item.type; + build(); + modal.close(); + }); }); let titleInput: TextComponent;