mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 08:58:13 +08:00
Tidy up the full frontend codebase and use optional chaining where possible (#620)
* Tidy up the full frontend codebase and use optional chaining where possible * Code review changes
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
<template>
|
||||
<div>{{ widgetData.name }}</div>
|
||||
<div class="widget-row">
|
||||
<template v-for="(component, index) in widgetData.widgets" :key="index">
|
||||
<!-- TODO: Use `<component :is="" v-bind="attributesObject"></component>` to avoid all the separate components with `v-if` -->
|
||||
|
||||
@@ -69,7 +69,7 @@ export default defineComponent({
|
||||
handleClick() {
|
||||
(this.$refs.floatingMenu as typeof FloatingMenu).setOpen();
|
||||
|
||||
if (this.action) this.action();
|
||||
this.action?.();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -161,13 +161,13 @@ export default defineComponent({
|
||||
},
|
||||
onPointerDown(e: PointerEvent) {
|
||||
const saturationPicker = this.$refs.saturationPicker as typeof LayoutCol;
|
||||
const saturationPickerElement = saturationPicker && (saturationPicker.$el as HTMLElement);
|
||||
const saturationPickerElement = saturationPicker?.$el as HTMLElement | undefined;
|
||||
|
||||
const huePicker = this.$refs.huePicker as typeof LayoutCol;
|
||||
const huePickerElement = huePicker && (huePicker.$el as HTMLElement);
|
||||
const huePickerElement = huePicker?.$el as HTMLElement | undefined;
|
||||
|
||||
const opacityPicker = this.$refs.opacityPicker as typeof LayoutCol;
|
||||
const opacityPickerElement = opacityPicker && (opacityPicker.$el as HTMLElement);
|
||||
const opacityPickerElement = opacityPicker?.$el as HTMLElement | undefined;
|
||||
|
||||
if (!(e.currentTarget instanceof HTMLElement) || !saturationPickerElement || !huePickerElement || !opacityPickerElement) return;
|
||||
|
||||
@@ -216,13 +216,13 @@ export default defineComponent({
|
||||
},
|
||||
updateRects() {
|
||||
const saturationPicker = this.$refs.saturationPicker as typeof LayoutCol;
|
||||
const saturationPickerElement = saturationPicker && (saturationPicker.$el as HTMLElement);
|
||||
const saturationPickerElement = saturationPicker?.$el as HTMLElement | undefined;
|
||||
|
||||
const huePicker = this.$refs.huePicker as typeof LayoutCol;
|
||||
const huePickerElement = huePicker && (huePicker.$el as HTMLElement);
|
||||
const huePickerElement = huePicker?.$el as HTMLElement | undefined;
|
||||
|
||||
const opacityPicker = this.$refs.opacityPicker as typeof LayoutCol;
|
||||
const opacityPickerElement = opacityPicker && (opacityPicker.$el as HTMLElement);
|
||||
const opacityPickerElement = opacityPicker?.$el as HTMLElement | undefined;
|
||||
|
||||
if (!saturationPickerElement || !huePickerElement || !opacityPickerElement) return;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<TextLabel :bold="true" class="heading">{{ dialog.state.heading }}</TextLabel>
|
||||
<TextLabel class="details">{{ dialog.state.details }}</TextLabel>
|
||||
<LayoutRow class="buttons-row" v-if="dialog.state.buttons.length > 0">
|
||||
<TextButton v-for="(button, index) in dialog.state.buttons" :key="index" :title="button.tooltip" :action="() => button.callback && button.callback()" v-bind="button.props" />
|
||||
<TextButton v-for="(button, index) in dialog.state.buttons" :key="index" :title="button.tooltip" :action="() => button.callback?.()" v-bind="button.props" />
|
||||
</LayoutRow>
|
||||
</LayoutCol>
|
||||
</LayoutRow>
|
||||
|
||||
@@ -212,7 +212,7 @@ export default defineComponent({
|
||||
const workspace = document.querySelector("[data-workspace]");
|
||||
const floatingMenuContainer = this.$refs.floatingMenuContainer as HTMLElement;
|
||||
const floatingMenuContentComponent = this.$refs.floatingMenuContent as typeof LayoutCol;
|
||||
const floatingMenuContent = floatingMenuContentComponent && (floatingMenuContentComponent.$el as HTMLElement);
|
||||
const floatingMenuContent: HTMLElement | undefined = floatingMenuContentComponent?.$el;
|
||||
const floatingMenu = this.$refs.floatingMenu as HTMLElement;
|
||||
|
||||
if (!workspace || !floatingMenuContainer || !floatingMenuContentComponent || !floatingMenuContent || !floatingMenu) return;
|
||||
@@ -298,30 +298,28 @@ export default defineComponent({
|
||||
},
|
||||
getWidth(callback: (width: number) => void) {
|
||||
this.$nextTick(() => {
|
||||
const floatingMenuContent = (this.$refs.floatingMenuContent as typeof LayoutCol).$el as HTMLElement;
|
||||
const floatingMenuContent: HTMLElement = (this.$refs.floatingMenuContent as typeof LayoutCol).$el;
|
||||
const width = floatingMenuContent.clientWidth;
|
||||
callback(width);
|
||||
});
|
||||
},
|
||||
disableMinWidth(callback: (minWidth: string) => void) {
|
||||
this.$nextTick(() => {
|
||||
const floatingMenuContent = (this.$refs.floatingMenuContent as typeof LayoutCol).$el as HTMLElement;
|
||||
const floatingMenuContent: HTMLElement = (this.$refs.floatingMenuContent as typeof LayoutCol).$el;
|
||||
const initialMinWidth = floatingMenuContent.style.minWidth;
|
||||
floatingMenuContent.style.minWidth = "0";
|
||||
callback(initialMinWidth);
|
||||
});
|
||||
},
|
||||
enableMinWidth(minWidth: string) {
|
||||
const floatingMenuContent = (this.$refs.floatingMenuContent as typeof LayoutCol).$el as HTMLElement;
|
||||
const floatingMenuContent: HTMLElement = (this.$refs.floatingMenuContent as typeof LayoutCol).$el;
|
||||
floatingMenuContent.style.minWidth = minWidth;
|
||||
},
|
||||
pointerMoveHandler(e: PointerEvent) {
|
||||
const target = e.target as HTMLElement;
|
||||
const pointerOverFloatingMenuKeepOpen = target && (target.closest("[data-hover-menu-keep-open]") as HTMLElement);
|
||||
const pointerOverFloatingMenuSpawner = target && (target.closest("[data-hover-menu-spawner]") as HTMLElement);
|
||||
// TODO: Simplify the following expression when optional chaining is supported by the build system
|
||||
const pointerOverOwnFloatingMenuSpawner =
|
||||
pointerOverFloatingMenuSpawner && pointerOverFloatingMenuSpawner.parentElement && pointerOverFloatingMenuSpawner.parentElement.contains(this.$refs.floatingMenu as HTMLElement);
|
||||
const target = e.target as HTMLElement | undefined;
|
||||
const pointerOverFloatingMenuKeepOpen = target?.closest("[data-hover-menu-keep-open]") as HTMLElement | undefined;
|
||||
const pointerOverFloatingMenuSpawner = target?.closest("[data-hover-menu-spawner]") as HTMLElement | undefined;
|
||||
const pointerOverOwnFloatingMenuSpawner = pointerOverFloatingMenuSpawner?.parentElement?.contains(this.$refs.floatingMenu as HTMLElement);
|
||||
// Swap this open floating menu with the one created by the floating menu spawner being hovered over
|
||||
if (pointerOverFloatingMenuSpawner && !pointerOverOwnFloatingMenuSpawner) {
|
||||
this.setClosed();
|
||||
@@ -372,10 +370,12 @@ export default defineComponent({
|
||||
},
|
||||
isPointerEventOutsideMenuElement(e: PointerEvent, element: HTMLElement, extraDistanceAllowed = 0): boolean {
|
||||
const floatingMenuBounds = element.getBoundingClientRect();
|
||||
|
||||
if (floatingMenuBounds.left - e.clientX >= extraDistanceAllowed) return true;
|
||||
if (e.clientX - floatingMenuBounds.right >= extraDistanceAllowed) return true;
|
||||
if (floatingMenuBounds.top - e.clientY >= extraDistanceAllowed) return true;
|
||||
if (e.clientY - floatingMenuBounds.bottom >= extraDistanceAllowed) return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
<span class="entry-label">{{ entry.label }}</span>
|
||||
|
||||
<IconLabel v-if="entry.shortcutRequiresLock && !fullscreen.state.keyboardLocked" :icon="'Info'" :title="keyboardLockInfoMessage" />
|
||||
<UserInputLabel v-else-if="entry.shortcut && entry.shortcut.length" :inputKeys="[entry.shortcut]" />
|
||||
<UserInputLabel v-else-if="entry.shortcut?.length" :inputKeys="[entry.shortcut]" />
|
||||
|
||||
<div class="submenu-arrow" v-if="entry.children && entry.children.length"></div>
|
||||
<div class="submenu-arrow" v-if="entry.children?.length"></div>
|
||||
<div class="no-submenu-arrow" v-else></div>
|
||||
|
||||
<MenuList
|
||||
@@ -175,10 +175,10 @@ const MenuList = defineComponent({
|
||||
scrollableY: { type: Boolean as PropType<boolean>, default: false },
|
||||
},
|
||||
methods: {
|
||||
setEntryRefs(menuEntry: MenuListEntry, ref: typeof FloatingMenu) {
|
||||
setEntryRefs(menuEntry: MenuListEntry, ref: typeof FloatingMenu): void {
|
||||
if (ref) menuEntry.ref = ref;
|
||||
},
|
||||
handleEntryClick(menuEntry: MenuListEntry) {
|
||||
handleEntryClick(menuEntry: MenuListEntry): void {
|
||||
(this.$refs.floatingMenu as typeof FloatingMenu).setClosed();
|
||||
|
||||
if (menuEntry.checkbox) menuEntry.checked = !menuEntry.checked;
|
||||
@@ -188,20 +188,20 @@ const MenuList = defineComponent({
|
||||
|
||||
this.$emit("update:activeEntry", menuEntry);
|
||||
},
|
||||
handleEntryPointerEnter(menuEntry: MenuListEntry) {
|
||||
if (!menuEntry.children || !menuEntry.children.length) return;
|
||||
handleEntryPointerEnter(menuEntry: MenuListEntry): void {
|
||||
if (!menuEntry.children?.length) return;
|
||||
|
||||
if (menuEntry.ref) menuEntry.ref.setOpen();
|
||||
else throw new Error("The menu bar floating menu has no associated ref");
|
||||
},
|
||||
handleEntryPointerLeave(menuEntry: MenuListEntry) {
|
||||
if (!menuEntry.children || !menuEntry.children.length) return;
|
||||
handleEntryPointerLeave(menuEntry: MenuListEntry): void {
|
||||
if (!menuEntry.children?.length) return;
|
||||
|
||||
if (menuEntry.ref) menuEntry.ref.setClosed();
|
||||
else throw new Error("The menu bar floating menu has no associated ref");
|
||||
},
|
||||
isMenuEntryOpen(menuEntry: MenuListEntry): boolean {
|
||||
if (!menuEntry.children || !menuEntry.children.length) return false;
|
||||
if (!menuEntry.children?.length) return false;
|
||||
|
||||
if (menuEntry.ref) return menuEntry.ref.isOpen();
|
||||
|
||||
@@ -215,7 +215,7 @@ const MenuList = defineComponent({
|
||||
},
|
||||
isOpen(): boolean {
|
||||
const floatingMenu = this.$refs.floatingMenu as typeof FloatingMenu;
|
||||
return Boolean(floatingMenu && floatingMenu.isOpen());
|
||||
return Boolean(floatingMenu?.isOpen());
|
||||
},
|
||||
async measureAndReportWidth() {
|
||||
// API is experimental but supported in all browsers - https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready
|
||||
@@ -242,10 +242,8 @@ const MenuList = defineComponent({
|
||||
},
|
||||
computed: {
|
||||
menuEntriesWithoutRefs(): MenuListEntryData[][] {
|
||||
const { menuEntries } = this;
|
||||
return menuEntries.map((entries) =>
|
||||
return this.menuEntries.map((entries) =>
|
||||
entries.map((entry) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { ref, ...entryWithoutRef } = entry;
|
||||
return entryWithoutRef;
|
||||
})
|
||||
|
||||
@@ -112,34 +112,45 @@ export default defineComponent({
|
||||
if (!this.disabled) (this.$refs.menuList as typeof MenuList).setOpen();
|
||||
},
|
||||
selectFont(newName: string) {
|
||||
if (this.isStyle) this.$emit("update:fontStyle", newName);
|
||||
else this.$emit("update:fontFamily", newName);
|
||||
let fontFamily;
|
||||
let fontStyle;
|
||||
|
||||
{
|
||||
const fontFamily = this.isStyle ? this.fontFamily : newName;
|
||||
const fontStyle = this.isStyle ? newName : getFontStyles(newName)[0];
|
||||
const fontFile = getFontFile(fontFamily, fontStyle);
|
||||
this.$emit("changeFont", { fontFamily, fontStyle, fontFile });
|
||||
if (this.isStyle) {
|
||||
this.$emit("update:fontStyle", newName);
|
||||
|
||||
fontFamily = this.fontFamily;
|
||||
fontStyle = newName;
|
||||
} else {
|
||||
this.$emit("update:fontFamily", newName);
|
||||
|
||||
fontFamily = newName;
|
||||
fontStyle = getFontStyles(newName)[0];
|
||||
}
|
||||
|
||||
const fontFile = getFontFile(fontFamily, fontStyle);
|
||||
this.$emit("changeFont", { fontFamily, fontStyle, fontFile });
|
||||
},
|
||||
onWidthChanged(newWidth: number) {
|
||||
this.minWidth = newWidth;
|
||||
},
|
||||
updateEntries(): { menuEntries: SectionsOfMenuListEntries; activeEntry: MenuListEntry } {
|
||||
let selectedIndex = -1;
|
||||
const menuEntries: SectionsOfMenuListEntries = [
|
||||
(this.isStyle ? getFontStyles(this.fontFamily) : fontNames()).map((name, index) => {
|
||||
if (name === (this.isStyle ? this.fontStyle : this.fontFamily)) selectedIndex = index;
|
||||
const choices = this.isStyle ? getFontStyles(this.fontFamily) : fontNames();
|
||||
const selectedChoice = this.isStyle ? this.fontStyle : this.fontFamily;
|
||||
|
||||
const result: MenuListEntry = {
|
||||
label: name,
|
||||
action: (): void => this.selectFont(name),
|
||||
};
|
||||
return result;
|
||||
}),
|
||||
];
|
||||
let selectedEntry: MenuListEntry | undefined;
|
||||
const entries = choices.map((name) => {
|
||||
const result: MenuListEntry = {
|
||||
label: name,
|
||||
action: (): void => this.selectFont(name),
|
||||
};
|
||||
|
||||
const activeEntry = selectedIndex < 0 ? { label: "-" } : menuEntries.flat()[selectedIndex];
|
||||
if (name === selectedChoice) selectedEntry = result;
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
const menuEntries: SectionsOfMenuListEntries = [entries];
|
||||
const activeEntry = selectedEntry || { label: "-" };
|
||||
|
||||
return { menuEntries, activeEntry };
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="entry-container" v-for="(entry, index) in menuEntries" :key="index">
|
||||
<div @click="() => handleEntryClick(entry)" class="entry" :class="{ open: entry.ref && entry.ref.isOpen() }" data-hover-menu-spawner>
|
||||
<div @click="() => handleEntryClick(entry)" class="entry" :class="{ open: entry.ref?.isOpen() }" data-hover-menu-spawner>
|
||||
<IconLabel :icon="entry.icon" v-if="entry.icon" />
|
||||
<span v-if="entry.label">{{ entry.label }}</span>
|
||||
</div>
|
||||
|
||||
@@ -152,7 +152,7 @@ export default defineComponent({
|
||||
onIncrement(direction: IncrementDirection) {
|
||||
if (Number.isNaN(this.value)) return;
|
||||
|
||||
({
|
||||
const actions = {
|
||||
Add: (): void => {
|
||||
const directionAddend = direction === "Increase" ? this.incrementFactor : -this.incrementFactor;
|
||||
this.updateValue(this.value + directionAddend);
|
||||
@@ -162,11 +162,13 @@ export default defineComponent({
|
||||
this.updateValue(this.value * directionMultiplier);
|
||||
},
|
||||
Callback: (): void => {
|
||||
if (direction === "Increase" && this.incrementCallbackIncrease) this.incrementCallbackIncrease();
|
||||
if (direction === "Decrease" && this.incrementCallbackDecrease) this.incrementCallbackDecrease();
|
||||
if (direction === "Increase") this.incrementCallbackIncrease?.();
|
||||
if (direction === "Decrease") this.incrementCallbackDecrease?.();
|
||||
},
|
||||
None: (): void => undefined,
|
||||
}[this.incrementBehavior]());
|
||||
};
|
||||
const action = actions[this.incrementBehavior];
|
||||
action();
|
||||
},
|
||||
updateValue(newValue: number) {
|
||||
const invalid = Number.isNaN(newValue);
|
||||
|
||||
@@ -91,7 +91,7 @@ export default defineComponent({
|
||||
const index = this.entries.indexOf(menuEntry);
|
||||
this.$emit("update:selectedIndex", index);
|
||||
|
||||
if (menuEntry.action) menuEntry.action();
|
||||
menuEntry.action?.();
|
||||
},
|
||||
},
|
||||
components: {
|
||||
|
||||
@@ -27,14 +27,12 @@
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { DefineComponent, defineComponent, PropType } from "vue";
|
||||
import { defineComponent, PropType } from "vue";
|
||||
|
||||
import { IconName, IconSize, ICON_LIST } from "@/utilities/icons";
|
||||
import { IconName, icons } from "@/utilities/icons";
|
||||
|
||||
import LayoutRow from "@/components/layout/LayoutRow.vue";
|
||||
|
||||
const icons: Record<IconName, { component: DefineComponent; size: IconSize }> = ICON_LIST;
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
icon: { type: String as PropType<IconName>, required: true },
|
||||
@@ -47,6 +45,7 @@ export default defineComponent({
|
||||
},
|
||||
components: {
|
||||
LayoutRow,
|
||||
// Import the components of all the icons
|
||||
...Object.fromEntries(Object.entries(icons).map(([name, data]) => [name, data.component])),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -52,7 +52,7 @@ const MINOR_MARK_THICKNESS = 3;
|
||||
|
||||
export type RulerDirection = "Horizontal" | "Vertical";
|
||||
|
||||
// Apparently the modulo operator in js does not work properly.
|
||||
// Modulo function that works for negative numbers, unlike the JS % operator
|
||||
const mod = (n: number, m: number): number => {
|
||||
const remainder = n % m;
|
||||
return Math.floor(remainder >= 0 ? remainder : remainder + m);
|
||||
|
||||
@@ -190,9 +190,7 @@ export default defineComponent({
|
||||
this.dragging = false;
|
||||
},
|
||||
pointerMove(e: PointerEvent) {
|
||||
if (this.dragging) {
|
||||
this.updateHandlePosition(e);
|
||||
}
|
||||
if (this.dragging) this.updateHandlePosition(e);
|
||||
},
|
||||
changePosition(difference: number) {
|
||||
this.clampHandlePosition(this.handlePosition + difference / this.trackLength());
|
||||
|
||||
Reference in New Issue
Block a user