Skip to content

WIP: New drag-and-drop type system#11487

Draft
eira-fransham wants to merge 26 commits intoslint-ui:feature/drag-and-dropfrom
eira-fransham:11400-drag-item-take-2
Draft

WIP: New drag-and-drop type system#11487
eira-fransham wants to merge 26 commits intoslint-ui:feature/drag-and-dropfrom
eira-fransham:11400-drag-item-take-2

Conversation

@eira-fransham
Copy link
Copy Markdown
Contributor

Closes #11400

This isn't a draft PR as I want CI to run, but it shouldn't be merged yet.

@LeonMatthes
Copy link
Copy Markdown
Member

This isn't a draft PR as I want CI to run, but it shouldn't be merged yet.

@eira-fransham CI should run on draft PRs 🤔 Did it not?

@eira-fransham
Copy link
Copy Markdown
Contributor Author

This isn't a draft PR as I want CI to run, but it shouldn't be merged yet.

@eira-fransham CI should run on draft PRs 🤔 Did it not?

Oh! My mistake

@eira-fransham eira-fransham marked this pull request as draft April 23, 2026 12:29
Copy link
Copy Markdown
Member

@LeonMatthes LeonMatthes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's going in a good direction, especially reading the data from the clipboard seems to be nice and easy.
The read side could still benefit a lot from optionals, so that you don't have to do two separate calls. But until we have those, this works well.

We will need to discuss the construction side of the clipboard data types in Slint though. Because as we are seeing here, just creating the data from a string and an image is not enough.
E.g. the component MIME type is now using text/plain in our preview UI, which it shouldn't.
We could use a built-in macro function, which could accept any data type as the data argument.
Something like: clipboard-data("application/x-slint-component", "...")

Another side note on this, maybe we should move away from using a property in the drag area, but rather have a callback like get-data so that we can load the data when you start the drag.

Comment thread tests/driver/rust/build.rs Outdated

