@alwith/module-drive 0.0.0-stage → 0.1.0-rc.23

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.
Files changed (107) hide show
  1. package/LICENSE +94 -0
  2. package/README.md +50 -2
  3. package/THIRD_PARTY_NOTICES.md +7 -0
  4. package/desktop-provenance.json +34 -0
  5. package/dist/badge-react.d.ts +9 -0
  6. package/dist/badge-react.js +1 -0
  7. package/dist/badge.d.ts +10 -0
  8. package/dist/badge.js +1 -0
  9. package/dist/browse.d.ts +33 -0
  10. package/dist/browse.js +1 -0
  11. package/dist/content/chat-condense.d.ts +22 -0
  12. package/dist/content/chat-condense.js +1 -0
  13. package/dist/content/collab.d.ts +34 -0
  14. package/dist/content/collab.js +1 -0
  15. package/dist/content/comment-anchors.d.ts +23 -0
  16. package/dist/content/comment-anchors.js +2 -0
  17. package/dist/content/comment-decorations.d.ts +23 -0
  18. package/dist/content/comment-decorations.js +3 -0
  19. package/dist/content/comment-drawer.d.ts +44 -0
  20. package/dist/content/comment-drawer.js +1 -0
  21. package/dist/content/comment-mentions.d.ts +18 -0
  22. package/dist/content/comment-mentions.js +1 -0
  23. package/dist/content/comment-surface.d.ts +25 -0
  24. package/dist/content/comment-surface.js +1 -0
  25. package/dist/content/condense-task.d.ts +44 -0
  26. package/dist/content/condense-task.js +1 -0
  27. package/dist/content/condense.d.ts +20 -0
  28. package/dist/content/condense.js +1 -0
  29. package/dist/content/editor.d.ts +5 -0
  30. package/dist/content/editor.js +1 -0
  31. package/dist/content/file-actions.d.ts +43 -0
  32. package/dist/content/file-actions.js +1 -0
  33. package/dist/content/file-link.d.ts +4 -0
  34. package/dist/content/file-link.js +1 -0
  35. package/dist/content/frontmatter-panel.d.ts +7 -0
  36. package/dist/content/frontmatter-panel.js +1 -0
  37. package/dist/content/frontmatter.d.ts +9 -0
  38. package/dist/content/frontmatter.js +7 -0
  39. package/dist/content/host.d.ts +49 -0
  40. package/dist/content/host.js +1 -0
  41. package/dist/content/html-bridge.d.ts +1 -0
  42. package/dist/content/html-bridge.js +187 -0
  43. package/dist/content/html-comments.d.ts +5 -0
  44. package/dist/content/html-comments.js +1 -0
  45. package/dist/content/markdown-comments.d.ts +4 -0
  46. package/dist/content/markdown-comments.js +2 -0
  47. package/dist/content/mention-picker.d.ts +10 -0
  48. package/dist/content/mention-picker.js +1 -0
  49. package/dist/content/save-version.d.ts +2 -0
  50. package/dist/content/save-version.js +1 -0
  51. package/dist/content/translations.d.ts +2 -0
  52. package/dist/content/translations.js +1 -0
  53. package/dist/content/use-file-comments.d.ts +12 -0
  54. package/dist/content/use-file-comments.js +1 -0
  55. package/dist/content/yuplink.d.ts +11 -0
  56. package/dist/content/yuplink.js +2 -0
  57. package/dist/content.css +64 -0
  58. package/dist/content.d.ts +10 -0
  59. package/dist/content.js +1 -0
  60. package/dist/contract.d.ts +780 -0
  61. package/dist/contract.js +0 -0
  62. package/dist/core.d.ts +22 -0
  63. package/dist/core.js +1 -0
  64. package/dist/files.d.ts +7 -0
  65. package/dist/files.js +1 -0
  66. package/dist/global-search.d.ts +34 -0
  67. package/dist/global-search.js +1 -0
  68. package/dist/icons.d.ts +5 -0
  69. package/dist/icons.js +1 -0
  70. package/dist/launcher.d.ts +15 -0
  71. package/dist/launcher.js +2 -0
  72. package/dist/locales.d.ts +985 -0
  73. package/dist/locales.js +1 -0
  74. package/dist/mass-delete.d.ts +9 -0
  75. package/dist/mass-delete.js +1 -0
  76. package/dist/notifications.d.ts +14 -0
  77. package/dist/notifications.js +1 -0
  78. package/dist/pinned-docs.d.ts +14 -0
  79. package/dist/pinned-docs.js +1 -0
  80. package/dist/pinned.d.ts +12 -0
  81. package/dist/pinned.js +1 -0
  82. package/dist/react.d.ts +29 -0
  83. package/dist/react.js +1 -0
  84. package/dist/roots.d.ts +10 -0
  85. package/dist/roots.js +1 -0
  86. package/dist/settings.d.ts +14 -0
  87. package/dist/settings.js +1 -0
  88. package/dist/sharing.d.ts +12 -0
  89. package/dist/sharing.js +1 -0
  90. package/dist/status.d.ts +16 -0
  91. package/dist/status.js +1 -0
  92. package/dist/styles.css +458 -0
  93. package/dist/summary.d.ts +10 -0
  94. package/dist/summary.js +1 -0
  95. package/dist/tauri.d.ts +6 -0
  96. package/dist/tauri.js +1 -0
  97. package/dist/transfer-feed.d.ts +36 -0
  98. package/dist/transfer-feed.js +1 -0
  99. package/dist/ui.d.ts +96 -0
  100. package/dist/ui.js +1 -0
  101. package/package.json +117 -4
  102. package/rust/Cargo.toml +14 -0
  103. package/rust/src/contract.rs +366 -0
  104. package/rust/src/lib.rs +5 -0
  105. package/rust/src/ownership.rs +4 -0
  106. package/rust/src/service.rs +140 -0
  107. package/rust/src/sync.rs +1602 -0
