@harryy/react-file-browser 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -26
- package/dist/chunks/file-types-DZ2qAUnj.js +331 -0
- package/dist/chunks/file-types-DZ2qAUnj.js.map +1 -0
- package/dist/chunks/list-BwYAbqhl.js +31 -0
- package/dist/chunks/list-BwYAbqhl.js.map +1 -0
- package/dist/chunks/spreadsheet-GqF9DCoj.js +118 -0
- package/dist/chunks/spreadsheet-GqF9DCoj.js.map +1 -0
- package/dist/components/file-browser.d.ts +11 -3
- package/dist/components/file-browser.d.ts.map +1 -1
- package/dist/components/file-plugins.d.ts +64 -0
- package/dist/components/file-plugins.d.ts.map +1 -0
- package/dist/components/file-types.d.ts +12 -0
- package/dist/components/file-types.d.ts.map +1 -0
- package/dist/components/file-view.d.ts +25 -0
- package/dist/components/file-view.d.ts.map +1 -0
- package/dist/core/use-file-browser.d.ts +0 -28
- package/dist/core/use-file-browser.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2196 -2130
- package/dist/index.js.map +1 -1
- package/dist/plugins/code/index.d.ts +26 -0
- package/dist/plugins/code/index.d.ts.map +1 -0
- package/dist/plugins/code/index.js +215 -0
- package/dist/plugins/code/index.js.map +1 -0
- package/dist/plugins/csv/index.d.ts +6 -0
- package/dist/plugins/csv/index.d.ts.map +1 -0
- package/dist/plugins/csv/index.js +48 -0
- package/dist/plugins/csv/index.js.map +1 -0
- package/dist/plugins/docx/index.d.ts +4 -0
- package/dist/plugins/docx/index.d.ts.map +1 -0
- package/dist/plugins/docx/index.js +40 -0
- package/dist/plugins/docx/index.js.map +1 -0
- package/dist/plugins/markdown/index.d.ts +13 -0
- package/dist/plugins/markdown/index.d.ts.map +1 -0
- package/dist/plugins/markdown/index.js +292 -0
- package/dist/plugins/markdown/index.js.map +1 -0
- package/dist/plugins/rich-text.d.ts +10 -0
- package/dist/plugins/rich-text.d.ts.map +1 -0
- package/dist/plugins/spreadsheet.d.ts +20 -0
- package/dist/plugins/spreadsheet.d.ts.map +1 -0
- package/dist/plugins/xlsx/index.d.ts +6 -0
- package/dist/plugins/xlsx/index.d.ts.map +1 -0
- package/dist/plugins/xlsx/index.js +84 -0
- package/dist/plugins/xlsx/index.js.map +1 -0
- package/package.json +86 -3
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import 'prismjs/components/prism-markdown';
|
|
2
|
+
import 'prismjs/components/prism-json';
|
|
3
|
+
import 'prismjs/components/prism-yaml';
|
|
4
|
+
import 'prismjs/components/prism-toml';
|
|
5
|
+
import 'prismjs/components/prism-typescript';
|
|
6
|
+
import 'prismjs/components/prism-jsx';
|
|
7
|
+
import 'prismjs/components/prism-tsx';
|
|
8
|
+
import 'prismjs/components/prism-python';
|
|
9
|
+
import 'prismjs/components/prism-bash';
|
|
10
|
+
import 'prismjs/components/prism-sql';
|
|
11
|
+
import 'prismjs/components/prism-go';
|
|
12
|
+
import 'prismjs/components/prism-rust';
|
|
13
|
+
import 'prismjs/components/prism-java';
|
|
14
|
+
import type { FileBrowserEditor, FileBrowserPreviewer } from '../../components/file-plugins';
|
|
15
|
+
import type { FileNode } from '../../core/types';
|
|
16
|
+
/** Prism language id for a file, or `undefined` for plain text. */
|
|
17
|
+
export declare function getCodeLanguage(item: FileNode<unknown>): string | undefined;
|
|
18
|
+
/** Plain-text and code editing with syntax highlighting (codejar + Prism). */
|
|
19
|
+
export declare const codeEditor: FileBrowserEditor;
|
|
20
|
+
/** Read-only syntax-highlighted view for code and structured text files. */
|
|
21
|
+
export declare const codePreviewer: FileBrowserPreviewer;
|
|
22
|
+
/** HTML and SVG source editing with a live preview beside it (codejar + Prism). */
|
|
23
|
+
export declare const markupEditor: FileBrowserEditor;
|
|
24
|
+
/** JSON editing with syntax highlighting, a Format button, and saving blocked while the JSON is invalid. */
|
|
25
|
+
export declare const jsonEditor: FileBrowserEditor;
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/code/index.tsx"],"names":[],"mappings":"AAEA,OAAO,mCAAmC,CAAA;AAC1C,OAAO,+BAA+B,CAAA;AACtC,OAAO,+BAA+B,CAAA;AACtC,OAAO,+BAA+B,CAAA;AACtC,OAAO,qCAAqC,CAAA;AAC5C,OAAO,8BAA8B,CAAA;AACrC,OAAO,8BAA8B,CAAA;AACrC,OAAO,iCAAiC,CAAA;AACxC,OAAO,+BAA+B,CAAA;AACtC,OAAO,8BAA8B,CAAA;AACrC,OAAO,6BAA6B,CAAA;AACpC,OAAO,+BAA+B,CAAA;AACtC,OAAO,+BAA+B,CAAA;AAEtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AAE5F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AA+BhD,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAG3E;AAsED,8EAA8E;AAC9E,eAAO,MAAM,UAAU,EAAE,iBAOxB,CAAA;AAED,4EAA4E;AAC5E,eAAO,MAAM,aAAa,EAAE,oBAgB3B,CAAA;AAuDD,mFAAmF;AACnF,eAAO,MAAM,YAAY,EAAE,iBAY1B,CAAA;AA2DD,4GAA4G;AAC5G,eAAO,MAAM,UAAU,EAAE,iBAQxB,CAAA"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { i as e, r as t, s as n } from "../../chunks/file-types-DZ2qAUnj.js";
|
|
2
|
+
import { useEffect as r, useRef as i, useState as a } from "react";
|
|
3
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
4
|
+
import { CodeJar as c } from "codejar";
|
|
5
|
+
import l from "prismjs";
|
|
6
|
+
import "prismjs/components/prism-markdown";
|
|
7
|
+
import "prismjs/components/prism-json";
|
|
8
|
+
import "prismjs/components/prism-yaml";
|
|
9
|
+
import "prismjs/components/prism-toml";
|
|
10
|
+
import "prismjs/components/prism-typescript";
|
|
11
|
+
import "prismjs/components/prism-jsx";
|
|
12
|
+
import "prismjs/components/prism-tsx";
|
|
13
|
+
import "prismjs/components/prism-python";
|
|
14
|
+
import "prismjs/components/prism-bash";
|
|
15
|
+
import "prismjs/components/prism-sql";
|
|
16
|
+
import "prismjs/components/prism-go";
|
|
17
|
+
import "prismjs/components/prism-rust";
|
|
18
|
+
import "prismjs/components/prism-java";
|
|
19
|
+
//#region src/plugins/code/index.tsx
|
|
20
|
+
var u = {
|
|
21
|
+
md: "markdown",
|
|
22
|
+
markdown: "markdown",
|
|
23
|
+
mdx: "markdown",
|
|
24
|
+
json: "json",
|
|
25
|
+
jsonl: "json",
|
|
26
|
+
yaml: "yaml",
|
|
27
|
+
yml: "yaml",
|
|
28
|
+
toml: "toml",
|
|
29
|
+
html: "markup",
|
|
30
|
+
htm: "markup",
|
|
31
|
+
xml: "markup",
|
|
32
|
+
svg: "markup",
|
|
33
|
+
css: "css",
|
|
34
|
+
scss: "css",
|
|
35
|
+
js: "javascript",
|
|
36
|
+
mjs: "javascript",
|
|
37
|
+
cjs: "javascript",
|
|
38
|
+
jsx: "jsx",
|
|
39
|
+
ts: "typescript",
|
|
40
|
+
tsx: "tsx",
|
|
41
|
+
py: "python",
|
|
42
|
+
sh: "bash",
|
|
43
|
+
sql: "sql",
|
|
44
|
+
go: "go",
|
|
45
|
+
rs: "rust",
|
|
46
|
+
java: "java"
|
|
47
|
+
};
|
|
48
|
+
function d(t) {
|
|
49
|
+
let n = u[e(t.name)];
|
|
50
|
+
return n && l.languages[n] ? n : void 0;
|
|
51
|
+
}
|
|
52
|
+
var f = `min-h-[min(520px,60dvh)] w-full min-w-0 overflow-auto whitespace-pre-wrap rounded-[var(--fb-radius)] border border-[var(--fb-border)] bg-[var(--fb-surface)] p-4 text-left font-mono text-[calc(var(--fb-font)-1px)] leading-relaxed text-[var(--fb-text)] outline-none [overflow-wrap:anywhere] [tab-size:2] focus:border-[var(--fb-accent)] ${[
|
|
53
|
+
"[&_.token.comment]:text-[var(--fb-muted)] [&_.token.comment]:italic",
|
|
54
|
+
"[&_.token.prolog]:text-[var(--fb-muted)] [&_.token.doctype]:text-[var(--fb-muted)]",
|
|
55
|
+
"[&_.token.keyword]:text-[var(--fb-accent)] [&_.token.atrule]:text-[var(--fb-accent)]",
|
|
56
|
+
"[&_.token.important]:text-[var(--fb-accent)] [&_.token.title]:font-bold [&_.token.title]:text-[var(--fb-accent)]",
|
|
57
|
+
"[&_.token.string]:text-[var(--fb-ok,var(--fb-text))] [&_.token.attr-value]:text-[var(--fb-ok,var(--fb-text))]",
|
|
58
|
+
"[&_.token.number]:text-[var(--fb-folder)] [&_.token.boolean]:text-[var(--fb-folder)]",
|
|
59
|
+
"[&_.token.tag]:text-[var(--fb-danger)] [&_.token.property]:text-[var(--fb-danger)]",
|
|
60
|
+
"[&_.token.function]:text-[var(--fb-folder)] [&_.token.attr-name]:text-[var(--fb-folder)]",
|
|
61
|
+
"[&_.token.punctuation]:text-[var(--fb-muted)] [&_.token.bold]:font-bold [&_.token.italic]:italic"
|
|
62
|
+
].join(" ")}`;
|
|
63
|
+
function p(e, t) {
|
|
64
|
+
return t ? l.highlight(e, l.languages[t], t) : null;
|
|
65
|
+
}
|
|
66
|
+
function m({ content: e, item: t, onChange: n, onSave: a }) {
|
|
67
|
+
let s = i(null), l = i({
|
|
68
|
+
onChange: n,
|
|
69
|
+
onSave: a
|
|
70
|
+
});
|
|
71
|
+
return l.current = {
|
|
72
|
+
onChange: n,
|
|
73
|
+
onSave: a
|
|
74
|
+
}, r(() => {
|
|
75
|
+
let n = s.current;
|
|
76
|
+
if (!n) return;
|
|
77
|
+
let r = d(t), i = c(n, (e) => {
|
|
78
|
+
let t = p(e.textContent ?? "", r);
|
|
79
|
+
t !== null && (e.innerHTML = t);
|
|
80
|
+
}, {
|
|
81
|
+
tab: " ",
|
|
82
|
+
spellcheck: !1
|
|
83
|
+
});
|
|
84
|
+
return i.updateCode(e), i.onUpdate((t) => {
|
|
85
|
+
t !== e && l.current.onChange(t);
|
|
86
|
+
}), () => i.destroy();
|
|
87
|
+
}, []), /* @__PURE__ */ o("div", {
|
|
88
|
+
"aria-label": `${t.name} contents`,
|
|
89
|
+
"aria-multiline": "true",
|
|
90
|
+
className: f,
|
|
91
|
+
ref: s,
|
|
92
|
+
role: "textbox",
|
|
93
|
+
tabIndex: 0
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
var h = {
|
|
97
|
+
id: "code",
|
|
98
|
+
match: n,
|
|
99
|
+
read: "text",
|
|
100
|
+
component: ({ content: e, item: t, onChange: n, onSave: r }) => /* @__PURE__ */ o(m, {
|
|
101
|
+
content: typeof e == "string" ? e : "",
|
|
102
|
+
item: t,
|
|
103
|
+
onChange: n,
|
|
104
|
+
onSave: r
|
|
105
|
+
})
|
|
106
|
+
}, g = {
|
|
107
|
+
id: "code",
|
|
108
|
+
match: (e) => n(e) && t(e) !== "image" && !_(e) && d(e) !== void 0,
|
|
109
|
+
read: "text",
|
|
110
|
+
component: ({ content: e, item: t }) => {
|
|
111
|
+
let n = p(typeof e == "string" ? e : "", d(t)) ?? "";
|
|
112
|
+
return /* @__PURE__ */ o("pre", {
|
|
113
|
+
className: `m-0 max-h-[min(640px,65dvh)] ${f.replace("min-h-[min(520px,60dvh)] ", "")}`,
|
|
114
|
+
dangerouslySetInnerHTML: { __html: n }
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}, _ = (t) => ["html", "htm"].includes(e(t.name)) || t.mimeType === "text/html", v = (t) => e(t.name) === "svg" || t.mimeType === "image/svg+xml";
|
|
118
|
+
function y({ content: e, item: t, onChange: n, onSave: r }) {
|
|
119
|
+
let [i, c] = a(e);
|
|
120
|
+
return /* @__PURE__ */ s("div", {
|
|
121
|
+
className: "grid w-full min-w-0 grid-cols-1 gap-3 @min-[48rem]/fb:grid-cols-2",
|
|
122
|
+
children: [/* @__PURE__ */ o(m, {
|
|
123
|
+
content: e,
|
|
124
|
+
item: t,
|
|
125
|
+
onChange: (e) => {
|
|
126
|
+
c(e), n(e);
|
|
127
|
+
},
|
|
128
|
+
onSave: r
|
|
129
|
+
}), /* @__PURE__ */ o("div", {
|
|
130
|
+
"aria-label": `${t.name} live preview`,
|
|
131
|
+
className: "min-h-[min(520px,60dvh)] min-w-0 overflow-auto rounded-[var(--fb-radius)] border border-[var(--fb-border)] bg-[var(--fb-surface-2)]",
|
|
132
|
+
role: "group",
|
|
133
|
+
children: v(t) ? /* @__PURE__ */ o("img", {
|
|
134
|
+
alt: `${t.name} preview`,
|
|
135
|
+
className: "m-auto block max-h-full max-w-full p-4",
|
|
136
|
+
src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(i)}`
|
|
137
|
+
}) : /* @__PURE__ */ o("iframe", {
|
|
138
|
+
className: "size-full min-h-[min(520px,60dvh)] border-0 bg-white",
|
|
139
|
+
sandbox: "",
|
|
140
|
+
srcDoc: i,
|
|
141
|
+
title: `${t.name} preview`
|
|
142
|
+
})
|
|
143
|
+
})]
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
var b = {
|
|
147
|
+
id: "markup",
|
|
148
|
+
match: (e) => _(e) || v(e),
|
|
149
|
+
read: "text",
|
|
150
|
+
component: ({ content: e, item: t, onChange: n, onSave: r }) => /* @__PURE__ */ o(y, {
|
|
151
|
+
content: typeof e == "string" ? e : "",
|
|
152
|
+
item: t,
|
|
153
|
+
onChange: n,
|
|
154
|
+
onSave: r
|
|
155
|
+
})
|
|
156
|
+
}, x = (t) => e(t.name) === "json" || t.mimeType === "application/json";
|
|
157
|
+
function S(e) {
|
|
158
|
+
if (!e.trim()) return null;
|
|
159
|
+
try {
|
|
160
|
+
return JSON.parse(e), null;
|
|
161
|
+
} catch (e) {
|
|
162
|
+
return `Invalid JSON: ${e instanceof Error ? e.message : String(e)}. Fix it to save.`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function C({ content: e, item: t, onChange: n, onSave: r }) {
|
|
166
|
+
let [i, c] = a({
|
|
167
|
+
text: e,
|
|
168
|
+
version: 0
|
|
169
|
+
});
|
|
170
|
+
return /* @__PURE__ */ s("div", {
|
|
171
|
+
className: "flex w-full min-w-0 flex-col gap-2",
|
|
172
|
+
children: [/* @__PURE__ */ o("div", {
|
|
173
|
+
className: "flex justify-end",
|
|
174
|
+
children: /* @__PURE__ */ o("button", {
|
|
175
|
+
className: "inline-flex h-[var(--fb-bar-control-h,30px)] items-center rounded-[calc(var(--fb-radius)-2px)] border border-[var(--fb-border)] bg-[var(--fb-surface)] px-3 text-[calc(var(--fb-font)-1px)] font-semibold text-[var(--fb-text)] hover:bg-[var(--fb-surface-2)] disabled:cursor-not-allowed disabled:opacity-45",
|
|
176
|
+
disabled: !(i.text.trim() !== "" && S(i.text) === null),
|
|
177
|
+
onClick: () => {
|
|
178
|
+
let t = `${JSON.stringify(JSON.parse(i.text), null, 2)}\n`;
|
|
179
|
+
c((e) => ({
|
|
180
|
+
text: t,
|
|
181
|
+
version: e.version + 1
|
|
182
|
+
})), t !== e && n(t);
|
|
183
|
+
},
|
|
184
|
+
type: "button",
|
|
185
|
+
children: "Format"
|
|
186
|
+
})
|
|
187
|
+
}), /* @__PURE__ */ o(m, {
|
|
188
|
+
content: i.text,
|
|
189
|
+
item: t,
|
|
190
|
+
onChange: (e) => {
|
|
191
|
+
c((t) => ({
|
|
192
|
+
...t,
|
|
193
|
+
text: e
|
|
194
|
+
})), n(e);
|
|
195
|
+
},
|
|
196
|
+
onSave: r
|
|
197
|
+
}, i.version)]
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
var w = {
|
|
201
|
+
id: "json",
|
|
202
|
+
match: x,
|
|
203
|
+
read: "text",
|
|
204
|
+
validate: S,
|
|
205
|
+
component: ({ content: e, item: t, onChange: n, onSave: r }) => /* @__PURE__ */ o(C, {
|
|
206
|
+
content: typeof e == "string" ? e : "",
|
|
207
|
+
item: t,
|
|
208
|
+
onChange: n,
|
|
209
|
+
onSave: r
|
|
210
|
+
})
|
|
211
|
+
};
|
|
212
|
+
//#endregion
|
|
213
|
+
export { h as codeEditor, g as codePreviewer, d as getCodeLanguage, w as jsonEditor, b as markupEditor };
|
|
214
|
+
|
|
215
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/plugins/code/index.tsx"],"sourcesContent":["import { CodeJar } from 'codejar'\nimport Prism from 'prismjs'\nimport 'prismjs/components/prism-markdown'\nimport 'prismjs/components/prism-json'\nimport 'prismjs/components/prism-yaml'\nimport 'prismjs/components/prism-toml'\nimport 'prismjs/components/prism-typescript'\nimport 'prismjs/components/prism-jsx'\nimport 'prismjs/components/prism-tsx'\nimport 'prismjs/components/prism-python'\nimport 'prismjs/components/prism-bash'\nimport 'prismjs/components/prism-sql'\nimport 'prismjs/components/prism-go'\nimport 'prismjs/components/prism-rust'\nimport 'prismjs/components/prism-java'\nimport { useEffect, useRef, useState } from 'react'\nimport type { FileBrowserEditor, FileBrowserPreviewer } from '../../components/file-plugins'\nimport { getFileCategory, getFileExtension, isTextFile } from '../../components/file-types'\nimport type { FileNode } from '../../core/types'\n\nconst LANGUAGE_BY_EXTENSION: Record<string, string> = {\n\tmd: 'markdown',\n\tmarkdown: 'markdown',\n\tmdx: 'markdown',\n\tjson: 'json',\n\tjsonl: 'json',\n\tyaml: 'yaml',\n\tyml: 'yaml',\n\ttoml: 'toml',\n\thtml: 'markup',\n\thtm: 'markup',\n\txml: 'markup',\n\tsvg: 'markup',\n\tcss: 'css',\n\tscss: 'css',\n\tjs: 'javascript',\n\tmjs: 'javascript',\n\tcjs: 'javascript',\n\tjsx: 'jsx',\n\tts: 'typescript',\n\ttsx: 'tsx',\n\tpy: 'python',\n\tsh: 'bash',\n\tsql: 'sql',\n\tgo: 'go',\n\trs: 'rust',\n\tjava: 'java'\n}\n\n/** Prism language id for a file, or `undefined` for plain text. */\nexport function getCodeLanguage(item: FileNode<unknown>): string | undefined {\n\tconst language = LANGUAGE_BY_EXTENSION[getFileExtension(item.name)]\n\treturn language && Prism.languages[language] ? language : undefined\n}\n\n// Prism emits `.token.*` spans; these map them onto --fb-* tokens instead of shipping a Prism theme.\nconst TOKEN_COLORS = [\n\t'[&_.token.comment]:text-[var(--fb-muted)] [&_.token.comment]:italic',\n\t'[&_.token.prolog]:text-[var(--fb-muted)] [&_.token.doctype]:text-[var(--fb-muted)]',\n\t'[&_.token.keyword]:text-[var(--fb-accent)] [&_.token.atrule]:text-[var(--fb-accent)]',\n\t'[&_.token.important]:text-[var(--fb-accent)] [&_.token.title]:font-bold [&_.token.title]:text-[var(--fb-accent)]',\n\t'[&_.token.string]:text-[var(--fb-ok,var(--fb-text))] [&_.token.attr-value]:text-[var(--fb-ok,var(--fb-text))]',\n\t'[&_.token.number]:text-[var(--fb-folder)] [&_.token.boolean]:text-[var(--fb-folder)]',\n\t'[&_.token.tag]:text-[var(--fb-danger)] [&_.token.property]:text-[var(--fb-danger)]',\n\t'[&_.token.function]:text-[var(--fb-folder)] [&_.token.attr-name]:text-[var(--fb-folder)]',\n\t'[&_.token.punctuation]:text-[var(--fb-muted)] [&_.token.bold]:font-bold [&_.token.italic]:italic'\n].join(' ')\n\nconst SURFACE = `min-h-[min(520px,60dvh)] w-full min-w-0 overflow-auto whitespace-pre-wrap rounded-[var(--fb-radius)] border border-[var(--fb-border)] bg-[var(--fb-surface)] p-4 text-left font-mono text-[calc(var(--fb-font)-1px)] leading-relaxed text-[var(--fb-text)] outline-none [overflow-wrap:anywhere] [tab-size:2] focus:border-[var(--fb-accent)] ${TOKEN_COLORS}`\n\n// Prism escapes the source before wrapping tokens, so its output is safe to assign as HTML.\nfunction highlight(code: string, language: string | undefined) {\n\treturn language ? Prism.highlight(code, Prism.languages[language], language) : null\n}\n\nfunction CodeSurface({\n\tcontent,\n\titem,\n\tonChange,\n\tonSave\n}: {\n\tcontent: string\n\titem: FileNode<unknown>\n\tonChange: (next: string) => void\n\tonSave: () => void\n}) {\n\tconst ref = useRef<HTMLDivElement>(null)\n\tconst handlers = useRef({ onChange, onSave })\n\thandlers.current = { onChange, onSave }\n\n\tuseEffect(() => {\n\t\tconst element = ref.current\n\t\tif (!element) return\n\t\tconst language = getCodeLanguage(item)\n\t\tconst jar = CodeJar(\n\t\t\telement,\n\t\t\t(editor) => {\n\t\t\t\tconst html = highlight(editor.textContent ?? '', language)\n\t\t\t\tif (html !== null) editor.innerHTML = html\n\t\t\t},\n\t\t\t{ tab: ' ', spellcheck: false }\n\t\t)\n\t\tjar.updateCode(content)\n\t\tjar.onUpdate((code) => {\n\t\t\tif (code !== content) handlers.current.onChange(code)\n\t\t})\n\t\treturn () => jar.destroy()\n\t\t// The editor owns its text after mount; the dialog remounts it (via `key`) to reload.\n\t\t// oxlint-disable-next-line react/exhaustive-deps\n\t}, [])\n\n\treturn (\n\t\t<div\n\t\t\taria-label={`${item.name} contents`}\n\t\t\taria-multiline=\"true\"\n\t\t\tclassName={SURFACE}\n\t\t\tref={ref}\n\t\t\trole=\"textbox\"\n\t\t\ttabIndex={0}\n\t\t/>\n\t)\n}\n\n/** Plain-text and code editing with syntax highlighting (codejar + Prism). */\nexport const codeEditor: FileBrowserEditor = {\n\tid: 'code',\n\tmatch: isTextFile,\n\tread: 'text',\n\tcomponent: ({ content, item, onChange, onSave }) => (\n\t\t<CodeSurface content={typeof content === 'string' ? content : ''} item={item} onChange={onChange} onSave={onSave} />\n\t)\n}\n\n/** Read-only syntax-highlighted view for code and structured text files. */\nexport const codePreviewer: FileBrowserPreviewer = {\n\tid: 'code',\n\t// SVG and HTML are text too, but they preview rendered (image / sandboxed page); only editors show source.\n\tmatch: (item) =>\n\t\tisTextFile(item) && getFileCategory(item) !== 'image' && !isHtml(item) && getCodeLanguage(item) !== undefined,\n\tread: 'text',\n\tcomponent: ({ content, item }) => {\n\t\tconst html = highlight(typeof content === 'string' ? content : '', getCodeLanguage(item)) ?? ''\n\t\treturn (\n\t\t\t<pre\n\t\t\t\tclassName={`m-0 max-h-[min(640px,65dvh)] ${SURFACE.replace('min-h-[min(520px,60dvh)] ', '')}`}\n\t\t\t\t// oxlint-disable-next-line react/no-danger -- Prism escapes the source; only its token spans are HTML.\n\t\t\t\tdangerouslySetInnerHTML={{ __html: html }}\n\t\t\t/>\n\t\t)\n\t}\n}\n\nconst isHtml = (item: FileNode<unknown>) =>\n\t['html', 'htm'].includes(getFileExtension(item.name)) || item.mimeType === 'text/html'\nconst isSvg = (item: FileNode<unknown>) => getFileExtension(item.name) === 'svg' || item.mimeType === 'image/svg+xml'\n\nfunction MarkupSurface({\n\tcontent,\n\titem,\n\tonChange,\n\tonSave\n}: {\n\tcontent: string\n\titem: FileNode<unknown>\n\tonChange: (next: string) => void\n\tonSave: () => void\n}) {\n\tconst [source, setSource] = useState(content)\n\treturn (\n\t\t<div className=\"grid w-full min-w-0 grid-cols-1 gap-3 @min-[48rem]/fb:grid-cols-2\">\n\t\t\t<CodeSurface\n\t\t\t\tcontent={content}\n\t\t\t\titem={item}\n\t\t\t\tonChange={(next) => {\n\t\t\t\t\tsetSource(next)\n\t\t\t\t\tonChange(next)\n\t\t\t\t}}\n\t\t\t\tonSave={onSave}\n\t\t\t/>\n\t\t\t<div\n\t\t\t\taria-label={`${item.name} live preview`}\n\t\t\t\tclassName=\"min-h-[min(520px,60dvh)] min-w-0 overflow-auto rounded-[var(--fb-radius)] border border-[var(--fb-border)] bg-[var(--fb-surface-2)]\"\n\t\t\t\trole=\"group\"\n\t\t\t>\n\t\t\t\t{isSvg(item) ? (\n\t\t\t\t\t// An <img> renders SVG without running its scripts or loading external resources.\n\t\t\t\t\t<img\n\t\t\t\t\t\talt={`${item.name} preview`}\n\t\t\t\t\t\tclassName=\"m-auto block max-h-full max-w-full p-4\"\n\t\t\t\t\t\tsrc={`data:image/svg+xml;charset=utf-8,${encodeURIComponent(source)}`}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t// An empty sandbox blocks scripts, forms, and same-origin access for the edited HTML.\n\t\t\t\t\t<iframe\n\t\t\t\t\t\tclassName=\"size-full min-h-[min(520px,60dvh)] border-0 bg-white\"\n\t\t\t\t\t\tsandbox=\"\"\n\t\t\t\t\t\tsrcDoc={source}\n\t\t\t\t\t\ttitle={`${item.name} preview`}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n/** HTML and SVG source editing with a live preview beside it (codejar + Prism). */\nexport const markupEditor: FileBrowserEditor = {\n\tid: 'markup',\n\tmatch: (item) => isHtml(item) || isSvg(item),\n\tread: 'text',\n\tcomponent: ({ content, item, onChange, onSave }) => (\n\t\t<MarkupSurface\n\t\t\tcontent={typeof content === 'string' ? content : ''}\n\t\t\titem={item}\n\t\t\tonChange={onChange}\n\t\t\tonSave={onSave}\n\t\t/>\n\t)\n}\n\nconst isJson = (item: FileNode<unknown>) =>\n\tgetFileExtension(item.name) === 'json' || item.mimeType === 'application/json'\n\nfunction jsonError(text: string): string | null {\n\tif (!text.trim()) return null\n\ttry {\n\t\tJSON.parse(text)\n\t\treturn null\n\t} catch (error) {\n\t\treturn `Invalid JSON: ${error instanceof Error ? error.message : String(error)}. Fix it to save.`\n\t}\n}\n\nfunction JsonSurface({\n\tcontent,\n\titem,\n\tonChange,\n\tonSave\n}: {\n\tcontent: string\n\titem: FileNode<unknown>\n\tonChange: (next: string) => void\n\tonSave: () => void\n}) {\n\tconst [source, setSource] = useState({ text: content, version: 0 })\n\tconst canFormat = source.text.trim() !== '' && jsonError(source.text) === null\n\treturn (\n\t\t<div className=\"flex w-full min-w-0 flex-col gap-2\">\n\t\t\t<div className=\"flex justify-end\">\n\t\t\t\t<button\n\t\t\t\t\tclassName=\"inline-flex h-[var(--fb-bar-control-h,30px)] items-center rounded-[calc(var(--fb-radius)-2px)] border border-[var(--fb-border)] bg-[var(--fb-surface)] px-3 text-[calc(var(--fb-font)-1px)] font-semibold text-[var(--fb-text)] hover:bg-[var(--fb-surface-2)] disabled:cursor-not-allowed disabled:opacity-45\"\n\t\t\t\t\tdisabled={!canFormat}\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tconst text = `${JSON.stringify(JSON.parse(source.text), null, 2)}\\n`\n\t\t\t\t\t\t// Remount the code surface so it starts from the formatted text.\n\t\t\t\t\t\tsetSource((current) => ({ text, version: current.version + 1 }))\n\t\t\t\t\t\tif (text !== content) onChange(text)\n\t\t\t\t\t}}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t>\n\t\t\t\t\tFormat\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<CodeSurface\n\t\t\t\tcontent={source.text}\n\t\t\t\titem={item}\n\t\t\t\tkey={source.version}\n\t\t\t\tonChange={(next) => {\n\t\t\t\t\tsetSource((current) => ({ ...current, text: next }))\n\t\t\t\t\tonChange(next)\n\t\t\t\t}}\n\t\t\t\tonSave={onSave}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n\n/** JSON editing with syntax highlighting, a Format button, and saving blocked while the JSON is invalid. */\nexport const jsonEditor: FileBrowserEditor = {\n\tid: 'json',\n\tmatch: isJson,\n\tread: 'text',\n\tvalidate: jsonError,\n\tcomponent: ({ content, item, onChange, onSave }) => (\n\t\t<JsonSurface content={typeof content === 'string' ? content : ''} item={item} onChange={onChange} onSave={onSave} />\n\t)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { FileBrowserEditor, FileBrowserPreviewer } from '../../components/file-plugins';
|
|
2
|
+
/** Read-only CSV/TSV sheet (papaparse + jspreadsheet-ce). */
|
|
3
|
+
export declare const csvPreviewer: FileBrowserPreviewer;
|
|
4
|
+
/** Spreadsheet-style CSV/TSV editor that keeps the file's delimiter and line endings. */
|
|
5
|
+
export declare const csvEditor: FileBrowserEditor;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/csv/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AAa5F,6DAA6D;AAC7D,eAAO,MAAM,YAAY,EAAE,oBAO1B,CAAA;AAED,yFAAyF;AACzF,eAAO,MAAM,SAAS,EAAE,iBAwBvB,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { i as e } from "../../chunks/file-types-DZ2qAUnj.js";
|
|
2
|
+
import { n as t, t as n } from "../../chunks/spreadsheet-GqF9DCoj.js";
|
|
3
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
4
|
+
import i from "papaparse";
|
|
5
|
+
//#region src/plugins/csv/index.tsx
|
|
6
|
+
var a = (t) => ["csv", "tsv"].includes(e(t.name)) || t.mimeType === "text/csv";
|
|
7
|
+
function o(e) {
|
|
8
|
+
let t = i.parse(typeof e == "string" ? e : "", { skipEmptyLines: "greedy" });
|
|
9
|
+
return {
|
|
10
|
+
rows: t.data,
|
|
11
|
+
delimiter: t.meta.delimiter || ",",
|
|
12
|
+
newline: t.meta.linebreak || "\n"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
var s = {
|
|
16
|
+
id: "csv",
|
|
17
|
+
match: a,
|
|
18
|
+
read: "text",
|
|
19
|
+
component: ({ content: e, item: t }) => /* @__PURE__ */ r(n, {
|
|
20
|
+
label: t.name,
|
|
21
|
+
sheets: [{
|
|
22
|
+
name: t.name,
|
|
23
|
+
rows: o(e).rows
|
|
24
|
+
}]
|
|
25
|
+
})
|
|
26
|
+
}, c = {
|
|
27
|
+
id: "csv",
|
|
28
|
+
match: a,
|
|
29
|
+
read: "text",
|
|
30
|
+
component: ({ content: e, item: a, onChange: s }) => {
|
|
31
|
+
let c = o(e);
|
|
32
|
+
return /* @__PURE__ */ r(n, {
|
|
33
|
+
label: a.name,
|
|
34
|
+
onChange: ([e]) => s(i.unparse(t(e ?? []).map((e) => e.map((e) => String(e ?? ""))), {
|
|
35
|
+
delimiter: c.delimiter,
|
|
36
|
+
newline: c.newline
|
|
37
|
+
})),
|
|
38
|
+
sheets: [{
|
|
39
|
+
name: a.name,
|
|
40
|
+
rows: c.rows
|
|
41
|
+
}]
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { c as csvEditor, s as csvPreviewer };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/plugins/csv/index.tsx"],"sourcesContent":["import Papa from 'papaparse'\nimport type { FileBrowserEditor, FileBrowserPreviewer } from '../../components/file-plugins'\nimport { getFileExtension } from '../../components/file-types'\nimport type { FileNode } from '../../core/types'\nimport { Spreadsheet, trimSheet } from '../spreadsheet'\n\nconst isDelimited = (item: FileNode<unknown>) =>\n\t['csv', 'tsv'].includes(getFileExtension(item.name)) || item.mimeType === 'text/csv'\n\nfunction parse(content: unknown) {\n\tconst result = Papa.parse<string[]>(typeof content === 'string' ? content : '', { skipEmptyLines: 'greedy' })\n\treturn { rows: result.data, delimiter: result.meta.delimiter || ',', newline: result.meta.linebreak || '\\n' }\n}\n\n/** Read-only CSV/TSV sheet (papaparse + jspreadsheet-ce). */\nexport const csvPreviewer: FileBrowserPreviewer = {\n\tid: 'csv',\n\tmatch: isDelimited,\n\tread: 'text',\n\tcomponent: ({ content, item }) => (\n\t\t<Spreadsheet label={item.name} sheets={[{ name: item.name, rows: parse(content).rows }]} />\n\t)\n}\n\n/** Spreadsheet-style CSV/TSV editor that keeps the file's delimiter and line endings. */\nexport const csvEditor: FileBrowserEditor = {\n\tid: 'csv',\n\tmatch: isDelimited,\n\tread: 'text',\n\tcomponent: ({ content, item, onChange }) => {\n\t\tconst parsed = parse(content)\n\t\treturn (\n\t\t\t<Spreadsheet\n\t\t\t\tlabel={item.name}\n\t\t\t\tonChange={([rows]) =>\n\t\t\t\t\tonChange(\n\t\t\t\t\t\tPapa.unparse(\n\t\t\t\t\t\t\ttrimSheet(rows ?? []).map((row) => row.map((cell) => String(cell ?? ''))),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdelimiter: parsed.delimiter,\n\t\t\t\t\t\t\t\tnewline: parsed.newline\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tsheets={[{ name: item.name, rows: parsed.rows }]}\n\t\t\t/>\n\t\t)\n\t}\n}\n"],"mappings":";;;;;AAMA,IAAM,KAAe,MACpB,CAAC,OAAO,KAAK,CAAC,CAAC,SAAS,EAAiB,EAAK,IAAI,CAAC,KAAK,EAAK,aAAa;AAE3E,SAAS,EAAM,GAAkB;CAChC,IAAM,IAAS,EAAK,MAAgB,OAAO,KAAY,WAAW,IAAU,IAAI,EAAE,gBAAgB,SAAS,CAAC;CAC5G,OAAO;EAAE,MAAM,EAAO;EAAM,WAAW,EAAO,KAAK,aAAa;EAAK,SAAS,EAAO,KAAK,aAAa;CAAK;AAC7G;AAGA,IAAa,IAAqC;CACjD,IAAI;CACJ,OAAO;CACP,MAAM;CACN,YAAY,EAAE,YAAS,cACtB,kBAAC,GAAD;EAAa,OAAO,EAAK;EAAM,QAAQ,CAAC;GAAE,MAAM,EAAK;GAAM,MAAM,EAAM,CAAO,CAAC,CAAC;EAAK,CAAC;CAAI,CAAA;AAE5F,GAGa,IAA+B;CAC3C,IAAI;CACJ,OAAO;CACP,MAAM;CACN,YAAY,EAAE,YAAS,SAAM,kBAAe;EAC3C,IAAM,IAAS,EAAM,CAAO;EAC5B,OACC,kBAAC,GAAD;GACC,OAAO,EAAK;GACZ,WAAW,CAAC,OACX,EACC,EAAK,QACJ,EAAU,KAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,MAAQ,EAAI,KAAK,MAAS,OAAO,KAAQ,EAAE,CAAC,CAAC,GACxE;IACC,WAAW,EAAO;IAClB,SAAS,EAAO;GACjB,CACD,CACD;GAED,QAAQ,CAAC;IAAE,MAAM,EAAK;IAAM,MAAM,EAAO;GAAK,CAAC;EAC/C,CAAA;CAEH;AACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/docx/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AA6BzE,4CAA4C;AAC5C,eAAO,MAAM,aAAa,EAAE,oBAM3B,CAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { i as e } from "../../chunks/file-types-DZ2qAUnj.js";
|
|
2
|
+
import { useEffect as t, useRef as n, useState as r } from "react";
|
|
3
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
4
|
+
import { renderAsync as o } from "docx-preview";
|
|
5
|
+
//#region src/plugins/docx/index.tsx
|
|
6
|
+
var s = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
7
|
+
function c({ content: e }) {
|
|
8
|
+
let s = n(null), c = n(null), [l, u] = r(null);
|
|
9
|
+
return t(() => {
|
|
10
|
+
let t = s.current;
|
|
11
|
+
!t || !(e instanceof ArrayBuffer) || (t.replaceChildren(), o(e, t, c.current ?? void 0, {
|
|
12
|
+
className: "docx",
|
|
13
|
+
inWrapper: !0
|
|
14
|
+
}).catch((e) => u(e instanceof Error ? e.message : String(e))));
|
|
15
|
+
}, [e]), /* @__PURE__ */ a("div", {
|
|
16
|
+
className: "max-h-[min(640px,65dvh)] w-full overflow-auto rounded-[var(--fb-radius)] border border-[var(--fb-border)] bg-[var(--fb-surface-2)]",
|
|
17
|
+
children: [
|
|
18
|
+
l ? /* @__PURE__ */ i("p", {
|
|
19
|
+
className: "m-0 p-4 text-[var(--fb-danger)]",
|
|
20
|
+
children: l
|
|
21
|
+
}) : null,
|
|
22
|
+
/* @__PURE__ */ i("div", {
|
|
23
|
+
hidden: !0,
|
|
24
|
+
ref: c
|
|
25
|
+
}),
|
|
26
|
+
/* @__PURE__ */ i("div", { ref: s })
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
var l = {
|
|
31
|
+
id: "docx",
|
|
32
|
+
match: (t) => e(t.name) === "docx" || t.mimeType === s,
|
|
33
|
+
read: "binary",
|
|
34
|
+
maxBytes: 20 * 1024 * 1024,
|
|
35
|
+
component: ({ content: e }) => /* @__PURE__ */ i(c, { content: e })
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
export { l as docxPreviewer };
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/plugins/docx/index.tsx"],"sourcesContent":["import { renderAsync } from 'docx-preview'\nimport { useEffect, useRef, useState } from 'react'\nimport type { FileBrowserPreviewer } from '../../components/file-plugins'\nimport { getFileExtension } from '../../components/file-types'\n\nconst DOCX_MIME = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'\n\nfunction DocxView({ content }: { content: ArrayBuffer | string | null }) {\n\tconst bodyRef = useRef<HTMLDivElement>(null)\n\tconst styleRef = useRef<HTMLDivElement>(null)\n\tconst [error, setError] = useState<string | null>(null)\n\n\tuseEffect(() => {\n\t\tconst body = bodyRef.current\n\t\tif (!body || !(content instanceof ArrayBuffer)) return\n\t\tbody.replaceChildren()\n\t\t// docx-preview scopes its generated styles under the `docx` class inside the style container.\n\t\trenderAsync(content, body, styleRef.current ?? undefined, { className: 'docx', inWrapper: true }).catch(\n\t\t\t(caught: unknown) => setError(caught instanceof Error ? caught.message : String(caught))\n\t\t)\n\t}, [content])\n\n\treturn (\n\t\t<div className=\"max-h-[min(640px,65dvh)] w-full overflow-auto rounded-[var(--fb-radius)] border border-[var(--fb-border)] bg-[var(--fb-surface-2)]\">\n\t\t\t{error ? <p className=\"m-0 p-4 text-[var(--fb-danger)]\">{error}</p> : null}\n\t\t\t<div hidden ref={styleRef} />\n\t\t\t<div ref={bodyRef} />\n\t\t</div>\n\t)\n}\n\n/** Word document preview (docx-preview). */\nexport const docxPreviewer: FileBrowserPreviewer = {\n\tid: 'docx',\n\tmatch: (item) => getFileExtension(item.name) === 'docx' || item.mimeType === DOCX_MIME,\n\tread: 'binary',\n\tmaxBytes: 20 * 1024 * 1024,\n\tcomponent: ({ content }) => <DocxView content={content} />\n}\n"],"mappings":";;;;;AAKA,IAAM,IAAY;AAElB,SAAS,EAAS,EAAE,cAAqD;CACxE,IAAM,IAAU,EAAuB,IAAI,GACrC,IAAW,EAAuB,IAAI,GACtC,CAAC,GAAO,KAAY,EAAwB,IAAI;CAYtD,OAVA,QAAgB;EACf,IAAM,IAAO,EAAQ;EACjB,CAAC,KAAQ,EAAE,aAAmB,iBAClC,EAAK,gBAAgB,GAErB,EAAY,GAAS,GAAM,EAAS,WAAW,KAAA,GAAW;GAAE,WAAW;GAAQ,WAAW;EAAK,CAAC,CAAC,CAAC,OAChG,MAAoB,EAAS,aAAkB,QAAQ,EAAO,UAAU,OAAO,CAAM,CAAC,CACxF;CACD,GAAG,CAAC,CAAO,CAAC,GAGX,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,IAAQ,kBAAC,KAAD;IAAG,WAAU;cAAmC;GAAS,CAAA,IAAI;GACtE,kBAAC,OAAD;IAAK,QAAA;IAAO,KAAK;GAAW,CAAA;GAC5B,kBAAC,OAAD,EAAK,KAAK,EAAU,CAAA;EAChB;;AAEP;AAGA,IAAa,IAAsC;CAClD,IAAI;CACJ,QAAQ,MAAS,EAAiB,EAAK,IAAI,MAAM,UAAU,EAAK,aAAa;CAC7E,MAAM;CACN,UAAU,KAAK,OAAO;CACtB,YAAY,EAAE,iBAAc,kBAAC,GAAD,EAAmB,WAAU,CAAA;AAC1D"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FileBrowserEditor, FileBrowserPreviewer } from '../../components/file-plugins';
|
|
2
|
+
/** Rendered Markdown preview (react-markdown). */
|
|
3
|
+
export declare const markdownPreviewer: FileBrowserPreviewer;
|
|
4
|
+
/** Markdown to the HTML the visual editor shows. */
|
|
5
|
+
export declare function markdownToHtml(markdown: string): string;
|
|
6
|
+
/** Visual editor HTML back to Markdown, without the empty paragraphs the editor keeps for the caret. */
|
|
7
|
+
export declare function htmlToMarkdown(html: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* WYSIWYG Markdown editor (Squire, with marked and turndown converting to and from Markdown).
|
|
10
|
+
* Saving rewrites the file's Markdown, so spacing and list markers may be normalized.
|
|
11
|
+
*/
|
|
12
|
+
export declare const markdownEditor: FileBrowserEditor;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/markdown/index.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AAqB5F,kDAAkD;AAClD,eAAO,MAAM,iBAAiB,EAAE,oBAS/B,CAAA;AASD,oDAAoD;AACpD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wGAAwG;AACxG,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,iBAiB5B,CAAA"}
|