weifuwu 0.85.0 → 0.86.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 +5 -5
- package/dist/components/Editor/Editor.d.ts +8 -7
- package/dist/components/Editor/edit-events.d.ts +27 -0
- package/dist/components/Editor/model/apply.d.ts +23 -0
- package/dist/components/Editor/model/diff.d.ts +25 -0
- package/dist/components/Editor/model/dom.d.ts +27 -0
- package/dist/components/Editor/model/history.d.ts +21 -0
- package/dist/components/Editor/model/html.d.ts +16 -0
- package/dist/components/Editor/model/inverse.d.ts +20 -0
- package/dist/components/Editor/model/types.d.ts +116 -0
- package/dist/components/Editor/tools/table.d.ts +5 -2
- package/dist/components/Editor/tools/toolbar.d.ts +1 -1
- package/dist/components/Editor/tools/types.d.ts +25 -0
- package/dist/components/FilePreview/FilePreview.d.ts +42 -0
- package/dist/components/FilePreview/markdown.d.ts +23 -0
- package/dist/components/OfficeEditor/ai/ai-bridge.d.ts +39 -0
- package/dist/components/OfficeEditor/model/apply.d.ts +25 -0
- package/dist/components/OfficeEditor/model/types.d.ts +224 -0
- package/dist/components/SheetGrid/SheetGrid.d.ts +30 -0
- package/dist/components/SlideCanvas/SlideCanvas.d.ts +28 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.js +54 -14
- package/dist/components/style.css +679 -4
- package/dist/index.js +38 -11
- package/dist/office/docx.d.ts +33 -0
- package/dist/office/pptx.d.ts +24 -0
- package/dist/office/xlsx.d.ts +25 -0
- package/dist/office/xml-serialize.d.ts +18 -0
- package/dist/office/xml.d.ts +21 -0
- package/dist/office/zip.d.ts +21 -0
- package/dist/ui-dom/index.js +7 -7
- package/dist/ui-dom/locale/en_US.d.ts +14 -0
- package/dist/ui-dom/locale/zh_CN.d.ts +14 -0
- package/dist/ui-dom/testing.js +5 -5
- package/dist/ui-dom/types.d.ts +3 -1
- package/dist/ui-dom/vdom3/delegate.d.ts +5 -0
- package/dist/ui-dom/vdom3.js +7 -7
- package/docs/components-map.md +12 -0
- package/docs/components.md +124 -2
- package/package.json +1 -1
- package/dist/components/Editor/tools/format.d.ts +0 -11
package/dist/index.js
CHANGED
|
@@ -3607,6 +3607,17 @@ function createClientBrowser() {
|
|
|
3607
3607
|
if (typeof window !== "undefined") window.location.hash = h2;
|
|
3608
3608
|
},
|
|
3609
3609
|
timeout: (fn, ms) => typeof window !== "undefined" ? window.setTimeout(fn, ms) : 0,
|
|
3610
|
+
/** 浏览器表单状态恢复(load/pageshow)监听——SSR 安全 no-op */
|
|
3611
|
+
onFormRestore: (cb) => {
|
|
3612
|
+
if (typeof window === "undefined" || typeof document === "undefined") return () => {
|
|
3613
|
+
};
|
|
3614
|
+
window.addEventListener("load", cb, { once: true });
|
|
3615
|
+
window.addEventListener("pageshow", cb);
|
|
3616
|
+
return () => {
|
|
3617
|
+
window.removeEventListener("load", cb);
|
|
3618
|
+
window.removeEventListener("pageshow", cb);
|
|
3619
|
+
};
|
|
3620
|
+
},
|
|
3610
3621
|
rootElement: () => typeof document !== "undefined" ? document.documentElement : null,
|
|
3611
3622
|
storageGet: (key) => {
|
|
3612
3623
|
try {
|
|
@@ -3770,7 +3781,15 @@ var globalHandlers = /* @__PURE__ */ new Map();
|
|
|
3770
3781
|
var globalRoots = /* @__PURE__ */ new Map();
|
|
3771
3782
|
var EVENT_MAP = {
|
|
3772
3783
|
focus: "focusin",
|
|
3773
|
-
blur: "focusout"
|
|
3784
|
+
blur: "focusout",
|
|
3785
|
+
mouseenter: "mouseover",
|
|
3786
|
+
mouseleave: "mouseout"
|
|
3787
|
+
};
|
|
3788
|
+
var REVERSE_MAP = {
|
|
3789
|
+
focusin: "focus",
|
|
3790
|
+
focusout: "blur",
|
|
3791
|
+
mouseover: "mouseenter",
|
|
3792
|
+
mouseout: "mouseleave"
|
|
3774
3793
|
};
|
|
3775
3794
|
var NON_BUBBLING = /* @__PURE__ */ new Set(["error", "load", "loadstart", "loadend", "abort", "unload", "resize", "message"]);
|
|
3776
3795
|
var TEXT_INPUT_EVENTS = /* @__PURE__ */ new Set(["input", "change", "compositionstart", "compositionend"]);
|
|
@@ -3805,11 +3824,11 @@ function rootOf(node) {
|
|
|
3805
3824
|
return null;
|
|
3806
3825
|
}
|
|
3807
3826
|
function ensureRootEvent(root, event) {
|
|
3827
|
+
const realEvent = EVENT_MAP[event] ?? event;
|
|
3808
3828
|
const set = registered.get(root) ?? /* @__PURE__ */ new Set();
|
|
3809
|
-
if (set.has(
|
|
3810
|
-
set.add(
|
|
3829
|
+
if (set.has(realEvent)) return;
|
|
3830
|
+
set.add(realEvent);
|
|
3811
3831
|
registered.set(root, set);
|
|
3812
|
-
const realEvent = EVENT_MAP[event] ?? event;
|
|
3813
3832
|
const fn = (e) => dispatch(e);
|
|
3814
3833
|
const useCapture = NON_BUBBLING.has(realEvent);
|
|
3815
3834
|
root.addEventListener(realEvent, fn, useCapture ? { capture: true } : void 0);
|
|
@@ -3857,8 +3876,11 @@ function addGlobalListener(target, event, handler, opts) {
|
|
|
3857
3876
|
function dispatch(e) {
|
|
3858
3877
|
let el = e.target;
|
|
3859
3878
|
if (el && el.nodeType === 3) el = el.parentElement;
|
|
3860
|
-
const
|
|
3861
|
-
if (
|
|
3879
|
+
const keys = [];
|
|
3880
|
+
if (handlers.has(e.type)) keys.push(e.type);
|
|
3881
|
+
const mapped = REVERSE_MAP[e.type];
|
|
3882
|
+
if (mapped && mapped !== e.type && handlers.has(mapped)) keys.push(mapped);
|
|
3883
|
+
if (keys.length === 0) return;
|
|
3862
3884
|
while (el) {
|
|
3863
3885
|
if (!el.hasAttribute?.("data-v3-id")) {
|
|
3864
3886
|
const idEl = el.closest?.("[data-v3-id]");
|
|
@@ -3869,8 +3891,9 @@ function dispatch(e) {
|
|
|
3869
3891
|
}
|
|
3870
3892
|
const id = el.getAttribute?.("data-v3-id");
|
|
3871
3893
|
if (id) {
|
|
3872
|
-
const
|
|
3873
|
-
|
|
3894
|
+
for (const k of keys) {
|
|
3895
|
+
const entry = handlers.get(k)?.get(id);
|
|
3896
|
+
if (!entry) continue;
|
|
3874
3897
|
try {
|
|
3875
3898
|
Object.defineProperty(e, "currentTarget", { value: el, configurable: true });
|
|
3876
3899
|
} catch {
|
|
@@ -3884,11 +3907,12 @@ function dispatch(e) {
|
|
|
3884
3907
|
stream.emit(ev("text", "input", id, { event: e.type, value: typeof value === "string" ? value.slice(0, 100) : null }));
|
|
3885
3908
|
}
|
|
3886
3909
|
if (entry.once) {
|
|
3887
|
-
|
|
3910
|
+
handlers.get(k).delete(id);
|
|
3888
3911
|
stream.emit(ev("event", "unbind", id, { event: e.type }));
|
|
3889
3912
|
}
|
|
3890
3913
|
if (e.cancelBubble) break;
|
|
3891
3914
|
}
|
|
3915
|
+
if (e.cancelBubble) break;
|
|
3892
3916
|
}
|
|
3893
3917
|
el = el.parentElement;
|
|
3894
3918
|
}
|
|
@@ -4402,7 +4426,8 @@ function usePopup(env, options) {
|
|
|
4402
4426
|
prevOpen = true;
|
|
4403
4427
|
lastEl = el;
|
|
4404
4428
|
}
|
|
4405
|
-
const props = content.props ?? {};
|
|
4429
|
+
const props = (content ?? h("span")).props ?? {};
|
|
4430
|
+
if (!content) return null;
|
|
4406
4431
|
latestContentRef = props.ref ?? null;
|
|
4407
4432
|
const cls = options.positioning === "none" ? props.class ?? "" : ["wf-popup", props.class].filter(Boolean).join(" ");
|
|
4408
4433
|
const style = options.positioning === "none" ? { ...props.style ?? {}, position: "fixed" } : {
|
|
@@ -5497,7 +5522,9 @@ async function buildVNode(vnode, ctx, oldV, isRoot = false) {
|
|
|
5497
5522
|
// SSR 下 document undefined → null/no-op——组件 36 处 ctx.browser 消费
|
|
5498
5523
|
// 无需各自 fallback(Tour 曾因 ctx.browser 缺失 → query 返回 undefined →
|
|
5499
5524
|
// targetEl 永不赋值 → rect 恒 0 → 引导高亮定位失效)
|
|
5500
|
-
browser
|
|
5525
|
+
// 注入优先(测试/宿主可覆盖——真实事故:ctx.browser 注入被覆盖——
|
|
5526
|
+
// Editor draftKey 的 storageSet 走真实 browser 而非 fake)
|
|
5527
|
+
browser: ctx.browser ?? createClientBrowser(),
|
|
5501
5528
|
ui: createV3Ui(compId, componentRender, (fn) => {
|
|
5502
5529
|
unmountHooks.set(compId, fn);
|
|
5503
5530
|
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/office/docx — docx ↔ ODES DocState 双向转换(前端/服务端通用——零依赖)
|
|
3
|
+
*
|
|
4
|
+
* 参考算法:office2json(unzip → XML 树 → 路径提取 w:body → w:p → w:r → w:t),
|
|
5
|
+
* 增强提取到 ODES IR(design/office-events-plan.md):
|
|
6
|
+
* - 段落属性:pStyle → h1/h2/h3、jc → 对齐(裁剪:样式名映射子集)
|
|
7
|
+
* - 内联格式:rPr b/i/u → marks(区间)
|
|
8
|
+
* - 表格:w:tbl → Editor 表格 embed 快照(HTML 复用现有模型)
|
|
9
|
+
* - 图片:w:drawing r:embed → rels → media → data url → img embed
|
|
10
|
+
*
|
|
11
|
+
* 导出(DocState → minimal docx):VNode 组件化(OOXML 也是 VNode——与前端
|
|
12
|
+
* "VNode → DOM"同构)→ vnodeToXml → store ZIP。块级 embed(pre/hr)打断段落。
|
|
13
|
+
*
|
|
14
|
+
* 前端可用(无需后端):ZIP 解压走 DecompressionStream(浏览器/Node 18+);
|
|
15
|
+
* base64 跨环境(Buffer 守卫/atob)。诚实裁剪:分节/页眉页脚/域代码/批注
|
|
16
|
+
* 不导入;http 图片导出裁剪(warning)。
|
|
17
|
+
*/
|
|
18
|
+
import type { DocState } from '../components/Editor/model/types.ts';
|
|
19
|
+
/** base64 → Uint8Array(跨环境——浏览器 atob / Node Buffer) */
|
|
20
|
+
export declare function base64ToBytes(b64: string): Uint8Array;
|
|
21
|
+
/** Uint8Array → base64(跨环境) */
|
|
22
|
+
export declare function bytesToBase64(u8: Uint8Array): string;
|
|
23
|
+
export interface DocxImportResult {
|
|
24
|
+
doc: DocState;
|
|
25
|
+
/** 裁剪提示(不可映射内容——诚实不静默) */
|
|
26
|
+
warnings: string[];
|
|
27
|
+
}
|
|
28
|
+
export declare function docxToDoc(u8: Uint8Array): Promise<DocxImportResult>;
|
|
29
|
+
export interface DocxExportResult {
|
|
30
|
+
data: Uint8Array;
|
|
31
|
+
warnings: string[];
|
|
32
|
+
}
|
|
33
|
+
export declare function docToDocx(doc: DocState): DocxExportResult;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/office/pptx — pptx ↔ ODES DeckState 双向转换(前端/服务端通用——零依赖)
|
|
3
|
+
*
|
|
4
|
+
* 参考算法:office2json(ppt/slides/slideN.xml → p:sld → p:cSld → p:spTree →
|
|
5
|
+
* p:sp → p:txBody → a:p → a:r → a:t),增强提取到 ODES IR:
|
|
6
|
+
* - 多幻灯片:slideN.xml 全量(office2json 只取文本——ODES 保留结构)
|
|
7
|
+
* - shape 几何:p:xfrm(a:off x/y + a:ext cx/cy——EMU → px:/9525)
|
|
8
|
+
* - shape 类型:p:sp(文本/图形——p:prstGeom prst)/ p:pic(图片)
|
|
9
|
+
* - 文本:txBody → 段落拼接(a:br 换行)
|
|
10
|
+
*
|
|
11
|
+
* 导出(DeckState → minimal pptx):slideN.xml(spTree 结构)+ presentation.xml
|
|
12
|
+
* + rels + contentTypes——store ZIP(VNode 组件化)。裁剪:动画/母版/备注/主题。
|
|
13
|
+
*/
|
|
14
|
+
import type { DeckState } from '../components/OfficeEditor/model/types.ts';
|
|
15
|
+
export interface PptxImportResult {
|
|
16
|
+
deck: DeckState;
|
|
17
|
+
warnings: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function pptxToDeck(u8: Uint8Array): Promise<PptxImportResult>;
|
|
20
|
+
export interface PptxExportResult {
|
|
21
|
+
data: Uint8Array;
|
|
22
|
+
warnings: string[];
|
|
23
|
+
}
|
|
24
|
+
export declare function deckToPptx(deck: DeckState): PptxExportResult;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/office/xlsx — xlsx ↔ ODES WorkbookState 双向转换(前端/服务端通用——零依赖)
|
|
3
|
+
*
|
|
4
|
+
* 参考算法:office2json(sheet1.xml → sheetData → row → c{t,v} + sharedStrings),
|
|
5
|
+
* 增强提取到 ODES IR(design/office-events-plan.md):
|
|
6
|
+
* - 多 sheet:workbook.xml(sheet 名 + rId)→ rels → 各 sheetN.xml
|
|
7
|
+
* - 单元格引用:c@r(A1——office2json 丢弃——ODES 必须)
|
|
8
|
+
* - 类型:c@t(s=shared/n=number/b=bool/f=formula)→ SheetCell.kind
|
|
9
|
+
* - 公式:f 元素(公式字符串保留——不计算——服务端导出重算)
|
|
10
|
+
* - 行高/列宽/样式索引:裁剪(v1——诚实:不读不写)
|
|
11
|
+
*
|
|
12
|
+
* 导出(WorkbookState → minimal xlsx):共享字符串表去重 + sheetData XML +
|
|
13
|
+
* store ZIP(VNode 组件化——OOXML 也是 VNode)。
|
|
14
|
+
*/
|
|
15
|
+
import type { WorkbookState } from '../components/OfficeEditor/model/types.ts';
|
|
16
|
+
export interface XlsxImportResult {
|
|
17
|
+
workbook: WorkbookState;
|
|
18
|
+
warnings: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function xlsxToWorkbook(u8: Uint8Array): Promise<XlsxImportResult>;
|
|
21
|
+
export interface XlsxExportResult {
|
|
22
|
+
data: Uint8Array;
|
|
23
|
+
warnings: string[];
|
|
24
|
+
}
|
|
25
|
+
export declare function workbookToXlsx(wb: WorkbookState): XlsxExportResult;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/office/xml-serialize — VNode 树 → XML 字符串(服务端 OOXML 生成)
|
|
3
|
+
*
|
|
4
|
+
* 架构(与前端 "VNode → DOM" 同构——"OOXML 也是写 VNode"):
|
|
5
|
+
* DocState → VNode 树(h()——vdom3 纯数据结构,零 DOM 依赖)
|
|
6
|
+
* → vnodeToXml(本模块)→ ZIP 打包
|
|
7
|
+
*
|
|
8
|
+
* 序列化约定(仅输出 XML 子集——与 vdom3 渲染管线解耦):
|
|
9
|
+
* - type: string = 元素名(含命名空间前缀——w:p、a:graphic 等原样输出)
|
|
10
|
+
* - props: 字符串值 = XML 属性;number/boolean 字符串化;key/children 排除
|
|
11
|
+
* - children: 字符串 = 文本(转义);VNode = 子元素;数组 = 序列
|
|
12
|
+
* - 空元素 → 自闭合 <w:b/>(OOXML 合法——MS Word 接受)
|
|
13
|
+
* - 函数/symbol type、事件 props(on*)→ 抛错(诚实——序列化器不支持)
|
|
14
|
+
*/
|
|
15
|
+
import type { VNode, VNodeChild } from '../ui-dom/vdom3/types.ts';
|
|
16
|
+
export declare function vnodeToXml(v: VNode | VNodeChild, xmlDecl?: boolean): string;
|
|
17
|
+
/** 便捷:把 VNode 树序列化为 OOXML 部件 XML(名称检查由调用方保证) */
|
|
18
|
+
export declare function vnodeToXmlDecl(v: VNode): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/office/xml — 自研轻量 XML 解析(零 npm 依赖)
|
|
3
|
+
*
|
|
4
|
+
* 参考算法:office2json(@xmldom/xmldom → { name, attrs, children } 树)。
|
|
5
|
+
* OOXML 是规整 XML——只做元素树 + 文本;裁剪:DTD/实体展开(除内建五实体)/
|
|
6
|
+
* 命名空间处理(前缀保留原名——w:p 等)。解析失败抛错(诚实——不静默)。
|
|
7
|
+
*/
|
|
8
|
+
export interface XmlNode {
|
|
9
|
+
name: string;
|
|
10
|
+
attrs: Record<string, string>;
|
|
11
|
+
children: XmlNode[];
|
|
12
|
+
/** 直接文本内容(子元素外的文本) */
|
|
13
|
+
text: string;
|
|
14
|
+
}
|
|
15
|
+
/** 手写扫描器:<name attrs>...</name> / <name/> / 文本 / 指令 / 注释 / CDATA */
|
|
16
|
+
export declare function parseXml(xml: string): XmlNode;
|
|
17
|
+
/** 便捷:找子元素(按名字——含命名空间前缀匹配) */
|
|
18
|
+
export declare function child(el: XmlNode, name: string): XmlNode | null;
|
|
19
|
+
export declare function children(el: XmlNode, name: string): XmlNode[];
|
|
20
|
+
/** 全部后代文本(拼接) */
|
|
21
|
+
export declare function allText(el: XmlNode): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/office/zip — 自研 ZIP 容器读写(零 npm 依赖)
|
|
3
|
+
*
|
|
4
|
+
* 参考算法:office2json(unzip 结构——EOCD → central directory → local header)。
|
|
5
|
+
* 实现取舍:
|
|
6
|
+
* - 读:EOCD(尾部扫描)→ central directory → local header offset 取数据;
|
|
7
|
+
* 压缩方法 0(store)/ 8(deflate——Node 内置 zlib.inflateRawSync)
|
|
8
|
+
* - 写:store(无压缩——合法 ZIP,文件较大但零依赖正确性优先);
|
|
9
|
+
* CRC32 自研查表
|
|
10
|
+
* - 裁剪:ZIP64/加密/数据描述符(flags bit3)/多盘——不支持(诚实——读到即抛错)
|
|
11
|
+
*/
|
|
12
|
+
export interface ZipEntry {
|
|
13
|
+
name: string;
|
|
14
|
+
data: Uint8Array;
|
|
15
|
+
}
|
|
16
|
+
export declare function crc32(buf: Uint8Array): number;
|
|
17
|
+
/** inflate(ZIP method 8)——跨环境:浏览器 DecompressionStream / Node 18+(同 API)。
|
|
18
|
+
* 老环境无 DecompressionStream → 抛错(诚实裁剪:OOXML 必用 deflate)。 */
|
|
19
|
+
export declare function inflateRaw(data: Uint8Array): Promise<Uint8Array>;
|
|
20
|
+
export declare function readZip(u8: Uint8Array): Promise<Map<string, Uint8Array>>;
|
|
21
|
+
export declare function writeZip(files: Map<string, Uint8Array>): Uint8Array;
|