minecodex 2.0.4 → 2.0.6
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/DESIGN.md +40 -1
- package/README.md +9 -3
- package/apps/dashboard/DESIGN.md +53 -31
- package/apps/dashboard/app.js +55 -39
- package/apps/dashboard/assets/OFL.txt +93 -0
- package/apps/dashboard/assets/info.svg +15 -0
- package/apps/dashboard/assets/moon.svg +13 -0
- package/apps/dashboard/assets/refresh-cw.svg +16 -0
- package/apps/dashboard/assets/silkscreen.ttf +0 -0
- package/apps/dashboard/assets/sun.svg +21 -0
- package/apps/dashboard/assets/terrain.js +89 -0
- package/apps/dashboard/assets/triangle-alert.svg +15 -0
- package/apps/dashboard/favicon.svg +12 -17
- package/apps/dashboard/index.html +24 -18
- package/apps/dashboard/styles.css +147 -181
- package/assets/brand/README.md +19 -0
- package/assets/brand/minecodex-icon-dark.svg +9 -0
- package/assets/brand/minecodex-icon-light.svg +9 -0
- package/assets/brand/minecodex-icon.svg +8 -0
- package/assets/brand/references/lucide-LICENSE.txt +43 -0
- package/assets/readme/hero.svg +93 -0
- package/features/hide-upsell-banner/README.md +7 -5
- package/features/hide-upsell-banner/codex-feature.json +2 -2
- package/features/hide-upsell-banner/src/hide-upsell-banner.mjs +30 -12
- package/features/images/DESIGN.md +117 -41
- package/features/images/README.md +26 -16
- package/features/images/codex-feature.json +6 -3
- package/features/images/src/adapters/codex/image-prompt.mjs +24 -2
- package/features/images/src/adapters/codex/image-sources.mjs +19 -0
- package/features/images/src/adapters/codex/library-api.mjs +2 -0
- package/features/images/src/adapters/codex/library-viewer.mjs +26 -2
- package/features/images/src/adapters/codex/native-image-modules.mjs +211 -0
- package/features/images/src/adapters/codex/native-image-source.mjs +449 -0
- package/features/images/src/backend/local-image-source.mjs +138 -0
- package/features/images/src/frontend/cloud-image-actions.mjs +41 -0
- package/features/images/src/frontend/local-image-source.mjs +195 -0
- package/features/images/src/library-prompt-page.mjs +163 -53
- package/features/images/src/library-prompt-source.mjs +9 -3
- package/features/images/src/prompt-index.mjs +14 -2
- package/features/model-slider/DESIGN.md +2 -0
- package/features/model-slider/codex-feature.json +2 -2
- package/features/model-slider/src/frontend/install.mjs +78 -11
- package/features/notes/DESIGN.md +7 -3
- package/features/notes/codex-feature.json +2 -2
- package/features/notes/src/frontend/entry.mjs +26 -9
- package/features/session-status/DESIGN.md +4 -2
- package/features/session-status/codex-feature.json +2 -2
- package/features/session-status/src/adapters/codex/session-log.mjs +2 -1
- package/features/session-status/src/domain/session-stats.mjs +17 -9
- package/features/session-status/src/session-status.mjs +47 -11
- package/features/sidebar-focus/DESIGN.md +4 -4
- package/features/sidebar-focus/codex-feature.json +3 -2
- package/features/sidebar-focus/src/adapters/codex/renderer.mjs +1 -1
- package/features/sidebar-focus/src/sidebar-focus.mjs +9 -7
- package/features/sites/DESIGN.md +25 -3
- package/features/sites/README.md +6 -2
- package/features/sites/codex-feature.json +3 -2
- package/features/sites/src/adapters/codex/renderer.mjs +25 -4
- package/features/sites/src/backend/project-sites.mjs +18 -6
- package/features/sites/src/backend/sites-service.mjs +22 -10
- package/features/sites/src/domain/discovery-candidates.mjs +53 -0
- package/features/sites/src/frontend/entry.mjs +76 -38
- package/features/sites/src/frontend/styles.css +3 -3
- package/features/unread-inbox/DESIGN.md +24 -25
- package/features/unread-inbox/codex-feature.json +3 -2
- package/features/unread-inbox/src/adapters/codex/modules.mjs +52 -0
- package/features/unread-inbox/src/adapters/codex/renderer.mjs +90 -0
- package/features/unread-inbox/src/domain/notifications.mjs +21 -0
- package/features/unread-inbox/src/injection-source.mjs +5 -2
- package/features/unread-inbox/src/unread-inbox.mjs +212 -297
- package/features/usage-meter/codex-feature.json +2 -2
- package/package.json +11 -3
- package/packages/cli/native/MineCodex.app/Contents/Info.plist +4 -2
- package/packages/cli/native/MineCodex.app/Contents/MacOS/MineCodexServiceManager +0 -0
- package/packages/cli/native/MineCodex.app/Contents/Resources/MineCodex.icns +0 -0
- package/packages/cli/native/MineCodex.app/Contents/_CodeSignature/CodeResources +11 -0
- package/packages/cli/native/README.md +31 -0
- package/packages/cli/src/browser-control-panel.mjs +48 -0
- package/packages/cli/src/commands.mjs +3 -1
- package/packages/cli/src/control-server.mjs +6 -3
- package/packages/cli/src/platform.mjs +5 -0
- package/packages/codex-adapter/README.md +2 -1
- package/packages/codex-adapter/src/renderer/environment.mjs +24 -6
- package/packages/runtime-host/README.md +10 -5
- package/packages/runtime-host/src/codex-injection.mjs +13 -9
- package/packages/runtime-host/src/codex-runtime.mjs +26 -5
- package/packages/runtime-host/src/feature-registry.mjs +1 -0
- package/packages/ui/DESIGN.md +9 -2
- package/packages/ui/assets/arrow-up-right.svg +14 -0
- package/packages/ui/assets/lucide-LICENSE.txt +43 -0
- package/packages/ui/src/components/account-menu.mjs +74 -0
- package/packages/ui/src/components/button.mjs +2 -0
- package/packages/ui/src/components/navigation-rail.mjs +18 -10
- package/packages/ui/src/components/page.mjs +9 -2
- package/packages/ui/src/foundation/layers.mjs +1 -0
- package/packages/ui/src/install.mjs +6 -1
- package/packages/ui/src/native/account-menu.mjs +21 -0
- package/packages/ui/src/native/navigation-rail.mjs +6 -1
- package/packages/ui/src/native/page.mjs +38 -0
- package/packages/ui/src/native/tokens.mjs +4 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// 按文件预览的调用关系读取角色,不依赖构建时分配的短变量名。
|
|
2
|
+
export function discoverFilePreviewComposerBindings(source) {
|
|
3
|
+
const starts = [...source.matchAll(/function [\w$]+\(/g)].map(match => match.index);
|
|
4
|
+
const bodies = starts.map((start,index) => source.slice(start,starts[index+1] ?? source.length));
|
|
5
|
+
const requireBody = marker => {
|
|
6
|
+
const found=bodies.filter(body=>marker.test(body));
|
|
7
|
+
if(found.length!==1)throw new Error("Native file preview Composer contract changed");
|
|
8
|
+
return found[0];
|
|
9
|
+
};
|
|
10
|
+
const scopeBody=requireBody(/draftId:[\w$]+,imageDataUrl:/);
|
|
11
|
+
const homeBody=requireBody(/homeComposerController:[\w$]+,homeComposerMode:/);
|
|
12
|
+
const composerBody=requireBody(/lockedLayout:`single-line`/);
|
|
13
|
+
const alias=(body,local,call=false)=>{
|
|
14
|
+
const escaped=local?.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");
|
|
15
|
+
const value=escaped&&body.match(new RegExp(`(?:[,;]|let )${escaped}=([\\w$]+)${call?"\\(":"(?=[,;])"}`))?.[1];
|
|
16
|
+
if(!value)throw new Error("Native file preview Composer role changed");
|
|
17
|
+
return value;
|
|
18
|
+
};
|
|
19
|
+
const controller=scopeBody.match(/composerController:([\w$]+)/)?.[1];
|
|
20
|
+
const scopes=[...scopeBody.matchAll(/jsx\)\(([\w$]+),\{scope:([\w$]+),value:([\w$]+)/g)];
|
|
21
|
+
if(scopes.length!==2)throw new Error("Native file preview Composer scopes changed");
|
|
22
|
+
const scopeProvider=alias(scopeBody,scopes[0][1]);
|
|
23
|
+
if(scopeProvider!==alias(scopeBody,scopes[1][1]))throw new Error("Native file preview Composer providers changed");
|
|
24
|
+
const roles={
|
|
25
|
+
useComposerController:alias(scopeBody,controller,true),
|
|
26
|
+
useHomeComposer:homeBody.match(/let [\w$]+=([\w$]+)\([\w$]+\),[\w$]+=[\w$]+\?\.composerProps/)?.[1],
|
|
27
|
+
Composer:composerBody.match(/jsx\)\(([\w$]+),\{\.\.\.[\w$]+,className:`mx-auto w-full max-w-2xl px-toolbar`/)?.[1],
|
|
28
|
+
ComposerSurface:composerBody.match(/jsx\)\(([\w$]+),\{placement:/)?.[1],
|
|
29
|
+
ScopeProvider:scopeProvider,
|
|
30
|
+
composerScope:alias(scopeBody,scopes[0][2]),
|
|
31
|
+
createComposerValue:alias(scopeBody,scopes[0][3],true),
|
|
32
|
+
composerRouteScope:alias(scopeBody,scopes[1][2]),
|
|
33
|
+
};
|
|
34
|
+
if(Object.values(roles).some(value=>!value))throw new Error("Native file preview Composer role changed");
|
|
35
|
+
return roles;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 构建产物发现只返回当前能力;原生组件呈现不参与引用解析。
|
|
39
|
+
export function createNativeImageModules({read = async url => (await fetch(url)).text(), load = url => import(url)} = {}) {
|
|
40
|
+
let starting, connecting, canvasConnecting;
|
|
41
|
+
function imported(source, local) {
|
|
42
|
+
for (const match of source.matchAll(/import\{([^}]+)\}from["']([^"']+)["']/g)) {
|
|
43
|
+
for (const binding of match[1].split(",")) {
|
|
44
|
+
const parts = binding.trim().split(/\s+as\s+/);
|
|
45
|
+
if (parts.at(-1) === local) return { name: parts[0], file: match[2] };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`Native Images import contract changed: ${local}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function bootstrap() {
|
|
52
|
+
if (!starting) starting = (async () => {
|
|
53
|
+
const urls = [...document.querySelectorAll('link[rel="modulepreload"],script[src]')].map(node => node.href || node.src);
|
|
54
|
+
const initialUrl = urls.find(url => /\/app-initial-[^/]+\.js/.test(url));
|
|
55
|
+
const mainUrl = urls.find(url => /\/app-main-[^/]+\.js/.test(url));
|
|
56
|
+
if (!initialUrl || !mainUrl) throw new Error("Native Images modules are unavailable");
|
|
57
|
+
const [initialSource, mainSource] = await Promise.all([read(initialUrl), read(mainUrl)]);
|
|
58
|
+
const asset = (name, references = initialSource) => {
|
|
59
|
+
const file = references.match(new RegExp(`(?:["'./])(${name}-[\\w-]+\\.js)`))?.[1];
|
|
60
|
+
if (!file) throw new Error(`Native Images capability is unavailable: ${name}`);
|
|
61
|
+
return new URL(file, initialUrl).href;
|
|
62
|
+
};
|
|
63
|
+
const module = async (name,references) => {
|
|
64
|
+
const url = asset(name,references);
|
|
65
|
+
const [source, exports] = await Promise.all([read(url), load(url)]);
|
|
66
|
+
// 调用产物公开的惰性初始化器,不扫描或执行任意导出函数。
|
|
67
|
+
for (const value of Object.values(exports)) {
|
|
68
|
+
if (typeof value === "function" && /^function ([\w$]+)\(\)\{return\(\1=/.test(String(value))) value();
|
|
69
|
+
}
|
|
70
|
+
return {url, source, exports};
|
|
71
|
+
};
|
|
72
|
+
const component = (exports, predicate, name) => {
|
|
73
|
+
const matches = Object.values(exports).filter(value => typeof value === "function" && predicate(String(value)));
|
|
74
|
+
if (matches.length !== 1) throw new Error(`Native Images contract changed: ${name}`);
|
|
75
|
+
return matches[0];
|
|
76
|
+
};
|
|
77
|
+
const binding = async (source, url, local) => {
|
|
78
|
+
if (!local) throw new Error("Native Images component contract changed");
|
|
79
|
+
const importedBinding = imported(source, local);
|
|
80
|
+
return (await load(new URL(importedBinding.file, url).href))[importedBinding.name];
|
|
81
|
+
};
|
|
82
|
+
const masonry = await module("library-masonry");
|
|
83
|
+
const rootOwner = mainSource.match(/\(0,([\w$]+)\.createRoot\)/)?.[1];
|
|
84
|
+
const rootInit = rootOwner && mainSource.match(new RegExp(`${rootOwner}=([\\w$]+)\\(\\)`))?.[1];
|
|
85
|
+
const reactOwner = masonry.source.match(/([\w$]+)\.useRef\b/)?.[1];
|
|
86
|
+
const reactInit = reactOwner && masonry.source.match(new RegExp(`${reactOwner}=([\\w$]+)\\(\\)`))?.[1];
|
|
87
|
+
const [reactFactory, rootFactory] = await Promise.all([
|
|
88
|
+
binding(masonry.source, masonry.url, reactInit), binding(mainSource, mainUrl, rootInit),
|
|
89
|
+
]);
|
|
90
|
+
const React = reactFactory(), ReactDOM = rootFactory();
|
|
91
|
+
const initial = await load(initialUrl);
|
|
92
|
+
return {React,ReactDOM,module,component,binding,initialUrl,initialSource,initial};
|
|
93
|
+
})().catch(error=>{starting=null;throw error;});
|
|
94
|
+
return starting;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function gallery() {
|
|
98
|
+
if (!connecting) connecting = (async () => {
|
|
99
|
+
const {React,ReactDOM,module,component,binding,initialUrl,initialSource,initial}=await bootstrap();
|
|
100
|
+
const [masonry,layout,sourceImage,menu,selection]=await Promise.all([
|
|
101
|
+
module("library-masonry"),module("library-item-layout"),module("generated-image-source"),
|
|
102
|
+
module("generated-image-context-menu"),module("library-selection-toolbar"),
|
|
103
|
+
]);
|
|
104
|
+
const [moveDialog,dialogs]=await Promise.all([module("library-move-dialog",selection.source),module("library-item-dialogs",selection.source)]);
|
|
105
|
+
const routerLocal = selection.source.match(/get\(([\w$]+)\)\.prepareNavigation\(/)?.[1];
|
|
106
|
+
const routerAtom = await binding(selection.source, selection.url, routerLocal);
|
|
107
|
+
const switchLocal = selection.source.match(/([\w$]+)\(e,i\);let _=t.length===1/)?.[1];
|
|
108
|
+
const switchMode = await binding(selection.source, selection.url, switchLocal);
|
|
109
|
+
const draftLocal = selection.source.match(/let u=([\w$]+)\(e,\[\]\);e.set/)?.[1];
|
|
110
|
+
const createChatDraft = await binding(selection.source, selection.url, draftLocal);
|
|
111
|
+
const dropdownLocal = selection.source.match(/\(0,[\w$]+\.jsxs?\)\(([\w$]+),\{contentWidth:`menu`/)?.[1];
|
|
112
|
+
const itemsLocal = selection.source.match(/\(0,[\w$]+\.jsxs?\)\(([\w$]+)\.Item,\{/)?.[1];
|
|
113
|
+
const buttonLocal = selection.source.match(/\(0,[\w$]+\.jsx\)\(([\w$]+),\{ref:[^,]+,color:`mediaOverlay`/)?.[1];
|
|
114
|
+
const iconLocal = selection.source.match(/color:`mediaOverlay`[^;]+?children:\(0,[\w$]+\.jsx\)\(([\w$]+),\{\}\)/)?.[1];
|
|
115
|
+
const [Dropdown, Menu, Button, MoreIcon] = await Promise.all([dropdownLocal, itemsLocal, buttonLocal, iconLocal].map(local => binding(selection.source, selection.url, local)));
|
|
116
|
+
const checkboxFunction = component(selection.exports,source=>/onCheckedChange:/.test(source)&&/viewMode:/.test(source),"selection checkbox");
|
|
117
|
+
const checkboxLocal = String(checkboxFunction).match(/\(0,[\w$]+\.jsx\)\(([\w$]+),\{className:`cursor-interaction`,variant:/)?.[1];
|
|
118
|
+
const Checkbox = await binding(selection.source,selection.url,checkboxLocal);
|
|
119
|
+
const rangeSelection = component(selection.exports,source=>/^function [\w$]+\(\{orderedIds:/.test(source)&&/extendRange:/.test(source),"range selection");
|
|
120
|
+
const selectionLocal = selection.source.match(/\.set\(([\w$]+),new Set\)/)?.[1];
|
|
121
|
+
const selectionExport = selection.source.match(/export\{([^}]+)\}/)?.[1].split(",").map(value=>value.trim().split(/\s+as\s+/)).find(parts=>parts[0]===selectionLocal)?.at(-1);
|
|
122
|
+
const nativeSelectedIds = selection.exports[selectionExport];
|
|
123
|
+
if (!nativeSelectedIds) throw new Error("Native selection state contract changed");
|
|
124
|
+
const clearPrefix = selection.source.slice(selection.source.indexOf("id:`libraryNext.selection.clear`"));
|
|
125
|
+
const clearLocal = clearPrefix.match(/\(0,[\w$]+\.jsx\)\(([\w$]+),\{\}\)/)?.[1];
|
|
126
|
+
const ClearIcon = await binding(selection.source,selection.url,clearLocal);
|
|
127
|
+
const dialogLocal = dialogs.source.match(/\(0,[\w$]+\.jsx\)\(([\w$]+),\{open:[^,]+,showDialogClose:!1/)?.[1];
|
|
128
|
+
const contentLocal = dialogs.source.match(/\(0,[\w$]+\.jsx\)\(([\w$]+),\{as:`form`,onSubmit:/)?.[1];
|
|
129
|
+
const [Dialog,DialogContent] = await Promise.all([dialogLocal,contentLocal].map(local=>binding(dialogs.source,dialogs.url,local)));
|
|
130
|
+
const menuCoreFile = menu.source.match(/from["']([^"']*generated-image-context-menu-[^"']+)["']/)?.[1];
|
|
131
|
+
const menuCoreUrl = menuCoreFile ? new URL(menuCoreFile,menu.url).href : menu.url;
|
|
132
|
+
const menuCoreSource = menuCoreFile ? await read(menuCoreUrl) : menu.source;
|
|
133
|
+
const imageActions = component(menu.exports,source=>/onOpenedInNewTab:/.test(source),"image actions");
|
|
134
|
+
const imageActionSource = String(imageActions);
|
|
135
|
+
const imageFileLocal = imageActionSource.match(/let\{file:[\w$]+\}=([\w$]+)\(/)?.[1];
|
|
136
|
+
const attachLocal = imageActionSource.match(/await ([\w$]+)\(e,i,\[n\],/)?.[1];
|
|
137
|
+
const downloadLocal = imageActionSource.match(/await ([\w$]+)\(\{downloadSrc:/)?.[1];
|
|
138
|
+
const [imageFile,attachChatImages,downloadImage] = await Promise.all([imageFileLocal,attachLocal,downloadLocal].map(local=>binding(menuCoreSource,menuCoreUrl,local)));
|
|
139
|
+
const toolbarClass = selection.source.match(/className:`(pointer-events-auto flex h-toolbar[^`]+)`/)?.[1];
|
|
140
|
+
const toolbarPositionClass = selection.source.match(/className:`(pointer-events-none fixed inset-x-4 bottom-6[^`]+)`/)?.[1];
|
|
141
|
+
if (!toolbarClass || !toolbarPositionClass) throw new Error("Native selection toolbar layout changed");
|
|
142
|
+
const libraryIcon = async label => {
|
|
143
|
+
const marker = selection.source.indexOf(`defaultMessage:\`${label}\``);
|
|
144
|
+
const prefix = selection.source.slice(Math.max(0, marker - 500), marker);
|
|
145
|
+
const match = [...prefix.matchAll(/leftIcon:\(0,[\w$]+\.jsx\)\(([\w$]+),\{icon:\{(assets:\{)?16:([\w$]+),20:([\w$]+)/g)].at(-1);
|
|
146
|
+
if (!match) throw new Error(`Native Library icon contract changed: ${label}`);
|
|
147
|
+
const [Icon, small, medium] = await Promise.all([match[1], match[3], match[4]].map(local => binding(selection.source, selection.url, local)));
|
|
148
|
+
const sizes = {16:small, 20:medium};
|
|
149
|
+
return React.createElement(Icon, {icon:match[2] ? {assets:sizes} : sizes});
|
|
150
|
+
};
|
|
151
|
+
const upload = component(initial, source => /async function/.test(source) && /libraryPersistenceMode:/.test(source) && /uploadPurpose:/.test(source), "Library upload");
|
|
152
|
+
const setFavorite = component(initial, source => /target_ref:/.test(source) && /showToast:/.test(source), "Library favorite");
|
|
153
|
+
const auth = String(setFavorite).match(/accountId:e.get\(([\w$]+)\),userId:e.get\(([\w$]+)\)/);
|
|
154
|
+
const [accountAtom,userAtom] = await Promise.all([auth?.[1],auth?.[2]].map(local => binding(initialSource,initialUrl,local)));
|
|
155
|
+
if (!accountAtom || !userAtom) throw new Error("Native Library account contract changed");
|
|
156
|
+
const toastLocal = selection.source.match(/get\(([\w$]+)\)\.danger\(/)?.[1];
|
|
157
|
+
const toastAtom = await binding(selection.source, selection.url, toastLocal);
|
|
158
|
+
const favoritePrefix = selection.source.slice(Math.max(0,selection.source.indexOf("id:`library.favorites.add`")-2000),selection.source.indexOf("id:`library.favorites.add`")+500);
|
|
159
|
+
const favoriteAsset = favoritePrefix.match(/\{16:([\w$]+),20:([\w$]+)\}:\{16:([\w$]+),20:([\w$]+)\}/);
|
|
160
|
+
if (!favoriteAsset) throw new Error("Native Library favorite icon contract changed");
|
|
161
|
+
const favoriteIconLocal = favoritePrefix.match(/icon:\{assets:/)?.index;
|
|
162
|
+
const favoriteIconOwner = favoritePrefix.slice(0,favoriteIconLocal).match(/\(0,[\w$]+\.jsx\)\(([\w$]+),\{$/)?.[1];
|
|
163
|
+
const [FavoriteIcon, savedSmall, savedMedium, emptySmall, emptyMedium] = await Promise.all([favoriteIconOwner,...favoriteAsset.slice(1)].map(local => binding(selection.source,selection.url,local)));
|
|
164
|
+
const favoriteIcon = saved => React.createElement(FavoriteIcon,{icon:{assets:saved?{16:savedSmall,20:savedMedium}:{16:emptySmall,20:emptyMedium}}});
|
|
165
|
+
const [chatIcon, downloadIcon, folderIcon, deleteIcon] = await Promise.all([
|
|
166
|
+
libraryIcon("Chat about this"), libraryIcon("Download"), libraryIcon("Add to folder"), libraryIcon("{kind, select, directory {Delete folder} other {Delete}}"),
|
|
167
|
+
]);
|
|
168
|
+
if (!React.createElement || !ReactDOM.createRoot || !Menu.Item) throw new Error("Native Images rendering contract changed");
|
|
169
|
+
return {
|
|
170
|
+
React, ReactDOM, Dropdown, Menu, Button, MoreIcon, chatIcon, downloadIcon, folderIcon, favoriteIcon, routerAtom, switchMode, createChatDraft, upload, setFavorite, toastAtom, accountAtom, userAtom,
|
|
171
|
+
MoveDialog:moveDialog.exports.MoveLibraryItemsDialog,
|
|
172
|
+
Checkbox,rangeSelection,nativeSelectedIds,ClearIcon,Dialog,DialogContent,ConfirmationContent:dialogs.exports.LibraryItemConfirmationContent,
|
|
173
|
+
imageFile,attachChatImages,downloadImage,toolbarClass,toolbarPositionClass,deleteIcon,
|
|
174
|
+
Masonry: component(masonry.exports, source => /\{items:[^}]+animate:/.test(source), "masonry"),
|
|
175
|
+
Skeleton: component(masonry.exports, source => /square:/.test(source) && /Loading library/.test(source), "skeleton"),
|
|
176
|
+
Card: component(layout.exports, source => /actionIndicator:/.test(source) && /documentHeader:/.test(source), "card"),
|
|
177
|
+
useImage: component(sourceImage.exports, source => /shouldLoadFileDataUrl:/.test(source), "image resolver"),
|
|
178
|
+
imageMenu: component(menu.exports, source => /onOpenedInNewTab:/.test(source), "image actions"),
|
|
179
|
+
openImage: component(initial, source => /availableImageCount:/.test(source) && /openInEditor:/.test(source) && /entrypoint:/.test(source), "image preview"),
|
|
180
|
+
};
|
|
181
|
+
})().catch(error=>{connecting=null;throw error;});
|
|
182
|
+
return connecting;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function canvas() {
|
|
186
|
+
if (!canvasConnecting) canvasConnecting = (async () => {
|
|
187
|
+
const {module,binding,component,initial}=await bootstrap();
|
|
188
|
+
const [canvas,canvasLayout,filePreview]=await Promise.all([
|
|
189
|
+
module("image-side-panel"),module("preview-layout"),module("library-cloud-file-preview"),
|
|
190
|
+
]);
|
|
191
|
+
const portalOwner=canvas.source.match(/\(0,([\w$]+)\.createPortal\)/)?.[1];
|
|
192
|
+
const portalInit=portalOwner&&canvas.source.match(new RegExp(`${portalOwner}=([\\w$]+)\\(\\)`))?.[1];
|
|
193
|
+
const createPortal=(await binding(canvas.source,canvas.url,portalInit))().createPortal;
|
|
194
|
+
// 文件画布使用原生 Home Composer 的控制器、附件 scope 和输入组件。
|
|
195
|
+
const composerLocals=Object.values(discoverFilePreviewComposerBindings(filePreview.source));
|
|
196
|
+
const [useComposerController,useHomeComposer,Composer,ComposerSurface,ScopeProvider,composerScope,createComposerValue,composerRouteScope] = await Promise.all(composerLocals.map(local=>binding(filePreview.source,filePreview.url,local)));
|
|
197
|
+
if (!canvas.exports.t || !canvasLayout.exports.r || !Composer || !ComposerSurface || !ScopeProvider
|
|
198
|
+
|| !composerScope || !composerRouteScope?.parent
|
|
199
|
+
|| [createPortal,useComposerController,useHomeComposer,createComposerValue].some(value=>typeof value!=="function")) {
|
|
200
|
+
throw new Error("Native Images canvas contract changed");
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
createPortal,Canvas:canvas.exports.t,CanvasLayout:canvasLayout.exports.r,
|
|
204
|
+
useComposerController,useHomeComposer,Composer,ComposerSurface,ScopeProvider,composerScope,createComposerValue,composerRouteScope,
|
|
205
|
+
editImage:component(initial,source=>/async function/.test(source)&&/requireDispatchAcceptance:/.test(source)&&/sourceAttachment:/.test(source)&&/imageVariant/.test(source),"image edit submission"),
|
|
206
|
+
};
|
|
207
|
+
})().catch(error=>{canvasConnecting=null;throw error;});
|
|
208
|
+
return canvasConnecting;
|
|
209
|
+
}
|
|
210
|
+
return {navigation:async()=>{const {React,ReactDOM}=await bootstrap();return {React,ReactDOM};},gallery,canvas};
|
|
211
|
+
}
|