@spicetify/kit 0.1.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/bin/spicetify-kit.js +4 -0
- package/dist/build.js +335 -0
- package/dist/check.js +284 -0
- package/dist/classmap.js +187 -0
- package/dist/cli.js +53 -0
- package/dist/create.js +429 -0
- package/dist/dev.js +100 -0
- package/dist/from-theme.js +96 -0
- package/dist/install.js +60 -0
- package/dist/launch.js +122 -0
- package/dist/pack.js +31 -0
- package/dist/push.js +211 -0
- package/dist/vault.js +108 -0
- package/package.json +49 -0
- package/vendor/classmaps/1020096/classmap-19f856aefd5.json +109 -0
- package/vendor/shims/chunks.d.ts +10 -0
- package/vendor/shims/remote-modules.d.ts +6 -0
- package/vendor/shims/spicetify.d.ts +2437 -0
- package/vendor/stdlib/deps.ts +24 -0
- package/vendor/stdlib/index.ts +24 -0
- package/vendor/stdlib/lib/modal.tsx +128 -0
- package/vendor/stdlib/lib/popover.ts +84 -0
- package/vendor/stdlib/lib/primitives-classes.ts +66 -0
- package/vendor/stdlib/lib/primitives-vanilla.ts +277 -0
- package/vendor/stdlib/lib/primitives.tsx +314 -0
- package/vendor/stdlib/load.ts +17 -0
- package/vendor/stdlib/metadata.json +18 -0
- package/vendor/stdlib/mixin.ts +32 -0
- package/vendor/stdlib/mod.ts +26 -0
- package/vendor/stdlib/src/chunks.d.ts +10 -0
- package/vendor/stdlib/src/client.ts +114 -0
- package/vendor/stdlib/src/createIconComponent.tsx +29 -0
- package/vendor/stdlib/src/events.mix.ts +55 -0
- package/vendor/stdlib/src/events.ts +58 -0
- package/vendor/stdlib/src/expose/GraphQL.ts +40 -0
- package/vendor/stdlib/src/expose/Platform.ts +48 -0
- package/vendor/stdlib/src/expose/React.ts +95 -0
- package/vendor/stdlib/src/expose/ReactFlipToolkitSpring.ts +27 -0
- package/vendor/stdlib/src/expose/ReduxStore.ts +39 -0
- package/vendor/stdlib/src/expose/SettingsSection.ts +60 -0
- package/vendor/stdlib/src/expose/Snackbar.ts +34 -0
- package/vendor/stdlib/src/expose/Tippy.ts +26 -0
- package/vendor/stdlib/src/expose/enqueueImageSnackbar.ts +25 -0
- package/vendor/stdlib/src/expose/index.ts +14 -0
- package/vendor/stdlib/src/expose/jsx-runtime.ts +46 -0
- package/vendor/stdlib/src/expose/react-dom-shim.ts +50 -0
- package/vendor/stdlib/src/expose/react-shim.ts +116 -0
- package/vendor/stdlib/src/logger.ts +35 -0
- package/vendor/stdlib/src/playbar-compat.tsx +136 -0
- package/vendor/stdlib/src/registers/index.ts +176 -0
- package/vendor/stdlib/src/registers/menu.ts +160 -0
- package/vendor/stdlib/src/registers/mount.ts +307 -0
- package/vendor/stdlib/src/registers/nativeAnchors.ts +49 -0
- package/vendor/stdlib/src/registers/navlink.tsx +165 -0
- package/vendor/stdlib/src/registers/order.ts +22 -0
- package/vendor/stdlib/src/registers/panel.ts +168 -0
- package/vendor/stdlib/src/registers/playbarButton.tsx +93 -0
- package/vendor/stdlib/src/registers/playbarWidget.tsx +71 -0
- package/vendor/stdlib/src/registers/registry.ts +12 -0
- package/vendor/stdlib/src/registers/root.ts +101 -0
- package/vendor/stdlib/src/registers/route.ts +123 -0
- package/vendor/stdlib/src/registers/settingsRow.tsx +56 -0
- package/vendor/stdlib/src/registers/settingsSection.ts +59 -0
- package/vendor/stdlib/src/registers/topbarLeftButton.tsx +86 -0
- package/vendor/stdlib/src/registers/topbarRightButton.tsx +87 -0
- package/vendor/stdlib/src/storage.ts +163 -0
- package/vendor/stdlib/src/util.ts +62 -0
- package/vendor/stdlib/src/utils/index.ts +16 -0
- package/vendor/stdlib/src/webpack/ClassNames.gen.ts +10 -0
- package/vendor/stdlib/src/webpack/ClassNames.ts +6 -0
- package/vendor/stdlib/src/webpack/ClassNames.xpui.ts +16 -0
- package/vendor/stdlib/src/webpack/ComponentLibrary.gen.ts +10 -0
- package/vendor/stdlib/src/webpack/ComponentLibrary.ts +6 -0
- package/vendor/stdlib/src/webpack/ComponentLibrary.xpui.ts +18 -0
- package/vendor/stdlib/src/webpack/FilterContext.gen.ts +10 -0
- package/vendor/stdlib/src/webpack/FilterContext.ts +6 -0
- package/vendor/stdlib/src/webpack/FilterContext.xpui.ts +10 -0
- package/vendor/stdlib/src/webpack/Mousetrap.gen.ts +10 -0
- package/vendor/stdlib/src/webpack/Mousetrap.ts +6 -0
- package/vendor/stdlib/src/webpack/Mousetrap.xpui.ts +12 -0
- package/vendor/stdlib/src/webpack/React.gen.ts +14 -0
- package/vendor/stdlib/src/webpack/React.ts +6 -0
- package/vendor/stdlib/src/webpack/React.xpui.ts +15 -0
- package/vendor/stdlib/src/webpack/ReactComponents.desktop.ts +17 -0
- package/vendor/stdlib/src/webpack/ReactComponents.gen.ts +74 -0
- package/vendor/stdlib/src/webpack/ReactComponents.panel.ts +19 -0
- package/vendor/stdlib/src/webpack/ReactComponents.ts +50 -0
- package/vendor/stdlib/src/webpack/ReactComponents.xpui.ts +164 -0
- package/vendor/stdlib/src/webpack/ReactFlipToolkit.gen.ts +12 -0
- package/vendor/stdlib/src/webpack/ReactFlipToolkit.ts +6 -0
- package/vendor/stdlib/src/webpack/ReactFlipToolkit.xpui.ts +14 -0
- package/vendor/stdlib/src/webpack/ReactHooks.fullscreen.ts +15 -0
- package/vendor/stdlib/src/webpack/ReactHooks.gen.ts +32 -0
- package/vendor/stdlib/src/webpack/ReactHooks.ts +6 -0
- package/vendor/stdlib/src/webpack/ReactHooks.xpui.ts +38 -0
- package/vendor/stdlib/src/webpack/ReactQuery.gen.ts +26 -0
- package/vendor/stdlib/src/webpack/ReactQuery.ts +6 -0
- package/vendor/stdlib/src/webpack/ReactQuery.xpui.ts +46 -0
- package/vendor/stdlib/src/webpack/ReactRouter.gen.ts +12 -0
- package/vendor/stdlib/src/webpack/ReactRouter.ts +6 -0
- package/vendor/stdlib/src/webpack/ReactRouter.xpui.ts +22 -0
- package/vendor/stdlib/src/webpack/Snackbar.gen.ts +12 -0
- package/vendor/stdlib/src/webpack/Snackbar.ts +6 -0
- package/vendor/stdlib/src/webpack/Snackbar.xpui.ts +27 -0
- package/vendor/stdlib/src/webpack/URI.gen.ts +26 -0
- package/vendor/stdlib/src/webpack/URI.ts +82 -0
- package/vendor/stdlib/src/webpack/URI.xpui.ts +111 -0
- package/vendor/stdlib/src/webpack/capture-readiness.ts +49 -0
- package/vendor/stdlib/src/webpack/index.ts +186 -0
- package/vendor/stdlib/src/webpack/misc.gen.ts +16 -0
- package/vendor/stdlib/src/webpack/misc.ts +6 -0
- package/vendor/stdlib/src/webpack/misc.xpui.ts +27 -0
- package/vendor/stdlib/src/wpunpk.mix.ts +104 -0
- package/vendor/stdlib/src/wpunpk.ts +36 -0
- package/vendor/stdlib/vendor/rxjs.d.ts +5 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { React } from "../expose/React.ts";
|
|
7
|
+
import { createIconComponent } from "../createIconComponent.tsx";
|
|
8
|
+
import { transformer } from "../../mixin.ts";
|
|
9
|
+
import { Tooltip } from "../webpack/ReactComponents.ts";
|
|
10
|
+
import { UI } from "../webpack/ComponentLibrary.ts";
|
|
11
|
+
import { mountRegistryAnchor } from "./mount.ts";
|
|
12
|
+
import { Registry } from "./registry.ts";
|
|
13
|
+
|
|
14
|
+
const registry = new (class extends Registry<React.ReactNode> {
|
|
15
|
+
override add(value: React.ReactNode): this {
|
|
16
|
+
refresh?.();
|
|
17
|
+
return super.add(value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override delete(value: React.ReactNode): boolean {
|
|
21
|
+
refresh?.();
|
|
22
|
+
return super.delete(value);
|
|
23
|
+
}
|
|
24
|
+
})();
|
|
25
|
+
export default registry;
|
|
26
|
+
|
|
27
|
+
let refresh: React.DispatchWithoutAction | undefined;
|
|
28
|
+
|
|
29
|
+
declare global {
|
|
30
|
+
var __renderTopbarLeftButtons: () => React.ReactNode;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
globalThis.__renderTopbarLeftButtons = () =>
|
|
34
|
+
React.createElement(() => {
|
|
35
|
+
[, refresh] = React.useReducer((n) => n + 1, 0);
|
|
36
|
+
|
|
37
|
+
return <>{registry.all()}</>;
|
|
38
|
+
});
|
|
39
|
+
transformer(
|
|
40
|
+
(emit) => (str) => {
|
|
41
|
+
emit();
|
|
42
|
+
|
|
43
|
+
str = str.replace(/("top-bar-forward-button"[^\]]*)/g, "$1,__renderTopbarLeftButtons()");
|
|
44
|
+
|
|
45
|
+
return str;
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
glob: /^\/xpui\.js/,
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
mountRegistryAnchor({
|
|
53
|
+
className: "spicetify-topbar-left-buttons",
|
|
54
|
+
registry,
|
|
55
|
+
setRefresh: (cb) => {
|
|
56
|
+
refresh = cb;
|
|
57
|
+
},
|
|
58
|
+
findSlot: () => {
|
|
59
|
+
const history = document.querySelector(".main-globalNav-historyButtons");
|
|
60
|
+
return history?.parentElement ? { parent: history.parentElement, before: history.nextSibling } : null;
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
type TopbarLeftButtonProps = {
|
|
65
|
+
label: string;
|
|
66
|
+
disabled?: boolean;
|
|
67
|
+
onClick: () => void;
|
|
68
|
+
icon?: string;
|
|
69
|
+
/** Position within the module-button group; lower renders earlier. Read by the mount sorter. */
|
|
70
|
+
order?: number;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type TopbarLeftButtonFactory = React.FC<TopbarLeftButtonProps>;
|
|
74
|
+
export const TopbarLeftButton: TopbarLeftButtonFactory = (props) => (
|
|
75
|
+
<Tooltip label={props.label}>
|
|
76
|
+
<UI.ButtonTertiary
|
|
77
|
+
size="medium"
|
|
78
|
+
iconOnly={() => props.icon && createIconComponent({ icon: props.icon, iconSize: 16, realIconSize: 24 })}
|
|
79
|
+
condensed
|
|
80
|
+
aria-label={props.label}
|
|
81
|
+
disabled={props.disabled}
|
|
82
|
+
onClick={props.onClick}
|
|
83
|
+
className={MAP.main.topbar.left.button_t.wrapper}
|
|
84
|
+
/>
|
|
85
|
+
</Tooltip>
|
|
86
|
+
);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { React } from "../expose/React.ts";
|
|
7
|
+
import { createIconComponent } from "../createIconComponent.tsx";
|
|
8
|
+
import { transformer } from "../../mixin.ts";
|
|
9
|
+
import { Tooltip } from "../webpack/ReactComponents.ts";
|
|
10
|
+
import { UI } from "../webpack/ComponentLibrary.ts";
|
|
11
|
+
import { mountRegistryAnchor } from "./mount.ts";
|
|
12
|
+
import { Registry } from "./registry.ts";
|
|
13
|
+
|
|
14
|
+
const registry = new (class extends Registry<React.ReactNode> {
|
|
15
|
+
override add(value: React.ReactNode): this {
|
|
16
|
+
refresh?.();
|
|
17
|
+
return super.add(value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override delete(value: React.ReactNode): boolean {
|
|
21
|
+
refresh?.();
|
|
22
|
+
return super.delete(value);
|
|
23
|
+
}
|
|
24
|
+
})();
|
|
25
|
+
export default registry;
|
|
26
|
+
|
|
27
|
+
let refresh: React.DispatchWithoutAction | undefined;
|
|
28
|
+
|
|
29
|
+
declare global {
|
|
30
|
+
var __renderTopbarRightButtons: () => React.ReactNode;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
globalThis.__renderTopbarRightButtons = () =>
|
|
34
|
+
React.createElement(() => {
|
|
35
|
+
[, refresh] = React.useReducer((n) => n + 1, 0);
|
|
36
|
+
|
|
37
|
+
return <>{registry.all().reverse()}</>;
|
|
38
|
+
});
|
|
39
|
+
transformer(
|
|
40
|
+
(emit) => (str) => {
|
|
41
|
+
emit();
|
|
42
|
+
|
|
43
|
+
str = str.replace(/("login-button"[^\}]*\}[^\}]*\}[^\}]*\}\))/, "$1,__renderTopbarRightButtons()");
|
|
44
|
+
|
|
45
|
+
return str;
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
glob: /^\/xpui\.js/,
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
mountRegistryAnchor({
|
|
53
|
+
className: "spicetify-topbar-right-buttons",
|
|
54
|
+
registry,
|
|
55
|
+
setRefresh: (cb) => {
|
|
56
|
+
refresh = cb;
|
|
57
|
+
},
|
|
58
|
+
findSlot: () => {
|
|
59
|
+
const actions = document.querySelector(".main-actionButtons");
|
|
60
|
+
return actions ? { parent: actions, before: actions.firstChild } : null;
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
type TopbarRightButtonProps = {
|
|
65
|
+
label: string;
|
|
66
|
+
disabled?: boolean;
|
|
67
|
+
onClick: () => void;
|
|
68
|
+
icon?: string;
|
|
69
|
+
/** Position within the module-button group; lower renders earlier. Read by the mount sorter. */
|
|
70
|
+
order?: number;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type TopbarRightButtonFactory = React.FC<TopbarRightButtonProps>;
|
|
74
|
+
|
|
75
|
+
export const TopbarRightButton: TopbarRightButtonFactory = (props) => (
|
|
76
|
+
<Tooltip label={props.label}>
|
|
77
|
+
<UI.ButtonTertiary
|
|
78
|
+
aria-label={props.label}
|
|
79
|
+
onClick={props.onClick}
|
|
80
|
+
size="small"
|
|
81
|
+
condensedAll
|
|
82
|
+
className={MAP.main.topbar.right.button_t.wrapper}
|
|
83
|
+
>
|
|
84
|
+
{props.icon && createIconComponent({ icon: props.icon, iconSize: 16 })}
|
|
85
|
+
</UI.ButtonTertiary>
|
|
86
|
+
</Tooltip>
|
|
87
|
+
);
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ModuleRuntimeContext } from "../mod.ts";
|
|
7
|
+
|
|
8
|
+
import { Platform } from "./expose/Platform.ts";
|
|
9
|
+
import { fromString } from "./webpack/URI.ts";
|
|
10
|
+
|
|
11
|
+
export const createStorage = (ctx: ModuleRuntimeContext) => {
|
|
12
|
+
const hookedNativeStorageMethods = new Set(["getItem", "setItem", "removeItem"]);
|
|
13
|
+
|
|
14
|
+
return new Proxy(globalThis.localStorage, {
|
|
15
|
+
get(target, p, receiver) {
|
|
16
|
+
const func: unknown = Reflect.get(target, p, receiver);
|
|
17
|
+
|
|
18
|
+
if (typeof p === "string" && hookedNativeStorageMethods.has(p) && typeof func === "function") {
|
|
19
|
+
return (key: string, ...data: any[]) => func.call(target, `module:${ctx.identifier}:${key}`, ...data);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return func;
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function createSyncedStorage(playlistUri: string) {
|
|
28
|
+
const CHUNK_SIZE = 200;
|
|
29
|
+
const MAX_DOUBLE_CHUNKS = 1000;
|
|
30
|
+
|
|
31
|
+
const PlaylistAPI = Platform.getPlaylistAPI();
|
|
32
|
+
|
|
33
|
+
function markKey(key: string) {
|
|
34
|
+
return `\x02${key}\x03`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function assertSmallerSize(encodedKey: string, chunk_size: number, chunk_count: number, message: string) {
|
|
38
|
+
for (let n = 0, o = 0, l = 0; ; l++) {
|
|
39
|
+
if (chunk_size * n + l + o >= encodedKey.length) {
|
|
40
|
+
return encodedKey;
|
|
41
|
+
}
|
|
42
|
+
if (n >= chunk_count) {
|
|
43
|
+
throw new Error(message);
|
|
44
|
+
}
|
|
45
|
+
if (encodedKey[chunk_size * n + l + o] === "%") {
|
|
46
|
+
o += 2;
|
|
47
|
+
}
|
|
48
|
+
if (l === chunk_size - 1) {
|
|
49
|
+
l = -1;
|
|
50
|
+
n++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function getUris(key: string) {
|
|
56
|
+
assertSmallerSize(encodeURIComponent(key), CHUNK_SIZE, 1, "Can't fit key in a single chunk");
|
|
57
|
+
|
|
58
|
+
const { items } = await PlaylistAPI.getContents(playlistUri, {
|
|
59
|
+
filter: key,
|
|
60
|
+
limit: 1e9,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return items
|
|
64
|
+
.map((item) => fromString(item.uri))
|
|
65
|
+
.filter((uri) => uri.type === "local")
|
|
66
|
+
.filter((uri) => uri.track === key);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function getKey(key: string) {
|
|
70
|
+
const uris = await getUris(key);
|
|
71
|
+
if (uris.length === 0) return null;
|
|
72
|
+
return uris
|
|
73
|
+
.sort((a, b) => a.duration - b.duration)
|
|
74
|
+
.map((uri) => uri.artist + uri.album)
|
|
75
|
+
.join("");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function removeKey(key: string) {
|
|
79
|
+
const uris = await getUris(key);
|
|
80
|
+
if (uris.length > 0) {
|
|
81
|
+
await PlaylistAPI.remove(
|
|
82
|
+
playlistUri,
|
|
83
|
+
uris.map((u) => ({ uri: u.toURI(), uid: "" })),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function addKey(key: string, encodedValue: string) {
|
|
88
|
+
assertSmallerSize(encodeURIComponent(key), CHUNK_SIZE, 1, "Can't fit key in a single chunk");
|
|
89
|
+
assertSmallerSize(
|
|
90
|
+
encodedValue,
|
|
91
|
+
CHUNK_SIZE,
|
|
92
|
+
MAX_DOUBLE_CHUNKS,
|
|
93
|
+
`Can't fit value in ${MAX_DOUBLE_CHUNKS} double chunks`,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const uris = Array.from(collectTuples(generateStringChunks(encodedValue, CHUNK_SIZE), 2, "")).map(
|
|
97
|
+
([a, b], i) => `spotify:local:${a}:${b}:${key}:${i + 1}`,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
await PlaylistAPI.add(playlistUri, uris, { after: "end" });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
async getItem(key: string) {
|
|
105
|
+
const encodedData = await getKey(markKey(key));
|
|
106
|
+
// decodeURIComponent(null) is the string "null", so a missing key
|
|
107
|
+
// would read back as truthy text instead of absent.
|
|
108
|
+
return encodedData === null ? null : decodeURIComponent(encodedData);
|
|
109
|
+
},
|
|
110
|
+
async removeItem(key: string) {
|
|
111
|
+
try {
|
|
112
|
+
await removeKey(markKey(key));
|
|
113
|
+
} catch (_) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
},
|
|
118
|
+
async setItem(key: string, value: string) {
|
|
119
|
+
const encodedValue = encodeURIComponent(value);
|
|
120
|
+
await removeKey(markKey(key));
|
|
121
|
+
await addKey(markKey(key), encodedValue);
|
|
122
|
+
return value;
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function* generateStringChunks(string: string, chunk_size: number) {
|
|
128
|
+
for (let s = "", n = 0, o = 0, l = 0; ; l++) {
|
|
129
|
+
if (chunk_size * n + l + o >= string.length) {
|
|
130
|
+
if (l > 0) {
|
|
131
|
+
yield s;
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
s += string[chunk_size * n + l + o];
|
|
136
|
+
if (string[chunk_size * n + l + o] === "%") {
|
|
137
|
+
s += string[chunk_size * n + l + ++o] + string[chunk_size * n + l + ++o];
|
|
138
|
+
}
|
|
139
|
+
if (l === chunk_size - 1) {
|
|
140
|
+
l = -1;
|
|
141
|
+
n++;
|
|
142
|
+
yield s;
|
|
143
|
+
s = "";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function* collectTuples<T>(gen: Generator<T, void, unknown>, l: number, unit: T) {
|
|
149
|
+
let result: IteratorResult<T, void>;
|
|
150
|
+
let done: boolean | undefined;
|
|
151
|
+
|
|
152
|
+
function next() {
|
|
153
|
+
if (done) return unit;
|
|
154
|
+
result = gen.next();
|
|
155
|
+
done = result.done;
|
|
156
|
+
if (done) return unit;
|
|
157
|
+
return result.value;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
while (!done) {
|
|
161
|
+
yield Array.from({ length: l }, next);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* Copyright (C) 2026 Afonso Jorge Ramos
|
|
4
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Inlined from the hooks-era /hooks/util.ts and /hooks/std/text.ts (a
|
|
8
|
+
// data-URL bundle of jsr:@std/text), which were stdlib's last imports
|
|
9
|
+
// from the retired hooks runtime. findBy carries the CLI compat pack's
|
|
10
|
+
// hostile-exports fix, which the hooks repo never received; inlining
|
|
11
|
+
// ends that typecheck-vs-runtime divergence.
|
|
12
|
+
|
|
13
|
+
type Predicate<A> = (value: A) => boolean;
|
|
14
|
+
|
|
15
|
+
// Some client exports are functions whose own toString is not callable;
|
|
16
|
+
// they can never match a needle, so they stringify to "".
|
|
17
|
+
const safeString = (x: any): string => {
|
|
18
|
+
try {
|
|
19
|
+
return x.toString();
|
|
20
|
+
} catch {
|
|
21
|
+
try {
|
|
22
|
+
return Function.prototype.toString.call(x);
|
|
23
|
+
} catch {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function findBy(...tests: Array<string | RegExp | Predicate<any>>) {
|
|
30
|
+
const testFns = tests.map((test): Predicate<any> => {
|
|
31
|
+
switch (typeof test) {
|
|
32
|
+
case "string":
|
|
33
|
+
return (x) => safeString(x).includes(test);
|
|
34
|
+
case "function":
|
|
35
|
+
return (x) => test(x);
|
|
36
|
+
default: // assume regex
|
|
37
|
+
return (x) => test.test(safeString(x));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const testFn = (x: any) => testFns.map((t) => t(x)).every(Boolean);
|
|
41
|
+
return <A>(xs: A[]) => xs.find(testFn)!;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const matchLast = (str: string, pattern: RegExp) => {
|
|
45
|
+
const matches = str.matchAll(pattern);
|
|
46
|
+
return Array.from(matches).at(-1)!;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// toPascalCase must stay byte-identical to @std/text@1.0.4: its outputs
|
|
50
|
+
// become webpack-needle registry keys (URI types, component names).
|
|
51
|
+
// Alternatives, in @std/text's order: capitalized word, acronym,
|
|
52
|
+
// lowercase word, any letters, digits.
|
|
53
|
+
const WORD_OR_NUMBER = /\p{Lu}\p{Ll}+|\p{Lu}+(?=(\p{Lu}\p{Ll})|\P{L}|\b)|(\p{Ll}+)|\p{L}+|\p{N}+/gu;
|
|
54
|
+
|
|
55
|
+
const splitToWords = (input: string) => input.match(WORD_OR_NUMBER) ?? [];
|
|
56
|
+
|
|
57
|
+
const capitalizeWord = (word: string) =>
|
|
58
|
+
word ? word[0].toLocaleUpperCase() + word.slice(1).toLocaleLowerCase() : word;
|
|
59
|
+
|
|
60
|
+
export function toPascalCase(input: string): string {
|
|
61
|
+
return splitToWords(input.trim()).map(capitalizeWord).join("");
|
|
62
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const isGlobalNavBarEnabled = () => {
|
|
7
|
+
return true;
|
|
8
|
+
// if (!Platform) {
|
|
9
|
+
// return undefined;
|
|
10
|
+
// }
|
|
11
|
+
// const RemoteConfiguration = Platform.getRemoteConfiguration();
|
|
12
|
+
// const enableGlobalNavBar = RemoteConfiguration.getValue("enableGlobalNavBar");
|
|
13
|
+
// return (
|
|
14
|
+
// enableGlobalNavBar === "home-next-to-navigation" || enableGlobalNavBar === "home-next-to-search"
|
|
15
|
+
// );
|
|
16
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as ClassNames_xpui_ts from "./ClassNames.xpui.ts";
|
|
7
|
+
export let classnames: typeof ClassNames_xpui_ts.classnames;
|
|
8
|
+
import("./ClassNames.xpui.ts").then(m => {
|
|
9
|
+
classnames = m.classnames;
|
|
10
|
+
}).catch((e) => console.warn("[stdlib] lazy webpack surface ./ClassNames.xpui.ts failed:", e));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { modules } from "./index.ts";
|
|
7
|
+
import { webpackRequire } from "../wpunpk.mix.ts";
|
|
8
|
+
|
|
9
|
+
type classNames = (...args: any[]) => string;
|
|
10
|
+
|
|
11
|
+
await globalThis.CHUNKS.xpui.promise;
|
|
12
|
+
|
|
13
|
+
export const classnames: classNames = modules
|
|
14
|
+
.filter(([_, v]) => v.toString().includes("[native code]"))
|
|
15
|
+
.map(([i]) => webpackRequire(i))
|
|
16
|
+
.find((e) => typeof e === "function");
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as ComponentLibrary_xpui_ts from "./ComponentLibrary.xpui.ts";
|
|
7
|
+
export let UI: typeof ComponentLibrary_xpui_ts.UI;
|
|
8
|
+
import("./ComponentLibrary.xpui.ts").then(m => {
|
|
9
|
+
UI = m.UI;
|
|
10
|
+
}).catch((e) => console.warn("[stdlib] lazy webpack surface ./ComponentLibrary.xpui.ts failed:", e));
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { exported, exportedForwardRefs, exportedFunctions, src } from "./index.ts";
|
|
7
|
+
|
|
8
|
+
await CHUNKS.xpui.promise;
|
|
9
|
+
|
|
10
|
+
const componentNames = Object.keys(
|
|
11
|
+
exported.find((e) => e.BrowserDefaultFocusStyleProvider && Object.hasOwn(e, "BrowserDefaultFocusStyleProvider")),
|
|
12
|
+
);
|
|
13
|
+
const componentRegexes = componentNames.map((n) => new RegExp(`"data-encore-id":(?:[a-zA-Z_\$][\w\$]*\\.){2}${n}\\b`));
|
|
14
|
+
const componentPairs = [exportedFunctions.map((f) => [f, f]), exportedForwardRefs.map((f) => [(f as any).render, f])]
|
|
15
|
+
.flat()
|
|
16
|
+
.map(([s, f]) => [componentNames.find((n, i) => src(s).match(componentRegexes[i])), f]);
|
|
17
|
+
|
|
18
|
+
export const UI: any = Object.fromEntries(componentPairs);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as FilterContext_xpui_ts from "./FilterContext.xpui.ts";
|
|
7
|
+
export let FilterContext: typeof FilterContext_xpui_ts.FilterContext;
|
|
8
|
+
import("./FilterContext.xpui.ts").then(m => {
|
|
9
|
+
FilterContext = m.FilterContext;
|
|
10
|
+
}).catch((e) => console.warn("[stdlib] lazy webpack surface ./FilterContext.xpui.ts failed:", e));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { exportedContexts } from "./index.ts";
|
|
7
|
+
|
|
8
|
+
await CHUNKS.xpui.promise;
|
|
9
|
+
|
|
10
|
+
export const FilterContext = exportedContexts.find((c) => (c as any)._currentValue2?.setFilter)!;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as Mousetrap_xpui_ts from "./Mousetrap.xpui.ts";
|
|
7
|
+
export let Mousetrap: typeof Mousetrap_xpui_ts.Mousetrap;
|
|
8
|
+
import("./Mousetrap.xpui.ts").then(m => {
|
|
9
|
+
Mousetrap = m.Mousetrap;
|
|
10
|
+
}).catch((e) => console.warn("[stdlib] lazy webpack surface ./Mousetrap.xpui.ts failed:", e));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { exports } from "./index.ts";
|
|
7
|
+
|
|
8
|
+
import type MousetrapT from "npm:@types/mousetrap";
|
|
9
|
+
|
|
10
|
+
await CHUNKS.xpui.promise;
|
|
11
|
+
|
|
12
|
+
export const Mousetrap: typeof MousetrapT = exports.find((m) => m.addKeycodes);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type * as React_xpui_ts from "./React.xpui.ts";
|
|
7
|
+
export let ReactJSX: typeof React_xpui_ts.ReactJSX;
|
|
8
|
+
export let ReactDOM: typeof React_xpui_ts.ReactDOM;
|
|
9
|
+
export let ReactDOMServer: typeof React_xpui_ts.ReactDOMServer;
|
|
10
|
+
import("./React.xpui.ts").then(m => {
|
|
11
|
+
ReactJSX = m.ReactJSX;
|
|
12
|
+
ReactDOM = m.ReactDOM;
|
|
13
|
+
ReactDOMServer = m.ReactDOMServer;
|
|
14
|
+
}).catch((e) => console.warn("[stdlib] lazy webpack surface ./React.xpui.ts failed:", e));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { exports } from "./index.ts";
|
|
7
|
+
|
|
8
|
+
import type ReactDOMT from "npm:@types/react-dom";
|
|
9
|
+
import type ReactDOMServerT from "npm:@types/react-dom/server";
|
|
10
|
+
|
|
11
|
+
await CHUNKS.xpui.promise;
|
|
12
|
+
|
|
13
|
+
export const ReactJSX: any = exports.find((m) => m.jsx)!;
|
|
14
|
+
export const ReactDOM: typeof ReactDOMT = exports.find((m) => m.createRoot)!;
|
|
15
|
+
export const ReactDOMServer: typeof ReactDOMServerT = exports.find((m) => m.renderToString)!;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Delusoire
|
|
3
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { analyzeWebpackRequire } from "./index.ts";
|
|
7
|
+
import { webpackRequire } from "../wpunpk.mix.ts";
|
|
8
|
+
|
|
9
|
+
await (CHUNKS["/xpui-desktop-routes-settings.js"] ??= Promise.withResolvers()).promise;
|
|
10
|
+
|
|
11
|
+
const { exports } = analyzeWebpackRequire(webpackRequire);
|
|
12
|
+
export const Settings: {
|
|
13
|
+
SettingsLabel: React.FC<any>;
|
|
14
|
+
SettingsRow: React.FC<any>;
|
|
15
|
+
SettingsRowEnd: React.FC<any>;
|
|
16
|
+
SettingsRowStart: React.FC<any>;
|
|
17
|
+
} = exports.find((m) => m.SettingsRow) as any;
|