@beyondwork/docx-react-component 1.0.2 → 1.0.3

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/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@beyondwork/docx-react-component",
3
3
  "publisher": "beyondwork",
4
- "version": "1.0.2",
4
+ "version": "1.0.3",
5
5
  "description": "Embeddable React Word (docx) editor with review, comments, tracked changes, and round-trip OOXML fidelity.",
6
- "packageManager": "pnpm@10.30.3",
7
6
  "type": "module",
8
7
  "files": [
9
8
  "README.md",
@@ -33,23 +32,6 @@
33
32
  "./package.json": "./package.json"
34
33
  },
35
34
  "types": "./src/index.ts",
36
- "scripts": {
37
- "build": "tsup",
38
- "test": "bash scripts/run-workspace-tests.sh",
39
- "test:repo": "pnpm exec tsx --test $(find test -type f \\( -name '*.test.ts' -o -name '*.test.tsx' \\) | sort)",
40
- "test:harness": "pnpm --filter @docx-react-component/react-word-editor-harness test",
41
- "lint:no-authored-js": "bash scripts/check-no-authored-js.sh",
42
- "context7:api-check": "bash scripts/context7-export-env.sh run bash scripts/context7-api-check.sh",
43
- "wave:doctor": "bash scripts/context7-export-env.sh run pnpm exec wave doctor --json",
44
- "wave:dry-run": "bash scripts/context7-export-env.sh run pnpm exec wave launch --lane main --dry-run --no-dashboard",
45
- "wave:launch": "bash scripts/context7-export-env.sh run pnpm exec wave launch --lane main",
46
- "wave:launch:managed": "bash scripts/wave-launch.sh",
47
- "wave:status": "bash scripts/wave-status.sh",
48
- "wave:watch": "bash scripts/wave-watch.sh --follow",
49
- "wave:dashboard:current": "bash scripts/wave-dashboard-attach.sh current",
50
- "wave:dashboard:global": "bash scripts/wave-dashboard-attach.sh global",
51
- "harness:dev": "pnpm --filter @docx-react-component/react-word-editor-harness dev"
52
- },
53
35
  "keywords": [
54
36
  "docx",
55
37
  "word",
@@ -71,6 +53,7 @@
71
53
  "@radix-ui/react-toggle": "^1.1.10",
72
54
  "@radix-ui/react-toggle-group": "^1.1.11",
73
55
  "@radix-ui/react-tooltip": "^1.2.8",
56
+ "fflate": "^0.8.2",
74
57
  "lucide-react": "^1.7.0"
75
58
  },
76
59
  "peerDependencies": {
@@ -101,14 +84,21 @@
101
84
  "tsup": "^8.3.0",
102
85
  "tsx": "^4.21.0"
103
86
  },
104
- "pnpm": {
105
- "onlyBuiltDependencies": [
106
- "esbuild",
107
- "sharp"
108
- ],
109
- "overrides": {
110
- "react": "19.2.4",
111
- "react-dom": "19.2.4"
112
- }
87
+ "scripts": {
88
+ "build": "tsup",
89
+ "test": "bash scripts/run-workspace-tests.sh",
90
+ "test:repo": "pnpm exec tsx --test $(find test -type f \\( -name '*.test.ts' -o -name '*.test.tsx' \\) | sort)",
91
+ "test:harness": "pnpm --filter @docx-react-component/react-word-editor-harness test",
92
+ "lint:no-authored-js": "bash scripts/check-no-authored-js.sh",
93
+ "context7:api-check": "bash scripts/context7-export-env.sh run bash scripts/context7-api-check.sh",
94
+ "wave:doctor": "bash scripts/context7-export-env.sh run pnpm exec wave doctor --json",
95
+ "wave:dry-run": "bash scripts/context7-export-env.sh run pnpm exec wave launch --lane main --dry-run --no-dashboard",
96
+ "wave:launch": "bash scripts/context7-export-env.sh run pnpm exec wave launch --lane main",
97
+ "wave:launch:managed": "bash scripts/wave-launch.sh",
98
+ "wave:status": "bash scripts/wave-status.sh",
99
+ "wave:watch": "bash scripts/wave-watch.sh --follow",
100
+ "wave:dashboard:current": "bash scripts/wave-dashboard-attach.sh current",
101
+ "wave:dashboard:global": "bash scripts/wave-dashboard-attach.sh global",
102
+ "harness:dev": "pnpm --filter @docx-react-component/react-word-editor-harness dev"
113
103
  }
114
104
  }
