@spicetify/kit 0.3.1 → 0.4.0
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/README.md +82 -0
- package/dist/args.js +15 -0
- package/dist/cli.js +4 -1
- package/dist/create.js +9 -5
- package/dist/dev.js +86 -22
- package/dist/install.js +4 -6
- package/dist/launch.js +24 -24
- package/dist/push.js +187 -44
- package/dist/remove.js +37 -0
- package/dist/stdlib-boundary.js +2 -2
- package/dist/version.js +1 -1
- package/package.json +6 -4
- package/vendor/classmaps/1030000/classmap-19f856aefd5.json +109 -0
- package/vendor/stdlib/metadata.json +1 -1
- package/vendor/stdlib/query.ts +31 -0
- package/vendor/stdlib/src/client.ts +89 -1
- package/vendor/stdlib/src/events.mix.ts +9 -0
- package/vendor/stdlib/src/events.ts +1 -1
- package/vendor/stdlib/src/registers/menu-order.ts +17 -0
- package/vendor/stdlib/src/registers/menu.ts +8 -4
- package/vendor/stdlib/src/registers/mount.ts +35 -9
- package/vendor/stdlib/src/registers/root.ts +1 -1
- package/vendor/stdlib/src/storage.ts +1 -1
- package/vendor/stdlib/src/webpack/ReactComponents.xpui.ts +3 -9
- package/vendor/stdlib/src/webpack/URI.xpui.ts +1 -1
- package/vendor/stdlib/src/webpack/capture-readiness.ts +5 -3
- package/vendor/stdlib/src/webpack/index.ts +10 -4
- package/vendor/stdlib/src/webpack/playlist-menu.ts +54 -0
- package/vendor/stdlib/src/wpunpk.mix.ts +1 -1
- package/vendor/classmaps/1020099/classmap-19f856aefd5.json +0 -109
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2026 Afonso Jorge Ramos
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const placeMenuItemsHost = (menu: Element, host: HTMLElement): void => {
|
|
7
|
+
const settingsRow = Array.from(menu.children).find(
|
|
8
|
+
(child) => child.matches('a[href="/preferences"]') || child.querySelector('a[href="/preferences"]'),
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
if (settingsRow) {
|
|
12
|
+
if (settingsRow.nextElementSibling !== host) settingsRow.after(host);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (host.parentElement !== menu) menu.append(host);
|
|
17
|
+
};
|
|
@@ -9,6 +9,7 @@ import { matchLast } from "../util.ts";
|
|
|
9
9
|
|
|
10
10
|
import { warn } from "../logger.ts";
|
|
11
11
|
import { transformer } from "../../mixin.ts";
|
|
12
|
+
import { placeMenuItemsHost } from "./menu-order.ts";
|
|
12
13
|
import { Registry } from "./registry.ts";
|
|
13
14
|
|
|
14
15
|
type __MenuContext = React.Context<MenuContext>;
|
|
@@ -125,14 +126,17 @@ if (
|
|
|
125
126
|
);
|
|
126
127
|
|
|
127
128
|
const ItemBoundary = createItemBoundary(R, "menu");
|
|
128
|
-
const live: Array<{ menu: Element; root: { unmount: () => void } }> = [];
|
|
129
|
+
const live: Array<{ menu: Element; host: HTMLElement; root: { unmount: () => void } }> = [];
|
|
129
130
|
const processed = new WeakSet<Element>();
|
|
130
131
|
|
|
131
|
-
const sweep = () => {
|
|
132
|
+
const sweep = (records: MutationRecord[] = []) => {
|
|
133
|
+
const changedMenus = new Set(records.map((record) => record.target));
|
|
132
134
|
for (let i = live.length - 1; i >= 0; i--) {
|
|
133
135
|
if (!live[i].menu.isConnected) {
|
|
134
136
|
live[i].root.unmount();
|
|
135
137
|
live.splice(i, 1);
|
|
138
|
+
} else if (changedMenus.has(live[i].menu)) {
|
|
139
|
+
placeMenuItemsHost(live[i].menu, live[i].host);
|
|
136
140
|
}
|
|
137
141
|
}
|
|
138
142
|
if (items.size === 0) return;
|
|
@@ -142,7 +146,7 @@ if (
|
|
|
142
146
|
const host = document.createElement("li");
|
|
143
147
|
host.setAttribute("role", "presentation");
|
|
144
148
|
host.className = "spicetify-menu-items";
|
|
145
|
-
menu
|
|
149
|
+
placeMenuItemsHost(menu, host);
|
|
146
150
|
const root = createRoot(host);
|
|
147
151
|
globalThis.__MenuContext ??= R.createContext(null);
|
|
148
152
|
root.render(
|
|
@@ -152,7 +156,7 @@ if (
|
|
|
152
156
|
...items.all().map((item, i) => R.createElement(ItemBoundary, { key: i }, item)),
|
|
153
157
|
),
|
|
154
158
|
);
|
|
155
|
-
live.push({ menu, root });
|
|
159
|
+
live.push({ menu, host, root });
|
|
156
160
|
}
|
|
157
161
|
};
|
|
158
162
|
new MutationObserver(sweep).observe(document.body, { childList: true, subtree: true });
|
|
@@ -143,10 +143,10 @@ const ensureAnchorStyle = () => {
|
|
|
143
143
|
// constantly, and per-anchor subtree observers multiply that cost. Each
|
|
144
144
|
// tick is one isConnected check per pending or placed anchor.
|
|
145
145
|
type WatchedAnchor = { host: HTMLElement; place: () => boolean; started: boolean; start: () => void };
|
|
146
|
-
const watched
|
|
146
|
+
const watched = new Set<WatchedAnchor>();
|
|
147
147
|
let bodyObserver: MutationObserver | undefined;
|
|
148
148
|
const watchAnchor = (anchor: WatchedAnchor) => {
|
|
149
|
-
watched.
|
|
149
|
+
watched.add(anchor);
|
|
150
150
|
bodyObserver ??= (() => {
|
|
151
151
|
const observer = new MutationObserver(() => {
|
|
152
152
|
for (const a of watched) {
|
|
@@ -160,6 +160,13 @@ const watchAnchor = (anchor: WatchedAnchor) => {
|
|
|
160
160
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
161
161
|
return observer;
|
|
162
162
|
})();
|
|
163
|
+
return () => {
|
|
164
|
+
watched.delete(anchor);
|
|
165
|
+
if (watched.size === 0) {
|
|
166
|
+
bodyObserver?.disconnect();
|
|
167
|
+
bodyObserver = undefined;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
163
170
|
};
|
|
164
171
|
|
|
165
172
|
export function mountRegistryAnchor(spec: AnchorSpec): void {
|
|
@@ -192,6 +199,8 @@ export function mountRegistryAnchor(spec: AnchorSpec): void {
|
|
|
192
199
|
const start = () => {
|
|
193
200
|
const root = createRoot(host);
|
|
194
201
|
const ItemBoundary = createItemBoundary(R, spec.className);
|
|
202
|
+
const itemKeys = new Map<unknown, number>();
|
|
203
|
+
let nextItemKey = 0;
|
|
195
204
|
const Wrapper = () => {
|
|
196
205
|
const [, refresh] = R.useReducer((n: number) => n + 1, 0);
|
|
197
206
|
R.useEffect(() => {
|
|
@@ -201,12 +210,20 @@ export function mountRegistryAnchor(spec: AnchorSpec): void {
|
|
|
201
210
|
if (spec.renderItems) {
|
|
202
211
|
return R.createElement(ItemBoundary, null, spec.renderItems(spec.registry.all()));
|
|
203
212
|
}
|
|
213
|
+
for (const item of itemKeys.keys()) {
|
|
214
|
+
if (!spec.registry.has(item)) itemKeys.delete(item);
|
|
215
|
+
}
|
|
204
216
|
return R.createElement(
|
|
205
217
|
R.Fragment,
|
|
206
218
|
null,
|
|
207
|
-
...byOrder(spec.registry.all()).map((item: unknown
|
|
208
|
-
|
|
209
|
-
|
|
219
|
+
...byOrder(spec.registry.all()).map((item: unknown) => {
|
|
220
|
+
let key = itemKeys.get(item);
|
|
221
|
+
if (key === undefined) {
|
|
222
|
+
key = nextItemKey++;
|
|
223
|
+
itemKeys.set(item, key);
|
|
224
|
+
}
|
|
225
|
+
return R.createElement(ItemBoundary, { key }, item);
|
|
226
|
+
}),
|
|
210
227
|
);
|
|
211
228
|
};
|
|
212
229
|
root.render(R.createElement(Wrapper));
|
|
@@ -240,6 +257,8 @@ export interface AdjacentSpec {
|
|
|
240
257
|
|
|
241
258
|
export function mountAdjacent(spec: AdjacentSpec): { remove: () => void } {
|
|
242
259
|
let removed = false;
|
|
260
|
+
let unwatch: (() => void) | undefined;
|
|
261
|
+
let retry: ReturnType<typeof setTimeout> | undefined;
|
|
243
262
|
let root: { render?: (node: unknown) => void; unmount?: () => void } | undefined;
|
|
244
263
|
const host = document.createElement("span");
|
|
245
264
|
host.className = spec.className;
|
|
@@ -247,6 +266,7 @@ export function mountAdjacent(spec: AdjacentSpec): { remove: () => void } {
|
|
|
247
266
|
host.dataset.spicetifyAnchor = "";
|
|
248
267
|
|
|
249
268
|
const place = (): boolean => {
|
|
269
|
+
if (removed) return false;
|
|
250
270
|
const target = spec.findTarget();
|
|
251
271
|
if (!target?.parentElement) return false;
|
|
252
272
|
const before = spec.side === "before" ? target : target.nextSibling;
|
|
@@ -255,9 +275,15 @@ export function mountAdjacent(spec: AdjacentSpec): { remove: () => void } {
|
|
|
255
275
|
};
|
|
256
276
|
|
|
257
277
|
const remove = () => {
|
|
278
|
+
if (removed) return;
|
|
258
279
|
removed = true;
|
|
259
|
-
|
|
260
|
-
|
|
280
|
+
clearTimeout(retry);
|
|
281
|
+
unwatch?.();
|
|
282
|
+
try {
|
|
283
|
+
root?.unmount?.();
|
|
284
|
+
} finally {
|
|
285
|
+
host.remove();
|
|
286
|
+
}
|
|
261
287
|
};
|
|
262
288
|
|
|
263
289
|
// Transform experiments render through injected __renderX() calls, and there
|
|
@@ -291,14 +317,14 @@ export function mountAdjacent(spec: AdjacentSpec): { remove: () => void } {
|
|
|
291
317
|
if (place()) {
|
|
292
318
|
start();
|
|
293
319
|
// Reuse the shared observer for re-placement only (already started).
|
|
294
|
-
watchAnchor({ host, place, started: true, start: () => {} });
|
|
320
|
+
unwatch = watchAnchor({ host, place, started: true, start: () => {} });
|
|
295
321
|
return;
|
|
296
322
|
}
|
|
297
323
|
if (Date.now() > deadline) {
|
|
298
324
|
spec.onGiveUp();
|
|
299
325
|
return;
|
|
300
326
|
}
|
|
301
|
-
setTimeout(attempt, 150);
|
|
327
|
+
retry = setTimeout(attempt, 150);
|
|
302
328
|
};
|
|
303
329
|
attempt();
|
|
304
330
|
});
|
|
@@ -56,7 +56,7 @@ globalThis.__renderRootChildren = () =>
|
|
|
56
56
|
return childrenRegistry.all();
|
|
57
57
|
});
|
|
58
58
|
globalThis.__renderRootProviders = (providers: React.ReactElement[]) => {
|
|
59
|
-
const MultiProvider = ({ children }) => {
|
|
59
|
+
const MultiProvider = ({ children }: React.PropsWithChildren) => {
|
|
60
60
|
const [, refresh] = React.useReducer((n) => n + 1, 0);
|
|
61
61
|
if (!providersRegistry.refresh.value) {
|
|
62
62
|
providersRegistry.refresh.resolve(refresh);
|
|
@@ -55,7 +55,7 @@ export function createSyncedStorage(playlistUri: string) {
|
|
|
55
55
|
async function getUris(key: string) {
|
|
56
56
|
assertSmallerSize(encodeURIComponent(key), CHUNK_SIZE, 1, "Can't fit key in a single chunk");
|
|
57
57
|
|
|
58
|
-
const { items } = await PlaylistAPI.getContents(playlistUri, {
|
|
58
|
+
const { items }: { items: Array<{ uri: string }> } = await PlaylistAPI.getContents(playlistUri, {
|
|
59
59
|
filter: key,
|
|
60
60
|
limit: 1e9,
|
|
61
61
|
});
|
|
@@ -11,6 +11,7 @@ import { Platform } from "../expose/Platform.ts";
|
|
|
11
11
|
import { exportedFunctions, exportedMemos, modules, src } from "./index.ts";
|
|
12
12
|
import { webpackRequire } from "../wpunpk.mix.ts";
|
|
13
13
|
import { React } from "../expose/React.ts";
|
|
14
|
+
import { findPlaylistMenu } from "./playlist-menu.ts";
|
|
14
15
|
|
|
15
16
|
type SnackbarProviderT = any;
|
|
16
17
|
|
|
@@ -43,16 +44,9 @@ const requireExports = (id: ReturnType<typeof findModuleId>): Record<string, any
|
|
|
43
44
|
id === undefined ? {} : (webpackRequire(id) as Record<string, any>);
|
|
44
45
|
|
|
45
46
|
const ContextMenuModuleID = findModuleId("toggleContextMenu", (s) => s.includes("toggleContextMenu"));
|
|
46
|
-
// Dead since 1.2.9x: no module carries value:"playlist" + canView +
|
|
47
|
-
// permissions anymore; Menus.Playlist stays undefined until re-needled.
|
|
48
|
-
const playlistMenuModuleID = findModuleId(
|
|
49
|
-
'value:"playlist" + canView + permissions',
|
|
50
|
-
(s) => s.includes('value:"playlist"') && s.includes("canView") && s.includes("permissions"),
|
|
51
|
-
);
|
|
52
47
|
|
|
53
|
-
Menus.Playlist =
|
|
54
|
-
|
|
55
|
-
);
|
|
48
|
+
Menus.Playlist = findPlaylistMenu(modules, requireExports);
|
|
49
|
+
if (Menus.Playlist === undefined) warn("[stdlib] webpack needle miss: playlist menu component");
|
|
56
50
|
|
|
57
51
|
export const Cards: any = Object.assign(
|
|
58
52
|
{
|
|
@@ -105,7 +105,7 @@ export const from: (uri: ParsableAsURI) => URIClass<any> = findAndExcludeBy("all
|
|
|
105
105
|
export const fromString: (str: string) => URIClass<any> = findAndExcludeBy("Argument `uri` must be a string.") as any;
|
|
106
106
|
|
|
107
107
|
is.PlaylistV1OrV2 = (
|
|
108
|
-
is.Playlist && is.PlaylistV2
|
|
108
|
+
typeof is.Playlist === "function" && typeof is.PlaylistV2 === "function"
|
|
109
109
|
? findAndExcludeBy(`${(is.Playlist as Function).name}(e)||${(is.PlaylistV2 as Function).name}(e)`)
|
|
110
110
|
: undefined
|
|
111
111
|
) as any;
|
|
@@ -3,18 +3,20 @@
|
|
|
3
3
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
type TimeoutHandle = ReturnType<typeof setTimeout> | number;
|
|
7
|
+
|
|
6
8
|
export interface CaptureReadinessOptions {
|
|
7
9
|
timeoutMs: number;
|
|
8
10
|
onTimeout?: () => void;
|
|
9
|
-
scheduleTimeout?:
|
|
10
|
-
clearScheduledTimeout?:
|
|
11
|
+
scheduleTimeout?: (callback: () => void, delay: number) => TimeoutHandle;
|
|
12
|
+
clearScheduledTimeout?: (timer: TimeoutHandle) => void;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export function createCaptureReadiness(options: CaptureReadinessOptions) {
|
|
14
16
|
const settled = Promise.withResolvers<void>();
|
|
15
17
|
let released = false;
|
|
16
18
|
let analyzed = false;
|
|
17
|
-
let timer:
|
|
19
|
+
let timer: TimeoutHandle | undefined;
|
|
18
20
|
const scheduleTimeout = options.scheduleTimeout ?? setTimeout;
|
|
19
21
|
const clearScheduledTimeout = options.clearScheduledTimeout ?? clearTimeout;
|
|
20
22
|
const release = () => {
|
|
@@ -64,6 +64,12 @@ export const analyzeWebpackRequire = (webpackRequire: WebpackRequire) => {
|
|
|
64
64
|
};
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
+
function resolveChunk(path: string): void {
|
|
68
|
+
const chunk = (CHUNKS[path] ??= Promise.withResolvers());
|
|
69
|
+
if (!chunk.resolve) throw new TypeError(`Chunk ${path} has no resolver`);
|
|
70
|
+
chunk.resolve(undefined);
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
CHUNKS["/vendor~xpui.js"] ??= Promise.withResolvers();
|
|
68
74
|
CHUNKS["/xpui.js"] ??= Promise.withResolvers();
|
|
69
75
|
Object.assign(CHUNKS, {
|
|
@@ -84,7 +90,7 @@ postWebpackRequireHooks.push((wpr: any) => {
|
|
|
84
90
|
load(
|
|
85
91
|
url,
|
|
86
92
|
(event: unknown) => {
|
|
87
|
-
(
|
|
93
|
+
resolveChunk(new URL(url, location.href).pathname);
|
|
88
94
|
return done(event);
|
|
89
95
|
},
|
|
90
96
|
key,
|
|
@@ -98,7 +104,7 @@ postWebpackRequireHooks.push((wpr: any) => {
|
|
|
98
104
|
const url = new URL(entry.name, location.href);
|
|
99
105
|
if (url.pathname === "/vendor~xpui.js" || url.pathname === "/xpui.js") continue;
|
|
100
106
|
if (url.origin === location.origin && url.pathname.endsWith(".js")) {
|
|
101
|
-
(
|
|
107
|
+
resolveChunk(url.pathname);
|
|
102
108
|
}
|
|
103
109
|
}
|
|
104
110
|
// Capture can fire while boot is still registering modules (xpui-modules
|
|
@@ -115,8 +121,8 @@ postWebpackRequireHooks.push((wpr: any) => {
|
|
|
115
121
|
last = count;
|
|
116
122
|
if (stable >= 3 || ++ticks > 100) {
|
|
117
123
|
clearInterval(settle);
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
resolveChunk("/vendor~xpui.js");
|
|
125
|
+
resolveChunk("/xpui.js");
|
|
120
126
|
}
|
|
121
127
|
}, 100);
|
|
122
128
|
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2026 Spicetify
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
function source(value: unknown): string {
|
|
7
|
+
return typeof value === "function" ? Function.prototype.toString.call(value) : "";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function hasPlaylistMenuActions(text: string): boolean {
|
|
11
|
+
return (
|
|
12
|
+
text.includes("contextmenu.share.copy-playlist-link") &&
|
|
13
|
+
text.includes("canView") &&
|
|
14
|
+
text.includes("permissions")
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function isPlaylistMenuFactory(value: unknown): boolean {
|
|
19
|
+
return hasPlaylistMenuActions(source(value));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isMenuComponent(value: unknown): boolean {
|
|
23
|
+
let render = value;
|
|
24
|
+
if (typeof render === "object" && render !== null && "$$typeof" in render) {
|
|
25
|
+
if (render.$$typeof === Symbol.for("react.memo") && "type" in render) render = render.type;
|
|
26
|
+
else if (render.$$typeof === Symbol.for("react.forward_ref") && "render" in render) render = render.render;
|
|
27
|
+
}
|
|
28
|
+
const text = source(render);
|
|
29
|
+
if (/^async\b/.test(text)) return false;
|
|
30
|
+
if (hasPlaylistMenuActions(text)) return /\b(?:jsx|jsxs|createElement)\s*\)?\s*\(/.test(text);
|
|
31
|
+
// Current clients export a thin JSX wrapper around the unexported memo.
|
|
32
|
+
// Match the whole wrapper, not JSX nested inside a page root.
|
|
33
|
+
return /^\(?([$\w]+)\)?=>\(0,[$\w]+\.jsx\)\([$\w]+,\{\.\.\.\1\}\)$/.test(text.replace(/\s/g, ""));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Match the menu factory, then its renderable export; never a playlist data mapper. */
|
|
37
|
+
export function findPlaylistMenu(
|
|
38
|
+
modules: Iterable<readonly [PropertyKey, unknown]>,
|
|
39
|
+
requireModule: (id: PropertyKey) => unknown,
|
|
40
|
+
): unknown {
|
|
41
|
+
const components = new Set<unknown>();
|
|
42
|
+
try {
|
|
43
|
+
for (const [id, factory] of modules) {
|
|
44
|
+
if (!isPlaylistMenuFactory(factory)) continue;
|
|
45
|
+
const exports = requireModule(id);
|
|
46
|
+
if (typeof exports !== "object" || exports === null) continue;
|
|
47
|
+
for (const value of Object.values(exports)) if (isMenuComponent(value)) components.add(value);
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
// An unreadable client export leaves uniqueness unproven; degrade only this menu.
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
return components.size === 1 ? components.values().next().value : undefined;
|
|
54
|
+
}
|
|
@@ -42,7 +42,7 @@ export { Subject, BehaviorSubject };
|
|
|
42
42
|
|
|
43
43
|
export const chunkLoadedSubjectPre = new Subject<unknown>();
|
|
44
44
|
export const chunkLoadedSubjectPost = new Subject<unknown>();
|
|
45
|
-
export const moduleLoadedSubject = new Subject<
|
|
45
|
+
export const moduleLoadedSubject = new Subject<[string, WebpackModule]>();
|
|
46
46
|
|
|
47
47
|
const pendingHooks: Array<(wpr: any) => void> = [];
|
|
48
48
|
export const postWebpackRequireHooks = {
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"main": {
|
|
3
|
-
"topbar": {
|
|
4
|
-
"wrapper": "oy96nRTKcIs7wm5K",
|
|
5
|
-
"left": {
|
|
6
|
-
"button": {
|
|
7
|
-
"wrapper": "e-10810-legacy-button e-10810-button-tertiary--icon-only-medium",
|
|
8
|
-
"icon": {
|
|
9
|
-
"wrapper": "e-10810-icon e-10810-icon--auto-mirror"
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
"button_t": {
|
|
13
|
-
"wrapper": "e-10810-legacy-button e-10810-button-tertiary--icon-only-medium"
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"right": {
|
|
17
|
-
"button": {
|
|
18
|
-
"wrapper": "e-10810-legacy-button e-10810-button-tertiary--condensed-all"
|
|
19
|
-
},
|
|
20
|
-
"button_t": {
|
|
21
|
-
"wrapper": "e-10810-legacy-button e-10810-button-tertiary--condensed-all"
|
|
22
|
-
},
|
|
23
|
-
"upgrade_button": {
|
|
24
|
-
"wrapper": "e-10810-legacy-button e-10810-legacy-button-primary"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"playbar": {
|
|
29
|
-
"widget": {},
|
|
30
|
-
"controls": {},
|
|
31
|
-
"buttons": {
|
|
32
|
-
"button": {
|
|
33
|
-
"wrapper": "e-10810-legacy-button e-10810-button-tertiary--icon-only-small",
|
|
34
|
-
"wrapper__active": "e-10810-legacy-button e-10810-legacy-button-primary",
|
|
35
|
-
"wrapper__indicator": "e-10810-button-primary__inner"
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
"navbar": {
|
|
40
|
-
"link": {
|
|
41
|
-
"wrapper": "main-globalNav-navLink",
|
|
42
|
-
"container": "main-globalNav-navLink",
|
|
43
|
-
"container__active": "main-globalNav-navLinkActive"
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
"global_navbar": {},
|
|
47
|
-
"sidebar": {},
|
|
48
|
-
"panel": {}
|
|
49
|
-
},
|
|
50
|
-
"tracklist": {
|
|
51
|
-
"column_header": "e-10810-legacy-list-row__header"
|
|
52
|
-
},
|
|
53
|
-
"search_chips": {
|
|
54
|
-
"wrapper_wrapper": "e-10810-chip-group",
|
|
55
|
-
"wrapper": "e-10810-chip-group__component",
|
|
56
|
-
"container": "e-10810-chip-group__component",
|
|
57
|
-
"chip": "e-10810-legacy-chip"
|
|
58
|
-
},
|
|
59
|
-
"modal": {
|
|
60
|
-
"widget_generator": {
|
|
61
|
-
"container": "main-embedWidgetGenerator-container",
|
|
62
|
-
"header": {
|
|
63
|
-
"container": "main-embedWidgetGenerator-header",
|
|
64
|
-
"close": "main-embedWidgetGenerator-closeBtn"
|
|
65
|
-
},
|
|
66
|
-
"content": {
|
|
67
|
-
"container": "main-embedWidgetGenerator-content"
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
"track_credits": {
|
|
71
|
-
"container": "main-trackCreditsModalV2-container",
|
|
72
|
-
"header": {
|
|
73
|
-
"container": "main-trackCreditsModalV2-header",
|
|
74
|
-
"close": "main-trackCreditsModalV2-closeBtn"
|
|
75
|
-
},
|
|
76
|
-
"content": {
|
|
77
|
-
"container": "main-trackCreditsModalV2-mainSection"
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
"settings": {
|
|
82
|
-
"header": {
|
|
83
|
-
"container": "fEEfljGMIEhhmWVi"
|
|
84
|
-
},
|
|
85
|
-
"section": {
|
|
86
|
-
"container": "nWR7PbHjFXQJiYNL"
|
|
87
|
-
},
|
|
88
|
-
"button": {
|
|
89
|
-
"wrapper": "e-10810-legacy-button e-10810-legacy-button--small e-10810-legacy-button-secondary"
|
|
90
|
-
},
|
|
91
|
-
"text_input": "e-10810-form-input e-10810-form-control encore-text-body-medium"
|
|
92
|
-
},
|
|
93
|
-
"scrollable_text": {
|
|
94
|
-
"container": "e-10810-legacy-box e-10810-legacy-box--naked",
|
|
95
|
-
"wrapper": "e-10810-legacy-box"
|
|
96
|
-
},
|
|
97
|
-
"sort_box": {
|
|
98
|
-
"list": {
|
|
99
|
-
"button": "x-sortBox-sortDropdown"
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
"search_box": {
|
|
103
|
-
"container": "main-globalNav-searchContainer",
|
|
104
|
-
"expand_button": "e-10810-legacy-button e-10810-button-tertiary--icon-only-medium main-globalNav-link-icon"
|
|
105
|
-
},
|
|
106
|
-
"context_menu": {
|
|
107
|
-
"menu_item": "main-contextMenu-menuItemButton"
|
|
108
|
-
}
|
|
109
|
-
}
|