@particle-academy/fancy-code 0.14.0 → 0.15.1
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 +28 -0
- package/dist/index.cjs +78 -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 +77 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,34 @@ 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.1] - 2026-11-01
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **The `@particle-academy/react-fancy` peer range now also accepts 6.x** (`>=5.49.0 <6.0.0` to `>=5.49.0 <7.0.0`). react-fancy 6.0.0 makes `Button` default to `type="button"` instead of submitting an enclosing form (Change Council CC-fancy-0003). Audited for that: it renders no react-fancy `Button` and no form. No `Button` needed `type="submit"` and no `PromptInput` is used, so the package behaves the same on 5 and 6. The devDependency moved to `^6.0.0`, so this package's own suite, typecheck and build now run against 6. Widening only adds candidates, so the react-fancy you already have still resolves. **Consumer action:** none on react-fancy 5; on react-fancy 6 it works as-is.
|
|
22
|
+
|
|
23
|
+
## [0.15.0] - 2026-10-19
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **Office files open in the kit's own viewers.** `registerOfficeViewer(kind,
|
|
28
|
+
View, { read })` wires a viewer for `pptx`, `xlsx` or `docx` into
|
|
29
|
+
`FileViewer`, one line per format at app start:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
registerOfficeViewer("pptx", DeckFileView, { read: (b) => new PptxReader().read(b) });
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`DeckFileView` ships in fancy-slides and `WorkbookFileView` in fancy-sheets.
|
|
36
|
+
The viewer gets the file's contents in this order: the new `document` prop,
|
|
37
|
+
the contents the app's server already read (preferred); else the file at
|
|
38
|
+
`src`, read in the browser by the registered `read`; else the download card
|
|
39
|
+
as before. A file the reader cannot open shows the reason beside the
|
|
40
|
+
download. A registry rather than an import so fancy-code never depends on the
|
|
41
|
+
slide or sheet packages, and an app with neither cannot fail to build on them.
|
|
42
|
+
**Nothing to do** unless you want Office previews: unregistered formats behave
|
|
43
|
+
exactly as in 0.14.
|
|
44
|
+
|
|
17
45
|
## [0.14.0] - 2026-10-19
|
|
18
46
|
|
|
19
47
|
### Changed
|
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,7 +1825,17 @@ 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
|
}
|
|
@@ -1872,6 +1895,57 @@ function FileViewer({
|
|
|
1872
1895
|
);
|
|
1873
1896
|
}
|
|
1874
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
|
+
}
|
|
1875
1949
|
var ESCAPES = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
1876
1950
|
function textToHtml(text) {
|
|
1877
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("");
|
|
@@ -2011,6 +2085,7 @@ exports.CodeEditor = CodeEditor;
|
|
|
2011
2085
|
exports.CodeEditorInputTag = CodeEditorInputTag;
|
|
2012
2086
|
exports.FileViewer = FileViewer;
|
|
2013
2087
|
exports.MarkdownEditor = MarkdownEditor;
|
|
2088
|
+
exports.clearOfficeViewers = clearOfficeViewers;
|
|
2014
2089
|
exports.diffMarkColor = diffMarkColor;
|
|
2015
2090
|
exports.diffRemovedColor = diffRemovedColor;
|
|
2016
2091
|
exports.getLanguage = getLanguage;
|
|
@@ -2019,7 +2094,9 @@ exports.getRegisteredThemes = getRegisteredThemes;
|
|
|
2019
2094
|
exports.getTheme = getTheme;
|
|
2020
2095
|
exports.gutterDiffMark = gutterDiffMark;
|
|
2021
2096
|
exports.hasDeletedAtEnd = hasDeletedAtEnd;
|
|
2097
|
+
exports.officeViewerFor = officeViewerFor;
|
|
2022
2098
|
exports.registerLanguage = registerLanguage;
|
|
2099
|
+
exports.registerOfficeViewer = registerOfficeViewer;
|
|
2023
2100
|
exports.registerTheme = registerTheme;
|
|
2024
2101
|
exports.renderMarkdown = renderMarkdown;
|
|
2025
2102
|
exports.resolveFileKind = resolveFileKind;
|