@@ -1,4 +1,4 @@
1
- import { inflateRawSync } from "node:zlib";
1
+ import { inflateRawSync } from "fflate";
2
2
 
3
3
  import {
4
4
  CONTENT_TYPES_PATH,
@@ -35,8 +35,7 @@ const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50;
35
35
 
36
36
  export function readOpcPackage(source: Uint8Array | ArrayBuffer): OpcPackage {
37
37
  const bytes = source instanceof Uint8Array ? source : new Uint8Array(source);
38
- const archive = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
39
- const centralDirectory = readCentralDirectory(archive);
38
+ const centralDirectory = readCentralDirectory(bytes);
40
39
  const parts = new Map<string, OpcPackagePart>();
41
40
 
42
41
  for (const entry of centralDirectory) {
@@ -44,7 +43,7 @@ export function readOpcPackage(source: Uint8Array | ArrayBuffer): OpcPackage {
44
43
  continue;
45
44
  }
46
45
 
47
- const storedBytes = readZipEntry(archive, entry);
46
+ const storedBytes = readZipEntry(bytes, entry);
48
47
  const normalizedPath = normalizePartPath(entry.path);
49
48
  const surfaceKind = getSurfaceKind(normalizedPath);
50
49
 
@@ -112,30 +111,31 @@ export function readOpcPackage(source: Uint8Array | ArrayBuffer): OpcPackage {
112
111
  };
113
112
  }
114
113
 
115
- function readCentralDirectory(archive: Buffer): ZipCentralDirectoryEntry[] {
116
- const eocdOffset = findEndOfCentralDirectory(archive);
117
- const entryCount = archive.readUInt16LE(eocdOffset + 10);
118
- const centralDirectoryOffset = archive.readUInt32LE(eocdOffset + 16);
114
+ function readCentralDirectory(archive: Uint8Array): ZipCentralDirectoryEntry[] {
115
+ const view = new DataView(archive.buffer, archive.byteOffset, archive.byteLength);
116
+ const eocdOffset = findEndOfCentralDirectory(archive, view);
117
+ const entryCount = view.getUint16(eocdOffset + 10, true);
118
+ const centralDirectoryOffset = view.getUint32(eocdOffset + 16, true);
119
119
  const entries: ZipCentralDirectoryEntry[] = [];
120
120
  let offset = centralDirectoryOffset;
121
121
 
122
122
  for (let index = 0; index < entryCount; index += 1) {
123
- const signature = archive.readUInt32LE(offset);
123
+ const signature = view.getUint32(offset, true);
124
124
  if (signature !== CENTRAL_DIRECTORY_SIGNATURE) {
125
125
  throw new Error(`Invalid ZIP central directory signature at offset ${offset}.`);
126
126
  }
127
127
 
128
- const generalPurposeBitFlag = archive.readUInt16LE(offset + 8);
129
- const compressionMethod = archive.readUInt16LE(offset + 10);
130
- const crc32 = archive.readUInt32LE(offset + 16);
131
- const compressedSize = archive.readUInt32LE(offset + 20);
132
- const uncompressedSize = archive.readUInt32LE(offset + 24);
133
- const fileNameLength = archive.readUInt16LE(offset + 28);
134
- const extraFieldLength = archive.readUInt16LE(offset + 30);
135
- const fileCommentLength = archive.readUInt16LE(offset + 32);
136
- const localHeaderOffset = archive.readUInt32LE(offset + 42);
128
+ const generalPurposeBitFlag = view.getUint16(offset + 8, true);
129
+ const compressionMethod = view.getUint16(offset + 10, true);
130
+ const crc32 = view.getUint32(offset + 16, true);
131
+ const compressedSize = view.getUint32(offset + 20, true);
132
+ const uncompressedSize = view.getUint32(offset + 24, true);
133
+ const fileNameLength = view.getUint16(offset + 28, true);
134
+ const extraFieldLength = view.getUint16(offset + 30, true);
135
+ const fileCommentLength = view.getUint16(offset + 32, true);
136
+ const localHeaderOffset = view.getUint32(offset + 42, true);
137
137
  const fileNameOffset = offset + 46;
138
- const fileName = archive.subarray(fileNameOffset, fileNameOffset + fileNameLength).toString("utf8");
138
+ const fileName = decodeUtf8(archive.subarray(fileNameOffset, fileNameOffset + fileNameLength));
139
139
 
140
140
  entries.push({
141
141
  path: fileName,
@@ -153,13 +153,13 @@ function readCentralDirectory(archive: Buffer): ZipCentralDirectoryEntry[] {
153
153
  return entries;
154
154
  }
155
155
 
156
- function findEndOfCentralDirectory(archive: Buffer): number {
156
+ function findEndOfCentralDirectory(archive: Uint8Array, view: DataView): number {
157
157
  const minimumEocdSize = 22;
158
158
  const maximumCommentSize = 0xffff;
159
159
  const searchStart = Math.max(0, archive.length - minimumEocdSize - maximumCommentSize);
160
160
 
161
161
  for (let offset = archive.length - minimumEocdSize; offset >= searchStart; offset -= 1) {
162
- if (archive.readUInt32LE(offset) === EOCD_SIGNATURE) {
162
+ if (view.getUint32(offset, true) === EOCD_SIGNATURE) {
163
163
  return offset;
164
164
  }
165
165
  }
@@ -167,15 +167,16 @@ function findEndOfCentralDirectory(archive: Buffer): number {
167
167
  throw new Error("Invalid ZIP archive: end of central directory not found.");
168
168
  }
169
169
 
170
- function readZipEntry(archive: Buffer, entry: ZipCentralDirectoryEntry): Uint8Array {
170
+ function readZipEntry(archive: Uint8Array, entry: ZipCentralDirectoryEntry): Uint8Array {
171
+ const view = new DataView(archive.buffer, archive.byteOffset, archive.byteLength);
171
172
  const headerOffset = entry.localHeaderOffset;
172
- const signature = archive.readUInt32LE(headerOffset);
173
+ const signature = view.getUint32(headerOffset, true);
173
174
  if (signature !== LOCAL_FILE_HEADER_SIGNATURE) {
174
175
  throw new Error(`Invalid ZIP local file header signature at offset ${headerOffset}.`);
175
176
  }
176
177
 
177
- const fileNameLength = archive.readUInt16LE(headerOffset + 26);
178
- const extraFieldLength = archive.readUInt16LE(headerOffset + 28);
178
+ const fileNameLength = view.getUint16(headerOffset + 26, true);
179
+ const extraFieldLength = view.getUint16(headerOffset + 28, true);
179
180
  const dataOffset = headerOffset + 30 + fileNameLength + extraFieldLength;
180
181
  const compressed = archive.subarray(dataOffset, dataOffset + entry.compressedSize);
181
182
 
@@ -183,7 +184,7 @@ function readZipEntry(archive: Buffer, entry: ZipCentralDirectoryEntry): Uint8Ar
183
184
  case "store":
184
185
  return new Uint8Array(compressed);
185
186
  case "deflate":
186
- return new Uint8Array(inflateRawSync(compressed));
187
+ return inflateRawSync(compressed);
187
188
  default:
188
189
  throw new Error(`Unsupported ZIP compression for ${entry.path}.`);
189
190
  }
@@ -213,7 +214,11 @@ function getSurfaceKind(path: string): OpcPartManifestEntry["surfaceKind"] {
213
214
  }
214
215
 
215
216
  function decodeXml(bytes: Uint8Array): string {
216
- return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("utf8");
217
+ return new TextDecoder("utf-8").decode(bytes);
218
+ }
219
+
220
+ function decodeUtf8(bytes: Uint8Array): string {
221
+ return new TextDecoder("utf-8").decode(bytes);
217
222
  }
218
223
 
219
224
  function parseContentTypesXml(xml: string): OpcPackageManifest["contentTypes"] {
@@ -880,6 +880,8 @@ function findRegionFocusTarget(
880
880
  if (regionId === "document" || regionId === "toolbar" || regionId === "review-rail" || regionId === "status") {
881
881
  return region;
882
882
  }
883
+
884
+ return null;
883
885
  }
884
886
 
885
887
  function isAccessibleRegionId(value: string | undefined): value is AccessibleRegionId {