Skip to content

Commit fa27d53

Browse files
authored
Add a Vite plugin to auto-prefix -webkit-user-select so it's not so often forgotten (#4288)
* Add a Vite plugin to auto-prefix -webkit-user-select so it's not so often forgotten * Enforce a property boundary on the left
1 parent cc465d6 commit fa27d53

5 files changed

Lines changed: 26 additions & 5 deletions

File tree

frontend/src/components/Editor.svelte

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@
233233
height: 100%;
234234
background: var(--color-2-mildblack);
235235
overscroll-behavior: none;
236-
-webkit-user-select: none; // Still required by Safari as of 2025
237236
user-select: none;
238237
}
239238

frontend/src/components/floating-menus/Dialog.svelte

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@
136136
}
137137
138138
.text-label.multiline {
139-
-webkit-user-select: text; // Still required by Safari as of 2026
140139
user-select: text;
141140
}
142141

frontend/src/components/panels/Layers.svelte

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,6 @@
884884
width: 100%;
885885
886886
&:disabled {
887-
-webkit-user-select: none; // Still required by Safari as of 2025
888887
user-select: none;
889888
// Workaround for `user-select: none` not working on <input> elements
890889
pointer-events: none;

frontend/src/components/views/Graph.svelte

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,6 @@
952952
&.faded:hover {
953953
z-index: 2;
954954
opacity: 1;
955-
-webkit-user-select: text;
956955
user-select: text;
957956
transition:
958957
opacity 0.2s,

frontend/vite.config.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const projectRootDir = path.resolve(__dirname);
1111
// https://vitejs.dev/config/
1212
export default defineConfig(({ mode }) => {
1313
return {
14-
plugins: [svelteGlobalStyles(), svelte(), staticAssets(), mode !== "native" && thirdPartyLicenses(), mode !== "native" && serviceWorker()],
14+
plugins: [svelteGlobalStyles(), webkitUserSelectPrefix(), svelte(), staticAssets(), mode !== "native" && thirdPartyLicenses(), mode !== "native" && serviceWorker()],
1515
resolve: {
1616
alias: [{ find: /\/..\/branding\/(.*\.svg)/, replacement: path.resolve(projectRootDir, "../branding", "$1?raw") }],
1717
},
@@ -35,6 +35,31 @@ function svelteGlobalStyles(): PluginOption {
3535
};
3636
}
3737

38+
// 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.
39+
// WebKit tracking issue:
40+
// https://bugs.webkit.org/show_bug.cgi?id=208677
41+
// Included in Interop 2026:
42+
// https://webkit.org/blog/17818/announcing-interop-2026/#web-compat
43+
// https://github.com/web-platform-tests/interop/issues/1000#issuecomment-3892214470
44+
// Web platform test for WebKit implementation status:
45+
// https://wpt.fyi/results/css/css-ui/parsing/user-select-computed.html?label=master&label=experimental&aligned&view=interop&q=label%3Ainterop-2026-webcompat
46+
function webkitUserSelectPrefix(): PluginOption {
47+
return {
48+
name: "webkit-user-select-prefix",
49+
enforce: "pre",
50+
transform(code, id) {
51+
if (!id.endsWith(".svelte")) return;
52+
53+
return code.replace(/<style(?=\s|>)([^>]*)>(.*?)<\/style>/gs, (_, attrs, content) => {
54+
// The lookbehind requires a property boundary on the left, so it skips `-webkit-`/`-moz-` prefixes, `--custom` properties, and `$scss-variables`.
55+
// Excluding newlines/braces from the value stops a `user-select` mentioned in a comment from swallowing the following declarations.
56+
const prefixed = content.replace(/(?<![\w$-])user-select\s*:\s*([^;{}\r\n]+);/g, "-webkit-user-select: $1; user-select: $1;");
57+
return `<style${attrs}>${prefixed}</style>`;
58+
});
59+
},
60+
};
61+
}
62+
3863
function staticAssets(): PluginOption {
3964
const STATIC_ASSET_DIRS: { source: string; urlPrefix: string }[] = [
4065
{ source: "../demo-artwork", urlPrefix: "/demo-artwork" },

0 commit comments

Comments
 (0)