@particle-academy/fancy-code 0.13.0 → 0.15.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/CHANGELOG.md +34 -0
- package/dist/index.cjs +80 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -3
- package/dist/index.d.ts +51 -3
- package/dist/index.js +79 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,40 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
14
14
|
|
|
15
15
|
## [Unreleased]
|
|
16
16
|
|
|
17
|
+
## [0.15.0] - 2026-10-19
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Office files open in the kit's own viewers.** `registerOfficeViewer(kind,
|
|
22
|
+
View, { read })` wires a viewer for `pptx`, `xlsx` or `docx` into
|
|
23
|
+
`FileViewer`, one line per format at app start:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
registerOfficeViewer("pptx", DeckFileView, { read: (b) => new PptxReader().read(b) });
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`DeckFileView` ships in fancy-slides and `WorkbookFileView` in fancy-sheets.
|
|
30
|
+
The viewer gets the file's contents in this order: the new `document` prop,
|
|
31
|
+
the contents the app's server already read (preferred); else the file at
|
|
32
|
+
`src`, read in the browser by the registered `read`; else the download card
|
|
33
|
+
as before. A file the reader cannot open shows the reason beside the
|
|
34
|
+
download. A registry rather than an import so fancy-code never depends on the
|
|
35
|
+
slide or sheet packages, and an app with neither cannot fail to build on them.
|
|
36
|
+
**Nothing to do** unless you want Office previews: unregistered formats behave
|
|
37
|
+
exactly as in 0.14.
|
|
38
|
+
|
|
39
|
+
## [0.14.0] - 2026-10-19
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- **Images and PDFs in `FileViewer` sit in the `FauxClient` frame**, like
|
|
44
|
+
documents: an image gets the frame's zoom bar (driving its own pan/zoom) and
|
|
45
|
+
full screen; a PDF gets full screen, with zoom left to the browser's PDF
|
|
46
|
+
toolbar, and its file name in the address bar. Revealed on hover.
|
|
47
|
+
**What to do:** nothing to keep the new look. To turn it off, pass
|
|
48
|
+
`mediaProps={{ imageProps: { frame: false } }}` (or `pdfProps`).
|
|
49
|
+
- **Requires react-fancy 5.49.0 or later** (peer `>=5.49.0 <6.0.0`).
|
|
50
|
+
|
|
17
51
|
## [0.13.0] - 2026-10-19
|
|
18
52
|
|
|
19
53
|
### Added
|
package/dist/index.cjs
CHANGED
|
@@ -1721,6 +1721,18 @@ function MarkdownEditor({
|
|
|
1721
1721
|
);
|
|
1722
1722
|
}
|
|
1723
1723
|
MarkdownEditor.displayName = "MarkdownEditor";
|
|
1724
|
+
|
|
1725
|
+
// src/office-viewers.ts
|
|
1726
|
+
var registry = /* @__PURE__ */ new Map();
|
|
1727
|
+
function registerOfficeViewer(kind, View, options = {}) {
|
|
1728
|
+
registry.set(kind, { View, read: options.read });
|
|
1729
|
+
}
|
|
1730
|
+
function officeViewerFor(kind) {
|
|
1731
|
+
return registry.get(kind);
|
|
1732
|
+
}
|
|
1733
|
+
function clearOfficeViewers() {
|
|
1734
|
+
registry.clear();
|
|
1735
|
+
}
|
|
1724
1736
|
var OFFICE_EXT = { docx: "docx", xlsx: "xlsx", xlsm: "xlsx", pptx: "pptx" };
|
|
1725
1737
|
var OFFICE_MIME = {
|
|
1726
1738
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
|
|
@@ -1780,6 +1792,7 @@ function FileViewer({
|
|
|
1780
1792
|
mediaProps,
|
|
1781
1793
|
view = "rendered",
|
|
1782
1794
|
frameProps,
|
|
1795
|
+
document,
|
|
1783
1796
|
className,
|
|
1784
1797
|
style
|
|
1785
1798
|
}) {
|
|
@@ -1812,12 +1825,24 @@ function FileViewer({
|
|
|
1812
1825
|
"data-office-kind": resolved.officeKind,
|
|
1813
1826
|
className: reactFancy.cn("overflow-hidden", className),
|
|
1814
1827
|
style,
|
|
1815
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1828
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1829
|
+
OfficeFile,
|
|
1830
|
+
{
|
|
1831
|
+
kind: resolved.officeKind,
|
|
1832
|
+
document,
|
|
1833
|
+
src,
|
|
1834
|
+
mime,
|
|
1835
|
+
filename,
|
|
1836
|
+
frameProps
|
|
1837
|
+
}
|
|
1838
|
+
)
|
|
1816
1839
|
}
|
|
1817
1840
|
);
|
|
1818
1841
|
}
|
|
1819
1842
|
if (resolved.kind === "media") {
|
|
1820
1843
|
const { className: mediaClassName, ...restMediaProps } = mediaProps ?? {};
|
|
1844
|
+
restMediaProps.imageProps = { frame: true, frameProps, ...restMediaProps.imageProps };
|
|
1845
|
+
restMediaProps.pdfProps = { frame: true, frameProps, ...restMediaProps.pdfProps };
|
|
1821
1846
|
const fill = resolved.mediaKind !== "audio";
|
|
1822
1847
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1823
1848
|
"div",
|
|
@@ -1870,6 +1895,57 @@ function FileViewer({
|
|
|
1870
1895
|
);
|
|
1871
1896
|
}
|
|
1872
1897
|
FileViewer.displayName = "FileViewer";
|
|
1898
|
+
function OfficeFile({
|
|
1899
|
+
kind,
|
|
1900
|
+
document,
|
|
1901
|
+
src,
|
|
1902
|
+
mime,
|
|
1903
|
+
filename,
|
|
1904
|
+
frameProps
|
|
1905
|
+
}) {
|
|
1906
|
+
const registration = officeViewerFor(kind);
|
|
1907
|
+
const read = registration?.read;
|
|
1908
|
+
const [state, setState] = react.useState({ status: "idle" });
|
|
1909
|
+
react.useEffect(() => {
|
|
1910
|
+
if (!registration || document !== void 0 || !src || !read) return;
|
|
1911
|
+
let live = true;
|
|
1912
|
+
setState({ status: "reading" });
|
|
1913
|
+
fetch(src).then(async (response) => {
|
|
1914
|
+
if (!response.ok) throw new Error(`The file could not be fetched (${response.status}).`);
|
|
1915
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
1916
|
+
const doc = read(bytes);
|
|
1917
|
+
if (live) setState({ status: "read", document: doc });
|
|
1918
|
+
}).catch((error) => {
|
|
1919
|
+
if (live) setState({ status: "failed", message: error instanceof Error ? error.message : String(error) });
|
|
1920
|
+
});
|
|
1921
|
+
return () => {
|
|
1922
|
+
live = false;
|
|
1923
|
+
};
|
|
1924
|
+
}, [registration, document, src, read]);
|
|
1925
|
+
const fallback = /* @__PURE__ */ jsxRuntime.jsx(reactFancy.MediaViewer, { src: src ?? "", mime, alt: filename, className: "h-full w-full" });
|
|
1926
|
+
if (!registration) return fallback;
|
|
1927
|
+
const View = registration.View;
|
|
1928
|
+
if (document !== void 0) return /* @__PURE__ */ jsxRuntime.jsx(View, { document, filename, frameProps });
|
|
1929
|
+
if (state.status === "read") return /* @__PURE__ */ jsxRuntime.jsx(View, { document: state.document, filename, frameProps });
|
|
1930
|
+
if (state.status === "reading") {
|
|
1931
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full items-center justify-center p-6 text-sm text-zinc-500", children: [
|
|
1932
|
+
"Opening ",
|
|
1933
|
+
filename ?? "the file",
|
|
1934
|
+
"\u2026"
|
|
1935
|
+
] });
|
|
1936
|
+
}
|
|
1937
|
+
if (state.status === "failed") {
|
|
1938
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col gap-2 p-2", children: [
|
|
1939
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactFancy.Callout, { color: "red", children: [
|
|
1940
|
+
filename ?? "This file",
|
|
1941
|
+
" could not be opened: ",
|
|
1942
|
+
state.message
|
|
1943
|
+
] }),
|
|
1944
|
+
fallback
|
|
1945
|
+
] });
|
|
1946
|
+
}
|
|
1947
|
+
return fallback;
|
|
1948
|
+
}
|
|
1873
1949
|
var ESCAPES = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
1874
1950
|
function textToHtml(text) {
|
|
1875
1951
|
return text.replace(/\r\n?/g, "\n").split(/\n{2,}/).filter((block) => block.trim() !== "").map((block) => `<p>${block.replace(/[&<>"']/g, (c) => ESCAPES[c]).replace(/\n/g, "<br>")}</p>`).join("");
|
|
@@ -2009,6 +2085,7 @@ exports.CodeEditor = CodeEditor;
|
|
|
2009
2085
|
exports.CodeEditorInputTag = CodeEditorInputTag;
|
|
2010
2086
|
exports.FileViewer = FileViewer;
|
|
2011
2087
|
exports.MarkdownEditor = MarkdownEditor;
|
|
2088
|
+
exports.clearOfficeViewers = clearOfficeViewers;
|
|
2012
2089
|
exports.diffMarkColor = diffMarkColor;
|
|
2013
2090
|
exports.diffRemovedColor = diffRemovedColor;
|
|
2014
2091
|
exports.getLanguage = getLanguage;
|
|
@@ -2017,7 +2094,9 @@ exports.getRegisteredThemes = getRegisteredThemes;
|
|
|
2017
2094
|
exports.getTheme = getTheme;
|
|
2018
2095
|
exports.gutterDiffMark = gutterDiffMark;
|
|
2019
2096
|
exports.hasDeletedAtEnd = hasDeletedAtEnd;
|
|
2097
|
+
exports.officeViewerFor = officeViewerFor;
|
|
2020
2098
|
exports.registerLanguage = registerLanguage;
|
|
2099
|
+
exports.registerOfficeViewer = registerOfficeViewer;
|
|
2021
2100
|
exports.registerTheme = registerTheme;
|
|
2022
2101
|
exports.renderMarkdown = renderMarkdown;
|
|
2023
2102
|
exports.resolveFileKind = resolveFileKind;
|