output.write_all(
b"#![deny(warnings)]\n#![deny(rust_2018_idioms)]\n#![deny(unsafe_code)]\n",
b"#![warn(rust_2018_idioms)]\n#![deny(unsafe_code)]\n#![allow(clippy::all)]",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is just temporary?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do kinda think we should merge something like this to main because deny(warnings) is considered harmful (we should either use a CLI flag on CI and/or explicitly deny each separate thing if we really want to do that), but you're right that I didn't mean to include it in this PR, it was just because clippy warnings were causing my LSP to go haywire

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Denying warnings is indeed harmful in library code that someone else may depend on, but this is our own testing code, where this is fine in my opinion.
Then you also get the same behavior when testing locally as you do in CI.

Comment thread internal/compiler/generator/rust.rs Outdated
Comment on lines +2676 to +2678
(Type::String | Type::Image, Type::ClipboardData) => {
quote!(sp::ClipboardData::from(#f))
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be quite convenient if we can cast these types to clipboard data but I don't know if this is expressive enough.

For example, what mime type does the image get? Is it an `"image/png"? Or the string? Is it just "text/plain" or "text/marked-down"?
I'm intrigued by the idea though. Maybe we can make it work. But we need to check whether the mime-type is defaulting to the right thing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think SharedString would be text/plain, and Image would be image/* (i.e. it can provide the image in any format you like). StyledText would be text/markdown, application/rtf (required to make copying styled text work on Windows), etc. We should have some way to read text/markdown as SharedString but I won't include that in this PR for now.

Comment thread internal/compiler/llr/expression.rs Outdated
| Type::LayoutCache
| Type::ArrayOfU16 => return None,
| Type::ArrayOfU16
| Type::ClipboardData => return None,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ClipboardData will need a default in Slint, otherwise it will blow up if it's used in a struct (see also: #11489 )

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! The default should be the same as for Type::Void, so I added it to this branch. Didn't realise that was how it worked (I'm guessing because void isn't a valid field type).

Comment thread internal/core/clipboard.rs Outdated
}
}

/// Private version of [`ClipboardData`] so we can implement the traits that we expect
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually not the private version, this is the public Slint type.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, outdated docs. Thanks for catching it, I made a mental note to fix it and then never did.

Comment thread internal/core/clipboard.rs Outdated
///
/// - `text/*`: `SharedString` (this will require boxing the `SharedString` inside an `Rc`)
pub trait ClipboardData {
pub trait ClipboardDataProvider {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, not a fan of this name, but also don't have a better idea atm, so let's bikeshed the naming.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was actually the original name I used for the trait until I decided that Rc<dyn ClipboardData> should be what's passed around. I kinda think that this name makes more sense, since IMO it makes it clearer that it does IO.

Comment thread internal/core/any_data.rs Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I missed the discussion here, but did we talk about adding an any-type to Slint?
Honestly, the motivation for this, even with clipboard, is probably not strong enough. Within Slint, you're most likely not going to use any. You're going to boil this down to concrete types.

So we could just stick with dyn Any in the Rust side and use concrete constructors for the clipboard data on the Slint side.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not adding an any type to Slint, I did try that but didn't like how implicit the interface was. I explain why I didn't want to use dyn Any in the chat (I'll send you a link as a DM since it's in the internal channel), but to sum it up: using dyn Any makes it trivial for implementers of ClipboardDataProvider to accidentally return the wrong type - e.g. String instead of SharedString - and limiting the interface makes that harder to do by accident.

@eira-fransham eira-fransham force-pushed the 11400-drag-item-take-2 branch from 55937ba to 73c8656 Compare April 27, 2026 12:26
dependabot Bot and others added 16 commits April 27, 2026 14:43
…i#11446)

Bumps the npm-patch-updates group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@napi-rs/cli](https://github.com/napi-rs/napi-rs) | `3.6.1` | `3.6.2` |
| [vite-plugin-singlefile](https://github.com/richardtallent/vite-plugin-singlefile) | `2.3.2` | `2.3.3` |
| [@astrojs/partytown](https://github.com/withastro/astro/tree/HEAD/packages/integrations/partytown) | `2.1.6` | `2.1.7` |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.11` | `2.4.12` |
| [astro](https://github.com/withastro/astro/tree/HEAD/packages/astro) | `6.1.5` | `6.1.8` |
| [typescript](https://github.com/microsoft/TypeScript) | `6.0.2` | `6.0.3` |

Updates `@napi-rs/cli` from 3.6.1 to 3.6.2
- [Release notes](https://github.com/napi-rs/napi-rs/releases)
- [Commits](https://github.com/napi-rs/napi-rs/compare/@napi-rs/cli@3.6.1...@napi-rs/cli@3.6.2)

Updates `vite-plugin-singlefile` from 2.3.2 to 2.3.3
- [Release notes](https://github.com/richardtallent/vite-plugin-singlefile/releases)
- [Changelog](https://github.com/richardtallent/vite-plugin-singlefile/blob/main/CHANGELOG.md)
- [Commits](https://github.com/richardtallent/vite-plugin-singlefile/commits)

Updates `@astrojs/partytown` from 2.1.6 to 2.1.7
- [Release notes](https://github.com/withastro/astro/releases)
- [Changelog](https://github.com/withastro/astro/blob/main/packages/integrations/partytown/CHANGELOG.md)
- [Commits](https://github.com/withastro/astro/commits/@astrojs/partytown@2.1.7/packages/integrations/partytown)

Updates `@biomejs/biome` from 2.4.11 to 2.4.12
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.12/packages/@biomejs/biome)

Updates `astro` from 6.1.5 to 6.1.8
- [Release notes](https://github.com/withastro/astro/releases)
- [Changelog](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md)
- [Commits](https://github.com/withastro/astro/commits/astro@6.1.8/packages/astro)

Updates `typescript` from 6.0.2 to 6.0.3
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](microsoft/TypeScript@v6.0.2...v6.0.3)

---
updated-dependencies:
- dependency-name: "@napi-rs/cli"
  dependency-version: 3.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-patch-updates
- dependency-name: vite-plugin-singlefile
  dependency-version: 2.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-patch-updates
- dependency-name: "@astrojs/partytown"
  dependency-version: 2.1.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-patch-updates
- dependency-name: "@biomejs/biome"
  dependency-version: 2.4.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-patch-updates
- dependency-name: astro
  dependency-version: 6.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-patch-updates
- dependency-name: typescript
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Lets AI agents fetch /docs/.../foo.md instead of the HTML page,
saving tokens on retrieval. Implemented as a static Astro endpoint
over the docs collection, so it works the same on Cloudflare Pages
and Netlify with no per-host routing.
The markdown sibling endpoint now resolves the <Link/> component into
a real markdown link pointing at the target page's .md sibling, so AI
agents can chain markdown fetches without rewriting URLs.

Two safety nets keep the output honest:

- A Playwright spec asserts no unresolved MDX components leak into any
  built .md file.
- A post-build script walks the .md corpus with remark and verifies
  every internal link points at an existing file. Wired into the build
  step so a broken link fails the build.
* refactor: use wgpu re-exported from slint and remove redundant wgpu-hal/wgpu dependencies

* refactor: improve lib

* docs: Update README for new implementation

* refactor: move get_wgpu_texture_from_metal from GPURenderingContext to metal module extension trait

* refactor: fix wgpu_hal import to wpgu::hal from slint

* hal

* refactor: decouple android and linux gpu rendering context configurations to support platform-specific API detection

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Migrate the testing backend introspection handle storage from generational-arena to slotmap.

This removes the unmaintained generational-arena dependency from the internal testing backend while keeping the existing handle serialization format used by the MCP and system-testing APIs.
Reject malformed wire handles before they reach slotmap so even generations and oversized parts do not normalize into live keys. This fixes the broken slotmap migration roundtrip test, propagates invalid-handle errors through the MCP and system-testing paths, and adds focused coverage for malformed handle decoding.
@eira-fransham eira-fransham force-pushed the 11400-drag-item-take-2 branch from 73c8656 to 77d3a58 Compare April 27, 2026 12:44
cmd.arg("--error-exitcode=1");
cmd.arg("--num-callers=50");
cmd.arg(binary_path.deref());
} else if std::env::var("USE_LLDB").is_ok() {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added as an alternative to valgrind for platforms where it doesn't work, since valgrind can't run on macOS, Windows, or CachyOS (Linux distro with AVX512 enabled for libraries).

- Rename `ClipboardData`/`clipboard-data` to `DataTransfer`/`data-transfer`
- Remove Slint API for `data-transfer`, forcing use of global callbacks
- New API for constructing `DataTransfer`, more similar to JS DOM API
- Bytes-based API for data
Copy link
Copy Markdown
Member

@tronical tronical left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A first round of review. I'll hold off until you give the signal for further review :). Glad that we've settled on DataTransfer btw :)

Type::DataTransfer => {
if let Some(clipboard_data) = unknown
.coerce_to_object()?
.get::<ExternalRef<DataTransfer>>("clipboard_data")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be transfer_data for the string literal as well as the variable.

Comment on lines +323 to +326
Type::DataTransfer => Expression::Cast {
from: Box::new(Expression::CodeBlock(Default::default())),
to: ty.clone(),
},
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be cleaner and clearer to have an expression instead of the implicit cast from an empty code block.

/// Enable support for additional formats supported by the [`image` crate](https://crates.io/crates/image) (
/// AVIF, BMP, DDS, Farbfeld, GIF, HDR, ICO, JPEG, EXR, PNG, PNM, QOI, TGA, TIFF, WebP)
/// by enabling the `image-default-formats` cargo feature.
pub fn load_from_dynamic_data(bytes: &[u8], format: &str) -> Result<Self, LoadImageError> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to leave that out from the public API as part of this PR and we do this separately.

Comment thread internal/core/api.rs
ClipboardTypeNotFound(String),
}

impl Clone for PlatformError {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the Clone needed?

}

impl DataTransfer {
pub fn set_internal(&mut self, value: Rc<dyn Any>) -> &mut Self {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean set_any here? I think that's the name we discussed and I can see it in the outline page.

(set_internal sounds too much like an internal function)

self.internal.clone()
}

pub fn read_plaintext(&self) -> Result<SharedString, PlatformError> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had discussed get_ instead of read in the review.

api::{Image, PlatformError},
};

pub mod mime;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's meant to be public API, right? (at least it's not in the outline page we discussed)

Comment thread internal/core/items.rs
pub use drag_n_drop::*;
#[cfg(feature = "path")]
mod path;
pub use crate::DataTransfer;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since DataTransfer isn't an Item, why does it have to be exported under items?

}

/// Try to convert the type to `to`, or return self unmodified as an error.
pub fn try_cast(self, to: LangType) -> Result<Self, Self> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that LangType isn't public, this function should probably also not be public.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants