@tutti-os/workspace-file-preview 0.0.190 → 0.0.192

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.
@@ -1,3 +1,69 @@
1
+ // src/react/toSurfaceState.ts
2
+ function toSurfaceState(state, copy) {
3
+ switch (state.status) {
4
+ case "empty":
5
+ return { status: "empty" };
6
+ case "directory":
7
+ return { entry: state.entry, status: "directory" };
8
+ case "loading":
9
+ return {
10
+ entry: state.entry,
11
+ previewKind: state.previewKind,
12
+ status: "loading"
13
+ };
14
+ case "text":
15
+ return {
16
+ content: state.content,
17
+ entry: state.entry,
18
+ previewKind: state.previewKind,
19
+ status: "text"
20
+ };
21
+ case "image":
22
+ return {
23
+ entry: state.entry,
24
+ objectUrl: state.objectUrl,
25
+ previewKind: "image",
26
+ status: "image"
27
+ };
28
+ case "video":
29
+ return {
30
+ entry: state.entry,
31
+ objectUrl: state.objectUrl,
32
+ previewKind: "video",
33
+ status: "video"
34
+ };
35
+ case "bytes":
36
+ return {
37
+ bytes: state.bytes,
38
+ contentType: state.contentType,
39
+ entry: state.entry,
40
+ previewKind: state.previewKind,
41
+ status: "bytes"
42
+ };
43
+ case "readonly":
44
+ return {
45
+ entry: state.entry,
46
+ message: copy.readonlyMessage(state.reason, state.maxSizeBytes),
47
+ previewKind: state.previewKind,
48
+ status: "readonly"
49
+ };
50
+ case "unsupported":
51
+ return {
52
+ entry: state.entry,
53
+ message: copy.unsupportedMessage(state.reason, state.previewKind),
54
+ previewKind: state.previewKind,
55
+ status: "unsupported"
56
+ };
57
+ case "error":
58
+ return {
59
+ entry: state.entry,
60
+ message: copy.errorMessage(state.error),
61
+ previewKind: state.previewKind,
62
+ status: "error"
63
+ };
64
+ }
65
+ }
66
+
1
67
  // src/react/workspaceFilePreviewSurface.tsx
2
68
  import { jsx, jsxs } from "react/jsx-runtime";
