@@ -11,7 +11,7 @@ const projectRootDir = path.resolve(__dirname);
1111// https://vitejs.dev/config/
1212export 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 : / \/ ..\/ b r a n d i n g \/ ( .* \. s v g ) / , 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 ( / < s t y l e (? = \s | > ) ( [ ^ > ] * ) > ( .* ?) < \/ s t y l e > / 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 $ - ] ) u s e r - s e l e c t \s * : \s * ( [ ^ ; { } \r \n ] + ) ; / g, "-webkit-user-select: $1; user-select: $1;" ) ;
57+ return `<style${ attrs } >${ prefixed } </style>` ;
58+ } ) ;
59+ } ,
60+ } ;
61+ }
62+
3863function staticAssets ( ) : PluginOption {
3964 const STATIC_ASSET_DIRS : { source : string ; urlPrefix : string } [ ] = [
4065 { source : "../demo-artwork" , urlPrefix : "/demo-artwork" } ,
0 commit comments