修正桌面壳分享动作表达

Tauri 桌面分享按钮按剪贴板复制语义展示

Expo 移动分享继续保留系统分享表达

测试和门禁覆盖跨宿主分享文案差异

文档和项目记忆同步 share.open 能力语义
This commit is contained in:
2026-06-20 18:11:31 +08:00
parent ae3cdf4e69
commit 6f91ebc787
6 changed files with 130 additions and 10 deletions
@@ -162,7 +162,7 @@ describe('PublishShareModal', () => {
expect(screen.getByRole('button', { name: '九宫切图' })).toBeTruthy();
});
test('uses native host share action inside native app runtime', async () => {
test('uses clipboard copy wording for Tauri native host share action', async () => {
const invoke = vi.fn(
async (_command: string, args?: Record<string, unknown>) => {
const request = (args as { request: { id: string } }).request;
@@ -189,11 +189,14 @@ describe('PublishShareModal', () => {
render(<PublishShareModal open payload={payload} onClose={() => {}} />);
const dialog = screen.getByRole('dialog', { name: '分享给朋友' });
fireEvent.click(within(dialog).getByRole('button', { name: '系统分享' }));
expect(within(dialog).queryByRole('button', { name: '系统分享' })).toBeNull();
fireEvent.click(
within(dialog).getByRole('button', { name: '复制分享文案' }),
);
await waitFor(() => {
expect(
within(dialog).getByRole('button', { name: '已打开' }),
within(dialog).getByRole('button', { name: '已复制' }),
).toBeTruthy();
});
const rawShareUrl = new URL(buildPublishShareUrl(payload));
@@ -213,6 +216,45 @@ describe('PublishShareModal', () => {
});
});
test('keeps system share wording for Expo native host share action', async () => {
window.history.replaceState(
null,
'',
'/?clientRuntime=native_app&hostShell=expo_mobile&hostCapabilities=share.open',
);
const postMessage = vi.fn((rawMessage: string) => {
const request = JSON.parse(rawMessage) as { id: string };
window.dispatchEvent(
new MessageEvent('message', {
data: JSON.stringify({
bridge: 'GenarrativeHostBridge',
version: 1,
id: request.id,
ok: true,
result: true,
}),
}),
);
});
window.ReactNativeWebView = {
postMessage,
};
render(<PublishShareModal open payload={payload} onClose={() => {}} />);
const dialog = screen.getByRole('dialog', { name: '分享给朋友' });
fireEvent.click(within(dialog).getByRole('button', { name: '系统分享' }));
await waitFor(() => {
expect(
within(dialog).getByRole('button', { name: '已打开' }),
).toBeTruthy();
});
expect(postMessage).toHaveBeenCalledWith(
expect.stringContaining('"method":"share.open"'),
);
});
test('uses native host image export for share card download inside native app runtime', async () => {
class MockFileReader {
result: string | ArrayBuffer | null = null;
+31 -4
View File
@@ -28,6 +28,12 @@ type PublishShareModalProps = {
type ActionState = 'idle' | 'success' | 'failed';
type NativeSharePresentation = {
idleLabel: string;
successLabel: string;
failedLabel: string;
};
function normalizePayloadTitle(payload: PublishShareModalPayload | null) {
return payload?.title.trim() || '我的作品';
}
@@ -44,6 +50,24 @@ function resolvePayloadWorkTypeLabel(payload: PublishShareModalPayload | null) {
return payload?.workTypeLabel?.trim() || '互动作品';
}
function resolveNativeSharePresentation(
hostShell: string | null,
): NativeSharePresentation {
if (hostShell === 'tauri_desktop') {
return {
idleLabel: '复制分享文案',
successLabel: '已复制',
failedLabel: '复制失败',
};
}
return {
idleLabel: '系统分享',
successLabel: '已打开',
failedLabel: '分享失败',
};
}
/**
* 发布完成后的通用分享弹窗。
* 分享事实仍来自公开作品号与 stage;弹窗只负责把它表现成可复制、可下载的分享卡。
@@ -60,7 +84,10 @@ export function PublishShareModal({
const [nativeShareState, setNativeShareState] =
useState<ActionState>('idle');
const resetTimerRef = useRef<number | null>(null);
const hostRuntimeKind = getHostRuntime().kind;
const hostRuntime = getHostRuntime();
const hostRuntimeKind = hostRuntime.kind;
const hostShell = hostRuntime.hostShell;
const nativeSharePresentation = resolveNativeSharePresentation(hostShell);
const shareCopyUrl = useMemo(
() =>
payload
@@ -230,10 +257,10 @@ export function PublishShareModal({
<Share2 className="h-4 w-4" />
)}
{nativeShareState === 'success'
? '已打开'
? nativeSharePresentation.successLabel
: nativeShareState === 'failed'
? '分享失败'
: '系统分享'}
? nativeSharePresentation.failedLabel
: nativeSharePresentation.idleLabel}
</button>
) : null}
<button