Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion frontend/src/components/Editor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@
height: 100%;
background: var(--color-2-mildblack);
overscroll-behavior: none;
-webkit-user-select: none; // Still required by Safari as of 2025
user-select: none;
}

Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/floating-menus/Dialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@
}

.text-label.multiline {
-webkit-user-select: text; // Still required by Safari as of 2026
user-select: text;
}

Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/panels/Layers.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,6 @@
width: 100%;

&:disabled {
-webkit-user-select: none; // Still required by Safari as of 2025
user-select: none;
// Workaround for `user-select: none` not working on <input> elements
pointer-events: none;
Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/views/Graph.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,6 @@
&.faded:hover {
z-index: 2;
opacity: 1;
-webkit-user-select: text;
user-select: text;
transition:
opacity 0.2s,
Expand Down
27 changes: 26 additions & 1 deletion frontend/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const projectRootDir = path.resolve(__dirname);
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
return {
plugins: [svelteGlobalStyles(), svelte(), staticAssets(), mode !== "native" && thirdPartyLicenses(), mode !== "native" && serviceWorker()],
plugins: [svelteGlobalStyles(), webkitUserSelectPrefix(), svelte(), staticAssets(), mode !== "native" && thirdPartyLicenses(), mode !== "native" && serviceWorker()],
resolve: {
alias: [{ find: /\/..\/branding\/(.*\.svg)/, replacement: path.resolve(projectRootDir, "../branding", "$1?raw") }],
},
Expand All @@ -35,6 +35,31 @@ function svelteGlobalStyles(): PluginOption {
};
}

// Adds the `-webkit-user-select` prefix alongside every `user-select` declaration in Svelte component styles (still required by Safari). Remove when Safari ships the unprefixed version.
// WebKit tracking issue:
// https://bugs.webkit.org/show_bug.cgi?id=208677
// Included in Interop 2026:
// https://webkit.org/blog/17818/announcing-interop-2026/#web-compat
// https://github.com/web-platform-tests/interop/issues/1000#issuecomment-3892214470
// Web platform test for WebKit implementation status:
// https://wpt.fyi/results/css/css-ui/parsing/user-select-computed.html?label=master&label=experimental&aligned&view=interop&q=label%3Ainterop-2026-webcompat
function webkitUserSelectPrefix(): PluginOption {
return {
name: "webkit-user-select-prefix",
enforce: "pre",
transform(code, id) {
if (!id.endsWith(".svelte")) return;

return code.replace(/<style(?=\s|>)([^>]*)>(.*?)<\/style>/gs, (_, attrs, content) => {
// The lookbehind requires a property boundary on the left, so it skips `-webkit-`/`-moz-` prefixes, `--custom` properties, and `$scss-variables`.
// Excluding newlines/braces from the value stops a `user-select` mentioned in a comment from swallowing the following declarations.
const prefixed = content.replace(/(?<![\w$-])user-select\s*:\s*([^;{}\r\n]+);/g, "-webkit-user-select: $1; user-select: $1;");
return `<style${attrs}>${prefixed}</style>`;
});
},
};
}

function staticAssets(): PluginOption {
const STATIC_ASSET_DIRS: { source: string; urlPrefix: string }[] = [
{ source: "../demo-artwork", urlPrefix: "/demo-artwork" },
Expand Down
Loading