@shellraining/dsh-fluent-theme 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +68 -2
- package/client.js +2874 -0
- package/cordis.patch.yml +3 -0
- package/icon.png +0 -0
- package/index.js +4 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +64 -3
package/client.js
ADDED
|
@@ -0,0 +1,2874 @@
|
|
|
1
|
+
// Generated by `pnpm run build`; edit src/, not this file.
|
|
2
|
+
window.__ModuleLoader__.load({
|
|
3
|
+
id: "@shellraining/dsh-fluent-theme",
|
|
4
|
+
factory: (require) => {
|
|
5
|
+
var module = { exports: {} };
|
|
6
|
+
var exports = module.exports;
|
|
7
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
8
|
+
let react = require("react");
|
|
9
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
|
+
// src/settings.ts
|
|
12
|
+
var PLUGIN_ID = "dsh-acrylic-wallpaper";
|
|
13
|
+
var FITS = Object.freeze([
|
|
14
|
+
"cover",
|
|
15
|
+
"contain",
|
|
16
|
+
"stretch",
|
|
17
|
+
"tile"
|
|
18
|
+
]);
|
|
19
|
+
var LIMITS = Object.freeze({
|
|
20
|
+
blur: 64,
|
|
21
|
+
tint: 95,
|
|
22
|
+
noise: 8
|
|
23
|
+
});
|
|
24
|
+
var SWITCHES = [
|
|
25
|
+
"enabled",
|
|
26
|
+
"fluent",
|
|
27
|
+
"reveal"
|
|
28
|
+
];
|
|
29
|
+
var DEFAULT_SETTINGS = Object.freeze({
|
|
30
|
+
enabled: true,
|
|
31
|
+
blur: 32,
|
|
32
|
+
tint: 72,
|
|
33
|
+
noise: 3,
|
|
34
|
+
fit: "cover",
|
|
35
|
+
fluent: true,
|
|
36
|
+
reveal: true
|
|
37
|
+
});
|
|
38
|
+
var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
39
|
+
var object = (value) => value !== null && typeof value === "object" ? value : {};
|
|
40
|
+
var isFit = (value) => FITS.includes(value);
|
|
41
|
+
function normalizeSettings(input) {
|
|
42
|
+
const value = object(input);
|
|
43
|
+
const result = { ...DEFAULT_SETTINGS };
|
|
44
|
+
for (const key of SWITCHES) {
|
|
45
|
+
const candidate = value[key];
|
|
46
|
+
if (own(value, key) && typeof candidate === "boolean") result[key] = candidate;
|
|
47
|
+
}
|
|
48
|
+
for (const [key, max] of Object.entries(LIMITS)) {
|
|
49
|
+
const candidate = value[key];
|
|
50
|
+
if (own(value, key) && typeof candidate === "number" && Number.isFinite(candidate)) result[key] = Math.max(0, Math.min(max, candidate));
|
|
51
|
+
}
|
|
52
|
+
if (isFit(value.fit)) result.fit = value.fit;
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
// src/style.ts
|
|
56
|
+
function createStyleSheet(document, id, css) {
|
|
57
|
+
const node = document.createElement("style");
|
|
58
|
+
node.dataset.plugin = id;
|
|
59
|
+
node.textContent = css;
|
|
60
|
+
return {
|
|
61
|
+
toggle(enabled) {
|
|
62
|
+
if (!enabled) node.remove();
|
|
63
|
+
else if (!node.isConnected) document.head.append(node);
|
|
64
|
+
},
|
|
65
|
+
set(next) {
|
|
66
|
+
if (node.textContent !== next) node.textContent = next;
|
|
67
|
+
},
|
|
68
|
+
dispose() {
|
|
69
|
+
node.remove();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// src/storage.ts
|
|
74
|
+
function record(input) {
|
|
75
|
+
const value = object(input);
|
|
76
|
+
const revision = value.imageRevision;
|
|
77
|
+
return {
|
|
78
|
+
settings: normalizeSettings(value.settings),
|
|
79
|
+
image: value.image instanceof Blob ? value.image : null,
|
|
80
|
+
name: typeof value.name === "string" ? value.name : "",
|
|
81
|
+
imageRevision: Number.isSafeInteger(revision) && revision >= 0 ? revision : 0
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function createStorage(indexedDB = globalThis.indexedDB) {
|
|
85
|
+
function open() {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
if (!indexedDB) return reject(/* @__PURE__ */ new Error("IndexedDB is unavailable"));
|
|
88
|
+
let settled = false;
|
|
89
|
+
const request = indexedDB.open(PLUGIN_ID, 1);
|
|
90
|
+
request.onupgradeneeded = () => {
|
|
91
|
+
if (settled) return request.transaction?.abort();
|
|
92
|
+
request.result.createObjectStore("state");
|
|
93
|
+
};
|
|
94
|
+
request.onerror = () => {
|
|
95
|
+
settled = true;
|
|
96
|
+
reject(request.error || /* @__PURE__ */ new Error("Cannot open wallpaper storage"));
|
|
97
|
+
};
|
|
98
|
+
request.onblocked = () => {
|
|
99
|
+
settled = true;
|
|
100
|
+
reject(/* @__PURE__ */ new Error("Wallpaper storage upgrade is blocked"));
|
|
101
|
+
};
|
|
102
|
+
request.onsuccess = () => {
|
|
103
|
+
const db = request.result;
|
|
104
|
+
if (settled) return db.close();
|
|
105
|
+
settled = true;
|
|
106
|
+
db.onversionchange = () => db.close();
|
|
107
|
+
resolve(db);
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async function transact(patch) {
|
|
112
|
+
const db = await open();
|
|
113
|
+
try {
|
|
114
|
+
return await new Promise((resolve, reject) => {
|
|
115
|
+
const tx = db.transaction("state", patch ? "readwrite" : "readonly");
|
|
116
|
+
let result;
|
|
117
|
+
let failure;
|
|
118
|
+
tx.oncomplete = () => resolve(result ?? record(void 0));
|
|
119
|
+
tx.onabort = () => reject(failure || tx.error || /* @__PURE__ */ new Error("Wallpaper storage transaction aborted"));
|
|
120
|
+
tx.onerror = () => {
|
|
121
|
+
failure ||= tx.error;
|
|
122
|
+
};
|
|
123
|
+
const store = tx.objectStore("state");
|
|
124
|
+
const request = store.get("current");
|
|
125
|
+
request.onsuccess = () => {
|
|
126
|
+
try {
|
|
127
|
+
const current = record(request.result);
|
|
128
|
+
result = current;
|
|
129
|
+
if (!patch) return;
|
|
130
|
+
current.settings = normalizeSettings({
|
|
131
|
+
...current.settings,
|
|
132
|
+
...patch.settings
|
|
133
|
+
});
|
|
134
|
+
if (patch.image !== void 0) {
|
|
135
|
+
current.image = patch.image;
|
|
136
|
+
current.imageRevision = current.imageRevision < Number.MAX_SAFE_INTEGER ? current.imageRevision + 1 : 0;
|
|
137
|
+
}
|
|
138
|
+
if (patch.name !== void 0) current.name = patch.name;
|
|
139
|
+
if (current.image === null) current.name = "";
|
|
140
|
+
store.put(current, "current");
|
|
141
|
+
} catch (error) {
|
|
142
|
+
failure = error;
|
|
143
|
+
tx.abort();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
} finally {
|
|
148
|
+
db.close();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const read = () => transact();
|
|
152
|
+
const update = async (input = {}) => {
|
|
153
|
+
const value = object(input);
|
|
154
|
+
const patch = { settings: {} };
|
|
155
|
+
const settings = object(value.settings);
|
|
156
|
+
const accepted = patch.settings;
|
|
157
|
+
for (const key of Object.keys(DEFAULT_SETTINGS)) if (own(settings, key)) accepted[key] = settings[key];
|
|
158
|
+
if (own(value, "image")) {
|
|
159
|
+
if (value.image !== null && !(value.image instanceof Blob)) throw new TypeError("image must be a Blob or null");
|
|
160
|
+
patch.image = value.image;
|
|
161
|
+
}
|
|
162
|
+
if (own(value, "name")) {
|
|
163
|
+
if (typeof value.name !== "string") throw new TypeError("name must be a string");
|
|
164
|
+
patch.name = value.name;
|
|
165
|
+
}
|
|
166
|
+
return transact(patch);
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
read,
|
|
170
|
+
update
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// src/image.ts
|
|
174
|
+
var MAX_BYTES = 20971520;
|
|
175
|
+
var MAX_PIXELS = 4e7;
|
|
176
|
+
var MAX_SIDE = 16384;
|
|
177
|
+
var MAX_EDGE = 3840;
|
|
178
|
+
function dimensions(type, width, height) {
|
|
179
|
+
if (!width || !height || width > MAX_SIDE || height > MAX_SIDE || width * height > MAX_PIXELS) throw new Error("Image exceeds dimension limits (16384 per side, 40 million pixels)");
|
|
180
|
+
return {
|
|
181
|
+
type,
|
|
182
|
+
width,
|
|
183
|
+
height
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function validateImageHeader(input) {
|
|
187
|
+
const bytes = input instanceof Uint8Array ? input : input instanceof ArrayBuffer ? new Uint8Array(input) : null;
|
|
188
|
+
if (!bytes) throw new TypeError("Expected ArrayBuffer or Uint8Array");
|
|
189
|
+
if (!bytes.length || bytes.length > MAX_BYTES) throw new Error("Image must be between 1 byte and 20 MiB");
|
|
190
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
191
|
+
const byte = (offset) => bytes[offset] ?? 0;
|
|
192
|
+
const text = (offset, value) => [...value].every((char, i) => bytes[offset + i] === char.charCodeAt(0));
|
|
193
|
+
const invalid = () => {
|
|
194
|
+
throw new Error("Invalid or unsupported image header; use PNG, JPEG or WebP");
|
|
195
|
+
};
|
|
196
|
+
if (byte(0) === 137 && text(1, "PNG\r\n\n")) {
|
|
197
|
+
if (bytes.length < 33 || view.getUint32(8) !== 13 || !text(12, "IHDR")) return invalid();
|
|
198
|
+
return dimensions("image/png", view.getUint32(16), view.getUint32(20));
|
|
199
|
+
}
|
|
200
|
+
if (byte(0) === 255 && byte(1) === 216) {
|
|
201
|
+
let offset = 2;
|
|
202
|
+
for (let markers = 0; markers < 4096 && offset < bytes.length; markers++) {
|
|
203
|
+
if (bytes[offset++] !== 255) return invalid();
|
|
204
|
+
while (offset < bytes.length && bytes[offset] === 255) offset++;
|
|
205
|
+
if (offset >= bytes.length) return invalid();
|
|
206
|
+
const marker = byte(offset++);
|
|
207
|
+
if (marker === 0 || marker === 216 || marker === 217 || marker === 218) return invalid();
|
|
208
|
+
if (marker === 1 || marker >= 208 && marker <= 215) continue;
|
|
209
|
+
if (offset + 2 > bytes.length) return invalid();
|
|
210
|
+
const length = view.getUint16(offset);
|
|
211
|
+
if (length < 2 || offset + length > bytes.length) return invalid();
|
|
212
|
+
if ([
|
|
213
|
+
192,
|
|
214
|
+
193,
|
|
215
|
+
194,
|
|
216
|
+
195,
|
|
217
|
+
197,
|
|
218
|
+
198,
|
|
219
|
+
199,
|
|
220
|
+
201,
|
|
221
|
+
202,
|
|
222
|
+
203,
|
|
223
|
+
205,
|
|
224
|
+
206,
|
|
225
|
+
207
|
|
226
|
+
].includes(marker)) {
|
|
227
|
+
if (length < 8 || !byte(offset + 7) || length !== 8 + 3 * byte(offset + 7)) return invalid();
|
|
228
|
+
return dimensions("image/jpeg", view.getUint16(offset + 5), view.getUint16(offset + 3));
|
|
229
|
+
}
|
|
230
|
+
offset += length;
|
|
231
|
+
}
|
|
232
|
+
return invalid();
|
|
233
|
+
}
|
|
234
|
+
if (bytes.length >= 12 && text(0, "RIFF") && text(8, "WEBP")) {
|
|
235
|
+
const end = view.getUint32(4, true) + 8;
|
|
236
|
+
if (end !== bytes.length) return invalid();
|
|
237
|
+
for (let offset = 12, chunks = 0; offset + 8 <= end && chunks < 4096; chunks++) {
|
|
238
|
+
const size = view.getUint32(offset + 4, true);
|
|
239
|
+
const start = offset + 8;
|
|
240
|
+
if (start + size + (size & 1) > end) return invalid();
|
|
241
|
+
if (text(offset, "VP8X")) {
|
|
242
|
+
if (size !== 10) return invalid();
|
|
243
|
+
const uint24 = (i) => byte(i) + byte(i + 1) * 256 + byte(i + 2) * 65536;
|
|
244
|
+
return dimensions("image/webp", uint24(start + 4) + 1, uint24(start + 7) + 1);
|
|
245
|
+
}
|
|
246
|
+
if (text(offset, "VP8 ")) {
|
|
247
|
+
if (size < 10 || byte(start) & 1 || !text(start + 3, "*")) return invalid();
|
|
248
|
+
return dimensions("image/webp", view.getUint16(start + 6, true) & 16383, view.getUint16(start + 8, true) & 16383);
|
|
249
|
+
}
|
|
250
|
+
if (text(offset, "VP8L")) {
|
|
251
|
+
if (size < 5 || byte(start) !== 47 || byte(start + 4) >> 5) return invalid();
|
|
252
|
+
const bits = view.getUint32(start + 1, true);
|
|
253
|
+
return dimensions("image/webp", (bits & 16383) + 1, (bits >>> 14 & 16383) + 1);
|
|
254
|
+
}
|
|
255
|
+
offset = start + size + (size & 1);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return invalid();
|
|
259
|
+
}
|
|
260
|
+
async function prepareImage(file) {
|
|
261
|
+
if (!(file instanceof Blob)) throw new TypeError("Expected an image Blob or File");
|
|
262
|
+
if (!file.size || file.size > MAX_BYTES) throw new Error("Image must be between 1 byte and 20 MiB");
|
|
263
|
+
const bytes = await file.arrayBuffer();
|
|
264
|
+
const header = validateImageHeader(bytes);
|
|
265
|
+
if (typeof globalThis.createImageBitmap !== "function") throw new Error("Image decoding is unavailable");
|
|
266
|
+
const bitmap = await globalThis.createImageBitmap(new Blob([bytes], { type: header.type }));
|
|
267
|
+
try {
|
|
268
|
+
dimensions(header.type, bitmap.width, bitmap.height);
|
|
269
|
+
const scale = Math.min(1, MAX_EDGE / Math.max(bitmap.width, bitmap.height));
|
|
270
|
+
const width = Math.max(1, Math.round(bitmap.width * scale));
|
|
271
|
+
const height = Math.max(1, Math.round(bitmap.height * scale));
|
|
272
|
+
const canvas = typeof globalThis.OffscreenCanvas === "function" ? new globalThis.OffscreenCanvas(width, height) : globalThis.document?.createElement("canvas");
|
|
273
|
+
if (!canvas) throw new Error("Canvas is unavailable");
|
|
274
|
+
canvas.width = width;
|
|
275
|
+
canvas.height = height;
|
|
276
|
+
const context = canvas.getContext("2d");
|
|
277
|
+
if (!context) throw new Error("Canvas rendering is unavailable");
|
|
278
|
+
context.drawImage(bitmap, 0, 0, width, height);
|
|
279
|
+
const encode = (type) => "convertToBlob" in canvas ? canvas.convertToBlob({
|
|
280
|
+
type,
|
|
281
|
+
quality: .9
|
|
282
|
+
}) : new Promise((resolve, reject) => {
|
|
283
|
+
try {
|
|
284
|
+
canvas.toBlob(resolve, type, .9);
|
|
285
|
+
} catch (error) {
|
|
286
|
+
reject(error);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
let image;
|
|
290
|
+
try {
|
|
291
|
+
image = await encode("image/webp");
|
|
292
|
+
} catch {}
|
|
293
|
+
if (!image?.size || !["image/webp", "image/png"].includes(image.type)) image = await encode("image/png");
|
|
294
|
+
if (!(image instanceof Blob) || !image.size || !["image/webp", "image/png"].includes(image.type)) throw new Error("Image encoding failed");
|
|
295
|
+
const name = file.name;
|
|
296
|
+
return {
|
|
297
|
+
name: typeof name === "string" ? name : "",
|
|
298
|
+
image
|
|
299
|
+
};
|
|
300
|
+
} finally {
|
|
301
|
+
bitmap.close();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// src/controller.ts
|
|
305
|
+
function createController(env = window) {
|
|
306
|
+
const storage = createStorage(env.indexedDB);
|
|
307
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
308
|
+
let disposed = false;
|
|
309
|
+
let serial = Promise.resolve();
|
|
310
|
+
let imageRevision = -1;
|
|
311
|
+
let url = "";
|
|
312
|
+
let snapshot = {
|
|
313
|
+
settings: { ...DEFAULT_SETTINGS },
|
|
314
|
+
name: "",
|
|
315
|
+
url: "",
|
|
316
|
+
loading: true,
|
|
317
|
+
busy: false,
|
|
318
|
+
error: ""
|
|
319
|
+
};
|
|
320
|
+
const dirty = /* @__PURE__ */ new Map();
|
|
321
|
+
const pending = /* @__PURE__ */ new Map();
|
|
322
|
+
let generation = 0;
|
|
323
|
+
function effective(settings) {
|
|
324
|
+
return normalizeSettings({
|
|
325
|
+
...settings,
|
|
326
|
+
...Object.fromEntries([...dirty].map(([key, entry]) => [key, entry.value]))
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
let channel;
|
|
330
|
+
try {
|
|
331
|
+
channel = new env.BroadcastChannel(PLUGIN_ID);
|
|
332
|
+
} catch {}
|
|
333
|
+
function publish(patch) {
|
|
334
|
+
if (disposed) return;
|
|
335
|
+
snapshot = {
|
|
336
|
+
...snapshot,
|
|
337
|
+
...patch
|
|
338
|
+
};
|
|
339
|
+
listeners.forEach((listener) => listener());
|
|
340
|
+
}
|
|
341
|
+
function adopt(stored) {
|
|
342
|
+
if (disposed) return;
|
|
343
|
+
const { image, imageRevision: revision, name } = stored;
|
|
344
|
+
const settings = effective(stored.settings);
|
|
345
|
+
if (revision !== imageRevision) {
|
|
346
|
+
const previous = url;
|
|
347
|
+
url = image ? env.URL.createObjectURL(image) : "";
|
|
348
|
+
imageRevision = revision;
|
|
349
|
+
publish({
|
|
350
|
+
settings,
|
|
351
|
+
name,
|
|
352
|
+
url,
|
|
353
|
+
loading: false,
|
|
354
|
+
error: ""
|
|
355
|
+
});
|
|
356
|
+
if (previous) env.URL.revokeObjectURL(previous);
|
|
357
|
+
} else publish({
|
|
358
|
+
settings,
|
|
359
|
+
name,
|
|
360
|
+
url,
|
|
361
|
+
loading: false,
|
|
362
|
+
error: ""
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
function enqueue(action) {
|
|
366
|
+
serial = serial.then(() => disposed ? void 0 : action()).catch((error) => {
|
|
367
|
+
publish({
|
|
368
|
+
loading: false,
|
|
369
|
+
busy: false,
|
|
370
|
+
error: error instanceof Error ? error.message : String(error)
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
return serial;
|
|
374
|
+
}
|
|
375
|
+
const refresh = () => enqueue(async () => adopt(await storage.read()));
|
|
376
|
+
const onFocus = () => {
|
|
377
|
+
refresh();
|
|
378
|
+
};
|
|
379
|
+
env.addEventListener("focus", onFocus);
|
|
380
|
+
if (channel) channel.onmessage = onFocus;
|
|
381
|
+
refresh();
|
|
382
|
+
async function save(patch, versions = /* @__PURE__ */ new Map()) {
|
|
383
|
+
const stored = await storage.update(patch);
|
|
384
|
+
if (disposed) {
|
|
385
|
+
try {
|
|
386
|
+
const notification = new env.BroadcastChannel(PLUGIN_ID);
|
|
387
|
+
notification.postMessage("changed");
|
|
388
|
+
notification.close();
|
|
389
|
+
} catch {}
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
for (const [key, version] of versions) if (dirty.get(key)?.version === version) dirty.delete(key);
|
|
393
|
+
adopt(stored);
|
|
394
|
+
channel?.postMessage("changed");
|
|
395
|
+
}
|
|
396
|
+
const keysOf = (settings) => Object.keys(settings);
|
|
397
|
+
return {
|
|
398
|
+
subscribe(listener) {
|
|
399
|
+
listeners.add(listener);
|
|
400
|
+
return () => {
|
|
401
|
+
listeners.delete(listener);
|
|
402
|
+
};
|
|
403
|
+
},
|
|
404
|
+
getSnapshot() {
|
|
405
|
+
return snapshot;
|
|
406
|
+
},
|
|
407
|
+
preview(settings) {
|
|
408
|
+
const normalized = normalizeSettings({
|
|
409
|
+
...snapshot.settings,
|
|
410
|
+
...settings
|
|
411
|
+
});
|
|
412
|
+
for (const key of keysOf(settings)) if (Object.hasOwn(DEFAULT_SETTINGS, key)) dirty.set(key, {
|
|
413
|
+
value: normalized[key],
|
|
414
|
+
version: ++generation
|
|
415
|
+
});
|
|
416
|
+
publish({ settings: effective(snapshot.settings) });
|
|
417
|
+
},
|
|
418
|
+
commit(settings) {
|
|
419
|
+
const versions = new Map(keysOf(settings).flatMap((key) => {
|
|
420
|
+
const entry = dirty.get(key);
|
|
421
|
+
return entry ? [[key, entry.version]] : [];
|
|
422
|
+
}));
|
|
423
|
+
return enqueue(() => save({ settings }, versions));
|
|
424
|
+
},
|
|
425
|
+
commitPreview(key) {
|
|
426
|
+
const entry = dirty.get(key);
|
|
427
|
+
if (!entry || pending.get(key) === entry.version) return Promise.resolve();
|
|
428
|
+
pending.set(key, entry.version);
|
|
429
|
+
const versions = /* @__PURE__ */ new Map([[key, entry.version]]);
|
|
430
|
+
return enqueue(async () => {
|
|
431
|
+
try {
|
|
432
|
+
await save({ settings: { [key]: entry.value } }, versions);
|
|
433
|
+
} finally {
|
|
434
|
+
if (pending.get(key) === entry.version) pending.delete(key);
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
},
|
|
438
|
+
upload(file) {
|
|
439
|
+
if (snapshot.busy || disposed) return Promise.resolve();
|
|
440
|
+
publish({
|
|
441
|
+
busy: true,
|
|
442
|
+
error: ""
|
|
443
|
+
});
|
|
444
|
+
return enqueue(async () => {
|
|
445
|
+
try {
|
|
446
|
+
const prepared = await prepareImage(file);
|
|
447
|
+
if (!disposed) await save({
|
|
448
|
+
...prepared,
|
|
449
|
+
settings: { enabled: true }
|
|
450
|
+
});
|
|
451
|
+
} finally {
|
|
452
|
+
publish({ busy: false });
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
},
|
|
456
|
+
remove() {
|
|
457
|
+
return enqueue(() => save({
|
|
458
|
+
image: null,
|
|
459
|
+
name: ""
|
|
460
|
+
}));
|
|
461
|
+
},
|
|
462
|
+
reset() {
|
|
463
|
+
dirty.clear();
|
|
464
|
+
return enqueue(() => save({ settings: DEFAULT_SETTINGS }));
|
|
465
|
+
},
|
|
466
|
+
dispose() {
|
|
467
|
+
disposed = true;
|
|
468
|
+
env.removeEventListener("focus", onFocus);
|
|
469
|
+
channel?.close();
|
|
470
|
+
listeners.clear();
|
|
471
|
+
if (url) env.URL.revokeObjectURL(url);
|
|
472
|
+
url = "";
|
|
473
|
+
imageRevision = -1;
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
// src/contract.ts
|
|
478
|
+
var FLUENT_MARKER = "data-acrylic-fluent";
|
|
479
|
+
var WALLPAPER_MARKER = "data-acrylic-wallpaper";
|
|
480
|
+
var POPUP_ATTRIBUTE = "data-acrylic-popup";
|
|
481
|
+
var NO_REVEAL_ATTRIBUTE = "data-acrylic-no-reveal";
|
|
482
|
+
// src/host/modules.ts
|
|
483
|
+
/** Host components without a semantic anchor, as [module id, local class]. */
|
|
484
|
+
var HOST_CLASSES = {
|
|
485
|
+
button: ["@deepseek-ai/dsh-client-ui-primitives/Button.module.css", "button"],
|
|
486
|
+
buttonOutline: ["@deepseek-ai/dsh-client-ui-primitives/Button.module.css", "outline"],
|
|
487
|
+
buttonToolbar: ["@deepseek-ai/dsh-client-ui-primitives/Button.module.css", "toolbar"],
|
|
488
|
+
buttonPrimary: ["@deepseek-ai/dsh-client-ui-primitives/Button.module.css", "primary"],
|
|
489
|
+
userBubble: ["@deepseek-ai/dsh-client-ui-chat/MessageItem.module.css", "bubble"],
|
|
490
|
+
turnRail: ["@deepseek-ai/dsh-client-ui-chat/TurnNavigator.module.css", "frame"],
|
|
491
|
+
searchResultRow: ["@deepseek-ai/dsh-client-ui-workspace/Rows.module.css", "searchResultRow"]
|
|
492
|
+
};
|
|
493
|
+
var MODULE_TAG = "style[data-plugin-css]";
|
|
494
|
+
var NAMES = Object.keys(HOST_CLASSES);
|
|
495
|
+
function resolve(document, name) {
|
|
496
|
+
const [module, local] = HOST_CLASSES[name];
|
|
497
|
+
const found = document.head.querySelector(`style[data-plugin-css=${JSON.stringify(module)}]`)?.textContent?.match(new RegExp(String.raw`\.([\w-]+_${local})(?![\w-])`))?.[1];
|
|
498
|
+
return found ? `[class~="${found}"]` : null;
|
|
499
|
+
}
|
|
500
|
+
function createHostModules(document, window) {
|
|
501
|
+
const resolved = new Map(NAMES.map((name) => [name, resolve(document, name)]));
|
|
502
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
503
|
+
const isModuleTag = (node) => node instanceof window.Element && node.matches(MODULE_TAG);
|
|
504
|
+
const observer = new window.MutationObserver((records) => {
|
|
505
|
+
if (!records.some((record) => isModuleTag(record.target) || isModuleTag(record.target.parentElement) || [...record.addedNodes, ...record.removedNodes].some(isModuleTag))) return;
|
|
506
|
+
let changed = false;
|
|
507
|
+
for (const name of NAMES) {
|
|
508
|
+
const next = resolve(document, name);
|
|
509
|
+
if (next !== resolved.get(name)) {
|
|
510
|
+
resolved.set(name, next);
|
|
511
|
+
changed = true;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (changed) for (const listener of listeners) listener();
|
|
515
|
+
});
|
|
516
|
+
observer.observe(document.head, {
|
|
517
|
+
childList: true,
|
|
518
|
+
subtree: true,
|
|
519
|
+
characterData: true
|
|
520
|
+
});
|
|
521
|
+
return {
|
|
522
|
+
select: (name) => resolved.get(name) ?? null,
|
|
523
|
+
subscribe(listener) {
|
|
524
|
+
listeners.add(listener);
|
|
525
|
+
return () => {
|
|
526
|
+
listeners.delete(listener);
|
|
527
|
+
};
|
|
528
|
+
},
|
|
529
|
+
dispose() {
|
|
530
|
+
observer.disconnect();
|
|
531
|
+
listeners.clear();
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
// src/palette.ts
|
|
536
|
+
var pair = (light, dark = light) => Object.freeze({
|
|
537
|
+
light,
|
|
538
|
+
dark
|
|
539
|
+
});
|
|
540
|
+
var CANVAS_TOKENS = Object.freeze({
|
|
541
|
+
"--dsw-alias-bg-base": pair("#ffffff", "#1f1f1f"),
|
|
542
|
+
"--dsw-alias-bg-document-preview": pair("#e6e6e6", "#171717"),
|
|
543
|
+
"--dsw-specific-sidebar-fill": pair("#f2f2f2", "#2b2b2b")
|
|
544
|
+
});
|
|
545
|
+
var LAYER_TOKENS = {
|
|
546
|
+
"--dsw-alias-bg-layer-1": pair("#f5f5f5", "#252525"),
|
|
547
|
+
"--dsw-alias-bg-layer-2": pair("#fafafa", "#2b2b2b"),
|
|
548
|
+
"--dsw-alias-bg-layer-3": pair("#ffffff", "#303030"),
|
|
549
|
+
"--dsw-alias-bg-module-platform": pair("#ededed", "#333333"),
|
|
550
|
+
"--dsw-alias-bg-multi-select": pair("#f2f2f2", "#262626"),
|
|
551
|
+
"--dsw-alias-bg-overlay": pair("#e6e6e6", "#5c5c5c"),
|
|
552
|
+
"--dsw-alias-bg-mask-drop": pair("rgb(255 255 255 / .7)", "rgb(31 31 31 / .7)"),
|
|
553
|
+
"--dsw-alias-settings-card-fill": pair("#f5f5f5", "#252525"),
|
|
554
|
+
"--dsw-specific-input-major": pair("#ffffff", "#2b2b2b"),
|
|
555
|
+
"--dsw-specific-login-input": pair("#f9f9f9", "#1c1c1c"),
|
|
556
|
+
"--dsw-specific-selector": pair("#f2f2f2", "#333333"),
|
|
557
|
+
"--dsw-specific-tip": pair("#f2f2f2", "#333333"),
|
|
558
|
+
"--dsw-specific-bubble": pair("#ededed", "#2d2d2d"),
|
|
559
|
+
"--dsw-specific-bubble-highlight": pair("#dedede", "#3d3d3d")
|
|
560
|
+
};
|
|
561
|
+
var CONTENT_TOKENS = {
|
|
562
|
+
"--dsw-alias-markdown-code-block": pair("#f7f7f7", "#1e1e1e"),
|
|
563
|
+
"--dsw-alias-markdown-code-block-banner": pair("#efefef", "#2b2b2b"),
|
|
564
|
+
"--dsw-alias-markdown-inline-code": pair("#f0f0f0", "#2d2d2d"),
|
|
565
|
+
"--dsw-alias-markdown-tag": pair("#ebebeb", "#2d2d2d"),
|
|
566
|
+
"--dsw-alias-markdown-placeholder": pair("#f2f2f2", "#2b2b2b"),
|
|
567
|
+
"--dsw-alias-markdown-citation": pair("#e6e6e6", "#333333"),
|
|
568
|
+
"--dsw-alias-markdown-code-segment-selected": pair("#ffffff", "#333333"),
|
|
569
|
+
"--dsw-alias-markdown-code-segment-unselected": pair("#ebebeb", "#1e1e1e"),
|
|
570
|
+
"--dsw-linear-gradient-think": pair("linear-gradient(180deg, #ffffff 20.19%, #ffffff00 100%)", "linear-gradient(180deg, #1f1f1f 20.19%, #1f1f1f00 100%)"),
|
|
571
|
+
"--dsw-linear-think-select": pair("linear-gradient(180deg, #f2f2f2 20.19%, #f2f2f200 100%)", "linear-gradient(180deg, #262626 20.19%, #26262600 100%)")
|
|
572
|
+
};
|
|
573
|
+
var CONTROL_TOKENS = {
|
|
574
|
+
"--dsw-alias-button-elevated-fill": pair("#ffffff", "#3a3a3a"),
|
|
575
|
+
"--dsw-alias-button-floating-fill": pair("#ffffff", "#2b2b2b"),
|
|
576
|
+
"--dsw-alias-button-floating-hover": pair("#f2f2f2", "#333333"),
|
|
577
|
+
"--dsw-alias-button-ghost-active-fill": pair("#e6e6e6", "#3d3d3d"),
|
|
578
|
+
"--dsw-alias-button-ghost-active-hover": pair("#dedede", "#4d4d4d"),
|
|
579
|
+
"--dsw-alias-button-ghost-active-border": pair("#999999", "#858585"),
|
|
580
|
+
"--dsw-alias-button-primary-dimmed": pair("#e6e6e6", "#3d3d3d"),
|
|
581
|
+
"--dsw-alias-interactive-bg-hover": pair("rgb(0 0 0 / .06)", "rgb(255 255 255 / .08)"),
|
|
582
|
+
"--dsw-alias-interactive-bg-active": pair("rgb(0 0 0 / .10)", "rgb(255 255 255 / .12)"),
|
|
583
|
+
"--dsw-alias-interactive-bg-hover-accent": pair("rgb(0 0 0 / .14)", "rgb(255 255 255 / .22)"),
|
|
584
|
+
"--dsw-alias-interactive-bg-hover-solid": pair("#ededed", "#333333"),
|
|
585
|
+
"--dsw-specific-sidebar-nav-item-hover": pair("rgb(0 0 0 / .05)", "rgb(255 255 255 / .06)"),
|
|
586
|
+
"--dsw-specific-sidebar-nav-item-active": pair("rgb(0 0 0 / .09)", "rgb(255 255 255 / .11)"),
|
|
587
|
+
"--dsw-alias-turn-trigger-bg": pair("#f7f7f7", "rgb(255 255 255 / .08)"),
|
|
588
|
+
"--dsw-alias-turn-trigger-bg-hover": pair("rgb(0 0 0 / .06)", "rgb(255 255 255 / .14)"),
|
|
589
|
+
"--dsw-alias-switch-thumb": pair("#ffffff", "#cccccc"),
|
|
590
|
+
"--dsw-alias-scrollbar-bg-l1": pair("#e0e0e0", "#3d3d3d"),
|
|
591
|
+
"--dsw-alias-scrollbar-hover-l1": pair("#cccccc", "#555555"),
|
|
592
|
+
"--dsw-alias-scrollbar-bg-l2": pair("#e0e0e0", "#555555"),
|
|
593
|
+
"--dsw-alias-scrollbar-hover-l2": pair("#cccccc", "#666666")
|
|
594
|
+
};
|
|
595
|
+
var STROKE_TOKENS = {
|
|
596
|
+
"--dsw-alias-settings-card-stroke": pair("rgb(0 0 0 / .16)", "rgb(255 255 255 / .16)"),
|
|
597
|
+
"--dsw-alias-border-l1": pair("rgb(0 0 0 / .22)", "rgb(255 255 255 / .22)"),
|
|
598
|
+
"--dsw-alias-border-l2": pair("rgb(0 0 0 / .16)", "rgb(255 255 255 / .16)"),
|
|
599
|
+
"--dsw-alias-border-l3": pair("rgb(0 0 0 / .12)", "rgb(255 255 255 / .12)"),
|
|
600
|
+
"--dsw-alias-border-l4": pair("rgb(0 0 0 / .08)", "rgb(255 255 255 / .08)"),
|
|
601
|
+
"--dsw-alias-border-l2-darkmode-thin": pair("rgb(0 0 0 / .10)", "rgb(255 255 255 / .08)")
|
|
602
|
+
};
|
|
603
|
+
var FLOATING_TOKENS = {
|
|
604
|
+
"--dsw-menu-surface-fill": pair("rgb(248 248 248 / .88)", "rgb(32 32 32 / .85)"),
|
|
605
|
+
"--dsw-specific-menu": pair("rgb(248 248 248 / .88)", "rgb(32 32 32 / .85)"),
|
|
606
|
+
"--dsw-menu-backdrop-filter": pair("blur(24px) saturate(1.15)"),
|
|
607
|
+
"--dsw-alias-menu-group-header-fill": pair("rgb(248 248 248 / .94)", "rgb(40 40 40 / .94)"),
|
|
608
|
+
"--dsw-alias-tooltip-bg": pair("#2b2b2b", "#3d3d3d"),
|
|
609
|
+
"--dsw-alias-toast-bg": pair("#333333", "#3d3d3d")
|
|
610
|
+
};
|
|
611
|
+
var FLUENT_PALETTE = Object.freeze({
|
|
612
|
+
...CANVAS_TOKENS,
|
|
613
|
+
...LAYER_TOKENS,
|
|
614
|
+
...CONTENT_TOKENS,
|
|
615
|
+
...CONTROL_TOKENS,
|
|
616
|
+
...STROKE_TOKENS,
|
|
617
|
+
...FLOATING_TOKENS
|
|
618
|
+
});
|
|
619
|
+
// src/shape.ts
|
|
620
|
+
var corner = (value) => Object.freeze({
|
|
621
|
+
light: value,
|
|
622
|
+
dark: value
|
|
623
|
+
});
|
|
624
|
+
var FLUENT_SHAPE = Object.freeze({
|
|
625
|
+
"--dsw-radius-xs": corner("2px"),
|
|
626
|
+
"--dsw-radius-sm": corner("2px"),
|
|
627
|
+
"--dsw-radius-md": corner("2px"),
|
|
628
|
+
"--dsw-radius-lg": corner("0px"),
|
|
629
|
+
"--dsw-radius-xl": corner("0px"),
|
|
630
|
+
"--dsw-radius-panel": corner("6px")
|
|
631
|
+
});
|
|
632
|
+
// src/elevation.ts
|
|
633
|
+
var ramp = (alpha, [y1, b1], [y2, b2]) => `0 ${y1}px ${b1}px 0 rgb(0 0 0 / ${alpha[0]}), 0 ${y2}px ${b2}px 0 rgb(0 0 0 / ${alpha[1]})`;
|
|
634
|
+
var depth = (strong, ...geometry) => Object.freeze({
|
|
635
|
+
light: ramp(strong ? [.22, .18] : [.132, .108], ...geometry),
|
|
636
|
+
dark: ramp(strong ? [.44, .36] : [.264, .216], ...geometry)
|
|
637
|
+
});
|
|
638
|
+
var DEPTH = Object.freeze({
|
|
639
|
+
4: depth(false, [1.6, 3.6], [.3, .9]),
|
|
640
|
+
8: depth(false, [3.2, 7.2], [.6, 1.8]),
|
|
641
|
+
16: depth(false, [6.4, 14.4], [1.2, 3.6]),
|
|
642
|
+
64: depth(true, [25.6, 57.6], [4.8, 14.4])
|
|
643
|
+
});
|
|
644
|
+
var FLUENT_SHADOWS = Object.freeze({
|
|
645
|
+
"--dsw-shadow-lv1": DEPTH[4],
|
|
646
|
+
"--dsw-shadow-lv1-blur": DEPTH[8],
|
|
647
|
+
"--dsw-shadow-lv2": DEPTH[8],
|
|
648
|
+
"--dsw-shadow-lv3": DEPTH[16]
|
|
649
|
+
});
|
|
650
|
+
var ELEVATIONS = {
|
|
651
|
+
"--dsw-elevation-soft": 4,
|
|
652
|
+
"--dsw-elevation-panel": 8,
|
|
653
|
+
"--dsw-elevation-prominent": 16
|
|
654
|
+
};
|
|
655
|
+
var WINDOWS = ":is(body > [role=\"presentation\"] > [role=\"dialog\"][aria-modal=\"true\"], [data-dockkit-float])";
|
|
656
|
+
var declare = (scheme, entries) => entries.map(([name, level]) => `${name}: var(--dsw-elevation-stroke), ${DEPTH[level][scheme]};`).join(" ");
|
|
657
|
+
var ELEVATION_CSS = ["light", "dark"].map((scheme) => {
|
|
658
|
+
const body = scheme === "dark" ? "body[data-acrylic-fluent][data-ds-dark-theme]" : "body[data-acrylic-fluent]";
|
|
659
|
+
return `${body}, ${body} * { ${declare(scheme, Object.entries(ELEVATIONS))} }
|
|
660
|
+
${body} ${WINDOWS} { ${declare(scheme, [["--dsw-elevation-prominent", 64]])} }`;
|
|
661
|
+
}).join("\n");
|
|
662
|
+
function createElevation(document) {
|
|
663
|
+
const sheet = createStyleSheet(document, "dsh-acrylic-wallpaper-elevation", ELEVATION_CSS);
|
|
664
|
+
return {
|
|
665
|
+
update: sheet.toggle,
|
|
666
|
+
dispose: sheet.dispose
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
// src/theme.ts
|
|
670
|
+
var FLUENT_TOKENS = Object.freeze({
|
|
671
|
+
...FLUENT_SHAPE,
|
|
672
|
+
...FLUENT_SHADOWS,
|
|
673
|
+
...FLUENT_PALETTE
|
|
674
|
+
});
|
|
675
|
+
function createFluentTheme(theme) {
|
|
676
|
+
let remove = null;
|
|
677
|
+
return {
|
|
678
|
+
update(enabled) {
|
|
679
|
+
if (enabled && !remove && typeof theme?.overrideTokens === "function") remove = theme.overrideTokens(PLUGIN_ID, FLUENT_TOKENS);
|
|
680
|
+
else if (!enabled && remove) {
|
|
681
|
+
const dispose = remove;
|
|
682
|
+
remove = null;
|
|
683
|
+
dispose();
|
|
684
|
+
}
|
|
685
|
+
},
|
|
686
|
+
dispose() {
|
|
687
|
+
const dispose = remove;
|
|
688
|
+
remove = null;
|
|
689
|
+
dispose?.();
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
// src/composer.ts
|
|
694
|
+
var COMPOSER_CARD = ":is([data-composer-card], [data-side-chat-composer])";
|
|
695
|
+
var COMPOSER_INPUT = ":is([data-composer-input], [data-side-chat-input])";
|
|
696
|
+
// src/adapters.ts
|
|
697
|
+
var FRAME$1 = "div:has(> [data-shell-bottom]):has(> [data-rightbar-col])";
|
|
698
|
+
var adapterCss = (searchRows) => `
|
|
699
|
+
/* HoverCard declares its own fill (#2C2C2E in both schemes) instead of a token. */
|
|
700
|
+
body[data-acrylic-fluent] > div[style*="--dsh-hover-preview-fade"] { --dsw-hovercard-bg: #2b2b2b; }
|
|
701
|
+
/* The macOS sidebar column layers a hard-coded blue vibrancy gradient over its
|
|
702
|
+
fill. Keep the neutral fill (frame anchors, not module hashes). */
|
|
703
|
+
html[data-platform="darwin"] body[data-acrylic-fluent] ${FRAME$1} > div:first-child { background-image: none; }
|
|
704
|
+
body[data-acrylic-fluent] [data-changed-files],
|
|
705
|
+
body[data-acrylic-fluent][data-ds-dark-theme] [data-changed-files] {
|
|
706
|
+
--changes-fill: var(--dsw-alias-bg-layer-1);
|
|
707
|
+
--changes-hover: var(--dsw-alias-bg-module-platform);
|
|
708
|
+
}
|
|
709
|
+
body[data-acrylic-fluent] [data-presented-file],
|
|
710
|
+
body[data-acrylic-fluent][data-ds-dark-theme] [data-presented-file] {
|
|
711
|
+
--deliverable-fill: var(--dsw-alias-bg-layer-1);
|
|
712
|
+
--deliverable-hover: var(--dsw-alias-bg-module-platform);
|
|
713
|
+
}
|
|
714
|
+
/* The changed-files header owns the first icon span. HoverCard may insert one
|
|
715
|
+
wrapper for a single-file preview; list-row spans must never be matched. */
|
|
716
|
+
body[data-acrylic-fluent] [data-changed-files] > button:first-child > span:first-child,
|
|
717
|
+
body[data-acrylic-fluent] [data-changed-files] > :first-child > button:first-child > span:first-child,
|
|
718
|
+
body[data-acrylic-fluent] [data-presented-file] > button:first-child + span {
|
|
719
|
+
border-radius: var(--dsw-radius-sm);
|
|
720
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
721
|
+
}
|
|
722
|
+
/* An editor gets a stable focus boundary, not a moving fill over text. Keep
|
|
723
|
+
the host's elevation and workspace-picker dashed pseudo-element intact. */
|
|
724
|
+
body[data-acrylic-fluent] ${COMPOSER_CARD}:has(${COMPOSER_INPUT}:focus) {
|
|
725
|
+
--dsw-elevation-stroke-color: var(--dsw-alias-state-business-primary);
|
|
726
|
+
outline: 1px solid var(--dsw-alias-state-business-primary);
|
|
727
|
+
outline-offset: -1px;
|
|
728
|
+
}
|
|
729
|
+
/* Sidebar tree rows have mouse semantics but no tab stop. Indicate focus in
|
|
730
|
+
their existing action buttons without changing the host keyboard model. */
|
|
731
|
+
body[data-acrylic-fluent] :is([role="treeitem"][data-row-key]${searchRows ? `, ${searchRows}` : ""}):has(:focus-visible:not([data-dsh-automatic-focus])) {
|
|
732
|
+
outline: 1px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
733
|
+
outline-offset: -1px;
|
|
734
|
+
}
|
|
735
|
+
@media (forced-colors: active) {
|
|
736
|
+
body[data-acrylic-fluent] ${COMPOSER_CARD}:has(${COMPOSER_INPUT}:focus) { outline-color: Highlight; }
|
|
737
|
+
}
|
|
738
|
+
/* rc.3 shell resize handles (frame children named by data-side) lack a visual
|
|
739
|
+
rail. Decorate their existing hit box; never change drag geometry, pointer
|
|
740
|
+
capture or keyboard semantics. */
|
|
741
|
+
body[data-acrylic-fluent] ${FRAME$1} > :is([data-side="sidebar"],[data-side="rightbar"])::after {
|
|
742
|
+
content: ''; position: absolute; inset-block: 0; left: 3px; width: 2px;
|
|
743
|
+
pointer-events: none; opacity: 0;
|
|
744
|
+
background: linear-gradient(transparent, var(--dsw-alias-state-business-primary), transparent);
|
|
745
|
+
}
|
|
746
|
+
body[data-acrylic-fluent] ${FRAME$1} > :is([data-side="sidebar"],[data-side="rightbar"]):hover::after { opacity: .45; }
|
|
747
|
+
body[data-acrylic-fluent] ${FRAME$1} > :is([data-side="sidebar"],[data-side="rightbar"])[data-dragging]::after { opacity: .75; }
|
|
748
|
+
body[data-acrylic-fluent] [data-dockkit-divider]:hover::before,
|
|
749
|
+
body[data-acrylic-fluent] [data-dockkit-divider]:active::before {
|
|
750
|
+
background: var(--dsw-alias-state-business-primary);
|
|
751
|
+
}
|
|
752
|
+
body[data-acrylic-fluent] [data-dockkit-float-resize]:is(:hover,:active)::after {
|
|
753
|
+
border-color: var(--dsw-alias-state-business-primary);
|
|
754
|
+
}
|
|
755
|
+
/* Native macOS menu backing stays opaque and anchored by the host. Only align
|
|
756
|
+
its color with the neutral menu family; never remove it or alter its z-index. */
|
|
757
|
+
html[data-platform="darwin"] body[data-acrylic-fluent] [data-menu-backing] {
|
|
758
|
+
background: #f8f8f8;
|
|
759
|
+
}
|
|
760
|
+
html[data-platform="darwin"] body[data-acrylic-fluent][data-ds-dark-theme] [data-menu-backing] {
|
|
761
|
+
background: #202020;
|
|
762
|
+
}
|
|
763
|
+
`;
|
|
764
|
+
function buttonStateCss(modules) {
|
|
765
|
+
const button = modules.select("button");
|
|
766
|
+
if (!button) return "";
|
|
767
|
+
const active = (variant) => `body[data-acrylic-fluent] button${button}${variant}:active:not(:disabled):not([aria-disabled="true"]):not([aria-busy="true"])`;
|
|
768
|
+
const outline = modules.select("buttonOutline"), toolbar = modules.select("buttonToolbar"), primary = modules.select("buttonPrimary");
|
|
769
|
+
return `
|
|
770
|
+
@media (forced-colors: none) {
|
|
771
|
+
${outline ? `${active(outline)} { background:var(--dsw-alias-interactive-bg-active); }` : ""}
|
|
772
|
+
${toolbar ? `${active(toolbar)} { background:linear-gradient(var(--dsw-alias-interactive-bg-active),var(--dsw-alias-interactive-bg-active)),var(--dsw-alias-button-tool-bar-fill); }` : ""}
|
|
773
|
+
${primary ? `${active(primary)} { background:color-mix(in srgb,var(--dsw-alias-button-primary-fill) 88%,var(--dsw-alias-label-primary-foreground)); }` : ""}
|
|
774
|
+
}
|
|
775
|
+
`;
|
|
776
|
+
}
|
|
777
|
+
function createAdapters(document, modules) {
|
|
778
|
+
const render = () => adapterCss(modules.select("searchResultRow")) + buttonStateCss(modules);
|
|
779
|
+
const sheet = createStyleSheet(document, "dsh-acrylic-wallpaper-adapters", render());
|
|
780
|
+
const unsubscribe = modules.subscribe(() => sheet.set(render()));
|
|
781
|
+
return {
|
|
782
|
+
update: sheet.toggle,
|
|
783
|
+
dispose() {
|
|
784
|
+
unsubscribe();
|
|
785
|
+
sheet.dispose();
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
// src/motion.ts
|
|
790
|
+
var HOLD = "acrylic-popup-hold";
|
|
791
|
+
var POPUP_SELECTOR = [
|
|
792
|
+
"[data-menu-material]",
|
|
793
|
+
"body > [role=\"presentation\"]:has(> [role=\"dialog\"][aria-modal=\"true\"])",
|
|
794
|
+
"body > :is([role=\"dialog\"], [role=\"menu\"], [role=\"listbox\"]):not([aria-modal=\"true\"])",
|
|
795
|
+
"body > div[style*=\"--dsh-hover-preview-fade\"]",
|
|
796
|
+
"body > ul",
|
|
797
|
+
"body > div:has(> [role=\"tree\"])",
|
|
798
|
+
"[role=\"tooltip\"]",
|
|
799
|
+
"[data-session-preview-card]",
|
|
800
|
+
`[${POPUP_ATTRIBUTE}]`
|
|
801
|
+
].join(",");
|
|
802
|
+
var MOTION = Object.freeze({
|
|
803
|
+
enter: "cubic-bezier(.1, .9, .2, 1)",
|
|
804
|
+
exit: "cubic-bezier(.4, 0, 1, 1)",
|
|
805
|
+
slide: 250,
|
|
806
|
+
fade: 167,
|
|
807
|
+
leave: 120,
|
|
808
|
+
tooltipIn: 120,
|
|
809
|
+
tooltipOut: 83,
|
|
810
|
+
dialogOut: 167
|
|
811
|
+
});
|
|
812
|
+
var GHOST_SKIP = "iframe, webview, video, audio, object, embed, canvas";
|
|
813
|
+
var GHOST_MAX_NODES = 1500;
|
|
814
|
+
var GHOST_DETACH = /^(?:id|autofocus|popover|name|for|form|aria-(?:activedescendant|controls|owns)|data-(?:modal-autofocus|shortcut-modal|window-drag(?:-recall)?|element-id|plugin-package|team-panel))$/;
|
|
815
|
+
var isHook = ({ name, value }) => name === "aria-modal" || name === "role" && value === "menu" || /^data-(?:dockkit|sidebar-right|composer)-/.test(name);
|
|
816
|
+
var STATE_PROPS = [
|
|
817
|
+
"background-color",
|
|
818
|
+
"background-image",
|
|
819
|
+
"color",
|
|
820
|
+
"border-top-color",
|
|
821
|
+
"border-right-color",
|
|
822
|
+
"border-bottom-color",
|
|
823
|
+
"border-left-color",
|
|
824
|
+
"box-shadow",
|
|
825
|
+
"outline-color",
|
|
826
|
+
"outline-style",
|
|
827
|
+
"outline-width",
|
|
828
|
+
"outline-offset",
|
|
829
|
+
"text-decoration-color",
|
|
830
|
+
"fill",
|
|
831
|
+
"stroke"
|
|
832
|
+
];
|
|
833
|
+
var STATE_CONTROL = "button, a[href], summary, [tabindex], [role^=\"menuitem\"], [role=\"option\"], [role=\"treeitem\"], [role=\"tab\"]";
|
|
834
|
+
var STATE_MAX_NODES = 40;
|
|
835
|
+
var STATE_TTL = 1e3;
|
|
836
|
+
var CLOSE_KEYS = /* @__PURE__ */ new Set([
|
|
837
|
+
"Escape",
|
|
838
|
+
"Enter",
|
|
839
|
+
" ",
|
|
840
|
+
"Tab"
|
|
841
|
+
]);
|
|
842
|
+
var PIN_PROPS = [
|
|
843
|
+
"display",
|
|
844
|
+
"position",
|
|
845
|
+
"box-sizing",
|
|
846
|
+
"width",
|
|
847
|
+
"height",
|
|
848
|
+
"min-width",
|
|
849
|
+
"min-height",
|
|
850
|
+
"max-width",
|
|
851
|
+
"max-height",
|
|
852
|
+
...[
|
|
853
|
+
"top",
|
|
854
|
+
"right",
|
|
855
|
+
"bottom",
|
|
856
|
+
"left"
|
|
857
|
+
].flatMap((side) => [
|
|
858
|
+
`margin-${side}`,
|
|
859
|
+
`padding-${side}`,
|
|
860
|
+
`border-${side}-width`,
|
|
861
|
+
`border-${side}-style`
|
|
862
|
+
]),
|
|
863
|
+
"border-top-left-radius",
|
|
864
|
+
"border-top-right-radius",
|
|
865
|
+
"border-bottom-right-radius",
|
|
866
|
+
"border-bottom-left-radius",
|
|
867
|
+
"flex-direction",
|
|
868
|
+
"flex-wrap",
|
|
869
|
+
"flex-grow",
|
|
870
|
+
"flex-shrink",
|
|
871
|
+
"flex-basis",
|
|
872
|
+
"align-items",
|
|
873
|
+
"justify-content",
|
|
874
|
+
"row-gap",
|
|
875
|
+
"column-gap",
|
|
876
|
+
"font-size",
|
|
877
|
+
"font-weight",
|
|
878
|
+
"line-height",
|
|
879
|
+
"letter-spacing",
|
|
880
|
+
"white-space",
|
|
881
|
+
"text-align",
|
|
882
|
+
"overflow-x",
|
|
883
|
+
"overflow-y",
|
|
884
|
+
"opacity",
|
|
885
|
+
"visibility",
|
|
886
|
+
"transform",
|
|
887
|
+
"z-index",
|
|
888
|
+
...STATE_PROPS
|
|
889
|
+
];
|
|
890
|
+
var PIN_MAX_NODES = 120;
|
|
891
|
+
var MOTION_CSS = `
|
|
892
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
893
|
+
body[data-acrylic-fluent] :is(${POPUP_SELECTOR}):not([data-acrylic-ghost]) { animation: ${HOLD} 300ms linear; }
|
|
894
|
+
body[data-acrylic-fluent] > [data-menu-backing] { animation: acrylic-backing-in ${MOTION.fade}ms linear; }
|
|
895
|
+
/* Preview HoverCards own a closing phase that unmounts after 100ms. */
|
|
896
|
+
body[data-acrylic-fluent] > div[style*="--dsh-hover-preview-fade"] { transition: opacity 90ms ${MOTION.exit}; }
|
|
897
|
+
}
|
|
898
|
+
@keyframes ${HOLD} { from, to { opacity: 0; } }
|
|
899
|
+
@keyframes acrylic-backing-in { from { opacity: 0; } }
|
|
900
|
+
/* Clones never anchor: a reopened menu reuses its anchor-name. */
|
|
901
|
+
[data-acrylic-ghost] { pointer-events: none !important; }
|
|
902
|
+
[data-acrylic-ghost], [data-acrylic-ghost] *, [data-acrylic-ghost] ::before, [data-acrylic-ghost] ::after {
|
|
903
|
+
animation: none !important; transition: none !important; anchor-name: none !important;
|
|
904
|
+
}
|
|
905
|
+
`;
|
|
906
|
+
var indexIn = (parent, child) => Array.prototype.indexOf.call(parent.children, child);
|
|
907
|
+
var inlineStyle = (node) => node.style;
|
|
908
|
+
function pathTo(root, node) {
|
|
909
|
+
const path = [];
|
|
910
|
+
for (let current = node; current && current !== root; current = current.parentElement) if (current.parentElement) path.unshift(indexIn(current.parentElement, current));
|
|
911
|
+
return path.join("/");
|
|
912
|
+
}
|
|
913
|
+
function nodeAt(root, path) {
|
|
914
|
+
let node = root;
|
|
915
|
+
for (const index of path ? path.split("/") : []) node = node?.children[Number(index)];
|
|
916
|
+
return node;
|
|
917
|
+
}
|
|
918
|
+
function scrollState(popup) {
|
|
919
|
+
const state = /* @__PURE__ */ new Map();
|
|
920
|
+
const nodes = popup.getElementsByTagName("*");
|
|
921
|
+
if (nodes.length > GHOST_MAX_NODES) return state;
|
|
922
|
+
for (const node of [popup, ...nodes]) if (node.scrollTop || node.scrollLeft) state.set(pathTo(popup, node), [node.scrollTop, node.scrollLeft]);
|
|
923
|
+
return state;
|
|
924
|
+
}
|
|
925
|
+
var attributesOf = (node) => [...node.attributes];
|
|
926
|
+
function readStyle(view, node, names) {
|
|
927
|
+
const style = view.getComputedStyle(node);
|
|
928
|
+
return (names ?? [...style]).map((name) => [name, style.getPropertyValue(name)]);
|
|
929
|
+
}
|
|
930
|
+
function interactionState(view, popup) {
|
|
931
|
+
const nodes = /* @__PURE__ */ new Set();
|
|
932
|
+
const follow = (start) => {
|
|
933
|
+
if (!start || start === popup || !popup.contains(start)) return;
|
|
934
|
+
for (let node = start; node && node !== popup; node = node.parentElement) nodes.add(node);
|
|
935
|
+
const control = start.closest(STATE_CONTROL);
|
|
936
|
+
if (control && control !== popup && popup.contains(control)) for (const node of [...control.getElementsByTagName("*")].slice(0, STATE_MAX_NODES)) nodes.add(node);
|
|
937
|
+
};
|
|
938
|
+
const hovered = popup.querySelectorAll(":hover");
|
|
939
|
+
follow(hovered[hovered.length - 1]);
|
|
940
|
+
follow(popup.ownerDocument.activeElement);
|
|
941
|
+
if (!nodes.size) return null;
|
|
942
|
+
return [...nodes].map((node) => ({
|
|
943
|
+
path: pathTo(popup, node),
|
|
944
|
+
tag: node.tagName,
|
|
945
|
+
values: readStyle(view, node, STATE_PROPS)
|
|
946
|
+
}));
|
|
947
|
+
}
|
|
948
|
+
function detachGhost(root) {
|
|
949
|
+
for (const node of [root, ...root.getElementsByTagName("*")]) for (const { name } of attributesOf(node)) if (GHOST_DETACH.test(name)) node.removeAttribute(name);
|
|
950
|
+
root.setAttribute("data-acrylic-ghost", "");
|
|
951
|
+
root.setAttribute("aria-hidden", "true");
|
|
952
|
+
root.inert = true;
|
|
953
|
+
}
|
|
954
|
+
function pinGhost(view, root, state) {
|
|
955
|
+
const nodes = [root, ...root.getElementsByTagName("*")];
|
|
956
|
+
const owners = nodes.filter((node) => attributesOf(node).some(isHook));
|
|
957
|
+
const scope = owners.length && nodes.length <= PIN_MAX_NODES ? nodes : owners;
|
|
958
|
+
const before = scope.map((node) => readStyle(view, node, owners.includes(node) ? null : PIN_PROPS));
|
|
959
|
+
for (const node of owners) for (const attribute of attributesOf(node)) if (isHook(attribute)) node.removeAttribute(attribute.name);
|
|
960
|
+
const pins = [];
|
|
961
|
+
scope.forEach((node, index) => {
|
|
962
|
+
const style = view.getComputedStyle(node);
|
|
963
|
+
const changed = (before[index] ?? []).filter(([name, value]) => style.getPropertyValue(name) !== value);
|
|
964
|
+
if (changed.length) pins.push([node, changed]);
|
|
965
|
+
});
|
|
966
|
+
for (const { path, tag, values } of state ?? []) {
|
|
967
|
+
const node = nodeAt(root, path);
|
|
968
|
+
if (node?.tagName === tag) pins.push([node, values]);
|
|
969
|
+
}
|
|
970
|
+
for (const [node, values] of pins) for (const [name, value] of values) inlineStyle(node)?.setProperty(name, value);
|
|
971
|
+
}
|
|
972
|
+
function restoreScroll(root, scroll) {
|
|
973
|
+
for (const [path, [top, left]] of scroll) {
|
|
974
|
+
const node = nodeAt(root, path);
|
|
975
|
+
if (node) {
|
|
976
|
+
node.scrollTop = top;
|
|
977
|
+
node.scrollLeft = left;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
function backingOf(view, popup) {
|
|
982
|
+
const anchor = inlineStyle(popup)?.getPropertyValue("--dsh-menu-anchor");
|
|
983
|
+
if (!anchor) return null;
|
|
984
|
+
for (const node of popup.ownerDocument.body.children) if (node.hasAttribute("data-menu-backing") && inlineStyle(node)?.getPropertyValue("--dsh-menu-anchor") === anchor) return view.getComputedStyle(node).display === "none" ? null : node;
|
|
985
|
+
return null;
|
|
986
|
+
}
|
|
987
|
+
function ghostBackings(view, template, root) {
|
|
988
|
+
return [root, ...root.querySelectorAll("[data-menu-material]")].map((surface) => [surface.getBoundingClientRect(), view.getComputedStyle(surface).borderRadius]).map(([rect, radius]) => {
|
|
989
|
+
const clone = template.cloneNode(false);
|
|
990
|
+
clone.setAttribute("data-acrylic-ghost", "");
|
|
991
|
+
const box = {
|
|
992
|
+
top: rect.top,
|
|
993
|
+
left: rect.left,
|
|
994
|
+
width: rect.width,
|
|
995
|
+
height: rect.height
|
|
996
|
+
};
|
|
997
|
+
const style = inlineStyle(clone);
|
|
998
|
+
for (const [name, value] of Object.entries(box)) style?.setProperty(name, `${value}px`);
|
|
999
|
+
style?.setProperty("border-radius", radius);
|
|
1000
|
+
root.ownerDocument.body.append(clone);
|
|
1001
|
+
return clone;
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
function slideFrom(rect, point) {
|
|
1005
|
+
const slack = 4;
|
|
1006
|
+
let direction = [0, 1];
|
|
1007
|
+
if (point) {
|
|
1008
|
+
if (rect.top >= point.y - slack) direction = [0, 1];
|
|
1009
|
+
else if (rect.bottom <= point.y + slack) direction = [0, -1];
|
|
1010
|
+
else if (rect.left >= point.x - slack) direction = [1, 0];
|
|
1011
|
+
else if (rect.right <= point.x + slack) direction = [-1, 0];
|
|
1012
|
+
}
|
|
1013
|
+
const extent = direction[1] ? rect.height : rect.width;
|
|
1014
|
+
return {
|
|
1015
|
+
direction,
|
|
1016
|
+
distance: Math.round(Math.min(24, Math.max(8, extent * .15)))
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
function createMotion(document, window, { onSettle } = {}) {
|
|
1020
|
+
const sheet = createStyleSheet(document, "dsh-acrylic-wallpaper-motion", MOTION_CSS);
|
|
1021
|
+
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
1022
|
+
const tracked = /* @__PURE__ */ new Map();
|
|
1023
|
+
const ghosts = /* @__PURE__ */ new Set();
|
|
1024
|
+
let enabled = false;
|
|
1025
|
+
let pointer = null;
|
|
1026
|
+
let keyboard = null;
|
|
1027
|
+
const removals = new window.MutationObserver(onRemovals);
|
|
1028
|
+
const from = (target, keyframe, duration, easing) => target.animate([{
|
|
1029
|
+
...keyframe,
|
|
1030
|
+
offset: 0
|
|
1031
|
+
}], {
|
|
1032
|
+
duration,
|
|
1033
|
+
easing,
|
|
1034
|
+
fill: "backwards"
|
|
1035
|
+
});
|
|
1036
|
+
const fadeIn = (target, duration, easing) => target.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
1037
|
+
duration,
|
|
1038
|
+
easing,
|
|
1039
|
+
fill: "backwards"
|
|
1040
|
+
});
|
|
1041
|
+
const to = (target, keyframe, duration, easing) => target.animate([{
|
|
1042
|
+
...keyframe,
|
|
1043
|
+
offset: 1
|
|
1044
|
+
}], {
|
|
1045
|
+
duration,
|
|
1046
|
+
easing,
|
|
1047
|
+
fill: "forwards"
|
|
1048
|
+
});
|
|
1049
|
+
function layerOf(popup) {
|
|
1050
|
+
const first = popup.firstElementChild;
|
|
1051
|
+
return first?.getAttribute("aria-hidden") === "true" && window.getComputedStyle(first).backdropFilter !== "none" ? first : null;
|
|
1052
|
+
}
|
|
1053
|
+
const faders = (popup) => layerOf(popup) ? [...popup.children] : [popup];
|
|
1054
|
+
function origin(popup) {
|
|
1055
|
+
if (keyboard && (!pointer || keyboard.time > pointer.time)) {
|
|
1056
|
+
const element = keyboard.element;
|
|
1057
|
+
if (element?.isConnected && element !== document.body && !popup.contains(element)) {
|
|
1058
|
+
const rect = element.getBoundingClientRect();
|
|
1059
|
+
return {
|
|
1060
|
+
x: rect.left + rect.width / 2,
|
|
1061
|
+
y: rect.top + rect.height / 2
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
return pointer;
|
|
1066
|
+
}
|
|
1067
|
+
function describe(popup) {
|
|
1068
|
+
const declared = popup.getAttribute(POPUP_ATTRIBUTE);
|
|
1069
|
+
if (declared === "tooltip" || declared === null && popup.matches("[role=\"tooltip\"]")) return { kind: "tooltip" };
|
|
1070
|
+
if (declared === "dialog") return { kind: "dialog" };
|
|
1071
|
+
const dialog = declared === null && popup.matches("[role=\"presentation\"]") && popup.querySelector(":scope > [role=\"dialog\"][aria-modal=\"true\"]");
|
|
1072
|
+
if (dialog) return {
|
|
1073
|
+
kind: "modal",
|
|
1074
|
+
dialog: indexIn(popup, dialog)
|
|
1075
|
+
};
|
|
1076
|
+
return {
|
|
1077
|
+
kind: "flyout",
|
|
1078
|
+
...slideFrom(popup.getBoundingClientRect(), origin(popup))
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
function enter(popup, info) {
|
|
1082
|
+
const { enter: ease, slide, fade } = MOTION;
|
|
1083
|
+
if (info.kind === "tooltip") return [fadeIn(popup, MOTION.tooltipIn, "linear")];
|
|
1084
|
+
if (info.kind === "dialog") return [from(popup, { scale: 1.05 }, slide, ease), fadeIn(popup, fade, ease)];
|
|
1085
|
+
if (info.kind === "modal") return [...popup.children].flatMap((child, index) => index === info.dialog ? [from(child, { scale: 1.05 }, slide, ease), fadeIn(child, fade, ease)] : [fadeIn(child, fade, "linear")]);
|
|
1086
|
+
const [x, y] = info.direction;
|
|
1087
|
+
const list = [from(popup, { translate: `${-x * info.distance}px ${-y * info.distance}px` }, slide, ease)];
|
|
1088
|
+
if (layerOf(popup)) list.push(from(popup, { boxShadow: "none" }, fade, ease));
|
|
1089
|
+
for (const target of faders(popup)) list.push(fadeIn(target, fade, ease));
|
|
1090
|
+
return list;
|
|
1091
|
+
}
|
|
1092
|
+
function leave(ghost, info, backings) {
|
|
1093
|
+
const { exit: ease, leave: duration } = MOTION;
|
|
1094
|
+
const out = (target, keyframe, time = duration) => to(target, keyframe, time, ease);
|
|
1095
|
+
if (info.kind === "tooltip") return [out(ghost, { opacity: 0 }, MOTION.tooltipOut)];
|
|
1096
|
+
if (info.kind === "dialog") return [out(ghost, { scale: 1.05 }, MOTION.dialogOut), out(ghost, { opacity: 0 })];
|
|
1097
|
+
if (info.kind === "modal") return [...ghost.children].flatMap((child, index) => index === info.dialog ? [out(child, { scale: 1.05 }, MOTION.dialogOut), out(child, { opacity: 0 })] : [out(child, { opacity: 0 }, MOTION.dialogOut)]);
|
|
1098
|
+
const [x, y] = info.direction;
|
|
1099
|
+
const back = Math.round(info.distance / 3);
|
|
1100
|
+
const translate = `${-x * back}px ${-y * back}px`;
|
|
1101
|
+
const list = [out(ghost, { translate })];
|
|
1102
|
+
if (layerOf(ghost)) list.push(out(ghost, { boxShadow: "none" }));
|
|
1103
|
+
for (const target of faders(ghost)) list.push(out(target, { opacity: 0 }));
|
|
1104
|
+
for (const backing of backings) list.push(out(backing, {
|
|
1105
|
+
translate,
|
|
1106
|
+
opacity: 0
|
|
1107
|
+
}));
|
|
1108
|
+
return list;
|
|
1109
|
+
}
|
|
1110
|
+
function settle(animations, done) {
|
|
1111
|
+
let finished = false;
|
|
1112
|
+
const finish = () => {
|
|
1113
|
+
if (!finished) {
|
|
1114
|
+
finished = true;
|
|
1115
|
+
done();
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
const timer = window.setTimeout(finish, MOTION.slide + 200);
|
|
1119
|
+
Promise.all(animations.map((animation) => animation.finished)).then(() => {
|
|
1120
|
+
window.clearTimeout(timer);
|
|
1121
|
+
finish();
|
|
1122
|
+
}, () => {});
|
|
1123
|
+
}
|
|
1124
|
+
function start(popup) {
|
|
1125
|
+
if (!enabled || !popup.isConnected) return;
|
|
1126
|
+
const info = {
|
|
1127
|
+
...describe(popup),
|
|
1128
|
+
scroll: scrollState(popup),
|
|
1129
|
+
backing: backingOf(window, popup),
|
|
1130
|
+
state: null
|
|
1131
|
+
};
|
|
1132
|
+
const animations = enter(popup, info);
|
|
1133
|
+
for (const [element] of tracked) if (!element.isConnected) tracked.delete(element);
|
|
1134
|
+
tracked.set(popup, info);
|
|
1135
|
+
if (popup.parentNode) removals.observe(popup.parentNode, { childList: true });
|
|
1136
|
+
if (onSettle) settle(animations, onSettle);
|
|
1137
|
+
}
|
|
1138
|
+
function whenPlaced(popup) {
|
|
1139
|
+
if (window.getComputedStyle(popup).visibility !== "hidden") return start(popup);
|
|
1140
|
+
const hold = popup.animate([{ opacity: 0 }, { opacity: 0 }], { duration: 1e3 });
|
|
1141
|
+
const poll = (frames) => window.requestAnimationFrame(() => {
|
|
1142
|
+
if (!popup.isConnected) return hold.cancel();
|
|
1143
|
+
if (frames && window.getComputedStyle(popup).visibility === "hidden") return poll(frames - 1);
|
|
1144
|
+
hold.cancel();
|
|
1145
|
+
start(popup);
|
|
1146
|
+
});
|
|
1147
|
+
poll(12);
|
|
1148
|
+
}
|
|
1149
|
+
function onStart(event) {
|
|
1150
|
+
const popup = event.target;
|
|
1151
|
+
if (event.animationName !== HOLD || !(popup instanceof window.Element)) return;
|
|
1152
|
+
for (const animation of popup.getAnimations()) if (animation.animationName === HOLD) animation.cancel();
|
|
1153
|
+
if (!enabled || reduce.matches || !popup.isConnected || popup.hasAttribute("data-acrylic-ghost")) return;
|
|
1154
|
+
whenPlaced(popup);
|
|
1155
|
+
}
|
|
1156
|
+
function ghost(node, info, record) {
|
|
1157
|
+
const parent = record.target;
|
|
1158
|
+
if (!enabled || reduce.matches || document.hidden || !parent.isConnected) return;
|
|
1159
|
+
if (node.hasAttribute("hidden") || node.hasAttribute("data-closing")) return;
|
|
1160
|
+
if (node.querySelector(GHOST_SKIP) || node.getElementsByTagName("*").length > GHOST_MAX_NODES) return;
|
|
1161
|
+
const clone = node.cloneNode(true);
|
|
1162
|
+
detachGhost(clone);
|
|
1163
|
+
const next = record.nextSibling?.parentNode === parent ? record.nextSibling : null;
|
|
1164
|
+
parent.insertBefore(clone, next);
|
|
1165
|
+
const state = info.state && window.performance.now() - info.state.time < STATE_TTL ? info.state.nodes : null;
|
|
1166
|
+
try {
|
|
1167
|
+
pinGhost(window, clone, state);
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
clone.remove();
|
|
1170
|
+
throw error;
|
|
1171
|
+
}
|
|
1172
|
+
restoreScroll(clone, info.scroll);
|
|
1173
|
+
const backings = info.kind === "flyout" && info.backing && !info.backing.isConnected ? ghostBackings(window, info.backing, clone) : [];
|
|
1174
|
+
const parts = [clone, ...backings];
|
|
1175
|
+
for (const part of parts) ghosts.add(part);
|
|
1176
|
+
settle(leave(clone, info, backings), () => {
|
|
1177
|
+
for (const part of parts) {
|
|
1178
|
+
part.remove();
|
|
1179
|
+
ghosts.delete(part);
|
|
1180
|
+
}
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
function onRemovals(records) {
|
|
1184
|
+
for (const record of records) for (const node of record.removedNodes) {
|
|
1185
|
+
const info = node instanceof window.Element ? tracked.get(node) : void 0;
|
|
1186
|
+
if (!info || !(node instanceof window.Element)) continue;
|
|
1187
|
+
if (node.isConnected) {
|
|
1188
|
+
if (node.parentNode) removals.observe(node.parentNode, { childList: true });
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
tracked.delete(node);
|
|
1192
|
+
ghost(node, info, record);
|
|
1193
|
+
}
|
|
1194
|
+
if (!tracked.size) removals.disconnect();
|
|
1195
|
+
}
|
|
1196
|
+
function onScroll(event) {
|
|
1197
|
+
const target = event.target;
|
|
1198
|
+
if (!tracked.size || !(target instanceof window.Element)) return;
|
|
1199
|
+
for (const [popup, info] of tracked) if (popup.contains(target)) {
|
|
1200
|
+
info.scroll.set(pathTo(popup, target), [target.scrollTop, target.scrollLeft]);
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
function capture() {
|
|
1205
|
+
const time = window.performance.now();
|
|
1206
|
+
for (const [popup, info] of tracked) {
|
|
1207
|
+
const nodes = popup.isConnected ? interactionState(window, popup) : null;
|
|
1208
|
+
info.state = nodes && {
|
|
1209
|
+
time,
|
|
1210
|
+
nodes
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
const onPointer = (event) => {
|
|
1215
|
+
pointer = {
|
|
1216
|
+
x: event.clientX,
|
|
1217
|
+
y: event.clientY,
|
|
1218
|
+
time: event.timeStamp
|
|
1219
|
+
};
|
|
1220
|
+
if (event.type === "pointerdown") capture();
|
|
1221
|
+
};
|
|
1222
|
+
const onKey = (event) => {
|
|
1223
|
+
keyboard = {
|
|
1224
|
+
element: document.activeElement,
|
|
1225
|
+
time: event.timeStamp
|
|
1226
|
+
};
|
|
1227
|
+
if (CLOSE_KEYS.has(event.key)) capture();
|
|
1228
|
+
};
|
|
1229
|
+
const LISTENERS = [
|
|
1230
|
+
["animationstart", onStart],
|
|
1231
|
+
["pointerdown", onPointer],
|
|
1232
|
+
["pointermove", onPointer],
|
|
1233
|
+
["click", capture],
|
|
1234
|
+
["keydown", onKey],
|
|
1235
|
+
["scroll", onScroll]
|
|
1236
|
+
];
|
|
1237
|
+
function update(next) {
|
|
1238
|
+
if (next === enabled) return;
|
|
1239
|
+
enabled = next;
|
|
1240
|
+
sheet.toggle(enabled);
|
|
1241
|
+
for (const [type, listener] of LISTENERS) if (enabled) document.addEventListener(type, listener, {
|
|
1242
|
+
capture: true,
|
|
1243
|
+
passive: true
|
|
1244
|
+
});
|
|
1245
|
+
else document.removeEventListener(type, listener, { capture: true });
|
|
1246
|
+
if (enabled) return;
|
|
1247
|
+
removals.disconnect();
|
|
1248
|
+
tracked.clear();
|
|
1249
|
+
for (const clone of ghosts) clone.remove();
|
|
1250
|
+
ghosts.clear();
|
|
1251
|
+
}
|
|
1252
|
+
return {
|
|
1253
|
+
update,
|
|
1254
|
+
dispose() {
|
|
1255
|
+
update(false);
|
|
1256
|
+
sheet.dispose();
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
// src/frame-motion.ts
|
|
1261
|
+
var PROPERTY = "grid-template-columns";
|
|
1262
|
+
var STILL = "[data-dragging],[data-rightbar-fullscreen],[data-rightbar-instant]";
|
|
1263
|
+
var BODY = "[data-conversation-content]";
|
|
1264
|
+
var COLUMN_WIDTH = "--dsh-conversation-column-width";
|
|
1265
|
+
/** Split a computed list at top-level commas; easing functions contain commas. */
|
|
1266
|
+
function items(value) {
|
|
1267
|
+
const parts = [];
|
|
1268
|
+
let depth = 0, start = 0;
|
|
1269
|
+
for (let index = 0; index < value.length; index++) {
|
|
1270
|
+
const char = value[index];
|
|
1271
|
+
if (char === "(") depth++;
|
|
1272
|
+
else if (char === ")") depth--;
|
|
1273
|
+
else if (char === "," && depth === 0) {
|
|
1274
|
+
parts.push(value.slice(start, index).trim());
|
|
1275
|
+
start = index + 1;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
parts.push(value.slice(start).trim());
|
|
1279
|
+
return parts;
|
|
1280
|
+
}
|
|
1281
|
+
var milliseconds = (value) => (value.endsWith("ms") ? 1 : 1e3) * (parseFloat(value) || 0);
|
|
1282
|
+
function createFrameMotion(document, window) {
|
|
1283
|
+
const probe = document.createElement("div");
|
|
1284
|
+
const observer = new window.MutationObserver(onChange);
|
|
1285
|
+
const finder = new window.MutationObserver(() => {
|
|
1286
|
+
if (acquire()) finder.disconnect();
|
|
1287
|
+
});
|
|
1288
|
+
let enabled = false;
|
|
1289
|
+
let frame = null;
|
|
1290
|
+
let replay = null;
|
|
1291
|
+
let pinned = [];
|
|
1292
|
+
function release() {
|
|
1293
|
+
for (const [body, value, priority] of pinned) if (value) body.style.setProperty(COLUMN_WIDTH, value, priority);
|
|
1294
|
+
else body.style.removeProperty(COLUMN_WIDTH);
|
|
1295
|
+
pinned = [];
|
|
1296
|
+
}
|
|
1297
|
+
function stop() {
|
|
1298
|
+
replay?.cancel();
|
|
1299
|
+
replay = null;
|
|
1300
|
+
release();
|
|
1301
|
+
}
|
|
1302
|
+
function pin(target) {
|
|
1303
|
+
const widths = [];
|
|
1304
|
+
for (const body of target.querySelectorAll(BODY)) if (body instanceof window.HTMLElement && body.offsetWidth) widths.push([body, body.offsetWidth]);
|
|
1305
|
+
for (const [body, width] of widths) {
|
|
1306
|
+
pinned.push([
|
|
1307
|
+
body,
|
|
1308
|
+
body.style.getPropertyValue(COLUMN_WIDTH),
|
|
1309
|
+
body.style.getPropertyPriority(COLUMN_WIDTH)
|
|
1310
|
+
]);
|
|
1311
|
+
body.style.setProperty(COLUMN_WIDTH, `${width}px`);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
function acquire() {
|
|
1315
|
+
if (frame?.isConnected) return true;
|
|
1316
|
+
stop();
|
|
1317
|
+
observer.disconnect();
|
|
1318
|
+
frame = null;
|
|
1319
|
+
const candidate = document.querySelector("[data-shell-bottom]")?.parentElement;
|
|
1320
|
+
if (!(candidate instanceof window.HTMLElement) || !candidate.querySelector(":scope > [data-rightbar-col]")) return false;
|
|
1321
|
+
frame = candidate;
|
|
1322
|
+
observer.observe(frame, {
|
|
1323
|
+
attributes: true,
|
|
1324
|
+
attributeOldValue: true,
|
|
1325
|
+
attributeFilter: [
|
|
1326
|
+
"style",
|
|
1327
|
+
"data-animating",
|
|
1328
|
+
"data-dragging"
|
|
1329
|
+
]
|
|
1330
|
+
});
|
|
1331
|
+
return true;
|
|
1332
|
+
}
|
|
1333
|
+
function timing(target) {
|
|
1334
|
+
const css = window.getComputedStyle(target);
|
|
1335
|
+
const index = items(css.transitionProperty).findIndex((name) => name === PROPERTY || name === "all");
|
|
1336
|
+
if (index < 0) return null;
|
|
1337
|
+
const at = (value) => {
|
|
1338
|
+
const list = items(value);
|
|
1339
|
+
return list[index % list.length] ?? "";
|
|
1340
|
+
};
|
|
1341
|
+
const duration = milliseconds(at(css.transitionDuration));
|
|
1342
|
+
return duration > 0 ? {
|
|
1343
|
+
duration,
|
|
1344
|
+
delay: milliseconds(at(css.transitionDelay)),
|
|
1345
|
+
easing: at(css.transitionTimingFunction) || "ease"
|
|
1346
|
+
} : null;
|
|
1347
|
+
}
|
|
1348
|
+
function onChange(records) {
|
|
1349
|
+
const target = frame;
|
|
1350
|
+
if (!enabled || !target) return;
|
|
1351
|
+
if (target.matches(STILL)) return stop();
|
|
1352
|
+
const change = records.find((record) => record.attributeName === "style");
|
|
1353
|
+
if (!change) return;
|
|
1354
|
+
probe.setAttribute("style", change.oldValue ?? "");
|
|
1355
|
+
const from = probe.style.gridTemplateColumns, to = target.style.gridTemplateColumns;
|
|
1356
|
+
if (!from || !to || from === to) return;
|
|
1357
|
+
stop();
|
|
1358
|
+
if (!target.hasAttribute("data-animating")) return;
|
|
1359
|
+
const options = timing(target);
|
|
1360
|
+
if (!options) return;
|
|
1361
|
+
for (const animation of target.getAnimations()) if (animation instanceof window.CSSTransition && animation.transitionProperty === PROPERTY) animation.cancel();
|
|
1362
|
+
pin(target);
|
|
1363
|
+
const current = target.animate([{ gridTemplateColumns: from }, { gridTemplateColumns: to }], options);
|
|
1364
|
+
current.addEventListener("finish", () => {
|
|
1365
|
+
if (replay === current) {
|
|
1366
|
+
replay = null;
|
|
1367
|
+
release();
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1370
|
+
replay = current;
|
|
1371
|
+
}
|
|
1372
|
+
function ensure() {
|
|
1373
|
+
if (acquire()) finder.disconnect();
|
|
1374
|
+
else finder.observe(document.body, {
|
|
1375
|
+
childList: true,
|
|
1376
|
+
subtree: true
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
const onInput = () => {
|
|
1380
|
+
if (!frame?.isConnected) ensure();
|
|
1381
|
+
};
|
|
1382
|
+
const LISTENERS = ["pointerdown", "keydown"];
|
|
1383
|
+
function update(next) {
|
|
1384
|
+
if (next === enabled) return;
|
|
1385
|
+
enabled = next;
|
|
1386
|
+
for (const type of LISTENERS) if (enabled) document.addEventListener(type, onInput, {
|
|
1387
|
+
capture: true,
|
|
1388
|
+
passive: true
|
|
1389
|
+
});
|
|
1390
|
+
else document.removeEventListener(type, onInput, { capture: true });
|
|
1391
|
+
if (enabled) return ensure();
|
|
1392
|
+
stop();
|
|
1393
|
+
observer.disconnect();
|
|
1394
|
+
finder.disconnect();
|
|
1395
|
+
frame = null;
|
|
1396
|
+
}
|
|
1397
|
+
return {
|
|
1398
|
+
update,
|
|
1399
|
+
dispose() {
|
|
1400
|
+
update(false);
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
// src/press.ts
|
|
1405
|
+
var PRESS_CSS = `
|
|
1406
|
+
[data-acrylic-press] { position:absolute;inset:-1px;border-radius:inherit;overflow:hidden;pointer-events:none; }
|
|
1407
|
+
[data-acrylic-press] > i { position:absolute;left:var(--reveal-x);top:var(--reveal-y);width:94.5px;height:94.5px;margin:-47.25px;border-radius:50%;opacity:0;scale:1;pointer-events:none;background:radial-gradient(47.25px circle,rgb(var(--reveal-rgb) / .065),transparent 70%); }
|
|
1408
|
+
[data-acrylic-press] > i + i { background:radial-gradient(47.25px circle,rgb(var(--reveal-rgb) / .055),transparent); }
|
|
1409
|
+
`;
|
|
1410
|
+
function createPressLight(document, window, overlay, onFinish) {
|
|
1411
|
+
const root = document.createElement("div");
|
|
1412
|
+
root.setAttribute("data-acrylic-press", "");
|
|
1413
|
+
const inner = document.createElement("i"), outer = document.createElement("i");
|
|
1414
|
+
root.append(inner, outer);
|
|
1415
|
+
overlay.append(root);
|
|
1416
|
+
let held = true, disposed = false, phase = "pressing", revision = 0;
|
|
1417
|
+
let animations = [];
|
|
1418
|
+
const releaseEase = "cubic-bezier(.33,0,.67,1)";
|
|
1419
|
+
function cancel() {
|
|
1420
|
+
revision++;
|
|
1421
|
+
for (const animation of animations) animation.cancel();
|
|
1422
|
+
animations = [];
|
|
1423
|
+
}
|
|
1424
|
+
function dispose() {
|
|
1425
|
+
if (disposed) return;
|
|
1426
|
+
disposed = true;
|
|
1427
|
+
cancel();
|
|
1428
|
+
root.remove();
|
|
1429
|
+
}
|
|
1430
|
+
function finish() {
|
|
1431
|
+
dispose();
|
|
1432
|
+
onFinish();
|
|
1433
|
+
}
|
|
1434
|
+
function settle(done) {
|
|
1435
|
+
const current = revision;
|
|
1436
|
+
Promise.all(animations.map((animation) => animation.finished)).then(() => {
|
|
1437
|
+
if (!disposed && current === revision) done();
|
|
1438
|
+
}, () => {});
|
|
1439
|
+
}
|
|
1440
|
+
function fade(fast) {
|
|
1441
|
+
const values = [inner, outer].map((node) => {
|
|
1442
|
+
const css = window.getComputedStyle(node);
|
|
1443
|
+
return {
|
|
1444
|
+
opacity: css.opacity,
|
|
1445
|
+
scale: css.scale
|
|
1446
|
+
};
|
|
1447
|
+
});
|
|
1448
|
+
cancel();
|
|
1449
|
+
phase = fast ? "fast" : "slow";
|
|
1450
|
+
const duration = fast ? 266 : 1500;
|
|
1451
|
+
for (const [index, node] of [inner, outer].entries()) {
|
|
1452
|
+
const from = values[index];
|
|
1453
|
+
if (!from) continue;
|
|
1454
|
+
animations.push(node.animate([{ opacity: from.opacity }, { opacity: 0 }], {
|
|
1455
|
+
duration: index === 0 ? fast ? 200 : 1e3 : duration,
|
|
1456
|
+
easing: releaseEase,
|
|
1457
|
+
fill: "forwards"
|
|
1458
|
+
}), node.animate([{ scale: from.scale }, { scale: 4.44 }], {
|
|
1459
|
+
duration,
|
|
1460
|
+
easing: releaseEase,
|
|
1461
|
+
fill: "forwards"
|
|
1462
|
+
}));
|
|
1463
|
+
}
|
|
1464
|
+
settle(finish);
|
|
1465
|
+
}
|
|
1466
|
+
animations = [inner.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
1467
|
+
duration: 66,
|
|
1468
|
+
easing: "linear",
|
|
1469
|
+
fill: "forwards"
|
|
1470
|
+
}), outer.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
1471
|
+
duration: 66,
|
|
1472
|
+
easing: "cubic-bezier(.5,0,.6,1)",
|
|
1473
|
+
fill: "forwards"
|
|
1474
|
+
})];
|
|
1475
|
+
settle(() => fade(!held));
|
|
1476
|
+
return {
|
|
1477
|
+
release() {
|
|
1478
|
+
if (disposed || !held) return;
|
|
1479
|
+
held = false;
|
|
1480
|
+
if (phase === "slow") fade(true);
|
|
1481
|
+
},
|
|
1482
|
+
dispose
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
// src/interaction.ts
|
|
1486
|
+
var ACTION_TARGETS = [
|
|
1487
|
+
"button,summary",
|
|
1488
|
+
"[role=\"button\"],[role=\"tab\"],[role=\"switch\"],[role=\"checkbox\"],[role=\"radio\"]",
|
|
1489
|
+
"[role=\"menuitem\"],[role=\"menuitemcheckbox\"],[role=\"menuitemradio\"],[role=\"option\"]",
|
|
1490
|
+
"[role=\"treeitem\"][data-row-key],[role=\"treeitem\"][tabindex][aria-level]",
|
|
1491
|
+
"[role=\"gridcell\"][tabindex][aria-selected]",
|
|
1492
|
+
"nav a[href],[role=\"navigation\"] a[href]",
|
|
1493
|
+
"tr[data-trajectory-row-key][tabindex=\"0\"]"
|
|
1494
|
+
].join(",");
|
|
1495
|
+
function actionSelector(modules) {
|
|
1496
|
+
const search = modules.select("searchResultRow");
|
|
1497
|
+
return search ? `${ACTION_TARGETS},${search}` : ACTION_TARGETS;
|
|
1498
|
+
}
|
|
1499
|
+
// src/press-geometry.ts
|
|
1500
|
+
function depression(width, height, u, v) {
|
|
1501
|
+
const angle = (d) => d > 925 ? 0 : Math.max(0, -7e-8 * d ** 3 + 15904e-8 * d ** 2 - .12506463 * d + 35.27311191);
|
|
1502
|
+
u = Math.max(0, Math.min(1, u));
|
|
1503
|
+
v = Math.max(0, Math.min(1, v));
|
|
1504
|
+
return {
|
|
1505
|
+
scale: .97 + .03 * (Math.abs(u - .5) + Math.abs(v - .5)),
|
|
1506
|
+
x: -(v - .5) * angle(height),
|
|
1507
|
+
y: (u - .5) * angle(width)
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
var projections = /* @__PURE__ */ new WeakMap();
|
|
1511
|
+
function forgetProjection(target) {
|
|
1512
|
+
projections.delete(target);
|
|
1513
|
+
}
|
|
1514
|
+
function insideProjection(target) {
|
|
1515
|
+
for (let parent = target.parentElement; parent; parent = parent.parentElement) if (projections.has(parent)) return true;
|
|
1516
|
+
return false;
|
|
1517
|
+
}
|
|
1518
|
+
function project(window, target, width, height, pose, amount) {
|
|
1519
|
+
const camera = new window.DOMMatrix();
|
|
1520
|
+
camera.m34 = -1 / 999;
|
|
1521
|
+
const rotation = new window.DOMMatrix().rotate(pose.x * amount, pose.y * amount).scale(1 + (pose.scale - 1) * amount);
|
|
1522
|
+
const m = camera.multiply(rotation);
|
|
1523
|
+
const matrix = new window.DOMMatrix([
|
|
1524
|
+
m.m11,
|
|
1525
|
+
m.m12,
|
|
1526
|
+
0,
|
|
1527
|
+
m.m14,
|
|
1528
|
+
m.m21,
|
|
1529
|
+
m.m22,
|
|
1530
|
+
0,
|
|
1531
|
+
m.m24,
|
|
1532
|
+
0,
|
|
1533
|
+
0,
|
|
1534
|
+
1,
|
|
1535
|
+
0,
|
|
1536
|
+
0,
|
|
1537
|
+
0,
|
|
1538
|
+
0,
|
|
1539
|
+
1
|
|
1540
|
+
]);
|
|
1541
|
+
const projection = {
|
|
1542
|
+
width,
|
|
1543
|
+
height,
|
|
1544
|
+
matrix,
|
|
1545
|
+
inverse: matrix.inverse(),
|
|
1546
|
+
transform: matrix.toString()
|
|
1547
|
+
};
|
|
1548
|
+
projections.set(target, projection);
|
|
1549
|
+
return projection;
|
|
1550
|
+
}
|
|
1551
|
+
function point(matrix, width, height, x, y) {
|
|
1552
|
+
const p = matrix.transformPoint({
|
|
1553
|
+
x: x - width / 2,
|
|
1554
|
+
y: y - height / 2
|
|
1555
|
+
});
|
|
1556
|
+
return {
|
|
1557
|
+
x: p.x / p.w + width / 2,
|
|
1558
|
+
y: p.y / p.w + height / 2
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
/** Recover the layout box from the projected bounds; no layout-style toggles. */
|
|
1562
|
+
function pressGeometry(target, bounds) {
|
|
1563
|
+
const projection = projections.get(target);
|
|
1564
|
+
if (!projection) return null;
|
|
1565
|
+
const { matrix, inverse, width, height, transform } = projection;
|
|
1566
|
+
const corners = [
|
|
1567
|
+
[0, 0],
|
|
1568
|
+
[width, 0],
|
|
1569
|
+
[width, height],
|
|
1570
|
+
[0, height]
|
|
1571
|
+
].map(([x = 0, y = 0]) => point(matrix, width, height, x, y));
|
|
1572
|
+
const left = bounds.left - Math.min(...corners.map((p) => p.x));
|
|
1573
|
+
const top = bounds.top - Math.min(...corners.map((p) => p.y));
|
|
1574
|
+
return {
|
|
1575
|
+
left,
|
|
1576
|
+
top,
|
|
1577
|
+
width,
|
|
1578
|
+
height,
|
|
1579
|
+
transform,
|
|
1580
|
+
local: (x, y) => point(inverse, width, height, x - left, y - top)
|
|
1581
|
+
};
|
|
1582
|
+
}
|
|
1583
|
+
/** Native up KeySpline (.1,.25,.75,.9), solved for time rather than parameter. */
|
|
1584
|
+
function releaseEase(time) {
|
|
1585
|
+
if (time <= 0) return 0;
|
|
1586
|
+
if (time >= 1) return 1;
|
|
1587
|
+
const curve = (t, a, b) => 3 * (1 - t) ** 2 * t * a + 3 * (1 - t) * t ** 2 * b + t ** 3;
|
|
1588
|
+
let low = 0, high = 1;
|
|
1589
|
+
for (let i = 0; i < 12; i++) {
|
|
1590
|
+
const mid = (low + high) / 2;
|
|
1591
|
+
if (curve(mid, .1, .75) < time) low = mid;
|
|
1592
|
+
else high = mid;
|
|
1593
|
+
}
|
|
1594
|
+
return curve((low + high) / 2, .25, .9);
|
|
1595
|
+
}
|
|
1596
|
+
// src/reveal.ts
|
|
1597
|
+
var REVEAL_FIELDS = "input:not([type=\"hidden\"]):not([type=\"file\"]):not([type=\"range\"]):not([type=\"color\"]),textarea,select,[role=\"textbox\"],[role=\"searchbox\"],[role=\"combobox\"],[contenteditable=\"true\"]";
|
|
1598
|
+
var REVEAL_TARGETS = `${ACTION_TARGETS},${REVEAL_FIELDS}`;
|
|
1599
|
+
var REVEAL_LAYERS = `[${POPUP_ATTRIBUTE}],[data-menu-material],[role="menu"],[role="dialog"],[role="alertdialog"],[role="listbox"],[role="tooltip"],[data-composer-overlay],[data-dockkit-float],[style*="--dsh-hover-preview-fade"]`;
|
|
1600
|
+
var REVEAL_EXCLUDED = `[${NO_REVEAL_ATTRIBUTE}],[hidden],[inert],[aria-hidden="true"],[data-closing],[data-acrylic-ghost],[data-acrylic-reveal],[data-width-handle],[data-dockkit-divider],[data-dockkit-float-resize],.monaco-editor,.xterm`;
|
|
1601
|
+
var REVEAL_CSS = `
|
|
1602
|
+
[data-acrylic-reveal] { --reveal-rgb:255 255 255;position:fixed;pointer-events:none;z-index:var(--reveal-z,0);box-sizing:border-box;border:1px solid transparent;border-radius:var(--reveal-radius,2px);background:radial-gradient(72px circle at var(--reveal-x) var(--reveal-y),rgb(var(--reveal-rgb) / var(--reveal-surface)),transparent) padding-box; }
|
|
1603
|
+
[data-acrylic-reveal]::before { content:'';position:absolute;inset:-1px;border-radius:inherit;padding:1px;background:radial-gradient(80px circle at var(--reveal-x) var(--reveal-y),rgb(var(--reveal-rgb) / var(--reveal-border)),transparent);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask-composite:exclude; }
|
|
1604
|
+
body:not([data-ds-dark-theme]) [data-acrylic-reveal] { --reveal-rgb:0 0 0; }
|
|
1605
|
+
${PRESS_CSS}
|
|
1606
|
+
@media (prefers-reduced-motion:reduce),(forced-colors:active) { [data-acrylic-reveal]{display:none} }
|
|
1607
|
+
`;
|
|
1608
|
+
function revealStrength(x, y, rect) {
|
|
1609
|
+
const dx = Math.max(rect.left - x, 0, x - rect.right);
|
|
1610
|
+
const dy = Math.max(rect.top - y, 0, y - rect.bottom);
|
|
1611
|
+
return Math.max(0, 1 - Math.hypot(dx, dy) / 64);
|
|
1612
|
+
}
|
|
1613
|
+
function createReveal(document, window, modules) {
|
|
1614
|
+
const media = [
|
|
1615
|
+
window.matchMedia("(prefers-reduced-motion: reduce)"),
|
|
1616
|
+
window.matchMedia("(forced-colors: active)"),
|
|
1617
|
+
window.matchMedia("(hover: hover) and (pointer: fine)")
|
|
1618
|
+
];
|
|
1619
|
+
let requested = false, running = false, disposed = false, frame = 0;
|
|
1620
|
+
let point = null;
|
|
1621
|
+
let press = null;
|
|
1622
|
+
function cancelPress() {
|
|
1623
|
+
press?.light?.dispose();
|
|
1624
|
+
press = null;
|
|
1625
|
+
}
|
|
1626
|
+
let controls = REVEAL_TARGETS, quiet = null;
|
|
1627
|
+
let surfaces = COMPOSER_CARD;
|
|
1628
|
+
function resolve() {
|
|
1629
|
+
controls = `${actionSelector(modules)},${REVEAL_FIELDS}`;
|
|
1630
|
+
const bubble = modules.select("userBubble");
|
|
1631
|
+
surfaces = `${COMPOSER_CARD},[data-testid="todo-panel"],[data-side-chat] .dsc-bubble:not([data-pending])${bubble ? `,:is([data-chat-flow-kind="user"],[data-chat-flow-kind="steering"]) ${bubble}` : ""}`;
|
|
1632
|
+
quiet = modules.select("turnRail");
|
|
1633
|
+
}
|
|
1634
|
+
const borderOnly = (target) => target.matches(`${REVEAL_FIELDS},${surfaces}`);
|
|
1635
|
+
resolve();
|
|
1636
|
+
const unsubscribe = modules.subscribe(() => {
|
|
1637
|
+
resolve();
|
|
1638
|
+
schedule();
|
|
1639
|
+
});
|
|
1640
|
+
const overlays = /* @__PURE__ */ new Map();
|
|
1641
|
+
const portals = /* @__PURE__ */ new Set();
|
|
1642
|
+
const portalSelector = `[${POPUP_ATTRIBUTE}],[role="tooltip"],[role="dialog"],[role="alertdialog"],[data-menu-material],[style*="--dsh-hover-preview-fade"]`;
|
|
1643
|
+
const activeObserver = new window.MutationObserver(() => schedule());
|
|
1644
|
+
const sizes = new window.ResizeObserver(() => schedule());
|
|
1645
|
+
function watchActive() {
|
|
1646
|
+
activeObserver.disconnect();
|
|
1647
|
+
sizes.disconnect();
|
|
1648
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1649
|
+
for (const target of overlays.keys()) {
|
|
1650
|
+
sizes.observe(target);
|
|
1651
|
+
for (let node = target; node && node !== document.body; node = node.parentElement) {
|
|
1652
|
+
if (seen.has(node)) break;
|
|
1653
|
+
seen.add(node);
|
|
1654
|
+
activeObserver.observe(node, {
|
|
1655
|
+
attributes: true,
|
|
1656
|
+
childList: true,
|
|
1657
|
+
attributeFilter: [
|
|
1658
|
+
"disabled",
|
|
1659
|
+
"aria-disabled",
|
|
1660
|
+
"aria-hidden",
|
|
1661
|
+
"aria-invalid",
|
|
1662
|
+
"hidden",
|
|
1663
|
+
"inert",
|
|
1664
|
+
"class",
|
|
1665
|
+
"style",
|
|
1666
|
+
"data-closing"
|
|
1667
|
+
]
|
|
1668
|
+
});
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
const sheet = createStyleSheet(document, "dsh-acrylic-wallpaper-reveal", REVEAL_CSS);
|
|
1673
|
+
function clear() {
|
|
1674
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
1675
|
+
frame = 0;
|
|
1676
|
+
point = null;
|
|
1677
|
+
cancelPress();
|
|
1678
|
+
activeObserver.disconnect();
|
|
1679
|
+
sizes.disconnect();
|
|
1680
|
+
for (const node of overlays.values()) node.remove();
|
|
1681
|
+
overlays.clear();
|
|
1682
|
+
}
|
|
1683
|
+
function control(node) {
|
|
1684
|
+
if (!node || node.closest(`[data-acrylic-no-reveal],[hidden],[inert],[data-closing],[data-acrylic-ghost],.monaco-editor,.xterm`) || quiet && node.closest(quiet)) return null;
|
|
1685
|
+
const editor = node.closest(COMPOSER_INPUT);
|
|
1686
|
+
if (editor) return editor.closest(COMPOSER_CARD);
|
|
1687
|
+
const target = node.closest(controls);
|
|
1688
|
+
const todo = node.closest("[data-testid=\"todo-panel\"]");
|
|
1689
|
+
if (todo && (!target || target.matches("[data-testid=\"todo-panel\"] > div > button[aria-expanded]"))) return todo;
|
|
1690
|
+
if (target) return target;
|
|
1691
|
+
const labelControl = node.closest("label")?.control;
|
|
1692
|
+
if (labelControl?.matches("input:is([type=\"checkbox\"],[type=\"radio\"])")) return labelControl;
|
|
1693
|
+
return node.closest(surfaces);
|
|
1694
|
+
}
|
|
1695
|
+
function layer(node) {
|
|
1696
|
+
return node?.closest(REVEAL_LAYERS) ?? document.body;
|
|
1697
|
+
}
|
|
1698
|
+
function candidates(x, y, hit) {
|
|
1699
|
+
const targets = /* @__PURE__ */ new Set(), surface = layer(hit), direct = control(hit);
|
|
1700
|
+
if (direct) targets.add(direct);
|
|
1701
|
+
const content = hit?.closest(surfaces);
|
|
1702
|
+
if (content && layer(content) === surface) targets.add(content);
|
|
1703
|
+
for (const target of overlays.keys()) if (target.isConnected && layer(target) === surface) targets.add(target);
|
|
1704
|
+
for (const dx of [
|
|
1705
|
+
0,
|
|
1706
|
+
-48,
|
|
1707
|
+
48
|
|
1708
|
+
]) for (const dy of [
|
|
1709
|
+
0,
|
|
1710
|
+
-48,
|
|
1711
|
+
48
|
|
1712
|
+
]) {
|
|
1713
|
+
const node = dx || dy ? document.elementFromPoint(x + dx, y + dy) : hit;
|
|
1714
|
+
if (!node || layer(node) !== surface) continue;
|
|
1715
|
+
const target = control(node);
|
|
1716
|
+
if (target && !(direct && target !== direct && target.contains(direct))) targets.add(target);
|
|
1717
|
+
}
|
|
1718
|
+
for (const target of targets) {
|
|
1719
|
+
if (target === direct || target.matches(surfaces)) continue;
|
|
1720
|
+
if (direct && !direct.matches(surfaces) && (target.contains(direct) || direct.contains(target))) targets.delete(target);
|
|
1721
|
+
else if ([...targets].some((other) => other !== target && target.contains(other))) targets.delete(target);
|
|
1722
|
+
}
|
|
1723
|
+
return targets;
|
|
1724
|
+
}
|
|
1725
|
+
function draw() {
|
|
1726
|
+
frame = 0;
|
|
1727
|
+
if (!point || !running || document.hidden) return clear();
|
|
1728
|
+
const { x, y } = point;
|
|
1729
|
+
const hit = document.elementFromPoint(x, y);
|
|
1730
|
+
if (press && (!press.target.isConnected || control(hit) !== press.target || borderOnly(press.target))) cancelPress();
|
|
1731
|
+
const rows = [], ancestors = /* @__PURE__ */ new Map();
|
|
1732
|
+
const blockers = [];
|
|
1733
|
+
for (const portal of portals) {
|
|
1734
|
+
if (!portal.isConnected) {
|
|
1735
|
+
portals.delete(portal);
|
|
1736
|
+
continue;
|
|
1737
|
+
}
|
|
1738
|
+
if (portal.contains(hit) || portal.closest("[hidden]")) continue;
|
|
1739
|
+
const css = window.getComputedStyle(portal);
|
|
1740
|
+
if (css.visibility === "hidden" || css.display === "none" || Number(css.opacity) === 0) continue;
|
|
1741
|
+
blockers.push(portal.getBoundingClientRect());
|
|
1742
|
+
}
|
|
1743
|
+
function geometry(element) {
|
|
1744
|
+
const known = ancestors.get(element);
|
|
1745
|
+
if (known) return known;
|
|
1746
|
+
{
|
|
1747
|
+
const css = window.getComputedStyle(element);
|
|
1748
|
+
const clipsX = /(auto|scroll|hidden|clip)/.test(css.overflowX);
|
|
1749
|
+
const clipsY = /(auto|scroll|hidden|clip)/.test(css.overflowY);
|
|
1750
|
+
const entry = {
|
|
1751
|
+
clipsX,
|
|
1752
|
+
clipsY,
|
|
1753
|
+
opacity: Number(css.opacity),
|
|
1754
|
+
z: css.zIndex === "auto" ? 0 : Number(css.zIndex),
|
|
1755
|
+
context: css.zIndex !== "auto" || Number(css.opacity) < 1 || css.transform !== "none" || css.scale !== "none" || css.rotate !== "none" || css.translate !== "none" || css.filter !== "none" || css.backdropFilter !== "none" || css.isolation === "isolate" || /(paint|layout|strict|content)/.test(css.contain) || css.position === "fixed" || css.position === "sticky",
|
|
1756
|
+
bounds: clipsX || clipsY ? element.getBoundingClientRect() : null
|
|
1757
|
+
};
|
|
1758
|
+
ancestors.set(element, entry);
|
|
1759
|
+
return entry;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
let inspected = 0;
|
|
1763
|
+
const found = quiet && hit?.closest(quiet) ? [] : candidates(x, y, hit);
|
|
1764
|
+
for (const target of found) {
|
|
1765
|
+
if (rows.length >= 4 || inspected++ >= 10) break;
|
|
1766
|
+
if (!target.isConnected || insideProjection(target) || target.matches(":disabled,[aria-disabled=\"true\"],[aria-invalid=\"true\"],[readonly]") || target.closest(REVEAL_EXCLUDED)) continue;
|
|
1767
|
+
const rect = target.getBoundingClientRect();
|
|
1768
|
+
if (!rect.width || !rect.height || rect.bottom < 0 || rect.top > window.innerHeight || rect.right < 0 || rect.left > window.innerWidth) continue;
|
|
1769
|
+
const strength = revealStrength(x, y, rect);
|
|
1770
|
+
if (!strength) continue;
|
|
1771
|
+
const computed = window.getComputedStyle(target);
|
|
1772
|
+
if (computed.visibility !== "visible" || computed.pointerEvents === "none") continue;
|
|
1773
|
+
let opacity = Number(computed.opacity), z = computed.zIndex === "auto" ? 0 : Number(computed.zIndex);
|
|
1774
|
+
const footprint = press?.target === target ? 212 : 84;
|
|
1775
|
+
let left = Math.max(0, rect.left, x - footprint), top = Math.max(0, rect.top, y - footprint);
|
|
1776
|
+
let right = Math.min(window.innerWidth, rect.right, x + footprint), bottom = Math.min(window.innerHeight, rect.bottom, y + footprint);
|
|
1777
|
+
for (let parent = target.parentElement; parent && parent !== document.body; parent = parent.parentElement) {
|
|
1778
|
+
const { clipsX, clipsY, bounds, opacity: alpha, context, z: parentZ } = geometry(parent);
|
|
1779
|
+
opacity *= alpha;
|
|
1780
|
+
if (context) z = parentZ;
|
|
1781
|
+
if (bounds && clipsX) {
|
|
1782
|
+
left = Math.max(left, bounds.left);
|
|
1783
|
+
right = Math.min(right, bounds.right);
|
|
1784
|
+
}
|
|
1785
|
+
if (bounds && clipsY) {
|
|
1786
|
+
top = Math.max(top, bounds.top);
|
|
1787
|
+
bottom = Math.min(bottom, bounds.bottom);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
if (opacity < .99 || right <= left || bottom <= top) continue;
|
|
1791
|
+
if (blockers.some((rect) => rect.width && rect.height && rect.left < right && rect.right > left && rect.top < bottom && rect.bottom > top)) continue;
|
|
1792
|
+
const owns = (px, py) => {
|
|
1793
|
+
const probe = document.elementFromPoint(px, py);
|
|
1794
|
+
return (probe === target || target.contains(probe)) && layer(probe) === layer(target);
|
|
1795
|
+
};
|
|
1796
|
+
if (!owns(Math.max(left + .5, Math.min(right - .5, x)), Math.max(top + .5, Math.min(bottom - .5, y)))) continue;
|
|
1797
|
+
const radius = computed.borderTopLeftRadius.includes("%") ? Math.min(rect.width, rect.height) / 2 : parseFloat(computed.borderTopLeftRadius) || 0;
|
|
1798
|
+
const inset = Math.min(Math.max(6, radius * .4), (right - left) / 2, (bottom - top) / 2);
|
|
1799
|
+
if (![
|
|
1800
|
+
[left + inset, top + inset],
|
|
1801
|
+
[right - inset, top + inset],
|
|
1802
|
+
[left + inset, bottom - inset],
|
|
1803
|
+
[right - inset, bottom - inset],
|
|
1804
|
+
[(left + right) / 2, (top + bottom) / 2]
|
|
1805
|
+
].every(([px, py]) => owns(px, py))) continue;
|
|
1806
|
+
if (computed.display === "inline" && target.getClientRects().length > 1) continue;
|
|
1807
|
+
const projection = pressGeometry(target, rect);
|
|
1808
|
+
const polygon = projection ? [
|
|
1809
|
+
[left, top],
|
|
1810
|
+
[right, top],
|
|
1811
|
+
[right, bottom],
|
|
1812
|
+
[left, bottom]
|
|
1813
|
+
].map(([px = 0, py = 0]) => {
|
|
1814
|
+
const local = projection.local(px, py);
|
|
1815
|
+
return `${local.x}px ${local.y}px`;
|
|
1816
|
+
}).join(",") : null;
|
|
1817
|
+
rows.push({
|
|
1818
|
+
target,
|
|
1819
|
+
rect,
|
|
1820
|
+
strength,
|
|
1821
|
+
borderOnly: borderOnly(target),
|
|
1822
|
+
z,
|
|
1823
|
+
hover: hit === target || target.contains(hit),
|
|
1824
|
+
radius: computed.borderRadius,
|
|
1825
|
+
projection,
|
|
1826
|
+
clip: polygon ? `polygon(${polygon})` : `inset(${top - rect.top}px ${rect.right - right}px ${rect.bottom - bottom}px ${left - rect.left}px)`
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
const active = new Set(rows.map((row) => row.target));
|
|
1830
|
+
if (press && !active.has(press.target)) cancelPress();
|
|
1831
|
+
const changed = active.size !== overlays.size || [...active].some((target) => !overlays.has(target));
|
|
1832
|
+
for (const [target, node] of overlays) if (!active.has(target)) {
|
|
1833
|
+
node.remove();
|
|
1834
|
+
overlays.delete(target);
|
|
1835
|
+
}
|
|
1836
|
+
for (const { target, rect, strength, hover, borderOnly, radius, clip, z, projection } of rows) {
|
|
1837
|
+
let node = overlays.get(target);
|
|
1838
|
+
if (!node) {
|
|
1839
|
+
node = document.createElement("div");
|
|
1840
|
+
node.setAttribute("data-acrylic-reveal", "");
|
|
1841
|
+
node.setAttribute("aria-hidden", "true");
|
|
1842
|
+
document.body.append(node);
|
|
1843
|
+
overlays.set(target, node);
|
|
1844
|
+
}
|
|
1845
|
+
const box = projection ?? rect;
|
|
1846
|
+
const local = projection?.local(x, y) ?? {
|
|
1847
|
+
x: x - rect.left,
|
|
1848
|
+
y: y - rect.top
|
|
1849
|
+
};
|
|
1850
|
+
Object.assign(node.style, {
|
|
1851
|
+
left: `${box.left}px`,
|
|
1852
|
+
top: `${box.top}px`,
|
|
1853
|
+
width: `${box.width}px`,
|
|
1854
|
+
height: `${box.height}px`,
|
|
1855
|
+
clipPath: clip,
|
|
1856
|
+
transform: projection?.transform ?? "none",
|
|
1857
|
+
transformOrigin: "50% 50%"
|
|
1858
|
+
});
|
|
1859
|
+
node.style.setProperty("--reveal-z", String(z));
|
|
1860
|
+
node.style.setProperty("--reveal-radius", radius);
|
|
1861
|
+
node.style.setProperty("--reveal-x", `${local.x}px`);
|
|
1862
|
+
node.style.setProperty("--reveal-y", `${local.y}px`);
|
|
1863
|
+
node.style.setProperty("--reveal-border", String(strength * (borderOnly ? .48 : .38)));
|
|
1864
|
+
node.style.setProperty("--reveal-surface", String(!borderOnly && hover ? .045 : 0));
|
|
1865
|
+
const current = press;
|
|
1866
|
+
if (current?.target === target && !current.light) {
|
|
1867
|
+
current.light = createPressLight(document, window, node, () => {
|
|
1868
|
+
if (press !== current) return;
|
|
1869
|
+
press = null;
|
|
1870
|
+
schedule();
|
|
1871
|
+
});
|
|
1872
|
+
if (current.released) current.light.release();
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
if (changed) watchActive();
|
|
1876
|
+
}
|
|
1877
|
+
function schedule() {
|
|
1878
|
+
if (running && point && !frame) frame = window.requestAnimationFrame(draw);
|
|
1879
|
+
}
|
|
1880
|
+
function pointer(event) {
|
|
1881
|
+
if (event.pointerType !== "mouse" && event.pointerType !== "pen") return clear();
|
|
1882
|
+
if (!event.isPrimary || press && press.pointerId !== event.pointerId) return;
|
|
1883
|
+
point = {
|
|
1884
|
+
x: event.clientX,
|
|
1885
|
+
y: event.clientY
|
|
1886
|
+
};
|
|
1887
|
+
const target = control(document.elementFromPoint(point.x, point.y));
|
|
1888
|
+
if (press && target !== press.target) cancelPress();
|
|
1889
|
+
if (event.type === "pointerdown") {
|
|
1890
|
+
cancelPress();
|
|
1891
|
+
if (event.button === 0 && target && !borderOnly(target)) press = {
|
|
1892
|
+
target,
|
|
1893
|
+
pointerId: event.pointerId,
|
|
1894
|
+
released: false,
|
|
1895
|
+
light: null
|
|
1896
|
+
};
|
|
1897
|
+
} else if (press && !press.released && !(event.buttons & 1)) {
|
|
1898
|
+
press.released = true;
|
|
1899
|
+
press.light?.release();
|
|
1900
|
+
}
|
|
1901
|
+
schedule();
|
|
1902
|
+
}
|
|
1903
|
+
function leave(event) {
|
|
1904
|
+
if (!event.relatedTarget) return clear();
|
|
1905
|
+
if (press && event.pointerId === press.pointerId) {
|
|
1906
|
+
if (control(event.relatedTarget instanceof window.Element ? event.relatedTarget : null) !== press.target) {
|
|
1907
|
+
cancelPress();
|
|
1908
|
+
schedule();
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
function lostCapture(event) {
|
|
1913
|
+
if (press?.pointerId === event.pointerId && !press.released) {
|
|
1914
|
+
cancelPress();
|
|
1915
|
+
schedule();
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
function collectPortals(root) {
|
|
1919
|
+
let found = false;
|
|
1920
|
+
if (root.matches(portalSelector)) {
|
|
1921
|
+
portals.add(root);
|
|
1922
|
+
found = true;
|
|
1923
|
+
}
|
|
1924
|
+
for (const node of root.querySelectorAll(portalSelector)) {
|
|
1925
|
+
portals.add(node);
|
|
1926
|
+
found = true;
|
|
1927
|
+
}
|
|
1928
|
+
return found;
|
|
1929
|
+
}
|
|
1930
|
+
const observer = new window.MutationObserver((records) => {
|
|
1931
|
+
let dirty = false;
|
|
1932
|
+
for (const record of records) {
|
|
1933
|
+
const target = record.target;
|
|
1934
|
+
if (!(target instanceof window.Element) || target.closest(".xterm,.monaco-editor,[data-acrylic-reveal]")) continue;
|
|
1935
|
+
if (record.type === "attributes") {
|
|
1936
|
+
const known = portals.delete(target);
|
|
1937
|
+
const matches = target.matches(portalSelector);
|
|
1938
|
+
if (matches) portals.add(target);
|
|
1939
|
+
if (known || matches || [...portals].some((portal) => target.contains(portal))) dirty = true;
|
|
1940
|
+
continue;
|
|
1941
|
+
}
|
|
1942
|
+
if (target.closest(portalSelector)) dirty = true;
|
|
1943
|
+
for (const node of record.removedNodes) if (node instanceof window.Element && !node.hasAttribute("data-acrylic-reveal")) {
|
|
1944
|
+
for (const portal of portals) if (node.contains(portal)) {
|
|
1945
|
+
portals.delete(portal);
|
|
1946
|
+
dirty = true;
|
|
1947
|
+
}
|
|
1948
|
+
if ([...overlays.keys()].some((control) => node.contains(control))) dirty = true;
|
|
1949
|
+
}
|
|
1950
|
+
for (const node of record.addedNodes) if (node instanceof window.Element && !node.matches("[data-acrylic-reveal],.xterm,.monaco-editor")) {
|
|
1951
|
+
if (collectPortals(node)) dirty = true;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
if (dirty) schedule();
|
|
1955
|
+
});
|
|
1956
|
+
function reconcile() {
|
|
1957
|
+
const [reduced, forced, fine] = media.map((query) => query.matches);
|
|
1958
|
+
const next = !disposed && requested && !reduced && !forced && Boolean(fine);
|
|
1959
|
+
if (next === running) return;
|
|
1960
|
+
running = next;
|
|
1961
|
+
const method = next ? "addEventListener" : "removeEventListener";
|
|
1962
|
+
const on = (target, type, listener, capture = false) => target[method](type, listener, capture);
|
|
1963
|
+
for (const type of [
|
|
1964
|
+
"pointermove",
|
|
1965
|
+
"pointerdown",
|
|
1966
|
+
"pointerup"
|
|
1967
|
+
]) on(document, type, pointer, true);
|
|
1968
|
+
on(document, "pointerout", leave, true);
|
|
1969
|
+
on(document, "pointercancel", clear, true);
|
|
1970
|
+
on(document, "lostpointercapture", lostCapture, true);
|
|
1971
|
+
on(document, "keydown", clear, true);
|
|
1972
|
+
on(document, "dragstart", clear, true);
|
|
1973
|
+
on(document, "scroll", schedule, true);
|
|
1974
|
+
on(document, "animationend", schedule, true);
|
|
1975
|
+
on(document, "transitionend", schedule, true);
|
|
1976
|
+
on(document, "visibilitychange", clear);
|
|
1977
|
+
on(window, "blur", clear);
|
|
1978
|
+
on(window, "resize", schedule);
|
|
1979
|
+
if (next) {
|
|
1980
|
+
sheet.toggle(true);
|
|
1981
|
+
collectPortals(document.body);
|
|
1982
|
+
observer.observe(document.body, {
|
|
1983
|
+
childList: true,
|
|
1984
|
+
subtree: true,
|
|
1985
|
+
attributes: true,
|
|
1986
|
+
attributeFilter: [
|
|
1987
|
+
"hidden",
|
|
1988
|
+
"inert",
|
|
1989
|
+
"aria-hidden",
|
|
1990
|
+
"role",
|
|
1991
|
+
POPUP_ATTRIBUTE
|
|
1992
|
+
]
|
|
1993
|
+
});
|
|
1994
|
+
} else {
|
|
1995
|
+
observer.disconnect();
|
|
1996
|
+
portals.clear();
|
|
1997
|
+
sheet.toggle(false);
|
|
1998
|
+
clear();
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
media.forEach((query) => query.addEventListener("change", reconcile));
|
|
2002
|
+
return {
|
|
2003
|
+
update(enabled) {
|
|
2004
|
+
requested = enabled;
|
|
2005
|
+
reconcile();
|
|
2006
|
+
},
|
|
2007
|
+
refresh: schedule,
|
|
2008
|
+
sync() {
|
|
2009
|
+
if (!running || !point) return;
|
|
2010
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
2011
|
+
draw();
|
|
2012
|
+
},
|
|
2013
|
+
dispose() {
|
|
2014
|
+
disposed = true;
|
|
2015
|
+
unsubscribe();
|
|
2016
|
+
reconcile();
|
|
2017
|
+
media.forEach((query) => query.removeEventListener("change", reconcile));
|
|
2018
|
+
sheet.dispose();
|
|
2019
|
+
}
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
// src/press-motion.ts
|
|
2023
|
+
var MARKER = "data-acrylic-press-motion";
|
|
2024
|
+
var INVERSE = "--acrylic-press-inverse";
|
|
2025
|
+
var SIDES = [
|
|
2026
|
+
"top",
|
|
2027
|
+
"right",
|
|
2028
|
+
"bottom",
|
|
2029
|
+
"left"
|
|
2030
|
+
];
|
|
2031
|
+
var CSS = `
|
|
2032
|
+
[${MARKER}="static"] { position:relative; }
|
|
2033
|
+
[${MARKER}]:not([${MARKER}="clip"])::after {
|
|
2034
|
+
content:''; position:absolute; display:block; pointer-events:auto; z-index:-1;
|
|
2035
|
+
inset:var(--acrylic-press-top) var(--acrylic-press-right) var(--acrylic-press-bottom) var(--acrylic-press-left);
|
|
2036
|
+
transform:var(${INVERSE}); transform-origin:50% 50%; transform-box:border-box;
|
|
2037
|
+
border-radius:inherit; background:transparent; border:0; padding:0; margin:0;
|
|
2038
|
+
}
|
|
2039
|
+
`;
|
|
2040
|
+
var GEOMETRY = [
|
|
2041
|
+
"display",
|
|
2042
|
+
"visibility",
|
|
2043
|
+
"pointer-events",
|
|
2044
|
+
"position",
|
|
2045
|
+
"scale",
|
|
2046
|
+
"rotate",
|
|
2047
|
+
"translate",
|
|
2048
|
+
"transform-origin",
|
|
2049
|
+
"transform-box",
|
|
2050
|
+
"zoom",
|
|
2051
|
+
"overflow-x",
|
|
2052
|
+
"overflow-y",
|
|
2053
|
+
"clip-path",
|
|
2054
|
+
"mask-image",
|
|
2055
|
+
"contain",
|
|
2056
|
+
"anchor-name",
|
|
2057
|
+
...SIDES.map((side) => `border-${side}-width`)
|
|
2058
|
+
];
|
|
2059
|
+
var geometry = (css) => GEOMETRY.map((name) => css.getPropertyValue(name)).join(";");
|
|
2060
|
+
var pseudoGeometry = (css) => [
|
|
2061
|
+
"content",
|
|
2062
|
+
"position",
|
|
2063
|
+
"display",
|
|
2064
|
+
"pointer-events",
|
|
2065
|
+
"z-index",
|
|
2066
|
+
"top",
|
|
2067
|
+
"right",
|
|
2068
|
+
"bottom",
|
|
2069
|
+
"left",
|
|
2070
|
+
"width",
|
|
2071
|
+
"height",
|
|
2072
|
+
"transform-origin",
|
|
2073
|
+
"background-image",
|
|
2074
|
+
"background-color",
|
|
2075
|
+
"border-width"
|
|
2076
|
+
].map((name) => css.getPropertyValue(name)).join(";");
|
|
2077
|
+
var SHAPE_KEYS = [
|
|
2078
|
+
"transform",
|
|
2079
|
+
"scale",
|
|
2080
|
+
"rotate",
|
|
2081
|
+
"translate",
|
|
2082
|
+
"width",
|
|
2083
|
+
"height",
|
|
2084
|
+
"opacity"
|
|
2085
|
+
];
|
|
2086
|
+
var clips = (css) => [css.overflowX, css.overflowY].some((value) => value !== "visible");
|
|
2087
|
+
var scrolls = (css) => [css.overflowX, css.overflowY].some((value) => value === "auto" || value === "scroll");
|
|
2088
|
+
/** Semantic actions share one lifecycle; geometry is a separately checked capability. */
|
|
2089
|
+
function createPressMotion(document, window, modules, refresh) {
|
|
2090
|
+
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
2091
|
+
const sheet = createStyleSheet(document, "dsh-acrylic-wallpaper-press-motion", CSS);
|
|
2092
|
+
let requested = false, running = false, disposed = false, frame = 0, timer = 0;
|
|
2093
|
+
let press = null;
|
|
2094
|
+
function resolve(node) {
|
|
2095
|
+
if (!(node instanceof window.Element) || node.closest("input,textarea,select,[role=\"textbox\"],[role=\"searchbox\"],[role=\"combobox\"],[contenteditable]:not([contenteditable=\"false\"])")) return null;
|
|
2096
|
+
const quiet = modules.select("turnRail");
|
|
2097
|
+
if (quiet && node.closest(quiet)) return null;
|
|
2098
|
+
const target = node.closest(actionSelector(modules));
|
|
2099
|
+
return target instanceof window.HTMLElement ? target : null;
|
|
2100
|
+
}
|
|
2101
|
+
function available(target) {
|
|
2102
|
+
return target.isConnected && !target.matches(":disabled,[aria-disabled=\"true\"],[aria-busy=\"true\"],[data-unavailable]") && !target.closest("[hidden],[inert],[aria-hidden=\"true\"],[data-closing],[data-acrylic-ghost],[data-acrylic-reveal],[data-width-handle],[data-dockkit-divider],[data-dockkit-float-resize],.monaco-editor,.xterm") && window.getComputedStyle(target).getPropertyValue("-webkit-app-region") !== "drag";
|
|
2103
|
+
}
|
|
2104
|
+
function childrenSafe(target, positioned) {
|
|
2105
|
+
const children = target.querySelectorAll("*");
|
|
2106
|
+
if (children.length > 160 || target.querySelector("input,textarea,select,[role=\"textbox\"],[role=\"searchbox\"],[role=\"combobox\"],[contenteditable]:not([contenteditable=\"false\"])")) return false;
|
|
2107
|
+
for (const child of children) {
|
|
2108
|
+
const css = window.getComputedStyle(child);
|
|
2109
|
+
if (css.display === "none") continue;
|
|
2110
|
+
if (/^(fixed|sticky)$/.test(css.position)) return false;
|
|
2111
|
+
if (css.position === "absolute" && !positioned) {
|
|
2112
|
+
const clippedLabel = parseFloat(css.width) <= 1 && parseFloat(css.height) <= 1 && (css.clip !== "auto" || css.clipPath !== "none");
|
|
2113
|
+
const contained = child instanceof window.HTMLElement && child.offsetParent && target.contains(child.offsetParent);
|
|
2114
|
+
if (!clippedLabel && !contained) return false;
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
return true;
|
|
2118
|
+
}
|
|
2119
|
+
function shapes(animation) {
|
|
2120
|
+
return animation.effect instanceof window.KeyframeEffect && animation.effect.getKeyframes().some((key) => SHAPE_KEYS.some((name) => key[name] !== void 0));
|
|
2121
|
+
}
|
|
2122
|
+
function moving(target) {
|
|
2123
|
+
return target.getAnimations().some((animation) => animation.playState === "running" && shapes(animation));
|
|
2124
|
+
}
|
|
2125
|
+
function animated(target) {
|
|
2126
|
+
return target.getAnimations().some((animation) => animation.playState !== "finished" || shapes(animation));
|
|
2127
|
+
}
|
|
2128
|
+
function flatAncestors(target) {
|
|
2129
|
+
for (let parent = target.parentElement; parent; parent = parent.parentElement) {
|
|
2130
|
+
const css = window.getComputedStyle(parent);
|
|
2131
|
+
if (css.transform !== "none" || css.scale !== "none" || css.rotate !== "none" || css.perspective !== "none" || ![
|
|
2132
|
+
"",
|
|
2133
|
+
"1",
|
|
2134
|
+
"normal"
|
|
2135
|
+
].includes(css.getPropertyValue("zoom"))) return false;
|
|
2136
|
+
}
|
|
2137
|
+
return true;
|
|
2138
|
+
}
|
|
2139
|
+
function canTransform(target, css) {
|
|
2140
|
+
if (target.hasAttribute(MARKER) || css.display.startsWith("table") || css.display === "inline" || css.transform !== "none" || css.scale !== "none" || css.rotate !== "none" || css.translate !== "none" || css.clipPath !== "none" || css.maskImage !== "none" || scrolls(css) || /paint|strict|content/.test(css.contain) || ![
|
|
2141
|
+
"",
|
|
2142
|
+
"1",
|
|
2143
|
+
"normal"
|
|
2144
|
+
].includes(css.getPropertyValue("zoom")) || css.getPropertyValue("anchor-name").trim() && css.getPropertyValue("anchor-name").trim() !== "none" || animated(target) || css.transitionDuration.split(",").some((value) => parseFloat(value) > 0) && css.transitionProperty.split(",").some((name) => /^(all|scale|transform)$/.test(name.trim()))) return false;
|
|
2145
|
+
const pseudo = window.getComputedStyle(target, "::after");
|
|
2146
|
+
if (pseudo.content !== "none" && pseudo.content !== "normal") return false;
|
|
2147
|
+
return flatAncestors(target) && childrenSafe(target, css.position !== "static");
|
|
2148
|
+
}
|
|
2149
|
+
function keepsPointer(target, input, pose, width, height) {
|
|
2150
|
+
if (!("pointerId" in input)) return true;
|
|
2151
|
+
const style = target.style;
|
|
2152
|
+
const saved = [
|
|
2153
|
+
"transform",
|
|
2154
|
+
"transform-origin",
|
|
2155
|
+
"transform-box"
|
|
2156
|
+
].map((name) => [
|
|
2157
|
+
name,
|
|
2158
|
+
style.getPropertyValue(name),
|
|
2159
|
+
style.getPropertyPriority(name)
|
|
2160
|
+
]);
|
|
2161
|
+
style.setProperty("transform-origin", "50% 50%", "important");
|
|
2162
|
+
style.setProperty("transform-box", "border-box", "important");
|
|
2163
|
+
style.setProperty("transform", project(window, target, width, height, pose, 1).transform, "important");
|
|
2164
|
+
const hit = document.elementFromPoint(input.x, input.y);
|
|
2165
|
+
for (const [name, value, priority] of saved) if (value) style.setProperty(name, value, priority);
|
|
2166
|
+
else style.removeProperty(name);
|
|
2167
|
+
forgetProjection(target);
|
|
2168
|
+
return hit !== null && target.contains(hit);
|
|
2169
|
+
}
|
|
2170
|
+
function own(current, name, value, priority = "") {
|
|
2171
|
+
const style = current.target.style;
|
|
2172
|
+
if (!current.saved.has(name)) current.saved.set(name, [style.getPropertyValue(name), style.getPropertyPriority(name)]);
|
|
2173
|
+
style.setProperty(name, value, priority);
|
|
2174
|
+
current.owned.set(name, [style.getPropertyValue(name), style.getPropertyPriority(name)]);
|
|
2175
|
+
}
|
|
2176
|
+
function hostStyle(current) {
|
|
2177
|
+
const style = current.target.style;
|
|
2178
|
+
return [...style].filter((name) => !current.owned.has(name)).sort().map((name) => `${name}:${style.getPropertyValue(name)}!${style.getPropertyPriority(name)}`).join(";");
|
|
2179
|
+
}
|
|
2180
|
+
function intact(current) {
|
|
2181
|
+
return [...current.owned].every(([name, [value, priority]]) => current.target.style.getPropertyValue(name) === value && current.target.style.getPropertyPriority(name) === priority);
|
|
2182
|
+
}
|
|
2183
|
+
function clear() {
|
|
2184
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
2185
|
+
if (timer) window.clearTimeout(timer);
|
|
2186
|
+
frame = 0;
|
|
2187
|
+
timer = 0;
|
|
2188
|
+
observer.disconnect();
|
|
2189
|
+
sizes.disconnect();
|
|
2190
|
+
const current = press;
|
|
2191
|
+
press = null;
|
|
2192
|
+
if (!current) return;
|
|
2193
|
+
forgetProjection(current.target);
|
|
2194
|
+
if (current.geometric) current.target.removeAttribute(MARKER);
|
|
2195
|
+
for (const [name, [value, priority]] of current.saved) {
|
|
2196
|
+
const owned = current.owned.get(name);
|
|
2197
|
+
if (!owned || current.target.style.getPropertyValue(name) !== owned[0] || current.target.style.getPropertyPriority(name) !== owned[1]) continue;
|
|
2198
|
+
if (value) current.target.style.setProperty(name, value, priority);
|
|
2199
|
+
else current.target.style.removeProperty(name);
|
|
2200
|
+
}
|
|
2201
|
+
refresh();
|
|
2202
|
+
}
|
|
2203
|
+
function paint(current, amount) {
|
|
2204
|
+
current.amount = amount;
|
|
2205
|
+
if (current.geometric) {
|
|
2206
|
+
const projection = project(window, current.target, current.width, current.height, current.pose, amount);
|
|
2207
|
+
own(current, "transform", projection.transform, "important");
|
|
2208
|
+
own(current, INVERSE, projection.inverse.toString());
|
|
2209
|
+
} else {
|
|
2210
|
+
const tint = `color-mix(in srgb,var(--dsw-alias-interactive-bg-active) ${Math.round(amount * 100)}%,transparent)`;
|
|
2211
|
+
own(current, "background-image", `linear-gradient(${tint},${tint}),${current.background}`, "important");
|
|
2212
|
+
}
|
|
2213
|
+
refresh();
|
|
2214
|
+
}
|
|
2215
|
+
function tick(now) {
|
|
2216
|
+
frame = 0;
|
|
2217
|
+
const current = press;
|
|
2218
|
+
if (!current) return;
|
|
2219
|
+
if (!available(current.target) || document.hidden) return clear();
|
|
2220
|
+
const progress = Math.max(0, Math.min(1, (now - current.releasedAt - 150) / 200));
|
|
2221
|
+
if (progress === 1) return clear();
|
|
2222
|
+
paint(current, 1 - releaseEase(progress));
|
|
2223
|
+
frame = window.requestAnimationFrame(tick);
|
|
2224
|
+
}
|
|
2225
|
+
function release() {
|
|
2226
|
+
const current = press;
|
|
2227
|
+
if (!current?.held) return;
|
|
2228
|
+
current.held = false;
|
|
2229
|
+
if (timer) window.clearTimeout(timer);
|
|
2230
|
+
timer = 0;
|
|
2231
|
+
if (!current.geometric) return clear();
|
|
2232
|
+
if (!current.amount) return clear();
|
|
2233
|
+
current.releasedAt = window.performance.now();
|
|
2234
|
+
timer = window.setTimeout(() => {
|
|
2235
|
+
timer = 0;
|
|
2236
|
+
if (press === current) frame = window.requestAnimationFrame(tick);
|
|
2237
|
+
}, 150);
|
|
2238
|
+
}
|
|
2239
|
+
function begin(target, input) {
|
|
2240
|
+
clear();
|
|
2241
|
+
if (!available(target)) return;
|
|
2242
|
+
const css = window.getComputedStyle(target), rect = target.getBoundingClientRect();
|
|
2243
|
+
if (!rect.width || !rect.height || css.visibility !== "visible" || css.pointerEvents === "none") return;
|
|
2244
|
+
const u = "pointerId" in input ? (input.x - rect.left) / rect.width : .5;
|
|
2245
|
+
const v = "pointerId" in input ? (input.y - rect.top) / rect.height : .5;
|
|
2246
|
+
const pose = depression(rect.width, rect.height, u, v);
|
|
2247
|
+
const clipped = clips(css);
|
|
2248
|
+
const geometric = !reduced.matches && canTransform(target, css) && (!clipped || keepsPointer(target, input, pose, rect.width, rect.height));
|
|
2249
|
+
const borders = SIDES.map((side) => css.getPropertyValue(`border-${side}-width`));
|
|
2250
|
+
const position = css.position;
|
|
2251
|
+
const current = {
|
|
2252
|
+
target,
|
|
2253
|
+
input,
|
|
2254
|
+
held: true,
|
|
2255
|
+
geometric,
|
|
2256
|
+
drag: Boolean(target.closest("[draggable=\"true\"],[data-dockkit-tab]")),
|
|
2257
|
+
width: rect.width,
|
|
2258
|
+
height: rect.height,
|
|
2259
|
+
pose,
|
|
2260
|
+
amount: 0,
|
|
2261
|
+
releasedAt: 0,
|
|
2262
|
+
saved: /* @__PURE__ */ new Map(),
|
|
2263
|
+
owned: /* @__PURE__ */ new Map(),
|
|
2264
|
+
geometry: "",
|
|
2265
|
+
pseudo: "",
|
|
2266
|
+
hostStyle: "",
|
|
2267
|
+
background: css.backgroundImage
|
|
2268
|
+
};
|
|
2269
|
+
press = current;
|
|
2270
|
+
if (geometric) {
|
|
2271
|
+
own(current, "transform-origin", "50% 50%", "important");
|
|
2272
|
+
own(current, "transform-box", "border-box", "important");
|
|
2273
|
+
SIDES.forEach((side, index) => own(current, `--acrylic-press-${side}`, `-${borders[index]}`));
|
|
2274
|
+
target.setAttribute(MARKER, clipped ? "clip" : position === "static" ? "static" : "");
|
|
2275
|
+
paint(current, 0);
|
|
2276
|
+
if (!clipped && position === "static" && window.getComputedStyle(target).position !== "relative") return clear();
|
|
2277
|
+
}
|
|
2278
|
+
if (!geometric) paint(current, 1);
|
|
2279
|
+
current.geometry = geometry(window.getComputedStyle(target));
|
|
2280
|
+
current.pseudo = pseudoGeometry(window.getComputedStyle(target, "::after"));
|
|
2281
|
+
current.hostStyle = hostStyle(current);
|
|
2282
|
+
sizes.observe(target, { box: "border-box" });
|
|
2283
|
+
observer.observe(document.documentElement, {
|
|
2284
|
+
subtree: true,
|
|
2285
|
+
childList: true,
|
|
2286
|
+
attributes: true
|
|
2287
|
+
});
|
|
2288
|
+
if (!geometric) return;
|
|
2289
|
+
timer = window.setTimeout(() => {
|
|
2290
|
+
timer = 0;
|
|
2291
|
+
if (press === current && current.held && available(target)) paint(current, 1);
|
|
2292
|
+
}, 10);
|
|
2293
|
+
}
|
|
2294
|
+
const sizes = new window.ResizeObserver((entries) => {
|
|
2295
|
+
const current = press;
|
|
2296
|
+
if (!current?.geometric) return;
|
|
2297
|
+
const box = entries.find((entry) => entry.target === current.target)?.borderBoxSize[0];
|
|
2298
|
+
if (!box) return;
|
|
2299
|
+
const vertical = window.getComputedStyle(current.target).writingMode.startsWith("vertical");
|
|
2300
|
+
const width = vertical ? box.blockSize : box.inlineSize, height = vertical ? box.inlineSize : box.blockSize;
|
|
2301
|
+
if (Math.abs(width - current.width) > .1 || Math.abs(height - current.height) > .1) clear();
|
|
2302
|
+
});
|
|
2303
|
+
const observer = new window.MutationObserver((records) => {
|
|
2304
|
+
const current = press;
|
|
2305
|
+
if (!current) return;
|
|
2306
|
+
if (!available(current.target) || !intact(current)) return clear();
|
|
2307
|
+
const relevant = records.filter((record) => record.attributeName !== MARKER && record.target instanceof window.Element && (record.target.contains(current.target) || current.target.contains(record.target)));
|
|
2308
|
+
if (!(relevant.length > 0)) return;
|
|
2309
|
+
const css = window.getComputedStyle(current.target);
|
|
2310
|
+
if (geometry(css) !== current.geometry || css.visibility !== "visible" || css.display === "none") return clear();
|
|
2311
|
+
if (current.geometric && (hostStyle(current) !== current.hostStyle || relevant.some((record) => record.target !== current.target || record.attributeName !== "style"))) {
|
|
2312
|
+
const marker = current.target.getAttribute(MARKER);
|
|
2313
|
+
current.target.removeAttribute(MARKER);
|
|
2314
|
+
const hostContent = window.getComputedStyle(current.target, "::after").content;
|
|
2315
|
+
if (marker !== null) current.target.setAttribute(MARKER, marker);
|
|
2316
|
+
if (hostContent !== "none" && hostContent !== "normal") return clear();
|
|
2317
|
+
if (!childrenSafe(current.target, true) || !flatAncestors(current.target) || moving(current.target) || pseudoGeometry(window.getComputedStyle(current.target, "::after")) !== current.pseudo) return clear();
|
|
2318
|
+
current.hostStyle = hostStyle(current);
|
|
2319
|
+
}
|
|
2320
|
+
if (records.some((record) => record.attributeName === "aria-expanded" && record.target === current.target && current.target.getAttribute("aria-expanded") === "true")) clear();
|
|
2321
|
+
});
|
|
2322
|
+
function down(event) {
|
|
2323
|
+
if (!event.isPrimary || event.button !== 0 || document.hidden) return;
|
|
2324
|
+
const target = resolve(event.target);
|
|
2325
|
+
if (target) begin(target, {
|
|
2326
|
+
pointerId: event.pointerId,
|
|
2327
|
+
x: event.clientX,
|
|
2328
|
+
y: event.clientY
|
|
2329
|
+
});
|
|
2330
|
+
else clear();
|
|
2331
|
+
}
|
|
2332
|
+
function up(event) {
|
|
2333
|
+
if (press && "pointerId" in press.input && press.input.pointerId === event.pointerId) release();
|
|
2334
|
+
}
|
|
2335
|
+
function move(event) {
|
|
2336
|
+
if (!press?.held || !("pointerId" in press.input) || press.input.pointerId !== event.pointerId) return;
|
|
2337
|
+
if (press.drag && (Math.abs(event.clientX - press.input.x) >= 4 || Math.abs(event.clientY - press.input.y) >= 4)) return clear();
|
|
2338
|
+
if (!(event.buttons & 1) || resolve(document.elementFromPoint(event.clientX, event.clientY)) !== press.target) clear();
|
|
2339
|
+
}
|
|
2340
|
+
function out(event) {
|
|
2341
|
+
if (press?.held && "pointerId" in press.input && press.input.pointerId === event.pointerId && resolve(event.relatedTarget) !== press.target) clear();
|
|
2342
|
+
}
|
|
2343
|
+
function cancel(event) {
|
|
2344
|
+
if (press?.held && "pointerId" in press.input && press.input.pointerId === event.pointerId) clear();
|
|
2345
|
+
}
|
|
2346
|
+
function keydown(event) {
|
|
2347
|
+
if (event.key === "Escape") return clear();
|
|
2348
|
+
if (event.repeat || event.isComposing || event.altKey || event.ctrlKey || event.metaKey || ![" ", "Enter"].includes(event.key)) return;
|
|
2349
|
+
const target = resolve(event.target);
|
|
2350
|
+
if (target && document.activeElement === target) begin(target, { key: event.key });
|
|
2351
|
+
}
|
|
2352
|
+
function keyup(event) {
|
|
2353
|
+
if (press && "key" in press.input && press.input.key === event.key) release();
|
|
2354
|
+
}
|
|
2355
|
+
function focusout(event) {
|
|
2356
|
+
if (press && "key" in press.input && event.target === press.target) clear();
|
|
2357
|
+
}
|
|
2358
|
+
function click() {
|
|
2359
|
+
if (press?.target.matches("[aria-haspopup]:not([aria-haspopup=\"false\"]),[aria-expanded],[popovertarget]")) clear();
|
|
2360
|
+
}
|
|
2361
|
+
const events = [
|
|
2362
|
+
["pointerdown", down],
|
|
2363
|
+
["pointerup", up],
|
|
2364
|
+
["pointermove", move],
|
|
2365
|
+
["pointerout", out],
|
|
2366
|
+
["pointercancel", cancel],
|
|
2367
|
+
["lostpointercapture", cancel],
|
|
2368
|
+
["keydown", keydown],
|
|
2369
|
+
["keyup", keyup],
|
|
2370
|
+
["focusout", focusout],
|
|
2371
|
+
["click", click],
|
|
2372
|
+
["dragstart", clear],
|
|
2373
|
+
["visibilitychange", clear],
|
|
2374
|
+
["scroll", clear]
|
|
2375
|
+
];
|
|
2376
|
+
function reconcile() {
|
|
2377
|
+
const next = requested && !disposed;
|
|
2378
|
+
if (next === running) return;
|
|
2379
|
+
running = next;
|
|
2380
|
+
const method = next ? "addEventListener" : "removeEventListener";
|
|
2381
|
+
for (const [type, listener] of events) document[method](type, listener, true);
|
|
2382
|
+
window[method]("blur", clear);
|
|
2383
|
+
window[method]("resize", clear);
|
|
2384
|
+
if (!next) clear();
|
|
2385
|
+
sheet.toggle(next);
|
|
2386
|
+
}
|
|
2387
|
+
const unsubscribe = modules.subscribe(clear);
|
|
2388
|
+
reduced.addEventListener("change", clear);
|
|
2389
|
+
return {
|
|
2390
|
+
update(enabled) {
|
|
2391
|
+
requested = enabled;
|
|
2392
|
+
reconcile();
|
|
2393
|
+
},
|
|
2394
|
+
dispose() {
|
|
2395
|
+
disposed = true;
|
|
2396
|
+
reconcile();
|
|
2397
|
+
unsubscribe();
|
|
2398
|
+
reduced.removeEventListener("change", clear);
|
|
2399
|
+
sheet.dispose();
|
|
2400
|
+
}
|
|
2401
|
+
};
|
|
2402
|
+
}
|
|
2403
|
+
// src/wallpaper.ts
|
|
2404
|
+
var FRAME = "body[data-acrylic-wallpaper] div:has(> [data-shell-bottom]):has(> [data-rightbar-col])";
|
|
2405
|
+
var FLUENT_FRAME = "body[data-acrylic-wallpaper][data-acrylic-fluent] div:has(> [data-shell-bottom]):has(> [data-rightbar-col])";
|
|
2406
|
+
var DOCK_TINT = "rgb(var(--acrylic-tint-rgb) / .08)";
|
|
2407
|
+
var TERMINAL_HOST = `${FRAME} :has(> .xterm)`;
|
|
2408
|
+
var TERMINAL_SURFACE = `${FRAME} .xterm:has(.xterm-rows) :is(.xterm-scrollable-element,.xterm-viewport)`;
|
|
2409
|
+
var COMPACTION_HEADER = "button[aria-expanded=\"true\"]:has(> span > [data-compaction-disclosure])";
|
|
2410
|
+
var CODE_BANNER = ".md-code-block > :has(> [data-code-block-banner])";
|
|
2411
|
+
var TINT = {
|
|
2412
|
+
light: "247 247 247",
|
|
2413
|
+
dark: "24 24 24"
|
|
2414
|
+
};
|
|
2415
|
+
var CANVAS_RULES = (() => {
|
|
2416
|
+
const names = Object.keys(CANVAS_TOKENS);
|
|
2417
|
+
const kept = (name) => `--acrylic-opaque${name.slice(1)}`;
|
|
2418
|
+
const join = (value) => names.map((name) => `${name}: ${value(name)};`).join(" ");
|
|
2419
|
+
return {
|
|
2420
|
+
keep: names.map((name) => `${kept(name)}: var(${name});`).join(" "),
|
|
2421
|
+
clear: join(() => "transparent"),
|
|
2422
|
+
restore: join((name) => `var(${kept(name)})`),
|
|
2423
|
+
bar: join((name) => `color-mix(in srgb, var(${kept(name)}) 82%, transparent)`),
|
|
2424
|
+
acrylic: `color-mix(in srgb, var(${kept("--dsw-alias-bg-base")}) 82%, transparent)`
|
|
2425
|
+
};
|
|
2426
|
+
})();
|
|
2427
|
+
var WALLPAPER_CSS = `
|
|
2428
|
+
body[data-acrylic-wallpaper] { isolation: isolate; --acrylic-tint-rgb: ${TINT.light}; }
|
|
2429
|
+
body[data-acrylic-wallpaper][data-ds-dark-theme] { --acrylic-tint-rgb: ${TINT.dark}; }
|
|
2430
|
+
[data-acrylic-layer] { position: fixed; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; background: rgb(var(--acrylic-tint-rgb, ${TINT.light})); }
|
|
2431
|
+
[data-acrylic-layer] > div { position: absolute; pointer-events: none; }
|
|
2432
|
+
[data-acrylic-image] { inset: calc(-3 * var(--acrylic-blur)); background-position: center; background-size: cover; background-repeat: no-repeat; filter: blur(var(--acrylic-blur)); }
|
|
2433
|
+
[data-acrylic-tint] { inset: 0; background: rgb(var(--acrylic-tint-rgb, ${TINT.light}) / var(--acrylic-tint)); }
|
|
2434
|
+
[data-acrylic-noise] { inset: 0; background-repeat: repeat; opacity: var(--acrylic-noise); }
|
|
2435
|
+
|
|
2436
|
+
/* Custom properties substitute where declared: body children keep the opaque
|
|
2437
|
+
palette values that the frame below replaces with transparent. */
|
|
2438
|
+
body[data-acrylic-wallpaper] > * { ${CANVAS_RULES.keep} }
|
|
2439
|
+
${FRAME} { ${CANVAS_RULES.clear} }
|
|
2440
|
+
/* Keep terminal palette sampling opaque: the host also uses this color for
|
|
2441
|
+
inverse text, selection and cursor contrast. Paint wallpaper over the fill
|
|
2442
|
+
instead of feeding transparent black into the emulator's theme. */
|
|
2443
|
+
${FRAME} > [data-shell-overlay], ${TERMINAL_HOST} { ${CANVAS_RULES.restore} }
|
|
2444
|
+
/* Both the host padding and xterm's inline-painted scroll surface need the
|
|
2445
|
+
material. clip-path clips viewport-fixed decoration without changing its
|
|
2446
|
+
containing block; fixed coordinates keep it aligned with the main wallpaper.
|
|
2447
|
+
The padding layers stay under the raised .xterm, so they cover no renderer;
|
|
2448
|
+
the surface layers lie inside xterm and are limited to the DOM renderer. */
|
|
2449
|
+
${TERMINAL_HOST},
|
|
2450
|
+
${TERMINAL_SURFACE} {
|
|
2451
|
+
isolation: isolate; clip-path: inset(0);
|
|
2452
|
+
}
|
|
2453
|
+
${TERMINAL_HOST}::before,
|
|
2454
|
+
${TERMINAL_SURFACE}::before {
|
|
2455
|
+
content: ''; position: fixed; inset: var(--acrylic-terminal-inset); z-index: 0; pointer-events: none;
|
|
2456
|
+
background-color: rgb(var(--acrylic-tint-rgb));
|
|
2457
|
+
background-image: var(--acrylic-terminal-image); background-position: center;
|
|
2458
|
+
background-size: var(--acrylic-terminal-size); background-repeat: var(--acrylic-terminal-repeat);
|
|
2459
|
+
filter: blur(var(--acrylic-terminal-blur));
|
|
2460
|
+
}
|
|
2461
|
+
${TERMINAL_HOST}::after,
|
|
2462
|
+
${TERMINAL_SURFACE}::after {
|
|
2463
|
+
content: ''; position: fixed; inset: 0; z-index: 0; pointer-events: none;
|
|
2464
|
+
background: rgb(var(--acrylic-tint-rgb) / var(--acrylic-terminal-tint));
|
|
2465
|
+
}
|
|
2466
|
+
${TERMINAL_HOST} > .xterm,
|
|
2467
|
+
${FRAME} .xterm:has(.xterm-rows) .xterm-screen { position: relative; z-index: 1; }
|
|
2468
|
+
|
|
2469
|
+
/* Reading surfaces (center column, docked panes) gain the same subtle tint. */
|
|
2470
|
+
${FRAME} > div:nth-child(2),
|
|
2471
|
+
${FRAME} [data-dockkit-host="dock"] > [data-dockkit-content],
|
|
2472
|
+
${FRAME} [data-dockkit-empty] { background: ${DOCK_TINT}; }
|
|
2473
|
+
/* A right panel without its own track (narrow window, fullscreen) lies over
|
|
2474
|
+
the conversation; give its panes in-app acrylic instead of see-through. */
|
|
2475
|
+
${FRAME}:is([data-rightbar-collapsed], [data-rightbar-fullscreen]) [data-rightbar-col] [data-dockkit-host="dock"] > [data-dockkit-content],
|
|
2476
|
+
${FRAME}:is([data-rightbar-collapsed], [data-rightbar-fullscreen]) [data-rightbar-col] [data-dockkit-empty] {
|
|
2477
|
+
background: ${CANVAS_RULES.acrylic};
|
|
2478
|
+
backdrop-filter: blur(30px) saturate(1.2);
|
|
2479
|
+
}
|
|
2480
|
+
/* The frame drops the track as soon as a close starts. While Win10 mode
|
|
2481
|
+
animates the columns, the closing panel slides off beside the widening
|
|
2482
|
+
conversation, not over it: keep the docked tint instead of an opaque slab.
|
|
2483
|
+
Instant exits (from fullscreen) do not animate and keep the acrylic. */
|
|
2484
|
+
${FLUENT_FRAME}[data-animating]:not([data-rightbar-instant], [data-rightbar-fullscreen]) [data-sidebar-right-panel]:not([data-sidebar-right-open]) :is([data-dockkit-host="dock"] > [data-dockkit-content], [data-dockkit-empty]) {
|
|
2485
|
+
background: ${DOCK_TINT};
|
|
2486
|
+
backdrop-filter: none;
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
/* Sticky rows that used the canvas to hide scrolled content become acrylic
|
|
2490
|
+
bars, matched by the host's own semantic anchors (host/modules.ts): an open
|
|
2491
|
+
compaction header (sticky exactly while expanded), and a code block's banner
|
|
2492
|
+
wrapper, which the host itself selects as :has(>[data-code-block-banner]). */
|
|
2493
|
+
${FRAME} [data-expanded] [data-open] [data-disclosure-header],
|
|
2494
|
+
${FRAME} ${COMPACTION_HEADER},
|
|
2495
|
+
${FRAME} ${CODE_BANNER},
|
|
2496
|
+
${FRAME} th {
|
|
2497
|
+
${CANVAS_RULES.bar}
|
|
2498
|
+
}
|
|
2499
|
+
${FRAME} [data-expanded] [data-open] [data-disclosure-header],
|
|
2500
|
+
${FRAME} ${COMPACTION_HEADER} {
|
|
2501
|
+
backdrop-filter: blur(20px) saturate(1.2);
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
/* Composer cards (host input bar, side chat) stay readable inputs over
|
|
2505
|
+
transcript text: blur a decorative pseudo-element, never the card (fixed
|
|
2506
|
+
menus inside it must stay viewport-relative). ::after belongs to the host
|
|
2507
|
+
workspace card. */
|
|
2508
|
+
body[data-acrylic-wallpaper] ${COMPOSER_CARD} { position: relative; isolation: isolate; background: transparent !important; }
|
|
2509
|
+
body[data-acrylic-wallpaper] ${COMPOSER_CARD}::before {
|
|
2510
|
+
content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
|
|
2511
|
+
background: var(--dsw-specific-input-major);
|
|
2512
|
+
}
|
|
2513
|
+
@supports (backdrop-filter: blur(1px)) {
|
|
2514
|
+
body[data-acrylic-wallpaper] ${COMPOSER_CARD}::before {
|
|
2515
|
+
background: color-mix(in srgb, var(--dsw-specific-input-major) 88%, transparent);
|
|
2516
|
+
backdrop-filter: blur(24px) saturate(1.15);
|
|
2517
|
+
}
|
|
2518
|
+
body[data-acrylic-wallpaper][data-ds-dark-theme] ${COMPOSER_CARD}::before {
|
|
2519
|
+
background: color-mix(in srgb, var(--dsw-specific-input-major) 85%, transparent);
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
/* The opaque layer already backs every menu; the macOS menu backing would
|
|
2523
|
+
otherwise sit between the wallpaper and the menu's acrylic. Host and Fluent
|
|
2524
|
+
adapter both paint it, hence !important. */
|
|
2525
|
+
html[data-platform="darwin"] body[data-acrylic-wallpaper] > [data-menu-backing] { background: transparent !important; }
|
|
2526
|
+
@media (forced-colors: active), (prefers-reduced-transparency: reduce) {
|
|
2527
|
+
[data-acrylic-layer] { display: none; }
|
|
2528
|
+
}
|
|
2529
|
+
`;
|
|
2530
|
+
function createNoise(document) {
|
|
2531
|
+
const canvas = document.createElement("canvas");
|
|
2532
|
+
canvas.width = canvas.height = 64;
|
|
2533
|
+
const context = canvas.getContext("2d");
|
|
2534
|
+
if (!context) return "";
|
|
2535
|
+
const data = context.createImageData(64, 64);
|
|
2536
|
+
let seed = 342685;
|
|
2537
|
+
for (let i = 0; i < data.data.length; i += 4) {
|
|
2538
|
+
seed ^= seed << 13;
|
|
2539
|
+
seed ^= seed >>> 17;
|
|
2540
|
+
seed ^= seed << 5;
|
|
2541
|
+
const value = seed & 255;
|
|
2542
|
+
data.data[i] = data.data[i + 1] = data.data[i + 2] = value;
|
|
2543
|
+
data.data[i + 3] = 255;
|
|
2544
|
+
}
|
|
2545
|
+
context.putImageData(data, 0, 0);
|
|
2546
|
+
return canvas.toDataURL("image/png");
|
|
2547
|
+
}
|
|
2548
|
+
function createWallpaper(document, window) {
|
|
2549
|
+
const sheet = createStyleSheet(document, PLUGIN_ID, WALLPAPER_CSS);
|
|
2550
|
+
const layer = document.createElement("div");
|
|
2551
|
+
layer.setAttribute("data-acrylic-layer", "");
|
|
2552
|
+
layer.setAttribute("aria-hidden", "true");
|
|
2553
|
+
const image = document.createElement("div");
|
|
2554
|
+
image.setAttribute("data-acrylic-image", "");
|
|
2555
|
+
const tint = document.createElement("div");
|
|
2556
|
+
tint.setAttribute("data-acrylic-tint", "");
|
|
2557
|
+
const noise = document.createElement("div");
|
|
2558
|
+
noise.setAttribute("data-acrylic-noise", "");
|
|
2559
|
+
const noiseUrl = createNoise(document);
|
|
2560
|
+
if (noiseUrl) noise.style.backgroundImage = `url("${noiseUrl}")`;
|
|
2561
|
+
layer.append(image, tint, noise);
|
|
2562
|
+
const terminalProperties = [
|
|
2563
|
+
"image",
|
|
2564
|
+
"size",
|
|
2565
|
+
"repeat",
|
|
2566
|
+
"inset",
|
|
2567
|
+
"blur",
|
|
2568
|
+
"tint"
|
|
2569
|
+
];
|
|
2570
|
+
function hide() {
|
|
2571
|
+
layer.remove();
|
|
2572
|
+
sheet.toggle(false);
|
|
2573
|
+
document.body.removeAttribute(WALLPAPER_MARKER);
|
|
2574
|
+
for (const name of terminalProperties) document.body.style.removeProperty(`--acrylic-terminal-${name}`);
|
|
2575
|
+
}
|
|
2576
|
+
return {
|
|
2577
|
+
update(state) {
|
|
2578
|
+
if (!state?.url || !window.CSS.supports("filter", "blur(1px)")) return hide();
|
|
2579
|
+
const { settings, url } = state;
|
|
2580
|
+
const { fit } = settings;
|
|
2581
|
+
image.style.backgroundImage = `url(${JSON.stringify(url)})`;
|
|
2582
|
+
image.style.backgroundSize = fit === "stretch" ? "100% 100%" : fit === "tile" ? "auto" : fit;
|
|
2583
|
+
image.style.backgroundRepeat = fit === "tile" ? "repeat" : "no-repeat";
|
|
2584
|
+
image.style.inset = fit === "cover" || fit === "tile" ? "calc(-3 * var(--acrylic-blur))" : "0";
|
|
2585
|
+
layer.style.setProperty("--acrylic-blur", `${settings.blur}px`);
|
|
2586
|
+
layer.style.setProperty("--acrylic-tint", String(settings.tint / 100));
|
|
2587
|
+
layer.style.setProperty("--acrylic-noise", String(settings.noise / 100));
|
|
2588
|
+
const terminal = [
|
|
2589
|
+
image.style.backgroundImage,
|
|
2590
|
+
image.style.backgroundSize,
|
|
2591
|
+
image.style.backgroundRepeat,
|
|
2592
|
+
fit === "cover" || fit === "tile" ? `${-3 * settings.blur}px` : "0px",
|
|
2593
|
+
`${settings.blur}px`,
|
|
2594
|
+
String(settings.tint / 100)
|
|
2595
|
+
];
|
|
2596
|
+
terminalProperties.forEach((name, index) => document.body.style.setProperty(`--acrylic-terminal-${name}`, terminal[index] ?? ""));
|
|
2597
|
+
sheet.toggle(true);
|
|
2598
|
+
if (!layer.isConnected) document.body.prepend(layer);
|
|
2599
|
+
document.body.setAttribute(WALLPAPER_MARKER, "");
|
|
2600
|
+
},
|
|
2601
|
+
dispose() {
|
|
2602
|
+
hide();
|
|
2603
|
+
image.style.backgroundImage = "";
|
|
2604
|
+
}
|
|
2605
|
+
};
|
|
2606
|
+
}
|
|
2607
|
+
// src/appearance.ts
|
|
2608
|
+
function createAppearance(document, window, theme) {
|
|
2609
|
+
const modules = createHostModules(document, window);
|
|
2610
|
+
const fluent = createFluentTheme(theme);
|
|
2611
|
+
const adapters = createAdapters(document, modules);
|
|
2612
|
+
const elevation = createElevation(document);
|
|
2613
|
+
const reveal = createReveal(document, window, modules);
|
|
2614
|
+
const pressMotion = createPressMotion(document, window, modules, reveal.sync);
|
|
2615
|
+
const motion = createMotion(document, window, { onSettle: reveal.refresh });
|
|
2616
|
+
const frameMotion = createFrameMotion(document, window);
|
|
2617
|
+
const wallpaper = createWallpaper(document, window);
|
|
2618
|
+
const media = [window.matchMedia("(forced-colors: active)"), window.matchMedia("(prefers-reduced-transparency: reduce)")];
|
|
2619
|
+
let snapshot = null;
|
|
2620
|
+
let disposed = false;
|
|
2621
|
+
function render() {
|
|
2622
|
+
if (disposed) return;
|
|
2623
|
+
const settings = snapshot?.settings;
|
|
2624
|
+
const on = Boolean(settings?.enabled && !media.some((query) => query.matches));
|
|
2625
|
+
const win10 = Boolean(on && settings?.fluent);
|
|
2626
|
+
document.body.toggleAttribute(FLUENT_MARKER, win10);
|
|
2627
|
+
fluent.update(win10);
|
|
2628
|
+
adapters.update(win10);
|
|
2629
|
+
elevation.update(win10);
|
|
2630
|
+
motion.update(win10);
|
|
2631
|
+
frameMotion.update(win10);
|
|
2632
|
+
pressMotion.update(win10);
|
|
2633
|
+
reveal.update(Boolean(win10 && settings?.reveal));
|
|
2634
|
+
wallpaper.update(on && snapshot?.url && settings ? {
|
|
2635
|
+
url: snapshot.url,
|
|
2636
|
+
settings
|
|
2637
|
+
} : null);
|
|
2638
|
+
}
|
|
2639
|
+
media.forEach((query) => query.addEventListener("change", render));
|
|
2640
|
+
return {
|
|
2641
|
+
update(next) {
|
|
2642
|
+
snapshot = next;
|
|
2643
|
+
render();
|
|
2644
|
+
},
|
|
2645
|
+
dispose() {
|
|
2646
|
+
disposed = true;
|
|
2647
|
+
media.forEach((query) => query.removeEventListener("change", render));
|
|
2648
|
+
for (const feature of [
|
|
2649
|
+
fluent,
|
|
2650
|
+
adapters,
|
|
2651
|
+
elevation,
|
|
2652
|
+
motion,
|
|
2653
|
+
frameMotion,
|
|
2654
|
+
pressMotion,
|
|
2655
|
+
reveal,
|
|
2656
|
+
wallpaper
|
|
2657
|
+
]) feature.dispose();
|
|
2658
|
+
modules.dispose();
|
|
2659
|
+
document.body.removeAttribute(FLUENT_MARKER);
|
|
2660
|
+
snapshot = null;
|
|
2661
|
+
}
|
|
2662
|
+
};
|
|
2663
|
+
}
|
|
2664
|
+
// src/panel.tsx
|
|
2665
|
+
var PANEL_CSS = `
|
|
2666
|
+
[data-acrylic-settings] { padding: 24px; max-width: 640px; margin: auto; color: var(--dsw-alias-label-primary); font: inherit; }
|
|
2667
|
+
[data-acrylic-settings] h2 { margin: 0 0 12px; font-size: 18px; }
|
|
2668
|
+
[data-acrylic-settings] p { color: var(--dsw-alias-label-secondary); line-height: 1.6; }
|
|
2669
|
+
[data-acrylic-settings] .acrylic-row { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; margin: 20px 0; }
|
|
2670
|
+
[data-acrylic-settings] .acrylic-row label { min-width: 100px; }
|
|
2671
|
+
[data-acrylic-settings] input[type=range] { flex: 1; min-width: 120px; accent-color: var(--dsw-alias-brand-primary); }
|
|
2672
|
+
[data-acrylic-settings] output { min-width: 48px; font-variant-numeric: tabular-nums; }
|
|
2673
|
+
[data-acrylic-settings] button:not([role=tab]) { border: 1px solid var(--dsw-alias-border-l2); border-radius: var(--dsw-radius-md, 2px); padding: 7px 12px; color: inherit; background: var(--dsw-alias-bg-layer-2); font: inherit; cursor: pointer; }
|
|
2674
|
+
[data-acrylic-settings] button:not([role=tab]):hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
2675
|
+
[data-acrylic-settings] button:not([role=tab]):active:not(:disabled) { background: var(--dsw-alias-interactive-bg-active); }
|
|
2676
|
+
[data-acrylic-settings] button:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 2px; }
|
|
2677
|
+
[data-acrylic-settings] button:disabled { opacity: .5; cursor: default; }
|
|
2678
|
+
[data-acrylic-settings] .acrylic-preview { width: 100%; max-height: 180px; object-fit: cover; border-radius: var(--dsw-radius-lg, 0px); }
|
|
2679
|
+
[data-acrylic-settings] [role=alert] { color: var(--dsw-alias-state-error-primary); }
|
|
2680
|
+
[data-acrylic-settings] .acrylic-filename { overflow-wrap: anywhere; }
|
|
2681
|
+
`;
|
|
2682
|
+
var FIT_HINTS = {
|
|
2683
|
+
cover: "保持比例,裁去多余部分。",
|
|
2684
|
+
contain: "显示整张图片,边缘可能留空。",
|
|
2685
|
+
stretch: "铺满窗口,图片可能变形。",
|
|
2686
|
+
tile: "按原尺寸重复排列。"
|
|
2687
|
+
};
|
|
2688
|
+
var FIT_OPTIONS = [
|
|
2689
|
+
{
|
|
2690
|
+
value: "cover",
|
|
2691
|
+
label: "填满"
|
|
2692
|
+
},
|
|
2693
|
+
{
|
|
2694
|
+
value: "contain",
|
|
2695
|
+
label: "适应"
|
|
2696
|
+
},
|
|
2697
|
+
{
|
|
2698
|
+
value: "stretch",
|
|
2699
|
+
label: "拉伸"
|
|
2700
|
+
},
|
|
2701
|
+
{
|
|
2702
|
+
value: "tile",
|
|
2703
|
+
label: "平铺"
|
|
2704
|
+
}
|
|
2705
|
+
];
|
|
2706
|
+
function createSettingsPanel(controller) {
|
|
2707
|
+
return function AcrylicSettings() {
|
|
2708
|
+
const state = (0, react.useSyncExternalStore)(controller.subscribe, controller.getSnapshot, controller.getSnapshot);
|
|
2709
|
+
const input = (0, react.useRef)(null);
|
|
2710
|
+
const id = (0, react.useId)();
|
|
2711
|
+
const locked = state.loading || state.busy;
|
|
2712
|
+
function toggle(key, title, disabled = locked) {
|
|
2713
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2714
|
+
className: "acrylic-row",
|
|
2715
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2716
|
+
type: "checkbox",
|
|
2717
|
+
checked: state.settings[key],
|
|
2718
|
+
disabled,
|
|
2719
|
+
onChange: (event) => void controller.commit({ [key]: event.target.checked })
|
|
2720
|
+
}), ` ${title}`] })
|
|
2721
|
+
});
|
|
2722
|
+
}
|
|
2723
|
+
function slider(key, title, unit) {
|
|
2724
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2725
|
+
className: "acrylic-row",
|
|
2726
|
+
children: [
|
|
2727
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
2728
|
+
htmlFor: `${id}-${key}`,
|
|
2729
|
+
children: title
|
|
2730
|
+
}),
|
|
2731
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2732
|
+
id: `${id}-${key}`,
|
|
2733
|
+
type: "range",
|
|
2734
|
+
min: 0,
|
|
2735
|
+
max: LIMITS[key],
|
|
2736
|
+
step: 1,
|
|
2737
|
+
value: state.settings[key],
|
|
2738
|
+
disabled: locked,
|
|
2739
|
+
onChange: (event) => controller.preview({ [key]: Number(event.target.value) }),
|
|
2740
|
+
onPointerUp: () => void controller.commitPreview(key),
|
|
2741
|
+
onKeyUp: () => void controller.commitPreview(key),
|
|
2742
|
+
onBlur: () => void controller.commitPreview(key)
|
|
2743
|
+
}),
|
|
2744
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("output", {
|
|
2745
|
+
htmlFor: `${id}-${key}`,
|
|
2746
|
+
children: `${state.settings[key]}${unit}`
|
|
2747
|
+
})
|
|
2748
|
+
]
|
|
2749
|
+
}, key);
|
|
2750
|
+
}
|
|
2751
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2752
|
+
"data-acrylic-settings": "",
|
|
2753
|
+
children: [
|
|
2754
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: "Win10 Fluent 主题" }),
|
|
2755
|
+
toggle("enabled", "启用主题"),
|
|
2756
|
+
toggle("fluent", "Win10 风格"),
|
|
2757
|
+
toggle("reveal", "悬停与按压光效", locked || !state.settings.fluent),
|
|
2758
|
+
state.url ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
2759
|
+
className: "acrylic-preview",
|
|
2760
|
+
src: state.url,
|
|
2761
|
+
alt: "壁纸预览"
|
|
2762
|
+
}) : null,
|
|
2763
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2764
|
+
className: "acrylic-filename",
|
|
2765
|
+
children: state.name || "未选择图片"
|
|
2766
|
+
}),
|
|
2767
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2768
|
+
ref: input,
|
|
2769
|
+
type: "file",
|
|
2770
|
+
accept: "image/png,image/jpeg,image/webp",
|
|
2771
|
+
hidden: true,
|
|
2772
|
+
onChange: (event) => {
|
|
2773
|
+
const file = event.target.files?.[0];
|
|
2774
|
+
event.target.value = "";
|
|
2775
|
+
if (file) controller.upload(file);
|
|
2776
|
+
}
|
|
2777
|
+
}),
|
|
2778
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2779
|
+
className: "acrylic-row",
|
|
2780
|
+
children: [
|
|
2781
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2782
|
+
type: "button",
|
|
2783
|
+
disabled: locked,
|
|
2784
|
+
onClick: () => input.current?.click(),
|
|
2785
|
+
children: state.busy ? "正在处理…" : "选择图片"
|
|
2786
|
+
}),
|
|
2787
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2788
|
+
type: "button",
|
|
2789
|
+
disabled: locked || !state.url,
|
|
2790
|
+
onClick: () => void controller.remove(),
|
|
2791
|
+
children: "移除图片"
|
|
2792
|
+
}),
|
|
2793
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2794
|
+
type: "button",
|
|
2795
|
+
disabled: locked,
|
|
2796
|
+
onClick: () => void controller.reset(),
|
|
2797
|
+
children: "恢复默认"
|
|
2798
|
+
})
|
|
2799
|
+
]
|
|
2800
|
+
}),
|
|
2801
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2802
|
+
className: "acrylic-row",
|
|
2803
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "填充方式" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
|
|
2804
|
+
id: `${id}-fit`,
|
|
2805
|
+
label: "填充方式",
|
|
2806
|
+
value: state.settings.fit,
|
|
2807
|
+
disabled: locked,
|
|
2808
|
+
onChange: (fit) => void controller.commit({ fit }),
|
|
2809
|
+
options: FIT_OPTIONS
|
|
2810
|
+
})]
|
|
2811
|
+
}),
|
|
2812
|
+
Object.entries(FIT_HINTS).map(([fit, text]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2813
|
+
id: `${id}-fit-${fit}-panel`,
|
|
2814
|
+
role: "tabpanel",
|
|
2815
|
+
"aria-labelledby": `${id}-fit-${fit}`,
|
|
2816
|
+
hidden: state.settings.fit !== fit,
|
|
2817
|
+
children: text
|
|
2818
|
+
}, fit)),
|
|
2819
|
+
slider("blur", "模糊", "px"),
|
|
2820
|
+
slider("tint", "遮罩", "%"),
|
|
2821
|
+
slider("noise", "颗粒", "%"),
|
|
2822
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "支持 PNG、JPEG、WebP,最大 20 MiB。图片仅保存在本机。" }),
|
|
2823
|
+
state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2824
|
+
role: "alert",
|
|
2825
|
+
children: `未能保存,请重试。${state.error}`
|
|
2826
|
+
}) : null,
|
|
2827
|
+
state.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2828
|
+
role: "status",
|
|
2829
|
+
children: "正在加载…"
|
|
2830
|
+
}) : null
|
|
2831
|
+
]
|
|
2832
|
+
});
|
|
2833
|
+
};
|
|
2834
|
+
}
|
|
2835
|
+
// src/client.ts
|
|
2836
|
+
var inject = ["slots", "theme"];
|
|
2837
|
+
function apply(ctx) {
|
|
2838
|
+
const controller = createController(window);
|
|
2839
|
+
const appearance = createAppearance(document, window, ctx.theme);
|
|
2840
|
+
const render = () => appearance.update(controller.getSnapshot());
|
|
2841
|
+
const unsubscribe = controller.subscribe(render);
|
|
2842
|
+
render();
|
|
2843
|
+
ctx.effect(() => () => {
|
|
2844
|
+
unsubscribe();
|
|
2845
|
+
appearance.dispose();
|
|
2846
|
+
controller.dispose();
|
|
2847
|
+
}, "acrylic wallpaper lifecycle");
|
|
2848
|
+
ctx.effect(() => {
|
|
2849
|
+
const sheet = createStyleSheet(document, `${PLUGIN_ID}-settings`, PANEL_CSS);
|
|
2850
|
+
sheet.toggle(true);
|
|
2851
|
+
return sheet.dispose;
|
|
2852
|
+
});
|
|
2853
|
+
ctx.effect(() => {
|
|
2854
|
+
const sheet = createStyleSheet(document, `${PLUGIN_ID}-hide-diff-hover`, `
|
|
2855
|
+
body > div:has(> [data-changes-hover-preview]) {
|
|
2856
|
+
display: none !important;
|
|
2857
|
+
}
|
|
2858
|
+
`);
|
|
2859
|
+
sheet.toggle(true);
|
|
2860
|
+
return sheet.dispose;
|
|
2861
|
+
});
|
|
2862
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
2863
|
+
name: "settings.section",
|
|
2864
|
+
id: "acrylic-wallpaper",
|
|
2865
|
+
order: 32,
|
|
2866
|
+
label: "Win10 Fluent 主题"
|
|
2867
|
+
}, createSettingsPanel(controller)));
|
|
2868
|
+
}
|
|
2869
|
+
exports.apply = apply;
|
|
2870
|
+
exports.inject = inject;
|
|
2871
|
+
|
|
2872
|
+
return module.exports;
|
|
2873
|
+
},
|
|
2874
|
+
});
|