@@ -0,0 +1,20 @@
1
+ import { type ReactNode } from "react";
2
+ import type { DriveController, Job, RemoteId } from "../core.js";
3
+ import { type DriveLocale } from "../locales.js";
4
+ import type { DriveControls } from "../react.js";
5
+ export interface CondenseScope {
6
+ projectId: RemoteId;
7
+ projectName: string;
8
+ scopePath: string | null;
9
+ }
10
+ export interface DriveCondenseProps {
11
+ controller: DriveController;
12
+ scope: CondenseScope;
13
+ controls: DriveControls;
14
+ locale?: DriveLocale;
15
+ initialJob?: Job;
16
+ onClose: () => void;
17
+ onOpenFile: (path: string) => Promise<void>;
18
+ onOpenExternal: (url: string) => Promise<void>;
19
+ }
20
+ export declare function DriveCondense({ controller, scope, controls: { Button }, locale, initialJob, onClose, onOpenFile, onOpenExternal }: DriveCondenseProps): ReactNode;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as t,Fragment as W}from"react/jsx-runtime";import{useEffect as z,useEffectEvent as A,useRef as _,useState as y,useSyncExternalStore as M}from"react";import{driveTranslator as Q}from"../locales.js";import{useDriveNotifications as V}from"../notifications.js";import{useDrive as X}from"../ui.js";import{condenseTask as q}from"./condense-task.js";function de({controller:a,scope:s,controls:{Button:r},locale:C="en",initialJob:w,onClose:U,onOpenFile:F,onOpenExternal:R}){let i=Q(C),j=V(),b=[s.projectId,s.scopePath,w?.id??""].join("\x00"),[k,T]=y(()=>({controller:a,taskKey:b,task:q(a,s,w)})),c=k.task;if(k.controller!==a||k.taskKey!==b)c=q(a,s,w),T({controller:a,taskKey:b,task:c});let h=M(c.subscribe,c.getSnapshot,c.getSnapshot),{snapshot:K}=X(a),{phase:d,job:S,unsynced:p,cancelling:D}=h,[O,x]=y([]),[H,f]=y(null),[o,P]=y(!1),N=_(!1),l=_(!0),G=A((n)=>{if(n==="succeeded")j?.success(i("condense.completed",{name:s.projectName}));else j?.error(i("condense.backgroundFailed",{name:s.projectName}))});z(()=>(l.current=!0,c.notify=(n)=>G(n),c.resume(),a.request({type:"proposedCondense",projectId:s.projectId}).then((n)=>{if(n.type!=="jobs")throw Error("Invalid proposed condense response");if(l.current)x(n.data)}).catch((n)=>{if(l.current)f(String(n))}),()=>{l.current=!1}),[a,c,s.projectId,s.projectName,j,C]);let I=async(n)=>{if(N.current)return;N.current=!0,P(!0),f(null);try{await n()}catch(u){if(l.current)f(String(u))}finally{if(N.current=!1,l.current)P(!1)}},m=d==="uploading"?K?.files.find((n)=>String(n.projectId)===String(s.projectId)&&n.state==="uploading"):void 0,E=["uploading","starting","running"].includes(d),J=["succeeded","failed","cancelled"].includes(d),v=h.error||H,g=S?.result;return t("section",{className:"alwith-drive-condense",role:"dialog","aria-label":i("condense.action"),children:[t("div",{className:"alwith-drive-dialog-summary",children:[e("p",{children:i("condense.scope")}),e("p",{className:"alwith-drive-dialog-scope",children:s.projectName}),s.scopePath&&e("p",{children:s.scopePath})]}),d==="idle"&&e("p",{children:i("condense.description")}),(E||J)&&t("div",{className:"alwith-drive-dialog-notice",role:"status","aria-live":"polite",children:[e("strong",{children:i(D?"condense.cancelling":d==="succeeded"?"condense.succeeded":d==="failed"?"condense.failed":d==="cancelled"?"condense.cancelled":m?"condense.uploading":"condense.processing")}),m&&e("p",{className:"alwith-drive-current-file",title:m.path,children:m.path}),E&&e("p",{className:"alwith-drive-task-hint",children:i(d==="uploading"||d==="starting"?"condense.uploadHint":"condense.closeHint")})]}),h.uploadIssue&&t("div",{role:"alert",className:"alwith-drive-dialog-notice",children:[e("p",{children:i("condense.uploadIssue")}),e("p",{children:h.uploadIssue})]}),v&&e("div",{role:"alert",className:"alwith-drive-dialog-notice",children:v.includes("SOURCE_IS_KNOWLEDGE_PROJECT")?t(W,{children:[e("p",{children:i("condense.knowledgeSource")}),t("details",{children:[e("summary",{children:i("condense.errorDetails")}),e("p",{children:v})]})]}):e("p",{children:v})}),p&&d==="unsynced"&&t("div",{className:"alwith-drive-dialog-notice",children:[e("h4",{children:i("condense.unsynced.title",{count:p.pending})}),e("p",{children:i("condense.unsynced.desc")}),p.failed>0&&e("p",{children:i("condense.unsynced.failed",{count:p.failed})}),e("ul",{children:p.paths.map((n)=>e("li",{children:n},n))})]}),d==="idle"&&O.map((n)=>t("div",{className:"alwith-drive-dialog-notice",children:[e("p",{children:i("condense.propose.title",{name:s.projectName})}),t("div",{className:"alwith-drive-dialog-actions",children:[e(r,{variant:"outline",disabled:o,onClick:()=>void I(async()=>{if(await a.request({type:"cancelJob",jobId:n.id}),l.current)x((u)=>u.filter((L)=>L.id!==n.id))}),children:i("condense.propose.dismiss")}),e(r,{disabled:o,onClick:()=>void I(async()=>{await a.request({type:"approveJob",jobId:n.id});let u=await a.request({type:"job",jobId:n.id});if(u.type!=="job")throw Error("Invalid approved job response");c.adopt(u.data)}),children:i("condense.propose.action")})]})]},String(n.id))),t("div",{className:"alwith-drive-dialog-actions",children:[e(r,{variant:"outline",onClick:U,children:d==="unsynced"?i("condense.unsynced.wait"):i("condense.close")}),d==="idle"&&e(r,{disabled:o,onClick:()=>{f(null),c.start()},children:i("condense.action")}),d==="unsynced"&&e(r,{disabled:o,onClick:()=>void c.start(!0),children:i("condense.unsynced.proceed")}),E&&e(r,{variant:"outline",disabled:D,onClick:()=>void c.cancel(),children:i("condense.cancelTask")}),d==="succeeded"&&g&&e(r,{disabled:o,onClick:()=>void I(async()=>{let n=await a.request({type:"localPath",fileId:g.knowledgeFileId});if(n.type!=="path")throw Error("Invalid draft location response");if(n.data)await F(n.data);else if(g.humanUrl)await R(g.humanUrl);else throw Error(i("condense.toast.noUrl"))}),children:i("condense.openResult")}),!h.stale&&(d==="cancelled"||d==="failed"&&S?.status!=="SUCCEEDED")&&e(r,{disabled:o,onClick:()=>{f(null),c.start()},children:i("condense.retry")})]})]})}export{de as DriveCondense};
@@ -0,0 +1,5 @@
1
+ import type { EditorDocument } from "@alwith/module-editor/core";
2
+ import type { MarkdownIntegration, PreviewContext, PreviewHost } from "@alwith/module-editor/previews";
3
+ import type { DriveContentHost } from "./host.js";
4
+ export declare function createDriveMarkdownIntegration(host: DriveContentHost, document: EditorDocument, context: PreviewContext): MarkdownIntegration;
5
+ export declare function drivePreviewIntegrations(host: DriveContentHost): Pick<PreviewHost, "createMarkdownIntegration" | "htmlIntegration">;
@@ -0,0 +1 @@
1
+ import{jsx as w,jsxs as O,Fragment as P}from"react/jsx-runtime";import{EditorStatus as j,editorViewCtx as J}from"@milkdown/core";import{collab as H,collabServiceCtx as A}from"@milkdown/plugin-collab";import{$prose as L,getMarkdown as U}from"@milkdown/utils";import{useSyncExternalStore as R}from"react";import{applyDiskMarkdown as T,colorFor as G,connectCollab as K,listCollaborators as Q,splitFrontmatter as _}from"./collab.js";import{commentAnchorsPlugin as X,createCommentAnchorBridge as Y}from"./comment-decorations.js";import{FrontmatterPanel as Z}from"./frontmatter-panel.js";import{htmlCommentBridge as ee}from"./html-bridge.js";import{HtmlComments as re}from"./html-comments.js";import{MarkdownComments as te}from"./markdown-comments.js";import{createVersionSaver as ae}from"./save-version.js";function ne(r,n,c){let u=crypto.randomUUID(),x=Y(),k=new Set,a={mode:n.dirty?"local":"probing",peers:[],frontmatter:"",canWrite:!c.readOnly,savingVersion:!1},b=n,i=!1,g=!1,d=null,f=null,v=null,C=null,D=null,h=r.generation,N=!1,V=()=>a.mode==="blocked",o=(e)=>{a={...a,...e};for(let t of k)t()},q=ae(r,n.path,()=>!i&&!c.readOnly&&a.mode==="live"&&a.canWrite,(e)=>{if(!i)o({savingVersion:e})}),m=async()=>{if(!g)return;g=!1,r.collaborationOwner(n.path,u,!1),await r.transport.request({type:"collabEnd",path:n.path,ownerId:u})},y=()=>{if(v)clearInterval(v),v=null;if(f){if(d!==null&&d.status===j.Created)d.action((e)=>e.get(A).disconnect());f.destroy(),f=null}},p=()=>{if(d!==null&&d.status===j.Created)d.action((e)=>e.get(J).setProps({editable:()=>!c.readOnly&&a.canWrite&&a.mode!=="probing"}))},I=(e)=>{y(),o({mode:"blocked",canWrite:!1,peers:[]}),p(),m().catch(r.onError),r.onError(e)},F=async()=>{let e=await r.transport.request({type:"collabSession",path:n.path,ownerId:u});if(e.type!=="collabSession")throw Error("Invalid collaboration heartbeat response");if(i||a.mode==="blocked"){g=e.data!==null,await m();return}if(!e.data)throw Error("Collaboration access is no longer available");if(JSON.stringify([e.data.serverUrl,e.data.room,e.data.token])!==D)throw Error("Drive collaboration credentials changed; reopen this document to reconnect");o({canWrite:e.data.canWrite}),p()};function B(){let e=R((t)=>(k.add(t),()=>k.delete(t)),()=>a,()=>a);return O(P,{children:[w(te,{bridge:x}),e.mode==="live"&&O(P,{children:[O("div",{className:"text-muted-foreground flex gap-2 text-xs",role:"status",children:[r.translate("editor.markdown.collab.live"),!e.canWrite&&r.translate("editor.markdown.collab.readOnly"),e.peers.map((t)=>w("span",{children:t.user.name},t.clientId))]}),w(Z,{frontmatter:e.frontmatter,readOnly:!e.canWrite||c.readOnly,saving:e.savingVersion,onChange:(t)=>{if(!d||!e.canWrite||c.readOnly)return;o({frontmatter:t}),c.onChange(t+d.action(U())),c.onSave()},onSaveVersion:()=>{q()}})]})]})}return{configure(e){e.use(H).use(L(()=>X(x)))},async ready(e){if(d=e,i)return;if(b.dirty){o({mode:"local"}),p();return}try{let t=await r.transport.subscribe((s)=>{if(i||a.mode==="blocked"||a.mode==="local")return;if(s.payload.type==="snapshot"&&(!s.payload.data.configured||!s.payload.data.running)){I(Error("Drive collaboration stopped; the current document is preserved read only"));return}if(a.mode==="live"&&h!==void 0&&s.generation!==h)h=s.generation,F().catch(I);else h=s.generation});if(i){t();return}C=t;let l=await r.transport.request({type:"collabSession",path:n.path,ownerId:u});if(l.type!=="collabSession")throw Error("Invalid collaboration session response");if(g=l.data!==null,g)r.collaborationOwner(n.path,u,!0);if(i||V()){await m();return}if(b.dirty){await m(),o({mode:"local"}),p();return}if(!l.data){o({mode:"local"}),p();return}D=JSON.stringify([l.data.serverUrl,l.data.room,l.data.token]),f=K(l.data,{name:r.userName,color:G(r.userName)});let E=await f.ready;if(i||V()){await m();return}if(!E){y(),await m(),o({mode:"local"}),p();return}if(b.dirty){y(),await m(),o({mode:"local"}),p();return}let{frontmatter:W,body:z}=_(b.text);N=!0,o({mode:"live",frontmatter:W,canWrite:l.data.canWrite});let S=f;e.action((s)=>{s.get(A).bindDoc(S.doc).setAwareness(S.awareness).applyTemplate(z).connect()});let M=()=>o({peers:Q(S.awareness)});S.awareness.on("change",M),M(),p(),v=setInterval(()=>{F().catch((s)=>{if(!i)I(s)})},300000)}catch(t){if(y(),await m().catch(r.onError),!i)o({mode:"local"}),p(),r.onError(t)}},dispose(){i=!0,C?.(),C=null,y(),m().catch(r.onError)},editable:()=>a.mode!=="probing"&&a.canWrite,serialize:(e)=>N?a.frontmatter+e:e,applyExternal(e,t){if(b=t,!f||a.mode!=="live")return!1;let{frontmatter:l,body:E}=_(t.text);if(o({frontmatter:l}),E!==e.action(U()))e.action((W)=>{if(!T(W,f,E,r.userName))throw Error("Collaboration binding is not ready")});return!0},render:()=>w(B,{})}}function we(r){return{createMarkdownIntegration:(n,c)=>ne(r,n,c),htmlIntegration:{transform:(n)=>`${n}<script>${ee.replaceAll(/<\/script/gi,String.raw`<\/script`)}</script>`,render:(n)=>w(re,{iframeRef:n})}}}export{ne as createDriveMarkdownIntegration,we as drivePreviewIntegrations};
@@ -0,0 +1,43 @@
1
+ import { type ReactNode } from "react";
2
+ import type { DriveController, RemoteId, RootInfo } from "../core.js";
3
+ import type { DriveLocale } from "../locales.js";
4
+ import type { DriveControls } from "../react.js";
5
+ import type { CondenseScope } from "./condense.js";
6
+ type KnownRoot = Pick<RootInfo, "projectId" | "name" | "localPath" | "drivePath">;
7
+ export declare function resolveDriveRoot<R extends KnownRoot>(path: string, roots: readonly R[]): {
8
+ root: R;
9
+ base: string;
10
+ } | null;
11
+ export declare function resolveCondenseScope(path: string, roots: readonly KnownRoot[]): CondenseScope | null;
12
+ export interface DriveFileActionHost {
13
+ writeClipboard: (text: string) => Promise<void>;
14
+ saveDocument: (path: string) => Promise<void>;
15
+ onSharing: (path: string) => void;
16
+ onPin: (path: string, fileId: RemoteId) => Promise<void>;
17
+ onCondense: (scope: CondenseScope) => void;
18
+ onMove: (path: string, kind: "file" | "directory") => void;
19
+ onError: (error: unknown) => void;
20
+ }
21
+ export declare function DriveFileActions({ path, kind, controller, controls: { Button }, locale, host }: {
22
+ path: string;
23
+ kind: "file" | "directory";
24
+ controller: DriveController;
25
+ controls: DriveControls;
26
+ locale?: DriveLocale;
27
+ host: DriveFileActionHost;
28
+ }): ReactNode;
29
+ export interface DriveMoveHost {
30
+ confirm: (message: string) => Promise<boolean>;
31
+ prepareMove: (path: string) => Promise<boolean>;
32
+ onMoved: (source: string, destination: string) => Promise<void>;
33
+ }
34
+ export declare function DriveMoveDialog({ path, kind, controller, controls: { Button }, locale, host, onClose }: {
35
+ path: string;
36
+ kind: "file" | "directory";
37
+ controller: DriveController;
38
+ controls: DriveControls;
39
+ locale?: DriveLocale;
40
+ host: DriveMoveHost;
41
+ onClose: () => void;
42
+ }): ReactNode;
43
+ export {};
@@ -0,0 +1 @@
1
+ import{jsx as i,Fragment as _,jsxs as f}from"react/jsx-runtime";import{useEffect as A,useEffectEvent as O,useRef as L,useState as m,useSyncExternalStore as q}from"react";import{driveFileDeepLink as K,driveFileWebUrl as V}from"./file-link.js";var N=(s)=>s.replaceAll("\\","/").replace(/\/+$/,"");function M(s,v){let t=N(s.replace(/\.yupcloud$/,"")),n=null;for(let g of v){if(!g.localPath||!g.drivePath.trim())continue;let r=N(g.localPath);if(t!==r&&!t.startsWith(`${r}/`))continue;if(!n||r.length>n.base.length)n={root:g,base:r}}return n}function G(s,v){let t=M(s,v);if(!t)return null;let n=N(s.replace(/\.yupcloud$/,"")).slice(t.base.length+1);return{projectId:t.root.projectId,projectName:t.root.name,scopePath:n||null}}function Y({path:s,kind:v,controller:t,controls:{Button:n},locale:g="en",host:r}){let S=q(t.subscribe,t.getSnapshot,t.getSnapshot),[h,o]=m(!1),j=L(!1),w=G(s,S.snapshot?.roots??[]),b=M(s,S.snapshot?.roots??[])?.root;if(!w||!b)return null;let y=s.replace(/\.yupcloud$/,""),c=(a)=>{if(j.current)return;j.current=!0,o(!0),a().catch(r.onError).finally(()=>{j.current=!1,o(!1)})},I=async(a)=>{let l=await t.request({type:"fileRemoteId",path:y});if(l.type!=="id")throw Error("Invalid Drive file identity response");if(l.data===null)throw Error(g==="zh-CN"?"文件尚未上传,暂时没有云端链接":"Upload this file before using its cloud link");await a(l.data)},d=(a,l)=>g==="zh-CN"?l:a;return f("div",{className:"alwith-drive-file-actions",children:[i(n,{disabled:h,onClick:()=>r.onSharing(y),children:d("Sharing and permissions","共享与权限")}),i(n,{disabled:h,onClick:()=>r.onCondense(w),children:d("Condense into knowledge","沉淀为知识")}),v==="file"&&f(_,{children:[i(n,{disabled:h,onClick:()=>c(()=>I(async(a)=>{let l=t.getSnapshot().snapshot?.webBaseUrl;if(!l)throw Error(d("Drive web address is unavailable","云盘网页地址不可用"));await r.writeClipboard(V(l,a))})),children:d("Copy web link","复制网页链接")}),i(n,{disabled:h,onClick:()=>c(()=>I((a)=>r.writeClipboard(K(a)))),children:d("Copy desktop link","复制桌面链接")}),i(n,{disabled:h,onClick:()=>c(()=>I((a)=>r.onPin(y,a))),children:d("Pin document","固定文档")}),b.canWrite&&!s.endsWith(".yupcloud")&&i(n,{disabled:h,onClick:()=>c(async()=>{await r.saveDocument(y),await t.request({type:"saveVersion",path:y})}),children:d("Save version now","立即保存版本")})]}),b.canWrite&&w.scopePath!==null&&i(n,{disabled:h,onClick:()=>r.onMove(s,v),children:d("Move to another project…","移动到其他项目…")})]})}function Z({path:s,kind:v,controller:t,controls:{Button:n},locale:g="en",host:r,onClose:S}){let h=q(t.subscribe,t.getSnapshot,t.getSnapshot),o=N(s.replace(/\.yupcloud$/,"")),j=M(o,h.snapshot?.roots??[])?.root,w=(h.snapshot?.roots??[]).filter((e)=>e.canWrite&&e.syncEnabled&&!e.cloudOnly&&e.kind!=="SKILL"&&e.drivePath.trim()&&e.localPath&&String(e.projectId)!==String(j?.projectId)),[b,y]=m(null),c=w.find((e)=>String(e.projectId)===b),[I,d]=m([]),[a,l]=m(""),[E,F]=m(!1),[P,R]=m(null),[k,W]=m(!1),[z,D]=m(null),x=L(!1),p=(e,u)=>g==="zh-CN"?u:e,T=O(()=>c);A(()=>{let e=!0;d([]),l(""),D(null);let u=T();if(!u)return;return F(!0),t.request({type:"cloudFolders",projectId:u.projectId}).then((C)=>{if(C.type!=="cloudFolders")throw Error("Invalid destination folders response");if(e)d(C.data)}).catch((C)=>{if(e)D(String(C))}).finally(()=>{if(e)F(!1)}),()=>{e=!1}},[t,b]);let U=async()=>{if(!c||x.current||P!==null)return;x.current=!0,W(!0),D(null);try{let e=o.slice(o.lastIndexOf("/")+1),u=`${N(c.localPath)}/${a?`${a}/`:""}${e}`,C=p(`Move ${v==="directory"?"this folder and all its contents":"this file"} from ${o} to ${u}? Cloud identity, history and comments are retained. The source entry will disappear after synchronization.`,`将${v==="directory"?"此目录及其全部内容":"此文件"}从 ${o} 移动到 ${u}?云端标识、历史与评论保留,同步后原位置条目会移除。`);if(!await r.confirm(C)||!await r.prepareMove(o))return;if((await t.request({type:"moveBetweenProjects",source:o,destination:u})).type!=="done")throw Error("Invalid Drive move response");R(u),await r.onMoved(o,u),S()}catch(e){D(String(e))}finally{x.current=!1,W(!1)}};return f("section",{className:"alwith-drive-move",role:"dialog","aria-label":p("Move to another project","移动到其他项目"),children:[f("div",{className:"alwith-drive-dialog-summary",children:[i("p",{children:p("Source","来源")}),i("p",{className:"alwith-drive-dialog-scope",children:o})]}),f("div",{className:"alwith-drive-dialog-notice",children:[i("h4",{children:p("Destination project","目标项目")}),i("div",{className:"alwith-drive-move-targets",children:w.map((e)=>i(n,{disabled:k,variant:b===String(e.projectId)?"outline":"ghost",onClick:()=>y(String(e.projectId)),children:e.name},String(e.projectId)))})]}),w.length===0&&i("p",{children:p("No other writable project is available","暂无其他可写项目")}),c&&f("div",{className:"alwith-drive-dialog-notice",children:[i("h4",{children:p("Destination folder","目标目录")}),f("div",{className:"alwith-drive-move-targets",children:[f(n,{disabled:k||E,variant:a===""?"outline":"ghost",onClick:()=>l(""),children:[c.name," /"]}),I.map((e)=>i(n,{disabled:k||E,variant:a===e.path?"outline":"ghost",onClick:()=>l(e.path),children:e.path},String(e.folderId)))]})]}),E&&i("p",{role:"status",children:p("Loading folders…","正在加载目录…")}),z&&i("p",{role:"alert",children:z}),P&&f("p",{role:"status",children:[p("Moved to","已移动到")," ",P]}),f("div",{className:"alwith-drive-dialog-actions",children:[i(n,{variant:"outline",disabled:k,onClick:S,children:p("Cancel","取消")}),i(n,{disabled:!c||k||E||P!==null,onClick:()=>void U(),children:p("Move","移动")})]})]})}export{Y as DriveFileActions,Z as DriveMoveDialog,G as resolveCondenseScope,M as resolveDriveRoot};
@@ -0,0 +1,4 @@
1
+ import type { RemoteId } from "../contract.js";
2
+ export declare function driveFileWebUrl(webBaseUrl: string, fileId: RemoteId): string;
3
+ export declare function driveFileDeepLink(fileId: RemoteId): string;
4
+ export declare function parseDriveFileDeepLinkPath(pathname: string): RemoteId | null;
@@ -0,0 +1 @@
1
+ function i(n,r){return`${n.replace(/\/+$/,"")}/file/${encodeURIComponent(String(r))}`}function o(n){return`alwith://yup-drive/file/${encodeURIComponent(String(n))}`}function u(n){let r=/^\/file\/([^/]+)$/.exec(n);if(!r)return null;let e;try{e=decodeURIComponent(r[1])}catch{return null}if(e==="")return null;if(!/^\d+$/.test(e))return e;let t=Number(e);return Number.isSafeInteger(t)?t:e}export{o as driveFileDeepLink,i as driveFileWebUrl,u as parseDriveFileDeepLinkPath};
@@ -0,0 +1,7 @@
1
+ export declare function FrontmatterPanel({ frontmatter, readOnly, saving, onChange, onSaveVersion }: {
2
+ frontmatter: string;
3
+ readOnly: boolean;
4
+ saving: boolean;
5
+ onChange: (next: string) => void;
6
+ onSaveVersion: () => void;
7
+ }): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ import{jsx as r,jsxs as d}from"react/jsx-runtime";import{ChevronRightIcon as S,PlusIcon as R,XIcon as B}from"lucide-react";import{useEffect as D,useRef as F,useState as p}from"react";import{buildFrontmatter as P,parseFrontmatterEntries as k,SUGGESTED_KEYS as _}from"./frontmatter.js";import{Button as G,cn as K,Input as C,useTranslation as T}from"./host.js";function A({frontmatter:n,readOnly:i,saving:x,onChange:y,onSaveVersion:E}){let{t:s}=T("common"),[f,h]=p(!1),u=F(0),j=(e)=>k(e).map((t)=>({id:u.current++,entry:t})),[a,c]=p(()=>j(n)),[v,g]=p(n);D(()=>{if(n===v)return;g(n),c(k(n).map((e)=>({id:u.current++,entry:e})))},[n,v]);let l=(e)=>{c(e);let t=P(e.map((o)=>o.entry));if(g(t),t!==n)y(t)},b=(e,t)=>{c((o)=>o.map((m)=>m.id===e?{...m,entry:{...m.entry,...t}}:m))},z=(e)=>l(a.filter((t)=>t.id!==e)),N=(e)=>{if(e&&a.some((t)=>t.entry.key===e))return;c((t)=>[...t,{id:u.current++,entry:{key:e,value:"",list:e==="topics"||e==="tags"}}]),h(!0)},w=a.map((e)=>e.entry),I=w.filter((e)=>e.raw===void 0).length;return d("div",{className:"border-border/60 mb-3 rounded-md border text-xs","data-testid":"frontmatter-panel",children:[d("div",{className:"flex items-center gap-1 px-2 py-1",children:[d("button",{type:"button",className:"text-muted-foreground hover:text-foreground flex flex-1 items-center gap-1 text-start",onClick:()=>h((e)=>!e),children:[r(S,{className:K("size-3.5 transition-transform",f&&"rotate-90")}),r("span",{className:"font-medium",children:s("editor.markdown.frontmatter.title")}),r("span",{className:"text-muted-foreground",children:s("editor.markdown.frontmatter.count",{count:I})})]}),r(G,{variant:"outline",size:"sm",className:"h-6 px-2 text-[11px]",disabled:i||x,onClick:E,children:x?s("editor.markdown.frontmatter.saving"):s("editor.markdown.frontmatter.saveVersion")})]}),f&&d("div",{className:"border-border/60 flex flex-col gap-1 border-t px-2 py-2",children:[a.map(({id:e,entry:t})=>t.raw!==void 0?r("pre",{className:"text-muted-foreground m-0 overflow-x-auto font-mono text-[11px] whitespace-pre",children:t.raw},e):d("div",{className:"flex items-center gap-1",children:[r(C,{className:"h-6 w-28 shrink-0 px-1.5 font-mono text-[11px]",value:t.key,disabled:i,placeholder:"key",onChange:(o)=>b(e,{key:o.target.value}),onBlur:()=>l(a)}),r(C,{className:"h-6 min-w-0 flex-1 px-1.5 text-[11px]",value:t.value,disabled:i,placeholder:t.list?s("editor.markdown.frontmatter.listPlaceholder"):"",onChange:(o)=>b(e,{value:o.target.value}),onBlur:()=>l(a),onKeyDown:(o)=>{if(o.key==="Enter")o.preventDefault(),l(a)}}),!i&&r("button",{type:"button",className:"text-muted-foreground hover:text-destructive flex size-5 shrink-0 items-center justify-center rounded",title:s("editor.markdown.frontmatter.remove"),onClick:()=>z(e),children:r(B,{className:"size-3"})})]},e)),!i&&d("div",{className:"flex flex-wrap items-center gap-1 pt-1",children:[r(R,{className:"text-muted-foreground size-3"}),_.filter((e)=>!w.some((t)=>t.key===e)).map((e)=>r("button",{type:"button",className:"text-muted-foreground hover:text-foreground hover:bg-accent rounded px-1.5 py-0.5 font-mono text-[11px]",onClick:()=>N(e),children:e},e)),r("button",{type:"button",className:"text-muted-foreground hover:text-foreground hover:bg-accent rounded px-1.5 py-0.5 text-[11px]",onClick:()=>N(""),children:s("editor.markdown.frontmatter.addCustom")})]})]})]})}export{A as FrontmatterPanel};
@@ -0,0 +1,9 @@
1
+ export type FrontmatterEntry = {
2
+ key: string;
3
+ value: string;
4
+ list: boolean;
5
+ raw?: string;
6
+ };
7
+ export declare function parseFrontmatterEntries(frontmatter: string): FrontmatterEntry[];
8
+ export declare function buildFrontmatter(entries: FrontmatterEntry[]): string;
9
+ export declare const SUGGESTED_KEYS: readonly ["title", "status", "owner", "topics", "department", "tags", "updated"];
@@ -0,0 +1,7 @@
1
+ var h=new Set(["topics","tags","keywords","owners","reviewers","专题","标签"]);function f(n){let t=n.trim();if(t.length>=2&&(t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")))return t.slice(1,-1);return t}function m(n){return n.split(",").map((t)=>f(t)).filter((t)=>t.length>0)}function w(n){let t=n.replace(/^---\r?\n/,"").replace(/(^|\r?\n)---[ \t]*(?:\r?\n|$)$/,"");if(!t.trim())return[];let e=t.split(/\r?\n/),i=[],s=0;while(s<e.length){let l=e[s];if(!l.trim()||l.trimStart().startsWith("#")){s++;continue}let c=/^([A-Za-z0-9_\-一-鿿㐀-䶿.]+)\s*:(.*)$/.exec(l);if(!c||/^\s/.test(l)){let u=i.at(-1);if(u?.raw!==void 0)u.raw+=`
2
+ ${l}`;else i.push({key:"",value:"",list:!1,raw:l});s++;continue}let a=c[1],o=c[2].trim();if(o===""&&e[s+1]!==void 0&&/^\s+-\s/.test(e[s+1])){let u=[],r=s+1;while(r<e.length&&/^\s+-\s/.test(e[r]))u.push(f(e[r].replace(/^\s+-\s?/,""))),r++;i.push({key:a,value:u.join("、"),list:!0}),s=r;continue}if(o===""||o==="|"||o===">"||o==="|-"||o===">-"){let u=l,r=s+1;while(r<e.length&&(/^\s+\S/.test(e[r])||!e[r].trim()))u+=`
3
+ ${e[r]}`,r++;i.push({key:a,value:"",list:!1,raw:u.replace(/\n+$/,"")}),s=r;continue}if(o.startsWith("[")&&o.endsWith("]"))i.push({key:a,value:m(o.slice(1,-1)).join("、"),list:!0});else i.push({key:a,value:f(o),list:h.has(a.toLowerCase())});s++}return i}function d(n){if(n==="")return!0;if(/^[\d.+-]/.test(n)&&!Number.isNaN(Number(n)))return!1;if(/^(true|false|null|yes|no|~)$/i.test(n))return!1;return/[:#[\]{}&*!|>'"%@`,]/.test(n)||/^\s|\s$/.test(n)}function p(n){let t=n.trim();if(!d(t))return t;return`"${t.replaceAll("\\",String.raw`\\`).replaceAll('"',String.raw`\"`)}"`}function g(n){let t=[];for(let e of n){if(e.raw!==void 0){t.push(e.raw);continue}let i=e.key.trim();if(!i)continue;if(e.list){let s=e.value.split(/[、,,]/).map((l)=>l.trim()).filter((l)=>l.length>0);t.push(`${i}: [${s.map(p).join(", ")}]`)}else t.push(`${i}: ${p(e.value)}`)}if(t.length===0)return"";return`---
4
+ ${t.join(`
5
+ `)}
6
+ ---
7
+ `}var S=["title","status","owner","topics","department","tags","updated"];export{S as SUGGESTED_KEYS,g as buildFrontmatter,w as parseFrontmatterEntries};
@@ -0,0 +1,49 @@
1
+ import { type ComponentProps, type ComponentType, type ReactNode } from "react";
2
+ import type { UserBrief } from "../contract.js";
3
+ import type { DriveTransport } from "../core.js";
4
+ export interface DriveContentHost {
5
+ transport: DriveTransport;
6
+ userName: string;
7
+ pushConnected: boolean;
8
+ generation?: number;
9
+ language: string;
10
+ translate: (key: string, values?: Record<string, unknown>) => string;
11
+ onError: (error: unknown) => void;
12
+ saveDocument: (path: string) => Promise<void>;
13
+ collaborationOwner: (path: string, ownerId: string, active: boolean) => void;
14
+ notify: {
15
+ error: (message: string, options?: {
16
+ description: string;
17
+ }) => void;
18
+ success: (message: string) => void;
19
+ };
20
+ searchUsers: (keyword: string) => Promise<UserBrief[]>;
21
+ controls: {
22
+ Button: ComponentType<ComponentProps<"button"> & {
23
+ variant?: "ghost" | "outline" | "default" | "destructive";
24
+ size?: "sm" | "icon" | "default";
25
+ }>;
26
+ Input: ComponentType<ComponentProps<"input">>;
27
+ Textarea: ComponentType<ComponentProps<"textarea">>;
28
+ Checkbox: ComponentType<{
29
+ checked: boolean;
30
+ onCheckedChange: (value: boolean | "indeterminate") => void;
31
+ }>;
32
+ };
33
+ }
34
+ export declare function DriveContentProvider({ host, children }: {
35
+ host: DriveContentHost;
36
+ children: ReactNode;
37
+ }): ReactNode;
38
+ export declare function useContentHost(): DriveContentHost;
39
+ export declare function useTranslation(_namespace: string): {
40
+ t: DriveContentHost["translate"];
41
+ i18n: {
42
+ language: string;
43
+ };
44
+ };
45
+ export declare function cn(...values: Array<string | false | null | undefined>): string;
46
+ export declare function Button(props: ComponentProps<DriveContentHost["controls"]["Button"]>): ReactNode;
47
+ export declare function Input(props: ComponentProps<"input">): ReactNode;
48
+ export declare function Textarea(props: ComponentProps<"textarea">): ReactNode;
49
+ export declare function Checkbox(props: ComponentProps<DriveContentHost["controls"]["Checkbox"]>): ReactNode;
@@ -0,0 +1 @@
1
+ import{jsx as n}from"react/jsx-runtime";import{createContext as u,useContext as c}from"react";var e=u(null);function a({host:t,children:o}){return n(e.Provider,{value:t,children:o})}function r(){let t=c(e);if(!t)throw Error("Drive content requires a host provider");return t}function l(t){let o=r();return{t:o.translate,i18n:{language:o.language}}}function x(...t){return t.filter(Boolean).join(" ")}function p(t){let o=r().controls.Button;return n(o,{...t})}function f(t){let o=r().controls.Input;return n(o,{...t})}function C(t){let o=r().controls.Textarea;return n(o,{...t})}function h(t){let o=r().controls.Checkbox;return n(o,{...t})}export{p as Button,h as Checkbox,a as DriveContentProvider,f as Input,C as Textarea,x as cn,r as useContentHost,l as useTranslation};
@@ -0,0 +1 @@
1
+ export declare const htmlCommentBridge = ";(function () {\n \"use strict\"\n if (window.__yupCommentBridge) return\n window.__yupCommentBridge = true\n\n var HIGHLIGHT_CLASS = \"yup-comment-highlight\"\n var MARKER_CLASS = \"yup-comment-marker\"\n var STYLE_ID = \"yup-comment-style\"\n var FLASH_CLASS = \"yup-comment-flash\"\n\n function post(message) {\n try {\n window.parent.postMessage(message, \"*\")\n } catch (error) { console.warn(\"Drive comment bridge could not notify its host\", error) }\n }\n\n function ensureStyle() {\n if (document.getElementById(STYLE_ID)) return\n var style = document.createElement(\"style\")\n style.id = STYLE_ID\n style.textContent = [\n \".\" + HIGHLIGHT_CLASS + \"{background:color-mix(in srgb,var(--primary,currentColor) 18%,transparent);border-bottom:2px solid var(--primary,currentColor);cursor:pointer;}\",\n \".\" + HIGHLIGHT_CLASS + \":hover{background:color-mix(in srgb,var(--primary,currentColor) 42%,transparent);}\",\n \".\" +\n MARKER_CLASS +\n \"{display:inline-flex;align-items:center;justify-content:center;min-width:15px;height:15px;\" +\n \"margin:0 2px;padding:0 3px;border-radius:8px;background:var(--primary,currentColor);color:var(--primary-foreground,Canvas);font-size:10px;\" +\n \"line-height:1;font-weight:600;font-style:normal;vertical-align:super;cursor:pointer;user-select:none;}\",\n \".\" + FLASH_CLASS + \"{animation:yup-comment-flash 1.2s ease-out;}\",\n \"@keyframes yup-comment-flash{0%{background:color-mix(in srgb,var(--primary,currentColor) 35%,transparent);}100%{background:color-mix(in srgb,var(--primary,currentColor) 18%,transparent);}}\"\n ].join(\"\")\n ;(document.head || document.documentElement).appendChild(style)\n }\n\n \n function flatten() {\n var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT)\n var segments = []\n var text = \"\"\n var node\n while ((node = walker.nextNode())) {\n var value = node.nodeValue || \"\"\n if (value.length === 0) continue\n segments.push({ start: text.length, end: text.length + value.length, node: node })\n text += value\n }\n return { text: text, segments: segments }\n }\n\n \n function clearMarkers() {\n var marks = document.querySelectorAll(\".\" + MARKER_CLASS)\n for (var i = 0; i < marks.length; i++) {\n if (marks[i].parentNode) marks[i].parentNode.removeChild(marks[i])\n }\n var spans = document.querySelectorAll(\".\" + HIGHLIGHT_CLASS)\n for (var j = 0; j < spans.length; j++) {\n var span = spans[j]\n var parent = span.parentNode\n if (!parent) continue\n while (span.firstChild) parent.insertBefore(span.firstChild, span)\n parent.removeChild(span)\n }\n document.body.normalize()\n }\n\n \n function wrapRange(segments, start, end, threadId) {\n var wrapped = []\n for (var i = 0; i < segments.length; i++) {\n var segment = segments[i]\n var from = Math.max(segment.start, start)\n var to = Math.min(segment.end, end)\n if (from >= to) continue\n try {\n var range = document.createRange()\n range.setStart(segment.node, from - segment.start)\n range.setEnd(segment.node, to - segment.start)\n var span = document.createElement(\"span\")\n span.className = HIGHLIGHT_CLASS\n span.setAttribute(\"data-thread-id\", threadId)\n range.surroundContents(span)\n wrapped.push(span)\n } catch (error) { console.warn(\"Drive comment quote changed during anchoring\", error) }\n }\n return wrapped\n }\n\n var applying = false\n\n \n function applyAnchors(anchors) {\n applying = true\n try {\n clearMarkers()\n ensureStyle()\n var flat = flatten()\n var anchored = []\n for (var i = 0; i < anchors.length; i++) {\n var anchor = anchors[i]\n var spans = wrapRange(flat.segments, anchor.start, anchor.end, String(anchor.threadId))\n if (spans.length === 0) continue\n var marker = document.createElement(\"span\")\n marker.className = MARKER_CLASS\n marker.setAttribute(\"data-thread-id\", String(anchor.threadId))\n marker.textContent = String(anchor.index)\n var last = spans[spans.length - 1]\n if (last.parentNode) last.parentNode.insertBefore(marker, last.nextSibling)\n anchored.push(anchor.threadId)\n }\n post({ type: \"yup:anchored\", threadIds: anchored })\n } finally {\n applying = false\n }\n }\n\n function scrollToThread(threadId) {\n var target = document.querySelector(\".\" + HIGHLIGHT_CLASS + '[data-thread-id=\"' + threadId + '\"]')\n if (!target) return\n target.scrollIntoView({ behavior: \"smooth\", block: \"center\" })\n target.classList.remove(FLASH_CLASS)\n void target.offsetWidth // Restart the highlight animation.\n target.classList.add(FLASH_CLASS)\n }\n\n document.addEventListener(\"click\", function (event) {\n var node = event.target\n while (node && node !== document.body) {\n if (node.classList && (node.classList.contains(MARKER_CLASS) || node.classList.contains(HIGHLIGHT_CLASS))) {\n post({ type: \"yup:marker-click\", threadId: node.getAttribute(\"data-thread-id\") })\n return\n }\n node = node.parentNode\n }\n })\n\n document.addEventListener(\"selectionchange\", function () {\n if (applying) return\n var selection = document.getSelection()\n if (!selection || selection.isCollapsed || selection.rangeCount === 0) {\n post({ type: \"yup:selection\", quote: null })\n return\n }\n var quote = selection.toString().trim()\n if (quote.length === 0 || quote.length > 1000) {\n post({ type: \"yup:selection\", quote: null })\n return\n }\n var range = selection.getRangeAt(0)\n var offset = 0\n var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT)\n var node\n var located = false\n while ((node = walker.nextNode())) {\n if (node === range.startContainer) {\n offset += range.startOffset\n located = true\n break\n }\n offset += (node.nodeValue || \"\").length\n }\n var rect = range.getBoundingClientRect()\n post({\n type: \"yup:selection\",\n quote: quote,\n quoteOffset: located ? offset : null,\n rect: { top: rect.top, left: rect.left, bottom: rect.bottom, right: rect.right }\n })\n })\n\n window.addEventListener(\"message\", function (event) {\n if (event.source !== window.parent) return\n var data = event.data\n if (!data || typeof data.type !== \"string\") return\n if (data.type === \"yup:anchors\") applyAnchors(data.anchors || [])\n else if (data.type === \"yup:scroll-to\") scrollToThread(String(data.threadId))\n else if (data.type === \"yup:flatten\") post({ type: \"yup:flat\", text: flatten().text })\n })\n\n function announce() {\n post({ type: \"yup:ready\", text: flatten().text })\n }\n\n if (document.readyState === \"loading\") document.addEventListener(\"DOMContentLoaded\", announce)\n else announce()\n})()\n";
@@ -0,0 +1,187 @@
1
+ var n=`;(function () {
2
+ "use strict"
3
+ if (window.__yupCommentBridge) return
4
+ window.__yupCommentBridge = true
5
+
6
+ var HIGHLIGHT_CLASS = "yup-comment-highlight"
7
+ var MARKER_CLASS = "yup-comment-marker"
8
+ var STYLE_ID = "yup-comment-style"
9
+ var FLASH_CLASS = "yup-comment-flash"
10
+
11
+ function post(message) {
12
+ try {
13
+ window.parent.postMessage(message, "*")
14
+ } catch (error) { console.warn("Drive comment bridge could not notify its host", error) }
15
+ }
16
+
17
+ function ensureStyle() {
18
+ if (document.getElementById(STYLE_ID)) return
19
+ var style = document.createElement("style")
20
+ style.id = STYLE_ID
21
+ style.textContent = [
22
+ "." + HIGHLIGHT_CLASS + "{background:color-mix(in srgb,var(--primary,currentColor) 18%,transparent);border-bottom:2px solid var(--primary,currentColor);cursor:pointer;}",
23
+ "." + HIGHLIGHT_CLASS + ":hover{background:color-mix(in srgb,var(--primary,currentColor) 42%,transparent);}",
24
+ "." +
25
+ MARKER_CLASS +
26
+ "{display:inline-flex;align-items:center;justify-content:center;min-width:15px;height:15px;" +
27
+ "margin:0 2px;padding:0 3px;border-radius:8px;background:var(--primary,currentColor);color:var(--primary-foreground,Canvas);font-size:10px;" +
28
+ "line-height:1;font-weight:600;font-style:normal;vertical-align:super;cursor:pointer;user-select:none;}",
29
+ "." + FLASH_CLASS + "{animation:yup-comment-flash 1.2s ease-out;}",
30
+ "@keyframes yup-comment-flash{0%{background:color-mix(in srgb,var(--primary,currentColor) 35%,transparent);}100%{background:color-mix(in srgb,var(--primary,currentColor) 18%,transparent);}}"
31
+ ].join("")
32
+ ;(document.head || document.documentElement).appendChild(style)
33
+ }
34
+
35
+
36
+ function flatten() {
37
+ var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT)
38
+ var segments = []
39
+ var text = ""
40
+ var node
41
+ while ((node = walker.nextNode())) {
42
+ var value = node.nodeValue || ""
43
+ if (value.length === 0) continue
44
+ segments.push({ start: text.length, end: text.length + value.length, node: node })
45
+ text += value
46
+ }
47
+ return { text: text, segments: segments }
48
+ }
49
+
50
+
51
+ function clearMarkers() {
52
+ var marks = document.querySelectorAll("." + MARKER_CLASS)
53
+ for (var i = 0; i < marks.length; i++) {
54
+ if (marks[i].parentNode) marks[i].parentNode.removeChild(marks[i])
55
+ }
56
+ var spans = document.querySelectorAll("." + HIGHLIGHT_CLASS)
57
+ for (var j = 0; j < spans.length; j++) {
58
+ var span = spans[j]
59
+ var parent = span.parentNode
60
+ if (!parent) continue
61
+ while (span.firstChild) parent.insertBefore(span.firstChild, span)
62
+ parent.removeChild(span)
63
+ }
64
+ document.body.normalize()
65
+ }
66
+
67
+
68
+ function wrapRange(segments, start, end, threadId) {
69
+ var wrapped = []
70
+ for (var i = 0; i < segments.length; i++) {
71
+ var segment = segments[i]
72
+ var from = Math.max(segment.start, start)
73
+ var to = Math.min(segment.end, end)
74
+ if (from >= to) continue
75
+ try {
76
+ var range = document.createRange()
77
+ range.setStart(segment.node, from - segment.start)
78
+ range.setEnd(segment.node, to - segment.start)
79
+ var span = document.createElement("span")
80
+ span.className = HIGHLIGHT_CLASS
81
+ span.setAttribute("data-thread-id", threadId)
82
+ range.surroundContents(span)
83
+ wrapped.push(span)
84
+ } catch (error) { console.warn("Drive comment quote changed during anchoring", error) }
85
+ }
86
+ return wrapped
87
+ }
88
+
89
+ var applying = false
90
+
91
+
92
+ function applyAnchors(anchors) {
93
+ applying = true
94
+ try {
95
+ clearMarkers()
96
+ ensureStyle()
97
+ var flat = flatten()
98
+ var anchored = []
99
+ for (var i = 0; i < anchors.length; i++) {
100
+ var anchor = anchors[i]
101
+ var spans = wrapRange(flat.segments, anchor.start, anchor.end, String(anchor.threadId))
102
+ if (spans.length === 0) continue
103
+ var marker = document.createElement("span")
104
+ marker.className = MARKER_CLASS
105
+ marker.setAttribute("data-thread-id", String(anchor.threadId))
106
+ marker.textContent = String(anchor.index)
107
+ var last = spans[spans.length - 1]
108
+ if (last.parentNode) last.parentNode.insertBefore(marker, last.nextSibling)
109
+ anchored.push(anchor.threadId)
110
+ }
111
+ post({ type: "yup:anchored", threadIds: anchored })
112
+ } finally {
113
+ applying = false
114
+ }
115
+ }
116
+
117
+ function scrollToThread(threadId) {
118
+ var target = document.querySelector("." + HIGHLIGHT_CLASS + '[data-thread-id="' + threadId + '"]')
119
+ if (!target) return
120
+ target.scrollIntoView({ behavior: "smooth", block: "center" })
121
+ target.classList.remove(FLASH_CLASS)
122
+ void target.offsetWidth // Restart the highlight animation.
123
+ target.classList.add(FLASH_CLASS)
124
+ }
125
+
126
+ document.addEventListener("click", function (event) {
127
+ var node = event.target
128
+ while (node && node !== document.body) {
129
+ if (node.classList && (node.classList.contains(MARKER_CLASS) || node.classList.contains(HIGHLIGHT_CLASS))) {
130
+ post({ type: "yup:marker-click", threadId: node.getAttribute("data-thread-id") })
131
+ return
132
+ }
133
+ node = node.parentNode
134
+ }
135
+ })
136
+
137
+ document.addEventListener("selectionchange", function () {
138
+ if (applying) return
139
+ var selection = document.getSelection()
140
+ if (!selection || selection.isCollapsed || selection.rangeCount === 0) {
141
+ post({ type: "yup:selection", quote: null })
142
+ return
143
+ }
144
+ var quote = selection.toString().trim()
145
+ if (quote.length === 0 || quote.length > 1000) {
146
+ post({ type: "yup:selection", quote: null })
147
+ return
148
+ }
149
+ var range = selection.getRangeAt(0)
150
+ var offset = 0
151
+ var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT)
152
+ var node
153
+ var located = false
154
+ while ((node = walker.nextNode())) {
155
+ if (node === range.startContainer) {
156
+ offset += range.startOffset
157
+ located = true
158
+ break
159
+ }
160
+ offset += (node.nodeValue || "").length
161
+ }
162
+ var rect = range.getBoundingClientRect()
163
+ post({
164
+ type: "yup:selection",
165
+ quote: quote,
166
+ quoteOffset: located ? offset : null,
167
+ rect: { top: rect.top, left: rect.left, bottom: rect.bottom, right: rect.right }
168
+ })
169
+ })
170
+
171
+ window.addEventListener("message", function (event) {
172
+ if (event.source !== window.parent) return
173
+ var data = event.data
174
+ if (!data || typeof data.type !== "string") return
175
+ if (data.type === "yup:anchors") applyAnchors(data.anchors || [])
176
+ else if (data.type === "yup:scroll-to") scrollToThread(String(data.threadId))
177
+ else if (data.type === "yup:flatten") post({ type: "yup:flat", text: flatten().text })
178
+ })
179
+
180
+ function announce() {
181
+ post({ type: "yup:ready", text: flatten().text })
182
+ }
183
+
184
+ if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", announce)
185
+ else announce()
186
+ })()
187
+ `;export{n as htmlCommentBridge};
@@ -0,0 +1,5 @@
1
+ export declare function HtmlComments({ iframeRef }: {
2
+ iframeRef: {
3
+ current: HTMLIFrameElement | null;
4
+ };
5
+ }): import("react").JSX.Element | null;
@@ -0,0 +1 @@
1
+ import{jsx as h,Fragment as b}from"react/jsx-runtime";import{useCallback as q,useEffect as x,useRef as I,useState as c}from"react";import{locateQuote as v}from"./comment-anchors.js";import{SelectionCommentButton as E}from"./comment-drawer.js";import{useCommentAnchoring as S}from"./comment-surface.js";var T=1000;function H({iframeRef:r}){let[l,i]=c(null),[p,m]=c(null),[w,O]=c(null),[A,C]=c(new Set),y=I(null),g=I([]),o=q((n)=>{r.current?.contentWindow?.postMessage(n,"*")},[r]),{source:F,anchors:a}=S({selection:p,onSelectionUsed:()=>m(null),onFocusQuote:(n)=>o({type:"yup:scroll-to",threadId:n}),focusRequest:w,anchoredThreadIds:A}),d=F.context;g.current=a;let u=q((n)=>{let s=y.current;if(s===null)return;let e=n.flatMap((t)=>{let f=v(s,t.quote,t.quoteOffset);if(f===null)return[];return[{threadId:t.threadId,index:t.index,start:f.start,end:f.end}]});o({type:"yup:anchors",anchors:e})},[o]);if(x(()=>{if(d===null)return;let n=(s)=>{if(s.source!==r.current?.contentWindow)return;let e=s.data;if(e===null||typeof e!=="object"||typeof e.type!=="string")return;switch(e.type){case"yup:ready":case"yup:flat":if(typeof e.text!=="string")return;y.current=e.text,u(g.current);return;case"yup:anchored":if(!Array.isArray(e.threadIds)||!e.threadIds.every((t)=>typeof t==="string"))return;C(new Set(e.threadIds));return;case"yup:marker-click":if(typeof e.threadId!=="string")return;O((t)=>({threadId:e.threadId,nonce:(t?.nonce??0)+1}));return;case"yup:selection":{if(typeof e.quote!=="string"||e.quote.length===0||e.quote.length>T||!e.rect||!Number.isFinite(e.rect.top)||!Number.isFinite(e.rect.left)||e.quoteOffset!=null&&(!Number.isInteger(e.quoteOffset)||e.quoteOffset<0)){i(null);return}let t=r.current?.getBoundingClientRect();if(t===void 0)return;i({quote:e.quote,quoteOffset:e.quoteOffset??null,rect:{top:e.rect.top+t.top,left:e.rect.left+t.left}});return}}};return window.addEventListener("message",n),o({type:"yup:flatten"}),()=>window.removeEventListener("message",n)},[d,r,u,o]),x(()=>{u(a)},[u,a]),d===null)return null;return h(b,{children:l!==null&&p===null&&h(E,{rect:l.rect,onClick:()=>{m(l),i(null)}})})}export{H as HtmlComments};
@@ -0,0 +1,4 @@
1
+ import { type CommentAnchorBridge } from "./comment-decorations.js";
2
+ export declare function MarkdownComments({ bridge }: {
3
+ bridge: CommentAnchorBridge;
4
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,2 @@
1
+ import{jsx as g,Fragment as q}from"react/jsx-runtime";import{useCallback as w,useEffect as m,useState as r}from"react";import{charIndexAt as E,flattenDocument as L,pushAnchors as y}from"./comment-decorations.js";import{SelectionCommentButton as D}from"./comment-drawer.js";import{useCommentAnchoring as F}from"./comment-surface.js";var I=1000;function H({bridge:t}){let[l,c]=r(null),[f,h]=r(null),[A,S]=r(null),[k,x]=r(new Set),M=w((o)=>{let n=t.view;if(n===null)return;let e=n.dom.querySelector(`.yup-comment-highlight[data-thread-id="${o}"]`);if(e===null)return;e.scrollIntoView({behavior:"smooth",block:"center"}),e.classList.remove("yup-comment-flash"),e.offsetWidth,e.classList.add("yup-comment-flash")},[t]),{source:O,anchors:d}=F({selection:f,onSelectionUsed:()=>h(null),onFocusQuote:M,focusRequest:A,anchoredThreadIds:k}),u=O.context,C=w((o)=>{S((n)=>({threadId:o,nonce:(n?.nonce??0)+1}))},[]);if(m(()=>(t.onMarkerClick=C,t.onAnchoredChange=(o)=>x(new Set(o)),()=>{t.onMarkerClick=()=>{},t.onAnchoredChange=()=>{}}),[t,C]),m(()=>{if(t.view===null)return;y(t.view,d)},[t,d]),m(()=>{if(u===null)return;let o=()=>{let n=t.view;if(n===null)return;let e=document.getSelection();if(e===null||e.isCollapsed||e.rangeCount===0){c(null);return}let s=e.getRangeAt(0);if(!n.dom.contains(s.commonAncestorContainer)){c(null);return}let a=n.posAtDOM(s.startContainer,s.startOffset),p=n.posAtDOM(s.endContainer,s.endOffset);if(a>=p){c(null);return}let i=n.state.doc.textBetween(a,p,`
2
+ `).trim();if(i.length===0||i.length>I){c(null);return}let{segments:T}=L(n.state.doc),v=s.getBoundingClientRect();c({quote:i,quoteOffset:E(T,a),rect:{top:v.top,left:v.left}})};return document.addEventListener("selectionchange",o),()=>document.removeEventListener("selectionchange",o)},[u,t]),u===null)return null;return g(q,{children:l!==null&&f===null&&g(D,{rect:l.rect,onClick:()=>{h(l),c(null)}})})}export{H as MarkdownComments};
@@ -0,0 +1,10 @@
1
+ import type { UserBrief } from "../contract.js";
2
+ import { type MentionQuery } from "./comment-mentions.js";
3
+ export declare function MentionPicker({ mention, onPick }: {
4
+ mention: MentionQuery | null;
5
+ onPick: (person: UserBrief) => void;
6
+ }): import("react").JSX.Element | null;
7
+ export declare function MentionedBody({ body, mentions }: {
8
+ body: string;
9
+ mentions?: UserBrief[] | null;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ import{jsx as s,jsxs as y,Fragment as p}from"react/jsx-runtime";import{useEffect as h,useMemo as b,useState as f}from"react";import{createDebouncedSearch as v,mentionNameOf as x}from"./comment-mentions.js";import{cn as N,useContentHost as w,useTranslation as M}from"./host.js";function k({mention:a,onPick:m}){let{t:i}=M("common"),[c,o]=f([]),[n,e]=f(0),t=w(),r=b(()=>v(t.searchUsers,o,t.onError),[t.searchUsers,t.onError]);h(()=>()=>r.cancel(),[r]);let u=a?.query??null;if(h(()=>{if(u===null){r.cancel(),o([]);return}e(0),r.query(u)},[u,r]),a===null)return null;return s("div",{"data-testid":"mention-picker",className:"bg-popover mt-1 max-h-40 overflow-y-auto rounded-md border p-1 shadow-md",children:c.length===0?s("div",{className:"text-muted-foreground px-2 py-1.5 text-[11px]",children:a.query===""?i("drive.comments.mention.hint"):i("drive.comments.mention.empty")}):c.map((l,d)=>y("button",{type:"button",className:N("flex w-full items-baseline gap-1.5 rounded px-2 py-1 text-start text-[11px]",d===n?"bg-accent":"hover:bg-accent/60"),onMouseEnter:()=>e(d),onMouseDown:(g)=>{g.preventDefault(),m(l)},children:[s("span",{className:"truncate font-medium",children:x(l)}),s("span",{className:"text-muted-foreground truncate text-[10px]",children:l.employeeNo})]},String(l.id)))})}function D({body:a,mentions:m}){let i=(m??[]).map(x).filter((e)=>e.length>0);if(i.length===0)return s(p,{children:a});let c=[...new Set(i)].toSorted((e,t)=>t.length-e.length),o=[],n=a;while(n.length>0){let e=null;for(let t of c){let r=n.indexOf(`@${t}`);if(r===-1)continue;if(e===null||r<e.index)e={index:r,name:t}}if(e===null)break;if(e.index>0)o.push(n.slice(0,e.index));o.push({name:e.name}),n=n.slice(e.index+1+e.name.length)}if(n.length>0)o.push(n);return s(p,{children:o.map((e,t)=>typeof e==="string"?s("span",{children:e},t):s("span",{"data-testid":"mention-chip",className:"bg-primary/15 text-primary rounded px-0.5 font-medium",children:`@${e.name}`},t))})}export{k as MentionPicker,D as MentionedBody};
@@ -0,0 +1,2 @@
1
+ import type { DriveContentHost } from "./host.js";
2
+ export declare function createVersionSaver(host: DriveContentHost, path: string, canSave: () => boolean, onSaving: (saving: boolean) => void): () => Promise<void>;
@@ -0,0 +1 @@
1
+ function o(e,n,a,i){let t=!1;return async()=>{if(t||!a())return;t=!0,i(!0);try{if(await e.saveDocument(n),!a())throw Error("Drive write access changed while saving the document");let r=await e.transport.request({type:"saveVersion",path:n});if(r.type!=="id")throw Error("Invalid Drive save-version response");if(r.data===null)e.notify.error(e.translate("editor.markdown.frontmatter.notInDrive"));else e.notify.success(e.translate("editor.markdown.frontmatter.saved"))}catch(r){e.notify.error(e.translate("editor.markdown.frontmatter.saveFailed"),{description:String(r)})}finally{t=!1,i(!1)}}}export{o as createVersionSaver};
@@ -0,0 +1,2 @@
1
+ import { type DriveLocale } from "../locales.js";
2
+ export declare function driveContentTranslator(locale: DriveLocale): (key: string, values?: Record<string, unknown>) => string;
@@ -0,0 +1 @@
1
+ import{driveTranslator as s}from"../locales.js";var m={en:{"frontmatter.title":"Properties","frontmatter.count":"{{count}} items","frontmatter.saveVersion":"Save version now","frontmatter.saving":"Saving…","frontmatter.saved":"Saved as a new version","frontmatter.saveFailed":"Failed to save version","frontmatter.notInDrive":"This file is not in the Drive index","frontmatter.listPlaceholder":"Separate values with 、","frontmatter.remove":"Remove property","frontmatter.addCustom":"Custom…","collab.live":"Live collaboration","collab.readOnly":"Read only","collab.alone":"No other collaborators yet"},"zh-CN":{"frontmatter.title":"属性","frontmatter.count":"{{count}} 项","frontmatter.saveVersion":"立即保存版本","frontmatter.saving":"保存中…","frontmatter.saved":"已保存为新版本","frontmatter.saveFailed":"保存版本失败","frontmatter.notInDrive":"此文件不在云盘索引中","frontmatter.listPlaceholder":"使用顿号分隔多个值","frontmatter.remove":"移除属性","frontmatter.addCustom":"自定义…","collab.live":"实时协作","collab.readOnly":"只读","collab.alone":"暂无其他协作者"}};function v(o){let l=s(o);return(r,n={})=>{if(!r.startsWith("editor.markdown."))return l(r,Object.fromEntries(Object.entries(n).map(([i,t])=>[i,typeof t==="number"?t:String(t)])));let a=m[o][r.slice(16)];if(!a)throw Error(`Missing Drive content translation: ${r}`);return a.replaceAll(/\{\{(\w+)\}\}/g,(i,t)=>{let e=n[t];return typeof e==="string"||typeof e==="number"?String(e):`{{${t}}}`})}}export{v as driveContentTranslator};
@@ -0,0 +1,12 @@
1
+ import type { CommentContext, CreateCommentRequest, FileComment, RemoteId } from "../contract.js";
2
+ export interface FileComments {
3
+ context: CommentContext | null;
4
+ comments: FileComment[];
5
+ loading: boolean;
6
+ reload: () => Promise<void>;
7
+ create: (request: CreateCommentRequest) => Promise<void>;
8
+ update: (commentId: RemoteId, body: string) => Promise<void>;
9
+ remove: (commentId: RemoteId) => Promise<void>;
10
+ apply: (commentId: RemoteId) => Promise<void>;
11
+ }
12
+ export declare function useFileComments(path: string): FileComments;
@@ -0,0 +1 @@
1
+ import{useCallback as v,useEffect as I,useRef as x,useState as l}from"react";import{useContentHost as g}from"./host.js";function S(c){let{transport:e,onError:s}=g(),[m,f]=l({path:c,context:null}),d=m.path===c?m.context:null,[h,p]=l([]),[C,u]=l(!0),i=x(0),y=x(0),o=d?.fileId??null,a=v(async()=>{if(o===null)return;let t=i.current,r=++y.current,n=await e.request({type:"comments",fileId:o});if(n.type!=="comments")throw Error("Invalid comments response");if(t===i.current&&r===y.current)p(n.data)},[e,o]);return I(()=>{let t=i,r=++i.current;return f({path:c,context:null}),p([]),u(!0),e.request({type:"commentContext",path:c}).then((n)=>{if(n.type!=="commentContext")throw Error("Invalid comment context response");if(r!==i.current)return;if(f({path:c,context:n.data}),n.data===null)u(!1)}).catch((n)=>{if(r===i.current)u(!1),s(n)}),()=>{t.current++}},[c,e,s]),I(()=>{if(o===null)return;let t=!1,r=crypto.randomUUID(),n;return(async()=>{let w=await e.subscribe((q)=>{if(q.payload.type==="comment"&&String(q.payload.data.fileId)===String(o))a().catch(s)});if(t){w();return}if(n=w,await e.request({type:"commentWatch",ownerId:r,fileIds:[o]}),t){await e.request({type:"commentWatch",ownerId:r,fileIds:[]});return}await a()})().catch(s).finally(()=>{if(!t)u(!1)}),()=>{t=!0,n?.(),e.request({type:"commentWatch",ownerId:r,fileIds:[]}).catch(s)}},[o,e,a,s]),{context:d,comments:h,loading:C,reload:a,create:async(t)=>{if(o===null)throw Error("The file is not available for comments");await e.request({type:"commentCreate",fileId:o,request:t}),await a()},update:async(t,r)=>{await e.request({type:"commentUpdate",commentId:t,body:r}),await a()},remove:async(t)=>{await e.request({type:"commentDelete",commentId:t}),await a()},apply:async(t)=>{await e.request({type:"commentApply",commentId:t}),await a()}}}export{S as useFileComments};
@@ -0,0 +1,11 @@
1
+ import type { RemoteId } from "../contract.js";
2
+ export declare const YUPLINK_EXTENSION = ".yuplink";
3
+ export declare function isYuplinkName(name: string): boolean;
4
+ export declare function yuplinkDisplayName(name: string): string;
5
+ export interface YuplinkTarget {
6
+ targetFileId: RemoteId;
7
+ name: string;
8
+ webUrl: string;
9
+ }
10
+ export declare function parseYuplink(text: string): YuplinkTarget | null;
11
+ export declare function buildYuplinkContent(target: YuplinkTarget): string;
@@ -0,0 +1,2 @@
1
+ var p=".yuplink";function u(n){return n.toLowerCase().endsWith(".yuplink")}function s(n){return u(n)?n.slice(0,-8):n}function a(n){let r;try{r=JSON.parse(n)}catch{return null}if(r===null||typeof r!=="object"||Array.isArray(r))return null;let l=r,{targetFileId:e,name:t,webUrl:i}=l;if(!(typeof e==="number"&&Number.isFinite(e)||typeof e==="string"&&e!==""))return null;if(typeof t!=="string"||t==="")return null;if(typeof i!=="string")return null;return{targetFileId:e,name:t,webUrl:i}}function f(n){return`${JSON.stringify({targetFileId:n.targetFileId,name:n.name,webUrl:n.webUrl},null,2)}
2
+ `}export{p as YUPLINK_EXTENSION,f as buildYuplinkContent,u as isYuplinkName,a as parseYuplink,s as yuplinkDisplayName};
@@ -0,0 +1,64 @@
1
+ .ProseMirror-yjs-cursor {
2
+ position: relative;
3
+ margin: 0 -1px;
4
+ border-inline: 1px solid;
5
+ word-break: normal;
6
+ pointer-events: none;
7
+ }
8
+ .ProseMirror-yjs-cursor > div {
9
+ position: absolute;
10
+ top: -1.4em;
11
+ left: -1px;
12
+ padding: 1px 4px;
13
+ border-radius: 3px 3px 3px 0;
14
+ font-size: 11px;
15
+ font-style: normal;
16
+ font-weight: 600;
17
+ line-height: normal;
18
+ color: var(--primary-foreground);
19
+ white-space: nowrap;
20
+ user-select: none;
21
+ }
22
+ .ProseMirror .yup-comment-highlight {
23
+ background: color-mix(in srgb, var(--primary) 18%, transparent);
24
+ border-bottom: 2px solid var(--primary);
25
+ cursor: pointer;
26
+ }
27
+ .ProseMirror .yup-comment-marker {
28
+ display: inline-flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ min-width: 15px;
32
+ height: 15px;
33
+ margin: 0 2px;
34
+ padding: 0 3px;
35
+ border-radius: 8px;
36
+ background: var(--primary);
37
+ color: var(--primary-foreground);
38
+ font-size: 10px;
39
+ font-weight: 600;
40
+ font-style: normal;
41
+ line-height: 1;
42
+ vertical-align: super;
43
+ cursor: pointer;
44
+ user-select: none;
45
+ }
46
+ .ProseMirror .yup-comment-flash {
47
+ animation: yup-comment-flash 1.2s ease-out;
48
+ }
49
+ @keyframes yup-comment-flash {
50
+ from {
51
+ background: color-mix(in srgb, var(--primary) 45%, transparent);
52
+ }
53
+ to {
54
+ background: color-mix(in srgb, var(--primary) 18%, transparent);
55
+ }
56
+ }
57
+ .alwith-drive-condense {
58
+ padding: 1rem;
59
+ max-height: 75vh;
60
+ overflow: auto;
61
+ }
62
+ .alwith-drive-condense button {
63
+ margin: 0.25rem;
64
+ }
@@ -0,0 +1,10 @@
1
+ export { DriveContentProvider, type DriveContentHost } from "./content/host.js";
2
+ export { CommentSurface, commentPathOf } from "./content/comment-surface.js";
3
+ export { drivePreviewIntegrations, createDriveMarkdownIntegration } from "./content/editor.js";
4
+ export { parseYuplink, buildYuplinkContent, yuplinkDisplayName, isYuplinkName, type YuplinkTarget } from "./content/yuplink.js";
5
+ export { driveFileWebUrl, driveFileDeepLink, parseDriveFileDeepLinkPath } from "./content/file-link.js";
6
+ export { splitFrontmatter } from "./content/collab.js";
7
+ export { DriveCondense, type DriveCondenseProps, type CondenseScope } from "./content/condense.js";
8
+ export { driveContentTranslator } from "./content/translations.js";
9
+ export { DriveFileActions, DriveMoveDialog, resolveDriveRoot, resolveCondenseScope, type DriveFileActionHost, type DriveMoveHost } from "./content/file-actions.js";
10
+ export { ChatCondenseEntry, type ChatCondenseEntryProps, type CondenseSnoozeHost } from "./content/chat-condense.js";
@@ -0,0 +1 @@
1
+ import{DriveContentProvider as o}from"./content/host.js";import{CommentSurface as i,commentPathOf as n}from"./content/comment-surface.js";import{drivePreviewIntegrations as a,createDriveMarkdownIntegration as m}from"./content/editor.js";import{parseYuplink as v,buildYuplinkContent as s,yuplinkDisplayName as f,isYuplinkName as D}from"./content/yuplink.js";import{driveFileWebUrl as x,driveFileDeepLink as C,parseDriveFileDeepLinkPath as k}from"./content/file-link.js";import{splitFrontmatter as c}from"./content/collab.js";import{DriveCondense as P}from"./content/condense.js";import{driveContentTranslator as h}from"./content/translations.js";import{DriveFileActions as Y,DriveMoveDialog as b,resolveDriveRoot as w,resolveCondenseScope as I}from"./content/file-actions.js";import{ChatCondenseEntry as M}from"./content/chat-condense.js";export{M as ChatCondenseEntry,i as CommentSurface,P as DriveCondense,o as DriveContentProvider,Y as DriveFileActions,b as DriveMoveDialog,s as buildYuplinkContent,n as commentPathOf,m as createDriveMarkdownIntegration,h as driveContentTranslator,C as driveFileDeepLink,x as driveFileWebUrl,a as drivePreviewIntegrations,D as isYuplinkName,k as parseDriveFileDeepLinkPath,v as parseYuplink,I as resolveCondenseScope,w as resolveDriveRoot,c as splitFrontmatter,f as yuplinkDisplayName};