mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-26 13:48:12 +08:00
Make font selection show a live preview on hover; move its code to the backend (#3487)
* Remove FontInput.svelte * Move font picking to the backend * Fix Text tool font choice style turning to "-" on font that doesn't support previous style
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
|
||||
export let parentsValuePath: string[] = [];
|
||||
export let entries: MenuListEntry[][];
|
||||
export let entriesHash: bigint;
|
||||
export let activeEntry: MenuListEntry | undefined = undefined;
|
||||
export let open: boolean;
|
||||
export let direction: MenuDirection = "Bottom";
|
||||
@@ -37,26 +38,29 @@
|
||||
export let drawIcon = false;
|
||||
export let interactive = false;
|
||||
export let scrollableY = false;
|
||||
export let virtualScrollingEntryHeight = 0;
|
||||
export let virtualScrolling = false;
|
||||
|
||||
// Keep the child references outside of the entries array so as to avoid infinite recursion.
|
||||
let childReferences: MenuList[][] = [];
|
||||
let search = "";
|
||||
|
||||
let reactiveEntries = entries;
|
||||
let highlighted = activeEntry as MenuListEntry | undefined;
|
||||
let virtualScrollingEntriesStart = 0;
|
||||
|
||||
// Called only when `open` is changed from outside this component
|
||||
// `watchOpen` is called only when `open` is changed from outside this component
|
||||
$: watchOpen(open);
|
||||
$: watchEntries(entries);
|
||||
$: watchEntriesHash(entriesHash);
|
||||
$: watchRemeasureWidth(filteredEntries, drawIcon);
|
||||
$: watchHighlightedWithSearch(filteredEntries, open);
|
||||
|
||||
$: filteredEntries = entries.map((section) => section.filter((entry) => inSearch(search, entry)));
|
||||
$: virtualScrollingTotalHeight = filteredEntries.length === 0 ? 0 : filteredEntries[0].length * virtualScrollingEntryHeight;
|
||||
$: virtualScrollingStartIndex = Math.floor(virtualScrollingEntriesStart / virtualScrollingEntryHeight) || 0;
|
||||
$: virtualScrollingEndIndex = filteredEntries.length === 0 ? 0 : Math.min(filteredEntries[0].length, virtualScrollingStartIndex + 1 + 400 / virtualScrollingEntryHeight);
|
||||
$: virtualScrollingEntryHeight = virtualScrolling ? 20 : 0;
|
||||
$: filteredEntries = reactiveEntries.map((section) => section.filter((entry) => inSearch(search, entry)));
|
||||
$: startIndex = virtualScrollingEntryHeight ? virtualScrollingStartIndex : 0;
|
||||
// Virtual scrolling calculations
|
||||
$: virtualScrollingTotalHeight = filteredEntries.length === 0 ? 0 : filteredEntries[0].length * virtualScrollingEntryHeight;
|
||||
$: virtualScrollingStartIndex = filteredEntries.length === 0 ? 0 : Math.floor(virtualScrollingEntriesStart / virtualScrollingEntryHeight) || 0;
|
||||
$: virtualScrollingEndIndex = filteredEntries.length === 0 ? 0 : Math.min(filteredEntries[0].length, virtualScrollingStartIndex + 1 + 400 / virtualScrollingEntryHeight);
|
||||
|
||||
// TODO: Move keyboard input handling entirely to the unified system in `input.ts`.
|
||||
// TODO: The current approach is hacky and blocks the allowances for shortcuts like the key to open the browser's dev tools.
|
||||
@@ -139,6 +143,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
function watchEntriesHash(_entriesHash: bigint) {
|
||||
reactiveEntries = entries;
|
||||
}
|
||||
|
||||
function watchRemeasureWidth(_: MenuListEntry[][], __: boolean) {
|
||||
self?.measureAndEmitNaturalWidth();
|
||||
}
|
||||
@@ -149,23 +157,31 @@
|
||||
}
|
||||
|
||||
function getChildReference(menuListEntry: MenuListEntry): MenuList | undefined {
|
||||
const index = filteredEntries.flat().indexOf(menuListEntry);
|
||||
return childReferences.flat().filter((x) => x)[index];
|
||||
const index = filteredEntries.flat().findIndex((entry) => entry.value === menuListEntry.value);
|
||||
|
||||
if (index !== -1) {
|
||||
return childReferences.flat().filter((x) => x)[index];
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("MenuListEntry not found in filteredEntries:", menuListEntry);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function onEntryClick(menuListEntry: MenuListEntry) {
|
||||
// Notify the parent about the clicked entry as the new active entry
|
||||
dispatch("activeEntry", menuListEntry);
|
||||
dispatch("selectedEntryValuePath", [...parentsValuePath, menuListEntry.value]);
|
||||
|
||||
// Close the containing menu
|
||||
let childReference = getChildReference(menuListEntry);
|
||||
if (childReference) {
|
||||
childReference.open = false;
|
||||
entries = entries;
|
||||
reactiveEntries = reactiveEntries;
|
||||
}
|
||||
dispatch("open", false);
|
||||
open = false;
|
||||
reactiveEntries = reactiveEntries;
|
||||
|
||||
// Notify the parent about the clicked entry as the new active entry
|
||||
dispatch("activeEntry", menuListEntry);
|
||||
dispatch("selectedEntryValuePath", [...parentsValuePath, menuListEntry.value]);
|
||||
}
|
||||
|
||||
function onEntryPointerEnter(menuListEntry: MenuListEntry) {
|
||||
@@ -177,8 +193,10 @@
|
||||
let childReference = getChildReference(menuListEntry);
|
||||
if (childReference) {
|
||||
childReference.open = true;
|
||||
entries = entries;
|
||||
} else dispatch("open", true);
|
||||
reactiveEntries = reactiveEntries;
|
||||
} else {
|
||||
dispatch("open", true);
|
||||
}
|
||||
}
|
||||
|
||||
function onEntryPointerLeave(menuListEntry: MenuListEntry) {
|
||||
@@ -190,8 +208,10 @@
|
||||
let childReference = getChildReference(menuListEntry);
|
||||
if (childReference) {
|
||||
childReference.open = false;
|
||||
entries = entries;
|
||||
} else dispatch("open", false);
|
||||
reactiveEntries = reactiveEntries;
|
||||
} else {
|
||||
dispatch("open", false);
|
||||
}
|
||||
}
|
||||
|
||||
function isEntryOpen(menuListEntry: MenuListEntry): boolean {
|
||||
@@ -365,7 +385,7 @@
|
||||
let container = scroller?.div?.();
|
||||
if (!container || !highlighted) return;
|
||||
let containerBoundingRect = container.getBoundingClientRect();
|
||||
let highlightedIndex = filteredEntries.flat().findIndex((entry) => entry === highlighted);
|
||||
let highlightedIndex = filteredEntries.flat().findIndex((entry) => entry.value === highlighted?.value);
|
||||
|
||||
let selectedBoundingRect = new DOMRect();
|
||||
if (virtualScrollingEntryHeight) {
|
||||
@@ -386,10 +406,6 @@
|
||||
container.scrollBy(0, selectedBoundingRect.y - (containerBoundingRect.y + containerBoundingRect.height) + selectedBoundingRect.height);
|
||||
}
|
||||
}
|
||||
|
||||
export function scrollViewTo(distanceDown: number) {
|
||||
scroller?.div?.()?.scrollTo(0, distanceDown);
|
||||
}
|
||||
</script>
|
||||
|
||||
<FloatingMenu
|
||||
@@ -419,8 +435,8 @@
|
||||
{#if virtualScrollingEntryHeight}
|
||||
<LayoutRow class="scroll-spacer" styles={{ height: `${virtualScrollingStartIndex * virtualScrollingEntryHeight}px` }} />
|
||||
{/if}
|
||||
{#each entries as section, sectionIndex (sectionIndex)}
|
||||
{#if includeSeparator(entries, section, sectionIndex, search)}
|
||||
{#each reactiveEntries as section, sectionIndex (sectionIndex)}
|
||||
{#if includeSeparator(reactiveEntries, section, sectionIndex, search)}
|
||||
<Separator type="Section" direction="Vertical" />
|
||||
{/if}
|
||||
{#each currentEntries(section, virtualScrollingEntryHeight, virtualScrollingStartIndex, virtualScrollingEndIndex, search) as entry, entryIndex (entryIndex + startIndex)}
|
||||
@@ -442,10 +458,10 @@
|
||||
{/if}
|
||||
|
||||
{#if entry.font}
|
||||
<link rel="stylesheet" href={entry.font?.toString()} />
|
||||
<link rel="stylesheet" href={entry.font} />
|
||||
{/if}
|
||||
|
||||
<TextLabel class="entry-label" styles={{ "font-family": `${!entry.font ? "inherit" : entry.value}` }}>{entry.label}</TextLabel>
|
||||
<TextLabel class="entry-label" styles={entry.font ? { "font-family": entry.value } : {}}>{entry.label}</TextLabel>
|
||||
|
||||
{#if entry.tooltipShortcut?.shortcut.length}
|
||||
<ShortcutLabel shortcut={entry.tooltipShortcut} />
|
||||
@@ -470,6 +486,7 @@
|
||||
open={getChildReference(entry)?.open || false}
|
||||
direction="TopRight"
|
||||
entries={entry.children}
|
||||
entriesHash={entry.childrenHash || 0n}
|
||||
{minWidth}
|
||||
{drawIcon}
|
||||
{scrollableY}
|
||||
|
||||
Reference in New Issue
Block a user