From 3684caea87d76f74f81f70d47c298ef79be3ec8c Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Sat, 7 Mar 2026 14:27:17 +0300 Subject: [PATCH] Fix duplicate :class, rename race, useFileDialog leak, restore clip/wrap --- src/components/AppMenu.vue | 17 ++++----- src/components/FontPicker.vue | 8 +++- src/components/MobileHud.vue | 8 +++- src/components/NodeContextMenuContent.vue | 4 +- src/components/Toolbar.vue | 14 ++++--- src/components/chat/ChatInput.vue | 29 ++++++++++++-- src/components/properties/LayoutSection.vue | 42 ++++++++++++++++++++- src/components/ui/button.ts | 10 +---- src/components/ui/menu.ts | 5 ++- src/components/ui/select.ts | 2 +- src/components/ui/surface.ts | 2 +- src/composables/use-menu.ts | 11 +++--- 12 files changed, 110 insertions(+), 42 deletions(-) diff --git a/src/components/AppMenu.vue b/src/components/AppMenu.vue index 6958eff26..86f88ed8f 100644 --- a/src/components/AppMenu.vue +++ b/src/components/AppMenu.vue @@ -27,15 +27,17 @@ import { useEditorStore } from '@/stores/editor' const store = useEditorStore() const DOCUMENT_NAME_ID = 'document-name' -const nameInputRef = ref(null) const rename = useInlineRename<'document-name'>((_id, name) => { store.state.documentName = name }) const editingName = computed(() => rename.editingId.value === DOCUMENT_NAME_ID) +function setNameInputRef(el: HTMLInputElement | null) { + if (el) void rename.focusInput(el) +} + function startRename() { rename.start(DOCUMENT_NAME_ID, store.state.documentName) - void rename.focusInput(nameInputRef.value) } function commitRename(input: HTMLInputElement) { @@ -176,7 +178,7 @@ const topMenus = [ OpenPencil - + {{ item.label }} - + diff --git a/src/components/ui/button.ts b/src/components/ui/button.ts index 2edb918be..bb126fb2c 100644 --- a/src/components/ui/button.ts +++ b/src/components/ui/button.ts @@ -1,5 +1,5 @@ -import { tv } from 'tailwind-variants' import { twMerge } from 'tailwind-merge' +import { tv } from 'tailwind-variants' const button = tv({ base: 'inline-flex items-center justify-center transition-colors select-none', @@ -24,10 +24,6 @@ const button = tv({ bordered: { true: 'border border-white/10', false: '' - }, - active: { - true: '', - false: '' } }, compoundVariants: [ @@ -43,8 +39,7 @@ const button = tv({ tone: 'ghost', shape: 'rounded', size: 'sm', - bordered: false, - active: false + bordered: false } }) @@ -53,7 +48,6 @@ export function uiButton(options?: { shape?: 'square' | 'rounded' | 'pill' size?: 'sm' | 'md' | 'icon' | 'iconSm' bordered?: boolean - active?: boolean class?: string }) { return twMerge(button(options), options?.class) diff --git a/src/components/ui/menu.ts b/src/components/ui/menu.ts index 0bc031b6c..a2e847a92 100644 --- a/src/components/ui/menu.ts +++ b/src/components/ui/menu.ts @@ -1,5 +1,5 @@ -import { tv } from 'tailwind-variants' import { twMerge } from 'tailwind-merge' +import { tv } from 'tailwind-variants' const content = tv({ base: 'z-50 rounded-lg border border-border bg-panel p-1 shadow-lg' @@ -10,7 +10,8 @@ const item = tv({ variants: { tone: { default: 'text-surface', - component: 'text-[#9747ff] data-[highlighted]:bg-[#9747ff]/12 data-[disabled]:text-[#9747ff]/40' + component: + 'text-[#9747ff] data-[highlighted]:bg-[#9747ff]/12 data-[disabled]:text-[#9747ff]/40' }, justify: { between: 'justify-between gap-6', diff --git a/src/components/ui/select.ts b/src/components/ui/select.ts index b98d1107d..aa3232a7f 100644 --- a/src/components/ui/select.ts +++ b/src/components/ui/select.ts @@ -1,5 +1,5 @@ -import { tv } from 'tailwind-variants' import { twMerge } from 'tailwind-merge' +import { tv } from 'tailwind-variants' const trigger = tv({ base: 'flex items-center justify-between border border-border bg-input text-surface outline-none hover:bg-hover' diff --git a/src/components/ui/surface.ts b/src/components/ui/surface.ts index 4eb9a9409..95b5d9288 100644 --- a/src/components/ui/surface.ts +++ b/src/components/ui/surface.ts @@ -1,5 +1,5 @@ -import { tv } from 'tailwind-variants' import { twMerge } from 'tailwind-merge' +import { tv } from 'tailwind-variants' const surface = tv({ base: 'border border-border bg-panel', diff --git a/src/composables/use-menu.ts b/src/composables/use-menu.ts index f849e0960..92abea26d 100644 --- a/src/composables/use-menu.ts +++ b/src/composables/use-menu.ts @@ -1,5 +1,4 @@ import { onUnmounted } from 'vue' -import { useFileDialog } from '@vueuse/core' import { IS_TAURI } from '@/constants' import { useEditorStore } from '@/stores/editor' @@ -38,12 +37,14 @@ export async function openFileDialog() { } } - const { open, onChange } = useFileDialog({ accept: '.fig', multiple: false }) - onChange((files) => { - const file = files?.[0] + const input = document.createElement('input') + input.type = 'file' + input.accept = '.fig' + input.addEventListener('change', () => { + const file = input.files?.[0] if (file) void openFileInNewTab(file) }) - open() + input.click() } const store = useEditorStore()