3
69
  function WorkspaceFilePreviewSurface({
@@ -6,11 +72,20 @@ function WorkspaceFilePreviewSurface({
6
72
  imageAlt,
7
73
  loadingIndicator,
8
74
  loadingMessage,
75
+ renderers,
9
76
  renderIcon,
10
77
  state,
11
78
  variant
12
79
  }) {
13
80
  const styles = workspaceFilePreviewSurfaceStyles[variant];
81
+ const hostRendered = renderHostPreview({
82
+ renderers,
83
+ state,
84
+ variant
85
+ });
86
+ if (hostRendered !== null) {
87
+ return /* @__PURE__ */ jsx(WorkspaceFilePreviewFrame, { className: styles.frame, children: hostRendered });
88
+ }
14
89
  switch (state.status) {
15
90
  case "directory":
16
91
  return /* @__PURE__ */ jsx(WorkspaceFilePreviewFrame, { className: styles.frame, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-2.5 text-center text-[13px] leading-5 text-[var(--text-tertiary)]", children: [
@@ -69,6 +144,11 @@ function WorkspaceFilePreviewSurface({
69
144
  )
70
145
  }
71
146
  );
147
+ case "bytes":
148
+ return /* @__PURE__ */ jsx(WorkspaceFilePreviewFrame, { className: styles.frame, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-3 px-4 text-center text-[13px] text-[var(--text-tertiary)]", children: [
149
+ renderIcon(state.entry),
150
+ /* @__PURE__ */ jsx("span", { className: styles.message, children: emptyMessage })
151
+ ] }) });
72
152
  case "readonly":
73
153
  case "unsupported":
74
154
  case "error":
@@ -80,6 +160,45 @@ function WorkspaceFilePreviewSurface({
80
160
  return /* @__PURE__ */ jsx(WorkspaceFilePreviewFrame, { className: styles.frame, children: /* @__PURE__ */ jsx("span", { className: styles.message, children: emptyMessage }) });
81
161
  }
82
162
  }
163
+ function renderHostPreview(input) {
164
+ const { renderers, state, variant } = input;
165
+ if (!renderers) {
166
+ return null;
167
+ }
168
+ switch (state.status) {
169
+ case "text": {
170
+ const renderer = renderers[state.previewKind];
171
+ return renderer ? renderer({
172
+ content: state.content,
173
+ entry: state.entry,
174
+ previewKind: state.previewKind,
175
+ variant
176
+ }) : null;
177
+ }
178
+ case "image":
179
+ case "video": {
180
+ const renderer = renderers[state.previewKind];
181
+ return renderer ? renderer({
182
+ entry: state.entry,
183
+ objectUrl: state.objectUrl,
184
+ previewKind: state.previewKind,
185
+ variant
186
+ }) : null;
187
+ }
188
+ case "bytes": {
189
+ const renderer = renderers[state.previewKind];
190
+ return renderer ? renderer({
191
+ bytes: state.bytes,
192
+ contentType: state.contentType,
193
+ entry: state.entry,
194
+ previewKind: state.previewKind,
195
+ variant
196
+ }) : null;
197
+ }
198
+ default:
199
+ return null;
200
+ }
201
+ }
83
202
  var workspaceFilePreviewSurfaceStyles = {
84
203
  compact: {
85
204
  frame: "flex aspect-[3/2] w-full flex-col items-center justify-center overflow-hidden rounded-[8px] border border-[var(--line-2,var(--border-2))] bg-[var(--transparency-block)] p-0 text-center",
@@ -122,6 +241,7 @@ function joinClassNames(...classNames) {
122
241
  return classNames.filter(Boolean).join(" ");
123
242
  }
124
243
  export {
125
- WorkspaceFilePreviewSurface
244
+ WorkspaceFilePreviewSurface,
245
+ toSurfaceState
126
246
  };
127
247
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/workspaceFilePreviewSurface.tsx"],"sourcesContent":["import type { ReactElement, ReactNode } from \"react\";\n\nexport type WorkspaceFilePreviewSurfaceState<TEntry> =\n | { status: \"empty\" }\n | { entry: TEntry; status: \"directory\" }\n | { entry: TEntry; status: \"loading\" }\n | { content: string; entry: TEntry; status: \"text\" }\n | { entry: TEntry; objectUrl: string; status: \"image\" }\n | { entry: TEntry; objectUrl: string; status: \"video\" }\n | { entry: TEntry; message: string; status: \"readonly\" }\n | { entry: TEntry; message: string; status: \"unsupported\" }\n | { entry: TEntry; message: string; status: \"error\" };\n\nexport type WorkspaceFilePreviewSurfaceVariant =\n | \"canvas\"\n | \"compact\"\n | \"detail\";\n\nexport interface WorkspaceFilePreviewSurfaceProps<TEntry> {\n directoryMessage: string;\n emptyMessage: string;\n imageAlt: (entry: TEntry) => string;\n loadingIndicator: ReactNode;\n loadingMessage: string;\n renderIcon: (entry: TEntry) => ReactNode;\n state: WorkspaceFilePreviewSurfaceState<TEntry>;\n variant: WorkspaceFilePreviewSurfaceVariant;\n}\n\nexport function WorkspaceFilePreviewSurface<TEntry>({\n directoryMessage,\n emptyMessage,\n imageAlt,\n loadingIndicator,\n loadingMessage,\n renderIcon,\n state,\n variant\n}: WorkspaceFilePreviewSurfaceProps<TEntry>): ReactElement {\n const styles = workspaceFilePreviewSurfaceStyles[variant];\n switch (state.status) {\n case \"directory\":\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n <div className=\"flex flex-col items-center justify-center gap-2.5 text-center text-[13px] leading-5 text-[var(--text-tertiary)]\">\n {renderIcon(state.entry)}\n <span>{directoryMessage}</span>\n </div>\n </WorkspaceFilePreviewFrame>\n );\n case \"loading\":\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n <div className=\"space-y-3 px-4 text-center text-[13px] text-[var(--text-tertiary)]\">\n {loadingIndicator}\n <span>{loadingMessage}</span>\n </div>\n </WorkspaceFilePreviewFrame>\n );\n case \"image\":\n return (\n <WorkspaceFilePreviewFrame\n className={joinClassNames(styles.frame, styles.imageFrame)}\n >\n <img\n alt={imageAlt(state.entry)}\n className={styles.image}\n src={state.objectUrl}\n />\n </WorkspaceFilePreviewFrame>\n );\n case \"text\":\n return (\n <WorkspaceFilePreviewFrame\n className={joinClassNames(styles.frame, styles.textFrame)}\n >\n <pre className={styles.text}>{state.content}</pre>\n </WorkspaceFilePreviewFrame>\n );\n case \"video\":\n return (\n <WorkspaceFilePreviewFrame\n className={joinClassNames(styles.frame, styles.videoFrame)}\n >\n <video\n aria-label={imageAlt(state.entry)}\n className={styles.video}\n muted\n playsInline\n preload=\"metadata\"\n src={state.objectUrl}\n onLoadedMetadata={(event) => {\n const video = event.currentTarget;\n if (video.duration > 0 && video.currentTime === 0) {\n video.currentTime = Math.min(0.1, video.duration / 2);\n }\n }}\n />\n </WorkspaceFilePreviewFrame>\n );\n case \"readonly\":\n case \"unsupported\":\n case \"error\":\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n <div className=\"flex flex-col items-center justify-center gap-3 px-4 text-center text-[13px] text-[var(--text-tertiary)]\">\n {renderIcon(state.entry)}\n <span className={styles.message}>{state.message}</span>\n </div>\n </WorkspaceFilePreviewFrame>\n );\n case \"empty\":\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n <span className={styles.message}>{emptyMessage}</span>\n </WorkspaceFilePreviewFrame>\n );\n }\n}\n\nconst workspaceFilePreviewSurfaceStyles: Record<\n WorkspaceFilePreviewSurfaceVariant,\n {\n frame: string;\n image: string;\n imageFrame: string;\n message: string;\n text: string;\n textFrame: string;\n video: string;\n videoFrame: string;\n }\n> = {\n compact: {\n frame:\n \"flex aspect-[3/2] w-full flex-col items-center justify-center overflow-hidden rounded-[8px] border border-[var(--line-2,var(--border-2))] bg-[var(--transparency-block)] p-0 text-center\",\n image: \"max-h-full max-w-full rounded-[6px] object-contain\",\n imageFrame: \"p-3\",\n message:\n \"mx-auto max-w-[24ch] text-center text-[13px] leading-5 text-[var(--text-secondary)] [overflow-wrap:anywhere]\",\n text: \"h-full w-full overflow-auto p-3 text-left text-[11px] leading-5 whitespace-pre-wrap break-words text-[var(--text-primary)]\",\n textFrame: \"items-stretch justify-stretch\",\n video: \"block max-h-full max-w-full rounded-[6px] object-contain\",\n videoFrame: \"p-3\"\n },\n detail: {\n frame:\n \"flex h-60 min-h-60 max-h-60 items-center justify-center overflow-hidden rounded-lg bg-[var(--transparency-block)]\",\n image: \"max-h-full max-w-full rounded-[6px] object-contain\",\n imageFrame: \"p-4\",\n message:\n \"max-w-[24ch] text-center text-[13px] leading-5 text-[var(--text-tertiary)] [overflow-wrap:anywhere]\",\n text: \"h-full overflow-auto p-4 text-[11px] leading-5 whitespace-pre-wrap break-words text-[var(--text-primary)]\",\n textFrame: \"items-stretch justify-stretch\",\n video: \"block max-h-full max-w-full rounded-[6px] object-contain\",\n videoFrame: \"p-4\"\n },\n canvas: {\n frame:\n \"flex h-full min-h-0 min-w-0 w-full items-center justify-center overflow-hidden bg-[var(--background-fronted)] text-[var(--text-tertiary)]\",\n image: \"block max-h-full max-w-full object-contain\",\n imageFrame: \"overflow-auto p-3\",\n message:\n \"max-w-[24ch] text-center text-[13px] leading-5 text-[var(--text-tertiary)] [overflow-wrap:anywhere]\",\n text: \"m-0 h-full min-h-0 min-w-0 w-full overflow-auto whitespace-pre-wrap break-words p-3 font-[var(--tsh-font-mono)] text-[11px] leading-[18px] text-[var(--text-secondary)]\",\n textFrame: \"items-stretch justify-stretch\",\n video: \"block max-h-full max-w-full object-contain\",\n videoFrame: \"overflow-auto p-3\"\n }\n};\n\nfunction WorkspaceFilePreviewFrame({\n children,\n className\n}: {\n children: ReactNode;\n className: string;\n}): ReactElement {\n return <div className={className}>{children}</div>;\n}\n\nfunction joinClassNames(\n ...classNames: Array<string | false | null | undefined>\n): string {\n return classNames.filter(Boolean).join(\" \");\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/react/toSurfaceState.ts","../../src/react/workspaceFilePreviewSurface.tsx"],"sourcesContent":["/**\n * Projects controller state into surface state with host-provided copy.\n *\n * Ownership rules: packages/workspace/file-preview/CONTRACT.md\n */\n\nimport type {\n WorkspaceFilePreviewControllerState,\n WorkspaceFilePreviewUnsupportedReason\n} from \"../core/workspaceFilePreviewController.ts\";\nimport type { WorkspaceFilePreviewReadonlyReason } from \"../core/workspaceFilePreview.ts\";\nimport type { WorkspaceFilePreviewKind } from \"../core/workspaceFilePreviewKinds.ts\";\nimport type { WorkspaceFilePreviewSurfaceState } from \"./workspaceFilePreviewSurface.tsx\";\n\nexport interface WorkspaceFilePreviewSurfaceCopy {\n errorMessage: (error: unknown) => string;\n readonlyMessage: (\n reason: WorkspaceFilePreviewReadonlyReason,\n maxSizeBytes?: number\n ) => string;\n unsupportedMessage: (\n reason: WorkspaceFilePreviewUnsupportedReason,\n previewKind?: WorkspaceFilePreviewKind\n ) => string;\n}\n\n/**\n * Shared projection from machine-readable controller state to the React\n * surface state. Controllers remain the source of truth; hosts inject copy.\n */\nexport function toSurfaceState<TEntry>(\n state: WorkspaceFilePreviewControllerState<TEntry>,\n copy: WorkspaceFilePreviewSurfaceCopy\n): WorkspaceFilePreviewSurfaceState<TEntry> {\n switch (state.status) {\n case \"empty\":\n return { status: \"empty\" };\n case \"directory\":\n return { entry: state.entry, status: \"directory\" };\n case \"loading\":\n return {\n entry: state.entry,\n previewKind: state.previewKind,\n status: \"loading\"\n };\n case \"text\":\n return {\n content: state.content,\n entry: state.entry,\n previewKind: state.previewKind,\n status: \"text\"\n };\n case \"image\":\n return {\n entry: state.entry,\n objectUrl: state.objectUrl,\n previewKind: \"image\",\n status: \"image\"\n };\n case \"video\":\n return {\n entry: state.entry,\n objectUrl: state.objectUrl,\n previewKind: \"video\",\n status: \"video\"\n };\n case \"bytes\":\n return {\n bytes: state.bytes,\n contentType: state.contentType,\n entry: state.entry,\n previewKind: state.previewKind,\n status: \"bytes\"\n };\n case \"readonly\":\n return {\n entry: state.entry,\n message: copy.readonlyMessage(state.reason, state.maxSizeBytes),\n previewKind: state.previewKind,\n status: \"readonly\"\n };\n case \"unsupported\":\n return {\n entry: state.entry,\n message: copy.unsupportedMessage(state.reason, state.previewKind),\n previewKind: state.previewKind,\n status: \"unsupported\"\n };\n case \"error\":\n return {\n entry: state.entry,\n message: copy.errorMessage(state.error),\n previewKind: state.previewKind,\n status: \"error\"\n };\n }\n}\n","/**\n * Thin built-in preview surface (image / video / text) plus host renderer hooks.\n *\n * Resolve order: host renderer for previewKind → built-in text degradation →\n * unsupported/fallback messaging already present in state.\n *\n * Ownership rules: packages/workspace/file-preview/CONTRACT.md\n */\n\nimport type { ReactElement, ReactNode } from \"react\";\nimport type { WorkspaceFilePreviewKind } from \"../core/workspaceFilePreviewKinds.ts\";\n\nexport type WorkspaceFilePreviewSurfaceState<TEntry> =\n | { status: \"empty\" }\n | { entry: TEntry; status: \"directory\" }\n | {\n entry: TEntry;\n previewKind?: WorkspaceFilePreviewKind;\n status: \"loading\";\n }\n | {\n content: string;\n entry: TEntry;\n previewKind: WorkspaceFilePreviewKind;\n status: \"text\";\n }\n | {\n entry: TEntry;\n objectUrl: string;\n previewKind: \"image\";\n status: \"image\";\n }\n | {\n entry: TEntry;\n objectUrl: string;\n previewKind: \"video\";\n status: \"video\";\n }\n | {\n bytes: Uint8Array<ArrayBuffer>;\n contentType: string | null;\n entry: TEntry;\n previewKind: WorkspaceFilePreviewKind;\n status: \"bytes\";\n }\n | {\n entry: TEntry;\n message: string;\n previewKind?: WorkspaceFilePreviewKind;\n status: \"readonly\";\n }\n | {\n entry: TEntry;\n message: string;\n previewKind?: WorkspaceFilePreviewKind;\n status: \"unsupported\";\n }\n | {\n entry: TEntry;\n message: string;\n previewKind?: WorkspaceFilePreviewKind;\n status: \"error\";\n };\n\nexport type WorkspaceFilePreviewSurfaceVariant =\n | \"canvas\"\n | \"compact\"\n | \"detail\";\n\nexport interface WorkspaceFilePreviewHostRendererProps<TEntry> {\n entry: TEntry;\n previewKind: WorkspaceFilePreviewKind;\n variant: WorkspaceFilePreviewSurfaceVariant;\n /** Present when the controller decoded text (including text-degradable kinds). */\n content?: string;\n /** Present for hook-only kinds loaded as raw bytes. */\n bytes?: Uint8Array<ArrayBuffer>;\n contentType?: string | null;\n /** Present for built-in media kinds when a host still overrides rendering. */\n objectUrl?: string;\n}\n\nexport type WorkspaceFilePreviewHostRenderer<TEntry> = (\n props: WorkspaceFilePreviewHostRendererProps<TEntry>\n) => ReactNode;\n\n/**\n * Host renderer registry keyed by previewKind. `variant` is passed as props;\n * optional (kind, variant) specificity may be added later.\n */\nexport type WorkspaceFilePreviewHostRenderers<TEntry> = Partial<\n Record<WorkspaceFilePreviewKind, WorkspaceFilePreviewHostRenderer<TEntry>>\n>;\n\nexport interface WorkspaceFilePreviewSurfaceProps<TEntry> {\n directoryMessage: string;\n emptyMessage: string;\n imageAlt: (entry: TEntry) => string;\n loadingIndicator: ReactNode;\n loadingMessage: string;\n /**\n * Optional host renderers registered by previewKind. When present for the\n * current kind, they win over built-in image / video / text shells.\n */\n renderers?: WorkspaceFilePreviewHostRenderers<TEntry>;\n renderIcon: (entry: TEntry) => ReactNode;\n state: WorkspaceFilePreviewSurfaceState<TEntry>;\n variant: WorkspaceFilePreviewSurfaceVariant;\n}\n\nexport function WorkspaceFilePreviewSurface<TEntry>({\n directoryMessage,\n emptyMessage,\n imageAlt,\n loadingIndicator,\n loadingMessage,\n renderers,\n renderIcon,\n state,\n variant\n}: WorkspaceFilePreviewSurfaceProps<TEntry>): ReactElement {\n const styles = workspaceFilePreviewSurfaceStyles[variant];\n const hostRendered = renderHostPreview({\n renderers,\n state,\n variant\n });\n if (hostRendered !== null) {\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n {hostRendered}\n </WorkspaceFilePreviewFrame>\n );\n }\n\n switch (state.status) {\n case \"directory\":\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n <div className=\"flex flex-col items-center justify-center gap-2.5 text-center text-[13px] leading-5 text-[var(--text-tertiary)]\">\n {renderIcon(state.entry)}\n <span>{directoryMessage}</span>\n </div>\n </WorkspaceFilePreviewFrame>\n );\n case \"loading\":\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n <div className=\"space-y-3 px-4 text-center text-[13px] text-[var(--text-tertiary)]\">\n {loadingIndicator}\n <span>{loadingMessage}</span>\n </div>\n </WorkspaceFilePreviewFrame>\n );\n case \"image\":\n return (\n <WorkspaceFilePreviewFrame\n className={joinClassNames(styles.frame, styles.imageFrame)}\n >\n <img\n alt={imageAlt(state.entry)}\n className={styles.image}\n src={state.objectUrl}\n />\n </WorkspaceFilePreviewFrame>\n );\n case \"text\":\n return (\n <WorkspaceFilePreviewFrame\n className={joinClassNames(styles.frame, styles.textFrame)}\n >\n <pre className={styles.text}>{state.content}</pre>\n </WorkspaceFilePreviewFrame>\n );\n case \"video\":\n return (\n <WorkspaceFilePreviewFrame\n className={joinClassNames(styles.frame, styles.videoFrame)}\n >\n <video\n aria-label={imageAlt(state.entry)}\n className={styles.video}\n muted\n playsInline\n preload=\"metadata\"\n src={state.objectUrl}\n onLoadedMetadata={(event) => {\n const video = event.currentTarget;\n if (video.duration > 0 && video.currentTime === 0) {\n video.currentTime = Math.min(0.1, video.duration / 2);\n }\n }}\n />\n </WorkspaceFilePreviewFrame>\n );\n case \"bytes\":\n // Hook-only kinds without a registered renderer fall through to the\n // unsupported messaging path via host-projected state; if bytes somehow\n // arrive without a hook, show the generic unsupported shell.\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n <div className=\"flex flex-col items-center justify-center gap-3 px-4 text-center text-[13px] text-[var(--text-tertiary)]\">\n {renderIcon(state.entry)}\n <span className={styles.message}>{emptyMessage}</span>\n </div>\n </WorkspaceFilePreviewFrame>\n );\n case \"readonly\":\n case \"unsupported\":\n case \"error\":\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n <div className=\"flex flex-col items-center justify-center gap-3 px-4 text-center text-[13px] text-[var(--text-tertiary)]\">\n {renderIcon(state.entry)}\n <span className={styles.message}>{state.message}</span>\n </div>\n </WorkspaceFilePreviewFrame>\n );\n case \"empty\":\n return (\n <WorkspaceFilePreviewFrame className={styles.frame}>\n <span className={styles.message}>{emptyMessage}</span>\n </WorkspaceFilePreviewFrame>\n );\n }\n}\n\nfunction renderHostPreview<TEntry>(input: {\n renderers: WorkspaceFilePreviewHostRenderers<TEntry> | undefined;\n state: WorkspaceFilePreviewSurfaceState<TEntry>;\n variant: WorkspaceFilePreviewSurfaceVariant;\n}): ReactNode | null {\n const { renderers, state, variant } = input;\n if (!renderers) {\n return null;\n }\n\n switch (state.status) {\n case \"text\": {\n const renderer = renderers[state.previewKind];\n return renderer\n ? renderer({\n content: state.content,\n entry: state.entry,\n previewKind: state.previewKind,\n variant\n })\n : null;\n }\n case \"image\":\n case \"video\": {\n const renderer = renderers[state.previewKind];\n return renderer\n ? renderer({\n entry: state.entry,\n objectUrl: state.objectUrl,\n previewKind: state.previewKind,\n variant\n })\n : null;\n }\n case \"bytes\": {\n const renderer = renderers[state.previewKind];\n return renderer\n ? renderer({\n bytes: state.bytes,\n contentType: state.contentType,\n entry: state.entry,\n previewKind: state.previewKind,\n variant\n })\n : null;\n }\n default:\n return null;\n }\n}\n\nconst workspaceFilePreviewSurfaceStyles: Record<\n WorkspaceFilePreviewSurfaceVariant,\n {\n frame: string;\n image: string;\n imageFrame: string;\n message: string;\n text: string;\n textFrame: string;\n video: string;\n videoFrame: string;\n }\n> = {\n compact: {\n frame:\n \"flex aspect-[3/2] w-full flex-col items-center justify-center overflow-hidden rounded-[8px] border border-[var(--line-2,var(--border-2))] bg-[var(--transparency-block)] p-0 text-center\",\n image: \"max-h-full max-w-full rounded-[6px] object-contain\",\n imageFrame: \"p-3\",\n message:\n \"mx-auto max-w-[24ch] text-center text-[13px] leading-5 text-[var(--text-secondary)] [overflow-wrap:anywhere]\",\n text: \"h-full w-full overflow-auto p-3 text-left text-[11px] leading-5 whitespace-pre-wrap break-words text-[var(--text-primary)]\",\n textFrame: \"items-stretch justify-stretch\",\n video: \"block max-h-full max-w-full rounded-[6px] object-contain\",\n videoFrame: \"p-3\"\n },\n detail: {\n frame:\n \"flex h-60 min-h-60 max-h-60 items-center justify-center overflow-hidden rounded-lg bg-[var(--transparency-block)]\",\n image: \"max-h-full max-w-full rounded-[6px] object-contain\",\n imageFrame: \"p-4\",\n message:\n \"max-w-[24ch] text-center text-[13px] leading-5 text-[var(--text-tertiary)] [overflow-wrap:anywhere]\",\n text: \"h-full overflow-auto p-4 text-[11px] leading-5 whitespace-pre-wrap break-words text-[var(--text-primary)]\",\n textFrame: \"items-stretch justify-stretch\",\n video: \"block max-h-full max-w-full rounded-[6px] object-contain\",\n videoFrame: \"p-4\"\n },\n canvas: {\n frame:\n \"flex h-full min-h-0 min-w-0 w-full items-center justify-center overflow-hidden bg-[var(--background-fronted)] text-[var(--text-tertiary)]\",\n image: \"block max-h-full max-w-full object-contain\",\n imageFrame: \"overflow-auto p-3\",\n message:\n \"max-w-[24ch] text-center text-[13px] leading-5 text-[var(--text-tertiary)] [overflow-wrap:anywhere]\",\n text: \"m-0 h-full min-h-0 min-w-0 w-full overflow-auto whitespace-pre-wrap break-words p-3 font-[var(--tsh-font-mono)] text-[11px] leading-[18px] text-[var(--text-secondary)]\",\n textFrame: \"items-stretch justify-stretch\",\n video: \"block max-h-full max-w-full object-contain\",\n videoFrame: \"overflow-auto p-3\"\n }\n};\n\nfunction WorkspaceFilePreviewFrame({\n children,\n className\n}: {\n children: ReactNode;\n className: string;\n}): ReactElement {\n return <div className={className}>{children}</div>;\n}\n\nfunction joinClassNames(\n ...classNames: Array<string | false | null | undefined>\n): string {\n return classNames.filter(Boolean).join(\" \");\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tutti-os/workspace-file-preview",
3
- "version": "0.0.190",
3
+ "version": "0.0.192",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/workspaceFilePreview.ts","../src/core/workspaceFilePreviewController.ts"],"sourcesContent":["export type WorkspaceFilePreviewEntryKind =\n | \"file\"\n | \"directory\"\n | \"folder\"\n | \"unknown\"\n | (string & {});\n\nexport type WorkspaceFilePreviewKind = \"image\" | \"text\" | \"video\";\n\nexport type WorkspaceFileVisualKind =\n | \"binary\"\n | \"code\"\n | \"directory\"\n | \"document\"\n | \"image\"\n | \"markdown\"\n | \"video\";\n\nexport interface WorkspaceFilePreviewEntry {\n displayName?: string;\n kind: WorkspaceFilePreviewEntryKind;\n mtimeMs?: number | null;\n name?: string;\n path: string;\n sizeBytes?: number | null;\n}\n\nexport interface WorkspaceFilePreviewActivationTarget {\n fileKind: WorkspaceFilePreviewKind;\n mtimeMs?: number | null;\n name: string;\n path: string;\n sizeBytes?: number | null;\n}\n\nexport type WorkspaceFilePreviewReadonlyReason =\n | \"binary\"\n | \"decode_failed\"\n | \"file_too_large\"\n | \"text_too_large\";\n\nexport type WorkspaceFilePreviewReadiness<\n TEntry extends WorkspaceFilePreviewEntry,\n TTarget extends WorkspaceFilePreviewActivationTarget =\n WorkspaceFilePreviewActivationTarget\n> =\n | { entry: TEntry; status: \"directory\" }\n | {\n entry: TEntry;\n maxSizeBytes: number;\n reason: Extract<\n WorkspaceFilePreviewReadonlyReason,\n \"file_too_large\" | \"text_too_large\"\n >;\n status: \"readonly\";\n }\n | { entry: TEntry; status: \"unsupported\" }\n | { entry: TEntry; status: \"ready\"; target: TTarget };\n\nexport type WorkspaceFilePreviewLoadedState<\n TEntry extends WorkspaceFilePreviewEntry,\n TTarget extends WorkspaceFilePreviewActivationTarget\n> =\n | { content: string; entry: TTarget; status: \"text\" }\n | {\n bytes: Uint8Array<ArrayBuffer>;\n contentType: string;\n entry: TTarget;\n status: \"image\";\n }\n | {\n bytes: Uint8Array<ArrayBuffer>;\n contentType: string;\n entry: TTarget;\n status: \"video\";\n }\n | {\n entry: TEntry;\n maxSizeBytes?: number;\n reason: WorkspaceFilePreviewReadonlyReason;\n status: \"readonly\";\n };\n\nconst imageExtensions = new Set([\n \"avif\",\n \"gif\",\n \"jpeg\",\n \"jpg\",\n \"png\",\n \"svg\",\n \"webp\"\n]);\nconst browserOpenableHtmlExtensions = new Set([\n \"htm\",\n \"html\",\n \"shtml\",\n \"xhtml\"\n]);\nconst browserOpenableVideoExtensions = new Set([\"mp4\", \"webm\"]);\n\nconst videoExtensions = new Set([\n \"avi\",\n \"m2ts\",\n \"mkv\",\n \"mov\",\n \"mp4\",\n \"mpeg\",\n \"mpg\",\n \"mts\",\n \"webm\",\n \"wmv\"\n]);\n/**\n * Extensions where macOS Launch Services may register video handlers even when\n * the workspace file is source code (UTI / uniform type collisions).\n */\nexport const workspaceFileVideoHandlerCollisionExtensions = new Set([\"ts\"]);\nconst markdownExtensions = new Set([\"md\", \"mdx\"]);\nconst codeExtensions = new Set([\n \"bash\",\n \"c\",\n \"cc\",\n \"conf\",\n \"cpp\",\n \"cs\",\n \"css\",\n \"go\",\n \"h\",\n \"hpp\",\n \"html\",\n \"java\",\n \"js\",\n \"jsx\",\n \"json\",\n \"lua\",\n \"m\",\n \"mm\",\n \"php\",\n \"plist\",\n \"proto\",\n \"py\",\n \"rb\",\n \"rs\",\n \"sh\",\n \"sql\",\n \"swift\",\n \"toml\",\n \"ts\",\n \"tsx\",\n \"xml\",\n \"yaml\",\n \"yml\",\n \"zsh\"\n]);\nconst documentExtensions = new Set([\n \"csv\",\n \"doc\",\n \"docx\",\n \"log\",\n \"pdf\",\n \"rtf\",\n \"txt\",\n \"xls\",\n \"xlsx\"\n]);\nconst textExtensions = new Set([\n \"bash\",\n \"c\",\n \"cc\",\n \"conf\",\n \"cpp\",\n \"cs\",\n \"css\",\n \"csv\",\n \"env\",\n \"go\",\n \"h\",\n \"hpp\",\n \"html\",\n \"ini\",\n \"java\",\n \"js\",\n \"json\",\n \"jsx\",\n \"log\",\n \"lua\",\n \"m\",\n \"md\",\n \"mdx\",\n \"mm\",\n \"php\",\n \"plist\",\n \"proto\",\n \"py\",\n \"rb\",\n \"rs\",\n \"sh\",\n \"sql\",\n \"swift\",\n \"toml\",\n \"ts\",\n \"tsx\",\n \"txt\",\n \"xml\",\n \"yaml\",\n \"yml\",\n \"zsh\"\n]);\nconst textFileNames = new Set([\n \".gitignore\",\n \".npmrc\",\n \".nvmrc\",\n \"dockerfile\",\n \"makefile\",\n \"readme\"\n]);\n\nexport const workspaceFileTextMaxBytes = 1024 * 1024;\nexport const workspaceFilePreviewMaxBytes = 20 * 1024 * 1024;\n\nexport function resolveWorkspaceFileVisualKind(\n entry: Pick<WorkspaceFilePreviewEntry, \"kind\" | \"name\" | \"path\">\n): WorkspaceFileVisualKind {\n if (entry.kind === \"directory\" || entry.kind === \"folder\") {\n return \"directory\";\n }\n\n const extension = resolveWorkspaceFileExtension(\n entry.path || entry.name || \"\"\n );\n if (imageExtensions.has(extension)) {\n return \"image\";\n }\n if (videoExtensions.has(extension)) {\n return \"video\";\n }\n if (markdownExtensions.has(extension)) {\n return \"markdown\";\n }\n if (codeExtensions.has(extension)) {\n return \"code\";\n }\n if (documentExtensions.has(extension)) {\n return \"document\";\n }\n return \"binary\";\n}\n\nexport function resolveWorkspaceFileExtension(pathOrName: string): string {\n const name = pathOrName.split(\"/\").pop()?.trim().toLowerCase() ?? \"\";\n const dotIndex = name.lastIndexOf(\".\");\n return dotIndex > 0 ? name.slice(dotIndex + 1) : \"\";\n}\n\nexport function isWorkspaceFileBrowserOpenable(\n entry: Pick<WorkspaceFilePreviewEntry, \"kind\" | \"name\" | \"path\">\n): boolean {\n if (entry.kind !== \"file\") {\n return false;\n }\n\n const extension = resolveWorkspaceFileExtension(\n entry.path || entry.name || \"\"\n );\n if (\n extension === \"pdf\" ||\n browserOpenableHtmlExtensions.has(extension) ||\n imageExtensions.has(extension) ||\n browserOpenableVideoExtensions.has(extension)\n ) {\n return true;\n }\n\n return classifyWorkspaceFilePreviewKind(entry) === \"text\";\n}\n\nexport function shouldFilterVideoPlayersForOpenWith(\n entry: Pick<WorkspaceFilePreviewEntry, \"kind\" | \"name\" | \"path\">\n): boolean {\n if (entry.kind !== \"file\") {\n return false;\n }\n\n const visualKind = resolveWorkspaceFileVisualKind(entry);\n if (visualKind === \"video\") {\n return false;\n }\n\n const extension = resolveWorkspaceFileExtension(\n entry.path || entry.name || \"\"\n );\n if (workspaceFileVideoHandlerCollisionExtensions.has(extension)) {\n return true;\n }\n\n if (visualKind === \"code\" || visualKind === \"markdown\") {\n return true;\n }\n\n return classifyWorkspaceFilePreviewKind(entry) === \"text\";\n}\n\nexport function resolveWorkspaceImageMimeType(\n pathOrName: string\n): string | null {\n switch (resolveWorkspaceFileExtension(pathOrName)) {\n case \"avif\":\n return \"image/avif\";\n case \"gif\":\n return \"image/gif\";\n case \"jpeg\":\n case \"jpg\":\n return \"image/jpeg\";\n case \"png\":\n return \"image/png\";\n case \"svg\":\n return \"image/svg+xml\";\n case \"webp\":\n return \"image/webp\";\n default:\n return null;\n }\n}\n\nexport function resolveWorkspaceVideoMimeType(\n pathOrName: string\n): string | null {\n switch (resolveWorkspaceFileExtension(pathOrName)) {\n case \"mp4\":\n return \"video/mp4\";\n case \"webm\":\n return \"video/webm\";\n default:\n return null;\n }\n}\n\nexport function classifyWorkspaceFilePreviewKind(\n entry: Pick<\n WorkspaceFilePreviewEntry,\n \"displayName\" | \"kind\" | \"name\" | \"path\"\n >\n): WorkspaceFilePreviewKind | null {\n if (entry.kind !== \"file\") {\n return null;\n }\n\n const name = resolveWorkspaceFilePreviewName(entry);\n if (resolveWorkspaceImageMimeType(name) !== null) {\n return \"image\";\n }\n if (resolveWorkspaceVideoMimeType(name) !== null) {\n return \"video\";\n }\n\n const normalizedName = name.trim().toLowerCase();\n const extension = resolveWorkspaceFileExtension(name);\n if (textExtensions.has(extension) || textFileNames.has(normalizedName)) {\n return \"text\";\n }\n\n return null;\n}\n\nexport function resolveWorkspaceFileActivationTarget(\n entry: WorkspaceFilePreviewEntry\n): WorkspaceFilePreviewActivationTarget | null {\n const fileKind = classifyWorkspaceFilePreviewKind(entry);\n if (!fileKind) {\n return null;\n }\n\n const target: WorkspaceFilePreviewActivationTarget = {\n fileKind,\n name: resolveWorkspaceFilePreviewName(entry),\n path: entry.path\n };\n if (entry.mtimeMs !== undefined) {\n target.mtimeMs = entry.mtimeMs;\n }\n if (entry.sizeBytes !== undefined) {\n target.sizeBytes = entry.sizeBytes;\n }\n return target;\n}\n\nexport function resolveWorkspaceFilePreviewReadiness<\n TEntry extends WorkspaceFilePreviewEntry\n>(entry: TEntry): WorkspaceFilePreviewReadiness<TEntry> {\n if (entry.kind === \"directory\" || entry.kind === \"folder\") {\n return {\n entry,\n status: \"directory\"\n };\n }\n\n const target = resolveWorkspaceFileActivationTarget(entry);\n if (!target) {\n return {\n entry,\n status: \"unsupported\"\n };\n }\n\n if (\n target.fileKind === \"text\" &&\n isWorkspaceTextFileTooLarge(entry.sizeBytes)\n ) {\n return {\n entry,\n maxSizeBytes: workspaceFileTextMaxBytes,\n reason: \"text_too_large\",\n status: \"readonly\"\n };\n }\n\n if (isWorkspacePreviewFileTooLarge(entry.sizeBytes)) {\n return {\n entry,\n maxSizeBytes: workspaceFilePreviewMaxBytes,\n reason: \"file_too_large\",\n status: \"readonly\"\n };\n }\n\n return {\n entry,\n status: \"ready\",\n target\n };\n}\n\nexport function createWorkspaceFilePreviewLoadedState<\n TEntry extends WorkspaceFilePreviewEntry,\n TTarget extends WorkspaceFilePreviewActivationTarget\n>(input: {\n bytes: Uint8Array | ArrayBuffer;\n contentType?: string | null;\n entry: TEntry;\n target: TTarget;\n}): WorkspaceFilePreviewLoadedState<TEntry, TTarget> {\n if (input.target.fileKind === \"image\") {\n return {\n bytes: copyWorkspaceFilePreviewBytes(input.bytes),\n contentType:\n input.contentType ??\n resolveWorkspaceImageMimeType(input.target.name) ??\n \"application/octet-stream\",\n entry: input.target,\n status: \"image\"\n };\n }\n if (input.target.fileKind === \"video\") {\n return {\n bytes: copyWorkspaceFilePreviewBytes(input.bytes),\n contentType:\n input.contentType ??\n resolveWorkspaceVideoMimeType(input.target.name) ??\n \"application/octet-stream\",\n entry: input.target,\n status: \"video\"\n };\n }\n\n try {\n const content = decodeWorkspaceTextFile(input.bytes);\n if (looksLikeBinaryText(content)) {\n return {\n entry: input.entry,\n reason: \"binary\",\n status: \"readonly\"\n };\n }\n return {\n content,\n entry: input.target,\n status: \"text\"\n };\n } catch {\n return {\n entry: input.entry,\n reason: \"decode_failed\",\n status: \"readonly\"\n };\n }\n}\n\nexport function resolveWorkspaceFilePreviewName(\n entry: Pick<WorkspaceFilePreviewEntry, \"displayName\" | \"name\" | \"path\">\n): string {\n return (\n entry.name?.trim() ||\n entry.displayName?.trim() ||\n entry.path.split(\"/\").pop()?.trim() ||\n entry.path\n );\n}\n\nexport function isWorkspaceTextFileTooLarge(\n sizeBytes?: number | null\n): boolean {\n return (\n typeof sizeBytes === \"number\" &&\n Number.isFinite(sizeBytes) &&\n sizeBytes > workspaceFileTextMaxBytes\n );\n}\n\nexport function isWorkspacePreviewFileTooLarge(\n sizeBytes?: number | null\n): boolean {\n return (\n typeof sizeBytes === \"number\" &&\n Number.isFinite(sizeBytes) &&\n sizeBytes > workspaceFilePreviewMaxBytes\n );\n}\n\nexport function decodeWorkspaceTextFile(\n bytes: Uint8Array | ArrayBuffer\n): string {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(\n normalizeWorkspaceFilePreviewBytes(bytes)\n );\n}\n\nexport function normalizeWorkspaceFilePreviewBytes(\n value: Uint8Array | ArrayBuffer\n): Uint8Array {\n if (value instanceof Uint8Array) {\n return value;\n }\n return new Uint8Array(value);\n}\n\nexport function copyWorkspaceFilePreviewBytes(\n bytes: Uint8Array | ArrayBuffer\n): Uint8Array<ArrayBuffer> {\n const normalized = normalizeWorkspaceFilePreviewBytes(bytes);\n const buffer = new ArrayBuffer(normalized.byteLength);\n const copy = new Uint8Array(buffer);\n copy.set(normalized);\n return copy;\n}\n\nexport function looksLikeBinaryText(content: string): boolean {\n if (content.length === 0) {\n return false;\n }\n\n const sample = content.slice(0, 4096);\n if (sample.includes(\"\\u0000\")) {\n return true;\n }\n\n let suspiciousControlChars = 0;\n for (let index = 0; index < sample.length; index += 1) {\n const code = sample.charCodeAt(index);\n const isAllowedWhitespace = code === 9 || code === 10 || code === 13;\n const isControlChar = code < 32 || (code >= 127 && code <= 159);\n if (isControlChar && !isAllowedWhitespace) {\n suspiciousControlChars += 1;\n }\n }\n\n return suspiciousControlChars / sample.length > 0.12;\n}\n\nexport function formatWorkspacePreviewByteLimit(sizeBytes: number): string {\n if (sizeBytes < 1024) {\n return `${sizeBytes} B`;\n }\n\n const mebibytes = sizeBytes / (1024 * 1024);\n if (Number.isInteger(mebibytes)) {\n return `${mebibytes} MiB`;\n }\n return `${mebibytes.toFixed(1)} MiB`;\n}\n","import {\n createWorkspaceFilePreviewLoadedState,\n resolveWorkspaceFilePreviewReadiness,\n type WorkspaceFilePreviewActivationTarget,\n type WorkspaceFilePreviewEntry,\n type WorkspaceFilePreviewKind,\n type WorkspaceFilePreviewReadonlyReason\n} from \"./workspaceFilePreview.ts\";\n\nexport type WorkspaceFilePreviewUnsupportedReason =\n | \"file_type\"\n | \"reader_unavailable\";\n\nexport type WorkspaceFilePreviewControllerState<TEntry> =\n | { status: \"empty\" }\n | { entry: TEntry; status: \"directory\" }\n | { entry: TEntry; status: \"loading\" }\n | {\n content: string;\n entry: TEntry;\n previewSizeBytes: number;\n status: \"text\";\n }\n | {\n entry: TEntry;\n objectUrl: string;\n previewSizeBytes: number;\n status: \"image\";\n }\n | {\n entry: TEntry;\n objectUrl: string;\n previewSizeBytes: number;\n status: \"video\";\n }\n | {\n entry: TEntry;\n maxSizeBytes?: number;\n previewSizeBytes?: number;\n reason: WorkspaceFilePreviewReadonlyReason;\n status: \"readonly\";\n }\n | {\n entry: TEntry;\n reason: WorkspaceFilePreviewUnsupportedReason;\n status: \"unsupported\";\n }\n | { entry: TEntry; error: unknown; status: \"error\" };\n\nexport interface WorkspaceFilePreviewReadInput<TEntry> {\n entry: TEntry;\n signal: AbortSignal;\n target: WorkspaceFilePreviewActivationTarget;\n}\n\nexport interface WorkspaceFilePreviewReadResult {\n bytes: Uint8Array | ArrayBuffer;\n contentType?: string | null;\n kind?: WorkspaceFilePreviewKind;\n}\n\nexport type WorkspaceFilePreviewReadOutput =\n | WorkspaceFilePreviewReadResult\n | Uint8Array\n | ArrayBuffer;\n\nexport interface WorkspaceFilePreviewObjectUrlFactory {\n create(bytes: Uint8Array<ArrayBuffer>, contentType: string): string;\n revoke(objectUrl: string): void;\n}\n\nexport interface CreateWorkspaceFilePreviewControllerInput<TEntry> {\n /**\n * Optional source capability gate. `false` blocks every non-directory read;\n * `true` also lets the reader classify locally unsupported files. When\n * omitted, the controller relies on local file classification.\n */\n canReadEntry?: (entry: TEntry) => boolean;\n getEntryKey?: (entry: TEntry) => string;\n objectUrls?: WorkspaceFilePreviewObjectUrlFactory;\n read?: (\n input: WorkspaceFilePreviewReadInput<TEntry>\n ) => Promise<WorkspaceFilePreviewReadOutput | null>;\n toPreviewEntry: (entry: TEntry) => WorkspaceFilePreviewEntry;\n}\n\nexport interface WorkspaceFilePreviewController<TEntry> {\n dispose(): void;\n getSnapshot(): WorkspaceFilePreviewControllerState<TEntry>;\n reload(): Promise<void>;\n setEntry(entry: TEntry | null): Promise<void>;\n subscribe(listener: () => void): () => void;\n}\n\nexport function createWorkspaceFilePreviewController<TEntry>(\n input: CreateWorkspaceFilePreviewControllerInput<TEntry>\n): WorkspaceFilePreviewController<TEntry> {\n return new WorkspaceFilePreviewControllerImpl(input);\n}\n\nclass WorkspaceFilePreviewControllerImpl<\n TEntry\n> implements WorkspaceFilePreviewController<TEntry> {\n private activeEntry: TEntry | null = null;\n private activeEntryKey: string | null = null;\n private abortController: AbortController | null = null;\n private disposed = false;\n private generation = 0;\n private loadPromise: Promise<void> = Promise.resolve();\n private objectUrl: string | null = null;\n private readonly listeners = new Set<() => void>();\n private readonly input: CreateWorkspaceFilePreviewControllerInput<TEntry>;\n private readonly objectUrls: WorkspaceFilePreviewObjectUrlFactory;\n private state: WorkspaceFilePreviewControllerState<TEntry> = {\n status: \"empty\"\n };\n\n constructor(input: CreateWorkspaceFilePreviewControllerInput<TEntry>) {\n this.input = input;\n this.objectUrls = input.objectUrls ?? browserWorkspaceFilePreviewObjectUrls;\n }\n\n dispose(): void {\n if (this.disposed) {\n return;\n }\n this.disposed = true;\n this.cancelLoad();\n this.revokeObjectUrl();\n this.listeners.clear();\n }\n\n getSnapshot(): WorkspaceFilePreviewControllerState<TEntry> {\n return this.state;\n }\n\n reload(): Promise<void> {\n if (this.disposed || !this.activeEntry) {\n return Promise.resolve();\n }\n return this.start(this.activeEntry);\n }\n\n setEntry(entry: TEntry | null): Promise<void> {\n if (this.disposed) {\n return Promise.resolve();\n }\n\n const nextKey = entry ? this.resolveEntryKey(entry) : null;\n if (nextKey === this.activeEntryKey) {\n return this.loadPromise;\n }\n\n this.activeEntry = entry;\n this.activeEntryKey = nextKey;\n if (!entry) {\n this.cancelLoad();\n this.revokeObjectUrl();\n this.updateState({ status: \"empty\" });\n this.loadPromise = Promise.resolve();\n return this.loadPromise;\n }\n return this.start(entry);\n }\n\n subscribe(listener: () => void): () => void {\n if (this.disposed) {\n return () => {};\n }\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private cancelLoad(): void {\n this.generation += 1;\n this.abortController?.abort();\n this.abortController = null;\n }\n\n private isStale(generation: number): boolean {\n return this.disposed || generation !== this.generation;\n }\n\n private async load(\n entry: TEntry,\n previewEntry: WorkspaceFilePreviewEntry,\n target: WorkspaceFilePreviewActivationTarget,\n generation: number,\n abortController: AbortController\n ): Promise<void> {\n try {\n const result = await this.input.read?.({\n entry,\n signal: abortController.signal,\n target\n });\n if (this.isStale(generation)) {\n return;\n }\n if (!result) {\n this.updateState({\n entry,\n reason: \"file_type\",\n status: \"unsupported\"\n });\n return;\n }\n\n const loaded = createWorkspaceFilePreviewLoadedState({\n bytes:\n result instanceof Uint8Array || result instanceof ArrayBuffer\n ? result\n : result.bytes,\n contentType:\n result instanceof Uint8Array || result instanceof ArrayBuffer\n ? undefined\n : result.contentType,\n entry: previewEntry,\n target:\n result instanceof Uint8Array || result instanceof ArrayBuffer\n ? target\n : { ...target, fileKind: result.kind ?? target.fileKind }\n });\n if (this.isStale(generation)) {\n return;\n }\n\n if (loaded.status === \"image\" || loaded.status === \"video\") {\n const previewSizeBytes = loaded.bytes.byteLength;\n const objectUrl = this.objectUrls.create(\n loaded.bytes,\n loaded.contentType\n );\n if (this.isStale(generation)) {\n this.objectUrls.revoke(objectUrl);\n return;\n }\n this.objectUrl = objectUrl;\n this.updateState({\n entry,\n objectUrl,\n previewSizeBytes,\n status: loaded.status\n });\n return;\n }\n if (loaded.status === \"text\") {\n this.updateState({\n content: loaded.content,\n entry,\n previewSizeBytes: byteLengthOfPreviewReadResult(result),\n status: \"text\"\n });\n return;\n }\n this.updateState({\n entry,\n previewSizeBytes: byteLengthOfPreviewReadResult(result),\n reason: loaded.reason,\n ...(loaded.maxSizeBytes === undefined\n ? {}\n : { maxSizeBytes: loaded.maxSizeBytes }),\n status: \"readonly\"\n });\n } catch (error) {\n if (this.isStale(generation)) {\n return;\n }\n this.updateState({ entry, error, status: \"error\" });\n } finally {\n if (!this.isStale(generation)) {\n this.abortController = null;\n }\n }\n }\n\n private resolveEntryKey(entry: TEntry): string {\n if (this.input.getEntryKey) {\n return this.input.getEntryKey(entry);\n }\n const previewEntry = this.input.toPreviewEntry(entry);\n return [\n previewEntry.kind,\n previewEntry.path,\n previewEntry.name ?? \"\",\n previewEntry.displayName ?? \"\",\n previewEntry.sizeBytes ?? \"\",\n previewEntry.mtimeMs ?? \"\"\n ].join(\"\\0\");\n }\n\n private revokeObjectUrl(): void {\n if (!this.objectUrl) {\n return;\n }\n this.objectUrls.revoke(this.objectUrl);\n this.objectUrl = null;\n }\n\n private start(entry: TEntry): Promise<void> {\n this.cancelLoad();\n this.revokeObjectUrl();\n\n const previewEntry = this.input.toPreviewEntry(entry);\n const readiness = resolveWorkspaceFilePreviewReadiness(previewEntry);\n\n if (readiness.status === \"directory\") {\n this.updateState({ entry, status: \"directory\" });\n this.loadPromise = Promise.resolve();\n return this.loadPromise;\n }\n\n const canRead = this.input.canReadEntry?.(entry);\n if (canRead === false) {\n this.updateState({\n entry,\n reason: \"reader_unavailable\",\n status: \"unsupported\"\n });\n this.loadPromise = Promise.resolve();\n return this.loadPromise;\n }\n\n if (readiness.status === \"unsupported\") {\n if (canRead !== true) {\n this.updateState({\n entry,\n reason: \"file_type\",\n status: \"unsupported\"\n });\n this.loadPromise = Promise.resolve();\n return this.loadPromise;\n }\n if (!this.input.read) {\n this.updateState({\n entry,\n reason: \"reader_unavailable\",\n status: \"unsupported\"\n });\n this.loadPromise = Promise.resolve();\n return this.loadPromise;\n }\n const target: WorkspaceFilePreviewActivationTarget = {\n fileKind: \"text\",\n name:\n previewEntry.name ??\n previewEntry.displayName ??\n previewEntry.path.split(\"/\").pop() ??\n previewEntry.path,\n path: previewEntry.path,\n ...(previewEntry.mtimeMs === undefined\n ? {}\n : { mtimeMs: previewEntry.mtimeMs }),\n ...(previewEntry.sizeBytes === undefined\n ? {}\n : { sizeBytes: previewEntry.sizeBytes })\n };\n const abortController = new AbortController();\n this.abortController = abortController;\n const generation = this.generation;\n this.updateState({ entry, status: \"loading\" });\n this.loadPromise = this.load(\n entry,\n previewEntry,\n target,\n generation,\n abortController\n );\n return this.loadPromise;\n }\n\n if (readiness.status === \"readonly\") {\n this.updateState({\n entry,\n maxSizeBytes: readiness.maxSizeBytes,\n reason: readiness.reason,\n status: \"readonly\"\n });\n this.loadPromise = Promise.resolve();\n return this.loadPromise;\n }\n\n if (!this.input.read) {\n this.updateState({\n entry,\n reason: \"reader_unavailable\",\n status: \"unsupported\"\n });\n this.loadPromise = Promise.resolve();\n return this.loadPromise;\n }\n\n const abortController = new AbortController();\n this.abortController = abortController;\n const generation = this.generation;\n this.updateState({ entry, status: \"loading\" });\n this.loadPromise = this.load(\n entry,\n previewEntry,\n readiness.target,\n generation,\n abortController\n );\n return this.loadPromise;\n }\n\n private updateState(\n state: WorkspaceFilePreviewControllerState<TEntry>\n ): void {\n if (this.disposed) {\n return;\n }\n this.state = state;\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n\nconst browserWorkspaceFilePreviewObjectUrls: WorkspaceFilePreviewObjectUrlFactory =\n {\n create(bytes, contentType) {\n return URL.createObjectURL(new Blob([bytes], { type: contentType }));\n },\n revoke(objectUrl) {\n URL.revokeObjectURL(objectUrl);\n }\n };\n\nfunction byteLengthOfPreviewReadResult(\n result: WorkspaceFilePreviewReadOutput\n): number {\n const bytes =\n result instanceof Uint8Array || result instanceof ArrayBuffer\n ? result\n : result.bytes;\n return bytes.byteLength;\n}\n"],"mappings":"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","names":["abortController","generation"]}