mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 14:28:11 +08:00
Replace the Vue frontend with Svelte
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
export type Debouncer = ReturnType<typeof debouncer>;
|
||||
|
||||
export type DebouncerOptions = {
|
||||
debounceTime: number;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export function debouncer<T>(callFn: (value: T) => unknown, { debounceTime = 60 }: Partial<DebouncerOptions> = {}) {
|
||||
let currentValue: T | undefined;
|
||||
|
||||
const emitValue = (): void => {
|
||||
if (currentValue === undefined) {
|
||||
throw new Error("Tried to emit undefined value from debouncer. This should never be possible");
|
||||
}
|
||||
const emittingValue = currentValue;
|
||||
currentValue = undefined;
|
||||
callFn(emittingValue);
|
||||
};
|
||||
|
||||
const updateValue = (newValue: T): void => {
|
||||
if (currentValue !== undefined) {
|
||||
currentValue = newValue;
|
||||
return;
|
||||
}
|
||||
|
||||
currentValue = newValue;
|
||||
setTimeout(emitValue, debounceTime);
|
||||
};
|
||||
|
||||
return { updateValue };
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
import GraphiteLogotypeSolid from "@/../assets/graphics/graphite-logotype-solid.svg";
|
||||
|
||||
const GRAPHICS = {
|
||||
GraphiteLogotypeSolid: { component: GraphiteLogotypeSolid, size: undefined },
|
||||
GraphiteLogotypeSolid: { svg: GraphiteLogotypeSolid, size: undefined },
|
||||
} as const;
|
||||
|
||||
// 12px Solid
|
||||
@@ -44,40 +44,40 @@ import WindowButtonWinMinimize from "@/../assets/icon-12px-solid/window-button-w
|
||||
import WindowButtonWinRestoreDown from "@/../assets/icon-12px-solid/window-button-win-restore-down.svg";
|
||||
|
||||
const SOLID_12PX = {
|
||||
Add: { component: Add, size: 12 },
|
||||
Checkmark: { component: Checkmark, size: 12 },
|
||||
CloseX: { component: CloseX, size: 12 },
|
||||
DropdownArrow: { component: DropdownArrow, size: 12 },
|
||||
Edit: { component: Edit, size: 12 },
|
||||
Empty12px: { component: Empty12px, size: 12 },
|
||||
FullscreenEnter: { component: FullscreenEnter, size: 12 },
|
||||
FullscreenExit: { component: FullscreenExit, size: 12 },
|
||||
Grid: { component: Grid, size: 12 },
|
||||
Info: { component: Info, size: 12 },
|
||||
KeyboardArrowDown: { component: KeyboardArrowDown, size: 12 },
|
||||
KeyboardArrowLeft: { component: KeyboardArrowLeft, size: 12 },
|
||||
KeyboardArrowRight: { component: KeyboardArrowRight, size: 12 },
|
||||
KeyboardArrowUp: { component: KeyboardArrowUp, size: 12 },
|
||||
KeyboardBackspace: { component: KeyboardBackspace, size: 12 },
|
||||
KeyboardCommand: { component: KeyboardCommand, size: 12 },
|
||||
KeyboardControl: { component: KeyboardControl, size: 12 },
|
||||
KeyboardEnter: { component: KeyboardEnter, size: 12 },
|
||||
KeyboardOption: { component: KeyboardOption, size: 12 },
|
||||
KeyboardShift: { component: KeyboardShift, size: 12 },
|
||||
KeyboardSpace: { component: KeyboardSpace, size: 12 },
|
||||
KeyboardTab: { component: KeyboardTab, size: 12 },
|
||||
Link: { component: Link, size: 12 },
|
||||
Overlays: { component: Overlays, size: 12 },
|
||||
Remove: { component: Remove, size: 12 },
|
||||
ResetColors: { component: ResetColors, size: 12 },
|
||||
Snapping: { component: Snapping, size: 12 },
|
||||
Swap: { component: Swap, size: 12 },
|
||||
VerticalEllipsis: { component: VerticalEllipsis, size: 12 },
|
||||
Warning: { component: Warning, size: 12 },
|
||||
WindowButtonWinClose: { component: WindowButtonWinClose, size: 12 },
|
||||
WindowButtonWinMaximize: { component: WindowButtonWinMaximize, size: 12 },
|
||||
WindowButtonWinMinimize: { component: WindowButtonWinMinimize, size: 12 },
|
||||
WindowButtonWinRestoreDown: { component: WindowButtonWinRestoreDown, size: 12 },
|
||||
Add: { svg: Add, size: 12 },
|
||||
Checkmark: { svg: Checkmark, size: 12 },
|
||||
CloseX: { svg: CloseX, size: 12 },
|
||||
DropdownArrow: { svg: DropdownArrow, size: 12 },
|
||||
Edit: { svg: Edit, size: 12 },
|
||||
Empty12px: { svg: Empty12px, size: 12 },
|
||||
FullscreenEnter: { svg: FullscreenEnter, size: 12 },
|
||||
FullscreenExit: { svg: FullscreenExit, size: 12 },
|
||||
Grid: { svg: Grid, size: 12 },
|
||||
Info: { svg: Info, size: 12 },
|
||||
KeyboardArrowDown: { svg: KeyboardArrowDown, size: 12 },
|
||||
KeyboardArrowLeft: { svg: KeyboardArrowLeft, size: 12 },
|
||||
KeyboardArrowRight: { svg: KeyboardArrowRight, size: 12 },
|
||||
KeyboardArrowUp: { svg: KeyboardArrowUp, size: 12 },
|
||||
KeyboardBackspace: { svg: KeyboardBackspace, size: 12 },
|
||||
KeyboardCommand: { svg: KeyboardCommand, size: 12 },
|
||||
KeyboardControl: { svg: KeyboardControl, size: 12 },
|
||||
KeyboardEnter: { svg: KeyboardEnter, size: 12 },
|
||||
KeyboardOption: { svg: KeyboardOption, size: 12 },
|
||||
KeyboardShift: { svg: KeyboardShift, size: 12 },
|
||||
KeyboardSpace: { svg: KeyboardSpace, size: 12 },
|
||||
KeyboardTab: { svg: KeyboardTab, size: 12 },
|
||||
Link: { svg: Link, size: 12 },
|
||||
Overlays: { svg: Overlays, size: 12 },
|
||||
Remove: { svg: Remove, size: 12 },
|
||||
ResetColors: { svg: ResetColors, size: 12 },
|
||||
Snapping: { svg: Snapping, size: 12 },
|
||||
Swap: { svg: Swap, size: 12 },
|
||||
VerticalEllipsis: { svg: VerticalEllipsis, size: 12 },
|
||||
Warning: { svg: Warning, size: 12 },
|
||||
WindowButtonWinClose: { svg: WindowButtonWinClose, size: 12 },
|
||||
WindowButtonWinMaximize: { svg: WindowButtonWinMaximize, size: 12 },
|
||||
WindowButtonWinMinimize: { svg: WindowButtonWinMinimize, size: 12 },
|
||||
WindowButtonWinRestoreDown: { svg: WindowButtonWinRestoreDown, size: 12 },
|
||||
} as const;
|
||||
|
||||
// 16px Solid
|
||||
@@ -138,61 +138,61 @@ import ZoomOut from "@/../assets/icon-16px-solid/zoom-out.svg";
|
||||
import ZoomReset from "@/../assets/icon-16px-solid/zoom-reset.svg";
|
||||
|
||||
const SOLID_16PX = {
|
||||
AlignBottom: { component: AlignBottom, size: 16 },
|
||||
AlignHorizontalCenter: { component: AlignHorizontalCenter, size: 16 },
|
||||
AlignLeft: { component: AlignLeft, size: 16 },
|
||||
AlignRight: { component: AlignRight, size: 16 },
|
||||
AlignTop: { component: AlignTop, size: 16 },
|
||||
AlignVerticalCenter: { component: AlignVerticalCenter, size: 16 },
|
||||
BooleanDifference: { component: BooleanDifference, size: 16 },
|
||||
BooleanIntersect: { component: BooleanIntersect, size: 16 },
|
||||
BooleanSubtractBack: { component: BooleanSubtractBack, size: 16 },
|
||||
BooleanSubtractFront: { component: BooleanSubtractFront, size: 16 },
|
||||
BooleanUnion: { component: BooleanUnion, size: 16 },
|
||||
CheckboxChecked: { component: CheckboxChecked, size: 16 },
|
||||
CheckboxUnchecked: { component: CheckboxUnchecked, size: 16 },
|
||||
Copy: { component: Copy, size: 16 },
|
||||
Eyedropper: { component: Eyedropper, size: 16 },
|
||||
EyeHidden: { component: EyeHidden, size: 16 },
|
||||
EyeVisible: { component: EyeVisible, size: 16 },
|
||||
File: { component: File, size: 16 },
|
||||
FlipHorizontal: { component: FlipHorizontal, size: 16 },
|
||||
FlipVertical: { component: FlipVertical, size: 16 },
|
||||
Folder: { component: Folder, size: 16 },
|
||||
GraphiteLogo: { component: GraphiteLogo, size: 16 },
|
||||
NodeArtboard: { component: NodeArtboard, size: 16 },
|
||||
NodeBlur: { component: NodeBlur, size: 16 },
|
||||
NodeBrushwork: { component: NodeBrushwork, size: 16 },
|
||||
NodeColorCorrection: { component: NodeColorCorrection, size: 16 },
|
||||
NodeFolder: { component: NodeFolder, size: 16 },
|
||||
NodeGradient: { component: NodeGradient, size: 16 },
|
||||
NodeImage: { component: NodeImage, size: 16 },
|
||||
NodeImaginate: { component: NodeImaginate, size: 16 },
|
||||
NodeMagicWand: { component: NodeMagicWand, size: 16 },
|
||||
NodeMask: { component: NodeMask, size: 16 },
|
||||
NodeMotionBlur: { component: NodeMotionBlur, size: 16 },
|
||||
NodeNodes: { component: NodeNodes, size: 16 },
|
||||
NodeOutput: { component: NodeOutput, size: 16 },
|
||||
NodeShape: { component: NodeShape, size: 16 },
|
||||
NodeText: { component: NodeText, size: 16 },
|
||||
NodeTransform: { component: NodeTransform, size: 16 },
|
||||
Paste: { component: Paste, size: 16 },
|
||||
Random: { component: Random, size: 16 },
|
||||
Regenerate: { component: Regenerate, size: 16 },
|
||||
Reload: { component: Reload, size: 16 },
|
||||
Rescale: { component: Rescale, size: 16 },
|
||||
Reset: { component: Reset, size: 16 },
|
||||
Settings: { component: Settings, size: 16 },
|
||||
Trash: { component: Trash, size: 16 },
|
||||
ViewModeNormal: { component: ViewModeNormal, size: 16 },
|
||||
ViewModeOutline: { component: ViewModeOutline, size: 16 },
|
||||
ViewModePixels: { component: ViewModePixels, size: 16 },
|
||||
ViewportDesignMode: { component: ViewportDesignMode, size: 16 },
|
||||
ViewportGuideMode: { component: ViewportGuideMode, size: 16 },
|
||||
ViewportSelectMode: { component: ViewportSelectMode, size: 16 },
|
||||
ZoomIn: { component: ZoomIn, size: 16 },
|
||||
ZoomOut: { component: ZoomOut, size: 16 },
|
||||
ZoomReset: { component: ZoomReset, size: 16 },
|
||||
AlignBottom: { svg: AlignBottom, size: 16 },
|
||||
AlignHorizontalCenter: { svg: AlignHorizontalCenter, size: 16 },
|
||||
AlignLeft: { svg: AlignLeft, size: 16 },
|
||||
AlignRight: { svg: AlignRight, size: 16 },
|
||||
AlignTop: { svg: AlignTop, size: 16 },
|
||||
AlignVerticalCenter: { svg: AlignVerticalCenter, size: 16 },
|
||||
BooleanDifference: { svg: BooleanDifference, size: 16 },
|
||||
BooleanIntersect: { svg: BooleanIntersect, size: 16 },
|
||||
BooleanSubtractBack: { svg: BooleanSubtractBack, size: 16 },
|
||||
BooleanSubtractFront: { svg: BooleanSubtractFront, size: 16 },
|
||||
BooleanUnion: { svg: BooleanUnion, size: 16 },
|
||||
CheckboxChecked: { svg: CheckboxChecked, size: 16 },
|
||||
CheckboxUnchecked: { svg: CheckboxUnchecked, size: 16 },
|
||||
Copy: { svg: Copy, size: 16 },
|
||||
Eyedropper: { svg: Eyedropper, size: 16 },
|
||||
EyeHidden: { svg: EyeHidden, size: 16 },
|
||||
EyeVisible: { svg: EyeVisible, size: 16 },
|
||||
File: { svg: File, size: 16 },
|
||||
FlipHorizontal: { svg: FlipHorizontal, size: 16 },
|
||||
FlipVertical: { svg: FlipVertical, size: 16 },
|
||||
Folder: { svg: Folder, size: 16 },
|
||||
GraphiteLogo: { svg: GraphiteLogo, size: 16 },
|
||||
NodeArtboard: { svg: NodeArtboard, size: 16 },
|
||||
NodeBlur: { svg: NodeBlur, size: 16 },
|
||||
NodeBrushwork: { svg: NodeBrushwork, size: 16 },
|
||||
NodeColorCorrection: { svg: NodeColorCorrection, size: 16 },
|
||||
NodeFolder: { svg: NodeFolder, size: 16 },
|
||||
NodeGradient: { svg: NodeGradient, size: 16 },
|
||||
NodeImage: { svg: NodeImage, size: 16 },
|
||||
NodeImaginate: { svg: NodeImaginate, size: 16 },
|
||||
NodeMagicWand: { svg: NodeMagicWand, size: 16 },
|
||||
NodeMask: { svg: NodeMask, size: 16 },
|
||||
NodeMotionBlur: { svg: NodeMotionBlur, size: 16 },
|
||||
NodeNodes: { svg: NodeNodes, size: 16 },
|
||||
NodeOutput: { svg: NodeOutput, size: 16 },
|
||||
NodeShape: { svg: NodeShape, size: 16 },
|
||||
NodeText: { svg: NodeText, size: 16 },
|
||||
NodeTransform: { svg: NodeTransform, size: 16 },
|
||||
Paste: { svg: Paste, size: 16 },
|
||||
Random: { svg: Random, size: 16 },
|
||||
Regenerate: { svg: Regenerate, size: 16 },
|
||||
Reload: { svg: Reload, size: 16 },
|
||||
Rescale: { svg: Rescale, size: 16 },
|
||||
Reset: { svg: Reset, size: 16 },
|
||||
Settings: { svg: Settings, size: 16 },
|
||||
Trash: { svg: Trash, size: 16 },
|
||||
ViewModeNormal: { svg: ViewModeNormal, size: 16 },
|
||||
ViewModeOutline: { svg: ViewModeOutline, size: 16 },
|
||||
ViewModePixels: { svg: ViewModePixels, size: 16 },
|
||||
ViewportDesignMode: { svg: ViewportDesignMode, size: 16 },
|
||||
ViewportGuideMode: { svg: ViewportGuideMode, size: 16 },
|
||||
ViewportSelectMode: { svg: ViewportSelectMode, size: 16 },
|
||||
ZoomIn: { svg: ZoomIn, size: 16 },
|
||||
ZoomOut: { svg: ZoomOut, size: 16 },
|
||||
ZoomReset: { svg: ZoomReset, size: 16 },
|
||||
} as const;
|
||||
|
||||
// 16px Two-Tone
|
||||
@@ -203,25 +203,23 @@ import MouseHintLmb from "@/../assets/icon-16px-two-tone/mouse-hint-lmb.svg";
|
||||
import MouseHintMmbDrag from "@/../assets/icon-16px-two-tone/mouse-hint-mmb-drag.svg";
|
||||
import MouseHintMmb from "@/../assets/icon-16px-two-tone/mouse-hint-mmb.svg";
|
||||
import MouseHintNone from "@/../assets/icon-16px-two-tone/mouse-hint-none.svg";
|
||||
import MouseHintRmbDouble from "@/../assets/icon-16px-two-tone/mouse-hint-rmb-double.svg";
|
||||
import MouseHintRmbDrag from "@/../assets/icon-16px-two-tone/mouse-hint-rmb-drag.svg";
|
||||
import MouseHintRmb from "@/../assets/icon-16px-two-tone/mouse-hint-rmb.svg";
|
||||
import MouseHintScrollDown from "@/../assets/icon-16px-two-tone/mouse-hint-scroll-down.svg";
|
||||
import MouseHintScrollUp from "@/../assets/icon-16px-two-tone/mouse-hint-scroll-up.svg";
|
||||
|
||||
const TWO_TONE_16PX = {
|
||||
MouseHintDrag: { component: MouseHintDrag, size: 16 },
|
||||
MouseHintLmb: { component: MouseHintLmb, size: 16 },
|
||||
MouseHintLmbDouble: { component: MouseHintLmbDouble, size: 16 },
|
||||
MouseHintLmbDrag: { component: MouseHintLmbDrag, size: 16 },
|
||||
MouseHintMmb: { component: MouseHintMmb, size: 16 },
|
||||
MouseHintMmbDrag: { component: MouseHintMmbDrag, size: 16 },
|
||||
MouseHintNone: { component: MouseHintNone, size: 16 },
|
||||
MouseHintRmb: { component: MouseHintRmb, size: 16 },
|
||||
MouseHintRmbDouble: { component: MouseHintRmbDouble, size: 16 },
|
||||
MouseHintRmbDrag: { component: MouseHintRmbDrag, size: 16 },
|
||||
MouseHintScrollDown: { component: MouseHintScrollDown, size: 16 },
|
||||
MouseHintScrollUp: { component: MouseHintScrollUp, size: 16 },
|
||||
MouseHintDrag: { svg: MouseHintDrag, size: 16 },
|
||||
MouseHintLmb: { svg: MouseHintLmb, size: 16 },
|
||||
MouseHintLmbDouble: { svg: MouseHintLmbDouble, size: 16 },
|
||||
MouseHintLmbDrag: { svg: MouseHintLmbDrag, size: 16 },
|
||||
MouseHintMmb: { svg: MouseHintMmb, size: 16 },
|
||||
MouseHintMmbDrag: { svg: MouseHintMmbDrag, size: 16 },
|
||||
MouseHintNone: { svg: MouseHintNone, size: 16 },
|
||||
MouseHintRmb: { svg: MouseHintRmb, size: 16 },
|
||||
MouseHintRmbDrag: { svg: MouseHintRmbDrag, size: 16 },
|
||||
MouseHintScrollDown: { svg: MouseHintScrollDown, size: 16 },
|
||||
MouseHintScrollUp: { svg: MouseHintScrollUp, size: 16 },
|
||||
} as const;
|
||||
|
||||
// 24px Two-Tone
|
||||
@@ -250,29 +248,29 @@ import VectorSplineTool from "@/../assets/icon-24px-two-tone/vector-spline-tool.
|
||||
import VectorTextTool from "@/../assets/icon-24px-two-tone/vector-text-tool.svg";
|
||||
|
||||
const TWO_TONE_24PX = {
|
||||
GeneralArtboardTool: { component: GeneralArtboardTool, size: 24 },
|
||||
GeneralEyedropperTool: { component: GeneralEyedropperTool, size: 24 },
|
||||
GeneralFillTool: { component: GeneralFillTool, size: 24 },
|
||||
GeneralGradientTool: { component: GeneralGradientTool, size: 24 },
|
||||
GeneralNavigateTool: { component: GeneralNavigateTool, size: 24 },
|
||||
GeneralSelectTool: { component: GeneralSelectTool, size: 24 },
|
||||
RasterImaginateTool: { component: RasterImaginateTool, size: 24 },
|
||||
RasterNodesTool: { component: RasterNodesTool, size: 24 },
|
||||
RasterBrushTool: { component: RasterBrushTool, size: 24 },
|
||||
RasterCloneTool: { component: RasterCloneTool, size: 24 },
|
||||
RasterDetailTool: { component: RasterDetailTool, size: 24 },
|
||||
RasterHealTool: { component: RasterHealTool, size: 24 },
|
||||
RasterPatchTool: { component: RasterPatchTool, size: 24 },
|
||||
RasterRelightTool: { component: RasterRelightTool, size: 24 },
|
||||
VectorEllipseTool: { component: VectorEllipseTool, size: 24 },
|
||||
VectorFreehandTool: { component: VectorFreehandTool, size: 24 },
|
||||
VectorLineTool: { component: VectorLineTool, size: 24 },
|
||||
VectorPathTool: { component: VectorPathTool, size: 24 },
|
||||
VectorPenTool: { component: VectorPenTool, size: 24 },
|
||||
VectorRectangleTool: { component: VectorRectangleTool, size: 24 },
|
||||
VectorShapeTool: { component: VectorShapeTool, size: 24 },
|
||||
VectorSplineTool: { component: VectorSplineTool, size: 24 },
|
||||
VectorTextTool: { component: VectorTextTool, size: 24 },
|
||||
GeneralArtboardTool: { svg: GeneralArtboardTool, size: 24 },
|
||||
GeneralEyedropperTool: { svg: GeneralEyedropperTool, size: 24 },
|
||||
GeneralFillTool: { svg: GeneralFillTool, size: 24 },
|
||||
GeneralGradientTool: { svg: GeneralGradientTool, size: 24 },
|
||||
GeneralNavigateTool: { svg: GeneralNavigateTool, size: 24 },
|
||||
GeneralSelectTool: { svg: GeneralSelectTool, size: 24 },
|
||||
RasterImaginateTool: { svg: RasterImaginateTool, size: 24 },
|
||||
RasterNodesTool: { svg: RasterNodesTool, size: 24 },
|
||||
RasterBrushTool: { svg: RasterBrushTool, size: 24 },
|
||||
RasterCloneTool: { svg: RasterCloneTool, size: 24 },
|
||||
RasterDetailTool: { svg: RasterDetailTool, size: 24 },
|
||||
RasterHealTool: { svg: RasterHealTool, size: 24 },
|
||||
RasterPatchTool: { svg: RasterPatchTool, size: 24 },
|
||||
RasterRelightTool: { svg: RasterRelightTool, size: 24 },
|
||||
VectorEllipseTool: { svg: VectorEllipseTool, size: 24 },
|
||||
VectorFreehandTool: { svg: VectorFreehandTool, size: 24 },
|
||||
VectorLineTool: { svg: VectorLineTool, size: 24 },
|
||||
VectorPathTool: { svg: VectorPathTool, size: 24 },
|
||||
VectorPenTool: { svg: VectorPenTool, size: 24 },
|
||||
VectorRectangleTool: { svg: VectorRectangleTool, size: 24 },
|
||||
VectorShapeTool: { svg: VectorShapeTool, size: 24 },
|
||||
VectorSplineTool: { svg: VectorSplineTool, size: 24 },
|
||||
VectorTextTool: { svg: VectorTextTool, size: 24 },
|
||||
} as const;
|
||||
|
||||
// All icons
|
||||
@@ -286,7 +284,7 @@ const ICON_LIST = {
|
||||
|
||||
// Exported icons and types
|
||||
export const ICONS: IconDefinitionType<typeof ICON_LIST> = ICON_LIST;
|
||||
export const ICON_COMPONENTS = Object.fromEntries(Object.entries(ICONS).map(([name, data]) => [name, data.component]));
|
||||
export const ICON_SVG_STRINGS = Object.fromEntries(Object.entries(ICONS).map(([name, data]) => [name, data.svg]));
|
||||
|
||||
export type IconName = keyof typeof ICONS;
|
||||
export type IconSize = undefined | 12 | 16 | 24 | 32;
|
||||
@@ -299,6 +297,6 @@ export type IconSize = undefined | 12 | 16 | 24 | 32;
|
||||
// map of all its individual entries. Having the full list of entries lets us automatically set the `IconName` type to the union of strings that is the full
|
||||
// list of keys. The result is that we don't have to maintain a separate list of icon names since this scheme infers it from the keys of the icon definitions.
|
||||
// Based on https://stackoverflow.com/a/64119715/775283
|
||||
type IconDefinition = { component: string; size: IconSize };
|
||||
type IconDefinition = { svg: string; size: IconSize };
|
||||
type EvaluateType<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
|
||||
type IconDefinitionType<T extends Record<string, IconDefinition>> = EvaluateType<{ [key in keyof T]: IconDefinition }>;
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
import { blobToBase64 } from "@/utility-functions/files";
|
||||
import { type RequestResult, requestWithUploadDownloadProgress } from "@/utility-functions/network";
|
||||
import { type Editor } from "@/wasm-communication/editor";
|
||||
import { type ImaginateGenerationParameters, type XY } from "@/wasm-communication/messages";
|
||||
import type { XY } from "@/wasm-communication/messages";
|
||||
import { type ImaginateGenerationParameters } from "@/wasm-communication/messages";
|
||||
|
||||
const MAX_POLLING_RETRIES = 4;
|
||||
const SERVER_STATUS_CHECK_TIMEOUT = 5000;
|
||||
|
||||
@@ -52,3 +52,19 @@ export function operatingSystem(detailed = false): string {
|
||||
export function platformIsMac(): boolean {
|
||||
return operatingSystem() === "Mac";
|
||||
}
|
||||
|
||||
export function isEventSupported(eventName: string) {
|
||||
const onEventName = `on${eventName}`;
|
||||
|
||||
let tag = "div";
|
||||
if (["select", "change"].includes(eventName)) tag = "select";
|
||||
if (["submit", "reset"].includes(eventName)) tag = "form";
|
||||
if (["error", "load", "abort"].includes(eventName)) tag = "img";
|
||||
const element = document.createElement(tag);
|
||||
|
||||
if (onEventName in element) return true;
|
||||
|
||||
// Check if "return;" gets converted into a function, meaning the event is supported
|
||||
element.setAttribute(eventName, "return;");
|
||||
return typeof (element as Record<string, any>)[onEventName] === "function";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user