@particle-academy/fancy-code 0.5.1 → 0.6.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 +28 -1
- package/dist/index.cjs +115 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +103 -3
- package/dist/index.d.ts +103 -3
- package/dist/index.js +114 -2
- package/dist/index.js.map +1 -1
- package/docs/FileViewer.md +78 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install @particle-academy/fancy-code
|
|
|
12
12
|
# or: yarn add @particle-academy/fancy-code
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
**Peer dependencies:** `react >= 18`, `react-dom >= 18`, `@particle-academy/react-fancy >=
|
|
15
|
+
**Peer dependencies:** `react >= 18`, `react-dom >= 18`, `@particle-academy/react-fancy >= 4.9` (the `FileViewer` delegates media to react-fancy's `<MediaViewer>`, added in 4.9)
|
|
16
16
|
|
|
17
17
|
## Setup
|
|
18
18
|
|
|
@@ -44,11 +44,38 @@ function App() {
|
|
|
44
44
|
|
|
45
45
|
The component ships with no default border or rounding — add your own via `className` for standalone use, or embed directly into IDE layouts without visual conflicts.
|
|
46
46
|
|
|
47
|
+
## Unified file viewer
|
|
48
|
+
|
|
49
|
+
Showing arbitrary files from a tree? `FileViewer` renders text in the
|
|
50
|
+
`CodeEditor` and delegates **media** (image / video / audio / PDF) to
|
|
51
|
+
react-fancy's `<MediaViewer>` — so an image no longer renders as binary text.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { FileViewer } from "@particle-academy/fancy-code";
|
|
55
|
+
|
|
56
|
+
// text → CodeEditor (read-only, language picked from the filename)
|
|
57
|
+
<FileViewer filename="app.tsx" value={source} />
|
|
58
|
+
|
|
59
|
+
// media → <MediaViewer> (pass the file URL as `src`)
|
|
60
|
+
<FileViewer filename="logo.png" src={url} style={{ height: 360 }} />
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Need to branch your own chrome (tabs, save buttons)? Call `resolveFileKind`
|
|
64
|
+
yourself — it's the same text-vs-media decision `FileViewer` makes internally:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { resolveFileKind } from "@particle-academy/fancy-code";
|
|
68
|
+
|
|
69
|
+
resolveFileKind({ filename: "logo.png" }); // { kind: "media", mediaKind: "image" }
|
|
70
|
+
resolveFileKind({ filename: "app.tsx" }); // { kind: "text", language: "typescript" }
|
|
71
|
+
```
|
|
72
|
+
|
|
47
73
|
## Documentation
|
|
48
74
|
|
|
49
75
|
| Topic | Doc |
|
|
50
76
|
|-------|-----|
|
|
51
77
|
| Full component API (props, sub-components, `useCodeEditor` hook) | [docs/CodeEditor.md](./docs/CodeEditor.md) |
|
|
78
|
+
| Unified file viewer (text + media), `resolveFileKind` | [docs/FileViewer.md](./docs/FileViewer.md) |
|
|
52
79
|
| Built-in languages + registering custom ones | [docs/languages.md](./docs/languages.md) |
|
|
53
80
|
| Built-in themes + custom theme registration | [docs/themes.md](./docs/themes.md) |
|
|
54
81
|
|
package/dist/index.cjs
CHANGED
|
@@ -1833,6 +1833,118 @@ function MarkdownEditor({
|
|
|
1833
1833
|
);
|
|
1834
1834
|
}
|
|
1835
1835
|
MarkdownEditor.displayName = "MarkdownEditor";
|
|
1836
|
+
var EXT_LANGUAGE = {
|
|
1837
|
+
js: "javascript",
|
|
1838
|
+
mjs: "javascript",
|
|
1839
|
+
cjs: "javascript",
|
|
1840
|
+
jsx: "javascript",
|
|
1841
|
+
json: "javascript",
|
|
1842
|
+
// the JS tokenizer highlights JSON acceptably
|
|
1843
|
+
jsonc: "javascript",
|
|
1844
|
+
ts: "typescript",
|
|
1845
|
+
mts: "typescript",
|
|
1846
|
+
cts: "typescript",
|
|
1847
|
+
tsx: "typescript",
|
|
1848
|
+
html: "html",
|
|
1849
|
+
htm: "html",
|
|
1850
|
+
xml: "html",
|
|
1851
|
+
xhtml: "html",
|
|
1852
|
+
vue: "html",
|
|
1853
|
+
php: "php",
|
|
1854
|
+
phtml: "php",
|
|
1855
|
+
py: "python",
|
|
1856
|
+
pyw: "python",
|
|
1857
|
+
go: "go",
|
|
1858
|
+
md: "markdown",
|
|
1859
|
+
markdown: "markdown",
|
|
1860
|
+
mkd: "markdown",
|
|
1861
|
+
mdx: "markdown"
|
|
1862
|
+
};
|
|
1863
|
+
function basename(filename) {
|
|
1864
|
+
return filename.split(/[?#]/, 1)[0].split(/[\\/]/).pop() ?? "";
|
|
1865
|
+
}
|
|
1866
|
+
function languageFromFilename(filename) {
|
|
1867
|
+
if (!filename) return "plaintext";
|
|
1868
|
+
const seg = basename(filename);
|
|
1869
|
+
const dot = seg.lastIndexOf(".");
|
|
1870
|
+
if (dot <= 0) return "plaintext";
|
|
1871
|
+
const ext = seg.slice(dot + 1).toLowerCase();
|
|
1872
|
+
return EXT_LANGUAGE[ext] ?? "plaintext";
|
|
1873
|
+
}
|
|
1874
|
+
function resolveFileKind({ filename, mime }) {
|
|
1875
|
+
const media = reactFancy.resolveMediaType({ mime, src: filename });
|
|
1876
|
+
if (media !== "unknown") return { kind: "media", mediaKind: media };
|
|
1877
|
+
return { kind: "text", language: languageFromFilename(filename) };
|
|
1878
|
+
}
|
|
1879
|
+
function FileViewer({
|
|
1880
|
+
filename,
|
|
1881
|
+
mime,
|
|
1882
|
+
src,
|
|
1883
|
+
value = "",
|
|
1884
|
+
onChange,
|
|
1885
|
+
readOnly = true,
|
|
1886
|
+
theme = "auto",
|
|
1887
|
+
fileKind,
|
|
1888
|
+
lineNumbers = true,
|
|
1889
|
+
wordWrap = false,
|
|
1890
|
+
minHeight,
|
|
1891
|
+
maxHeight,
|
|
1892
|
+
mediaProps,
|
|
1893
|
+
className,
|
|
1894
|
+
style
|
|
1895
|
+
}) {
|
|
1896
|
+
const resolved = fileKind ?? resolveFileKind({ filename, mime });
|
|
1897
|
+
if (resolved.kind === "media") {
|
|
1898
|
+
const { className: mediaClassName, ...restMediaProps } = mediaProps ?? {};
|
|
1899
|
+
const fill = resolved.mediaKind !== "audio";
|
|
1900
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1901
|
+
"div",
|
|
1902
|
+
{
|
|
1903
|
+
"data-fancy-file-viewer": "",
|
|
1904
|
+
"data-kind": "media",
|
|
1905
|
+
"data-media-kind": resolved.mediaKind,
|
|
1906
|
+
className: reactFancy.cn("overflow-hidden", className),
|
|
1907
|
+
style,
|
|
1908
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1909
|
+
reactFancy.MediaViewer,
|
|
1910
|
+
{
|
|
1911
|
+
src: src ?? "",
|
|
1912
|
+
mime,
|
|
1913
|
+
alt: filename,
|
|
1914
|
+
kind: resolved.mediaKind,
|
|
1915
|
+
className: reactFancy.cn(fill && "h-full w-full", mediaClassName),
|
|
1916
|
+
...restMediaProps
|
|
1917
|
+
}
|
|
1918
|
+
)
|
|
1919
|
+
}
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1923
|
+
"div",
|
|
1924
|
+
{
|
|
1925
|
+
"data-fancy-file-viewer": "",
|
|
1926
|
+
"data-kind": "text",
|
|
1927
|
+
className,
|
|
1928
|
+
style,
|
|
1929
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1930
|
+
CodeEditor,
|
|
1931
|
+
{
|
|
1932
|
+
value,
|
|
1933
|
+
onChange: readOnly ? void 0 : onChange,
|
|
1934
|
+
language: resolved.language,
|
|
1935
|
+
theme,
|
|
1936
|
+
readOnly,
|
|
1937
|
+
lineNumbers,
|
|
1938
|
+
wordWrap,
|
|
1939
|
+
minHeight,
|
|
1940
|
+
maxHeight,
|
|
1941
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CodeEditor.Panel, {})
|
|
1942
|
+
}
|
|
1943
|
+
)
|
|
1944
|
+
}
|
|
1945
|
+
);
|
|
1946
|
+
}
|
|
1947
|
+
FileViewer.displayName = "FileViewer";
|
|
1836
1948
|
function useCodeEditorInputTagAdapter() {
|
|
1837
1949
|
const ctx = useCodeEditor();
|
|
1838
1950
|
return react.useMemo(() => reactFancy.textareaAdapter(ctx.textareaRef), [ctx.textareaRef]);
|
|
@@ -1844,14 +1956,17 @@ function CodeEditorInputTag(props) {
|
|
|
1844
1956
|
|
|
1845
1957
|
exports.CodeEditor = CodeEditor;
|
|
1846
1958
|
exports.CodeEditorInputTag = CodeEditorInputTag;
|
|
1959
|
+
exports.FileViewer = FileViewer;
|
|
1847
1960
|
exports.MarkdownEditor = MarkdownEditor;
|
|
1848
1961
|
exports.getLanguage = getLanguage;
|
|
1849
1962
|
exports.getRegisteredLanguages = getRegisteredLanguages;
|
|
1850
1963
|
exports.getRegisteredThemes = getRegisteredThemes;
|
|
1851
1964
|
exports.getTheme = getTheme;
|
|
1965
|
+
exports.languageFromFilename = languageFromFilename;
|
|
1852
1966
|
exports.registerLanguage = registerLanguage;
|
|
1853
1967
|
exports.registerTheme = registerTheme;
|
|
1854
1968
|
exports.renderMarkdown = renderMarkdown;
|
|
1969
|
+
exports.resolveFileKind = resolveFileKind;
|
|
1855
1970
|
exports.tokenizeMarkdown = tokenizeMarkdown;
|
|
1856
1971
|
exports.useCodeEditor = useCodeEditor;
|
|
1857
1972
|
exports.useCodeEditorInputTagAdapter = useCodeEditorInputTagAdapter;
|