wails/docs/astro.config.mjs
Lea Anthony 53c2275fea
fix(v3): overhaul drag-and-drop for Linux reliability and simplify Windows implementation (#4848)
* fix(v3): overhaul drag-and-drop for Linux reliability and simplify Windows

This commit fixes drag-and-drop reliability on Linux and simplifies the
Windows implementation.

## Linux
- Rewrite GTK drag handlers to properly intercept external file drops
- Fix HTML5 internal drag-and-drop being broken when file drop enabled
- Add hover effects during file drag operations
- Fix multiple app instances interfering with each other

## Windows
- Remove native IDropTarget in favor of JavaScript approach (matches v2)
- File drops now handled via chrome.webview.postMessageWithAdditionalObjects

## All Platforms
- Rename EnableDragAndDrop to EnableFileDrop
- Rename data-wails-drop-target to data-file-drop-target
- Rename wails-drop-target-active to file-drop-target-active
- Add comprehensive drag-and-drop documentation

## Breaking Changes
- EnableDragAndDrop -> EnableFileDrop
- data-wails-dropzone -> data-file-drop-target
- wails-dropzone-hover -> file-drop-target-active
- DropZoneDetails -> DropTargetDetails
- Remove WindowDropZoneFilesDropped event (use WindowFilesDropped)

* feat(macos): optimize drag event performance with debouncing and caching

- Add 50ms debouncing to limit drag events to 20/sec (was 120/sec)
- Implement window implementation caching to avoid repeated lookups
- Maintain existing 5-pixel threshold for immediate response
- Keep zero-allocation path with pre-allocated buffers
- Rename linuxDragActive to nativeDragActive for clarity
- Update IMPLEMENTATION.md with optimization details and Windows guidance

Performance improvements:
- 83% reduction in event frequency
- ~6x reduction in CPU/memory usage during drag operations
- Maintains smooth visual feedback with InvokeSync for timer callbacks

* fix(windows): implement proper file drop support for Windows

- Remove incorrect AllowExternalDrag(false) call that was blocking file drops
- Fix message prefix from 'FilesDropped' to 'file:drop:' to match JS runtime
- Fix coordinate parsing for 'file:drop:x:y' format (indices 2,3 not 1,2)
- Add enableFileDrop flag injection to JS runtime during navigation
- Update JS runtime to check enableFileDrop flag before processing drops
- Always call preventDefault() to stop browser navigation on file drags
- Show 'no drop' cursor when file drops are disabled
- Update example to filter file drags from HTML drop zone handlers
- Add documentation for combining file drop with HTML drag-and-drop

* fix(v3): block file drops on Linux when EnableFileDrop is false

- Add disableDND() to intercept and reject external file drags at GTK level
- Show 'no drop' cursor when files are dragged over window
- Allow internal HTML5 drag-and-drop to work normally
- Initialize _wails.flags object in runtime core to prevent undefined errors
- Inject enableFileDrop flag on Linux and macOS (matching Windows)
- Fix bare _wails reference to use window._wails
- Update docs with info about blocked drops and combining with HTML DnD

* fix(darwin): add missing fmt import in webview_window_darwin.go

* fix(macOS): implement hover effects for file drag-and-drop with optimizations

- Added draggingUpdated: handler to track mouse movement during drag operations
- Implemented macosOnDragEnter/Exit/Over export functions for real-time hover state
- Fixed JS function call from '_wails.handlePlatformFileDrop' to correct 'wails.Window.HandlePlatformFileDrop'
- Added EnableFileDrop flag checks to prevent hover effects when file drops are disabled
- Renamed linuxDragActive to nativeDragActive for cross-platform consistency

Performance optimizations:
- Added 50ms debounce to reduce event frequency from ~120/sec to ~20/sec
- Implemented 5-pixel movement threshold for immediate response
- Added window caching with sync.Map to avoid repeated lookups
- Zero-allocation JavaScript calls with pre-allocated 128-byte buffer
- Reduced memory usage to ~18 bytes per event (6x reduction)

Build improvements:
- Updated runtime Taskfile to include documentation generation
- Added docs:build task to runtime build process
- Fixed build order: events → docs → runtime

Documentation:
- Added IMPLEMENTATION.md with optimization details
- Included guidance for Windows implementation

* chore(v3/examples): remove html-dnd-api example

The drag-n-drop example now demonstrates both external file drops
and internal HTML5 drag-and-drop, making this separate example redundant.

* docs(v3): move drag-and-drop implementation details to runtime-internals

- Add drag-and-drop section to contributing/runtime-internals.mdx
- Remove IMPLEMENTATION.md from example (content now in proper docs)
- Covers platform differences, debugging tips, and key files

* fix(v3): remove html-dnd-api from example build list

* fix(v3): remove duplicate json import in application_darwin.go

* fix(v3): address CodeRabbit review feedback

- Fix docs to use app.Window.NewWithOptions() instead of deprecated API
- Add mutex protection to dragOverJSBuffer to prevent race conditions
- Add mutex protection to dragThrottleState fields for thread safety

* docs: add coderabbit pre-push requirement to AGENTS.md

* fix(v3/test): use correct CSS class name file-drop-target-active

* chore(v3/test): remove dnd-test directory

This was a development test file that shouldn't be in the PR.
The drag-n-drop example serves as the proper test case.

* docs(v3): update Windows file drop comment to reflect implemented fix

Remove stale TODO - enableFileDrop flag is now injected in navigationCompleted

* refactor(v3): make handleDragAndDropMessage unexported

Internal method only called by application event loop, not part of public API.
2026-01-04 11:08:29 +11:00

348 lines
13 KiB
JavaScript

// @ts-check
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import sitemap from "@astrojs/sitemap";
import starlightLinksValidator from "starlight-links-validator";
import starlightImageZoom from "starlight-image-zoom";
import starlightBlog from "starlight-blog";
import { authors } from "./src/content/authors";
import d2 from 'astro-d2';
import react from '@astrojs/react';
// https://astro.build/config
export default defineConfig({
site: "https://wails.io",
trailingSlash: "ignore",
compressHTML: true,
output: "static",
build: { format: "directory" },
devToolbar: { enabled: true },
integrations: [
react(),
d2(),
sitemap(),
starlight({
title: "",
titleDelimiter: "",
logo: {
dark: "./src/assets/wails-logo-horizontal-dark.svg",
light: "./src/assets/wails-logo-horizontal-light.svg",
},
favicon: "./public/favicon.svg",
description: "Build beautiful desktop applications using Go and modern web technologies.",
pagefind: true,
customCss: ["./src/stylesheets/extra.css"],
lastUpdated: true,
pagination: true,
editLink: {
baseUrl: "https://github.com/wailsapp/wails/edit/v3-alpha/docs",
},
social: [
{ icon: 'github', label: 'GitHub', href: 'https://github.com/wailsapp/wails' },
{ icon: 'discord', label: 'Discord', href: 'https://discord.gg/JDdSxwjhGf' },
{ icon: 'x.com', label: 'X', href: 'https://x.com/wailsapp' },
],
head: [
{
tag: 'script',
content: `
document.addEventListener('DOMContentLoaded', () => {
const socialLinks = document.querySelector('.social-icons');
if (socialLinks) {
const sponsorLink = document.createElement('a');
sponsorLink.href = 'https://github.com/sponsors/leaanthony';
sponsorLink.className = 'sl-flex';
sponsorLink.title = 'Sponsor';
sponsorLink.innerHTML = '<span class="sr-only">Sponsor</span><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="#ef4444" stroke="none"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/></svg>';
socialLinks.appendChild(sponsorLink);
}
});
`,
},
],
defaultLocale: "root",
locales: {
root: { label: "English", lang: "en", dir: "ltr" },
},
plugins: [
starlightImageZoom(),
starlightBlog({
title: "Wails Blog",
authors: authors,
}),
],
sidebar: [
{ label: "Home", link: "/" },
// Progressive Onboarding - Netflix Principle: Start with the problem
{ label: "Why Wails?", link: "/quick-start/why-wails" },
{
label: "Quick Start",
collapsed: false,
items: [
{ label: "Installation", link: "/quick-start/installation" },
{ label: "Your First App", link: "/quick-start/first-app" },
{ label: "Next Steps", link: "/quick-start/next-steps" },
],
},
// Tutorials
{
label: "Tutorials",
collapsed: true,
autogenerate: { directory: "tutorials" },
},
// Core Concepts
{
label: "Core Concepts",
collapsed: true,
items: [
{ label: "How Wails Works", link: "/concepts/architecture" },
{ label: "Manager API", link: "/concepts/manager-api" },
{ label: "Application Lifecycle", link: "/concepts/lifecycle" },
{ label: "Go-Frontend Bridge", link: "/concepts/bridge" },
{ label: "Build System", link: "/concepts/build-system" },
],
},
{
label: "Features",
collapsed: true,
items: [
{
label: "Windows",
collapsed: true,
items: [
{ label: "Window Basics", link: "/features/windows/basics" },
{ label: "Window Options", link: "/features/windows/options" },
{ label: "Multiple Windows", link: "/features/windows/multiple" },
{ label: "Frameless Windows", link: "/features/windows/frameless" },
{ label: "Window Events", link: "/features/windows/events" },
],
},
{
label: "Menus",
collapsed: true,
items: [
{ label: "Application Menus", link: "/features/menus/application" },
{ label: "Context Menus", link: "/features/menus/context" },
{ label: "System Tray Menus", link: "/features/menus/systray" },
{ label: "Menu Reference", link: "/features/menus/reference" },
],
},
{
label: "Bindings & Services",
collapsed: true,
items: [
{ label: "Method Binding", link: "/features/bindings/methods" },
{ label: "Services", link: "/features/bindings/services" },
{ label: "Advanced Binding", link: "/features/bindings/advanced" },
{ label: "Best Practices", link: "/features/bindings/best-practices" },
],
},
{
label: "Events",
collapsed: true,
items: [
{ label: "Event System", link: "/features/events/system" },
{ label: "Application Events", link: "/features/events/application" },
{ label: "Window Events", link: "/features/events/window" },
{ label: "Custom Events", link: "/features/events/custom" },
],
},
{
label: "Dialogs",
collapsed: true,
items: [
{ label: "File Dialogs", link: "/features/dialogs/file" },
{ label: "Message Dialogs", link: "/features/dialogs/message" },
{ label: "Custom Dialogs", link: "/features/dialogs/custom" },
],
},
{
label: "Clipboard",
collapsed: true,
autogenerate: { directory: "features/clipboard" },
},
{
label: "Browser",
collapsed: true,
autogenerate: { directory: "features/browser" },
},
{
label: "Drag & Drop",
collapsed: true,
autogenerate: { directory: "features/drag-and-drop" },
},
{
label: "Keyboard",
collapsed: true,
autogenerate: { directory: "features/keyboard" },
},
{
label: "Notifications",
collapsed: true,
autogenerate: { directory: "features/notifications" },
},
{
label: "Screens",
collapsed: true,
autogenerate: { directory: "features/screens" },
},
{
label: "Environment",
collapsed: true,
autogenerate: { directory: "features/environment" },
},
{
label: "Platform-Specific",
collapsed: true,
autogenerate: { directory: "features/platform" },
},
],
},
// Guides - Task-oriented patterns (Netflix: When to use it, when not to use it)
{
label: "Guides",
collapsed: true,
items: [
{
label: "Development",
collapsed: true,
items: [
{ label: "Project Structure", link: "/guides/dev/project-structure" },
{ label: "Development Workflow", link: "/guides/dev/workflow" },
{ label: "Debugging", link: "/guides/dev/debugging" },
{ label: "Testing", link: "/guides/dev/testing" },
],
},
{
label: "Building & Packaging",
collapsed: true,
items: [
{ label: "Building Applications", link: "/guides/build/building" },
{ label: "Build Customization", link: "/guides/build/customization" },
{ label: "Cross-Platform Builds", link: "/guides/build/cross-platform" },
{ label: "Code Signing", link: "/guides/build/signing" },
{ label: "Windows Packaging", link: "/guides/build/windows" },
{ label: "macOS Packaging", link: "/guides/build/macos" },
{ label: "Linux Packaging", link: "/guides/build/linux" },
{ label: "MSIX Packaging", link: "/guides/build/msix" },
],
},
{
label: "Distribution",
collapsed: true,
items: [
{ label: "Auto-Updates", link: "/guides/distribution/auto-updates" },
{ label: "File Associations", link: "/guides/distribution/file-associations" },
{ label: "Custom Protocols", link: "/guides/distribution/custom-protocols" },
{ label: "Single Instance", link: "/guides/distribution/single-instance" },
],
},
{
label: "Integration Patterns",
collapsed: true,
items: [
{ label: "Using Gin Router", link: "/guides/patterns/gin-routing" },
{ label: "Gin Services", link: "/guides/patterns/gin-services" },
{ label: "Database Integration", link: "/guides/patterns/database" },
{ label: "REST APIs", link: "/guides/patterns/rest-api" },
],
},
{
label: "Advanced Topics",
collapsed: true,
items: [
{ label: "Custom Templates", link: "/guides/advanced/custom-templates" },
{ label: "WML (Wails Markup)", link: "/guides/advanced/wml" },
{ label: "Panic Handling", link: "/guides/advanced/panic-handling" },
{ label: "Security Best Practices", link: "/guides/advanced/security" },
],
},
],
},
// Reference - Comprehensive API docs (Netflix: Complete technical reference)
{
label: "API Reference",
collapsed: true,
items: [
{ label: "Overview", link: "/reference/overview" },
{ label: "Application", link: "/reference/application" },
{ label: "Window", link: "/reference/window" },
{ label: "Menu", link: "/reference/menu" },
{ label: "Events", link: "/reference/events" },
{ label: "Dialogs", link: "/reference/dialogs" },
{ label: "Frontend Runtime", link: "/reference/frontend-runtime" },
{ label: "CLI", link: "/reference/cli" },
],
},
// Contributing
{
label: "Contributing",
collapsed: true,
items: [
{ label: "Getting Started", link: "/contributing/getting-started" },
{ label: "Development Setup", link: "/contributing/setup" },
{ label: "Coding Standards", link: "/contributing/standards" },
],
},
// Migration & Troubleshooting
{
label: "Migration",
collapsed: true,
items: [
{ label: "From v2 to v3", link: "/migration/v2-to-v3" },
{ label: "From Electron", link: "/migration/from-electron" },
],
},
{
label: "Troubleshooting",
collapsed: true,
autogenerate: { directory: "troubleshooting" },
},
// Community & Resources
{
label: "Community",
collapsed: true,
items: [
{ label: "Links", link: "/community/links" },
{ label: "Templates", link: "/community/templates" },
{
label: "Showcase",
collapsed: true,
items: [
{ label: "Overview", link: "/community/showcase" },
{
label: "Applications",
autogenerate: {
directory: "community/showcase",
collapsed: true,
},
},
],
},
],
},
{ label: "What's New", link: "/whats-new" },
{ label: "Status", link: "/status" },
{ label: "Changelog", link: "/changelog" },
{
label: "Sponsor",
link: "https://github.com/sponsors/leaanthony",
badge: { text: "❤️" },
},
{ label: "Credits", link: "/credits" },
],
}),
],
});