wordinweb 0.1.3 → 0.1.5

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/LICENSE CHANGED
@@ -1,60 +1,17 @@
1
- # WordInWeb Small Business License 1.0
1
+ MIT License
2
2
 
3
3
  Copyright (c) 2026 WordInWeb contributors
4
4
 
5
- This is a source-available license. It is not the MIT License and is not an
6
- Open Source Initiative approved license.
7
-
8
- ## Eligible Users
9
-
10
- You are eligible to use the Software under this license if you are:
11
-
12
- 1. an individual using the Software on your own behalf;
13
- 2. a nonprofit organization, educational institution, public research
14
- organization, or government institution; or
15
- 3. a for-profit organization that, together with its Affiliates, has both:
16
- - no more than 1,000,000 USD in Gross Revenue for its most recently
17
- completed fiscal year; and
18
- - no more than 2,000,000 USD in aggregate Funding Raised.
19
-
20
- An individual using the Software on behalf of an organization is eligible only
21
- if that organization is eligible.
22
-
23
- ## Permission
24
-
25
- Subject to the eligibility requirements above, permission is hereby granted,
26
- free of charge, to any person obtaining a copy of this software and associated
27
- documentation files (the "Software"), to deal in the Software without
28
- restriction, including without limitation the rights to use, copy, modify,
29
- merge, publish, distribute, sublicense, and/or sell copies of the Software, and
30
- to permit persons to whom the Software is furnished to do so, subject to the
31
- following conditions:
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
32
11
 
33
12
  The above copyright notice and this permission notice shall be included in all
34
13
  copies or substantial portions of the Software.
35
14
 
36
- ## Larger Companies
37
-
38
- A for-profit organization that exceeds either eligibility threshold is not
39
- licensed under these terms. Use by such an organization requires a separate
40
- commercial license from the copyright holder.
41
-
42
- ## Definitions
43
-
44
- "Affiliate" means any entity that controls, is controlled by, or is under
45
- common control with an organization. "Control" means the direct or indirect
46
- power to direct an entity's management or policies, whether through ownership,
47
- contract, or otherwise.
48
-
49
- "Gross Revenue" means all revenue recognized before expenses, deductions, and
50
- taxes.
51
-
52
- "Funding Raised" means the aggregate gross proceeds received since formation
53
- from external financing, including equity, debt, convertible instruments,
54
- SAFEs, grants, and similar financing.
55
-
56
- ## Disclaimer
57
-
58
15
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59
16
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60
17
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
package/README.md CHANGED
@@ -265,8 +265,4 @@ and compared page-by-page. The test corpus and instructions are in
265
265
 
266
266
  ## License
267
267
 
268
- WordInWeb Small Business License 1.0 — MIT-style permissions for individuals,
269
- nonprofits, educational and public-research organizations, governments, and
270
- companies with no more than $1 million in annual revenue and $2 million in
271
- total funding. Larger companies require a separate commercial license. See
272
- `LICENSE`.
268
+ MIT. See `LICENSE`.
package/dist/index.js CHANGED
@@ -17563,6 +17563,33 @@ function deepTextNode(el11) {
17563
17563
  while (n && n.nodeType !== Node.TEXT_NODE) n = n.firstChild;
17564
17564
  return n;
17565
17565
  }
17566
+ function textElements(el11) {
17567
+ const out = [];
17568
+ const walk = (node) => {
17569
+ if (localName(node.name) === "t") out.push(node);
17570
+ for (const child3 of node.children) walk(child3);
17571
+ };
17572
+ walk(el11);
17573
+ return out;
17574
+ }
17575
+ function emptyParagraphLike(el11) {
17576
+ const prefix = el11.name.includes(":") ? el11.name.slice(0, el11.name.indexOf(":") + 1) : "";
17577
+ const text = {
17578
+ name: `${prefix}t`,
17579
+ attrs: { "xml:space": "preserve" },
17580
+ children: [],
17581
+ text: ""
17582
+ };
17583
+ return {
17584
+ paragraph: {
17585
+ name: `${prefix}p`,
17586
+ attrs: {},
17587
+ children: [{ name: `${prefix}r`, attrs: {}, children: [text], text: "" }],
17588
+ text: ""
17589
+ },
17590
+ text
17591
+ };
17592
+ }
17566
17593
  var _DocxEditor = class _DocxEditor {
17567
17594
  constructor(host) {
17568
17595
  this.host = host;
@@ -17576,7 +17603,7 @@ var _DocxEditor = class _DocxEditor {
17576
17603
  * our own highlight, which kills the flicker and survives toolbar focus). */
17577
17604
  this.selection = null;
17578
17605
  this.selectionRects = [];
17579
- this.restoreSelectAllPages = null;
17606
+ this.selectedAll = false;
17580
17607
  /** True while a drag-selection is in progress (checked by onMouseUp, which
17581
17608
  * bubbles from the container BEFORE the document-level drag-end listener). */
17582
17609
  this.dragSelecting = false;
@@ -18106,11 +18133,8 @@ var _DocxEditor = class _DocxEditor {
18106
18133
  }
18107
18134
  clearSelection() {
18108
18135
  this.selection = null;
18136
+ this.selectedAll = false;
18109
18137
  this.paintSelection();
18110
- const restore = this.restoreSelectAllPages;
18111
- this.restoreSelectAllPages = null;
18112
- restore?.();
18113
- this.host.getHandle()?.updateViewport?.();
18114
18138
  this.notifySelection();
18115
18139
  }
18116
18140
  notifySelection() {
@@ -18131,11 +18155,50 @@ var _DocxEditor = class _DocxEditor {
18131
18155
  }
18132
18156
  return boundary;
18133
18157
  }
18158
+ activeTextItems() {
18159
+ const handle = this.host.getHandle();
18160
+ if (!handle) return [];
18161
+ const activeTexts = /* @__PURE__ */ new Set();
18162
+ const collect = (element) => {
18163
+ if (localName(element.name) === "t") activeTexts.add(element);
18164
+ for (const child3 of element.children) collect(child3);
18165
+ };
18166
+ for (const root of this.host.doc.editableRoots()) {
18167
+ const name = localName(root.name);
18168
+ const headerFooter = name === "hdr" || name === "ftr";
18169
+ if (headerFooter === this.inHeaderFooter) collect(root);
18170
+ }
18171
+ const items = handle._pages ? handle._pages.flatMap((page) => page.page.items) : handle.bindings.map((binding) => binding.item);
18172
+ return items.filter(
18173
+ (item) => item.kind === "text" && !!item.src?.t && activeTexts.has(item.src.t)
18174
+ );
18175
+ }
18134
18176
  /** Segments covered by the owned selection, in document paint order. */
18135
18177
  getSelectionSegments() {
18136
18178
  const sel = this.selection;
18137
18179
  const handle = this.host.getHandle();
18138
18180
  if (!sel || !handle) return [];
18181
+ if (this.selectedAll) {
18182
+ const segments2 = [];
18183
+ for (const item of this.activeTextItems()) {
18184
+ const src = item.src;
18185
+ if (item.text.length === 0) continue;
18186
+ const segment = {
18187
+ run: src.run,
18188
+ t: src.t,
18189
+ start: src.offset,
18190
+ end: src.offset + item.text.length,
18191
+ props: item.props
18192
+ };
18193
+ const previous = segments2[segments2.length - 1];
18194
+ if (previous && previous.t === segment.t && segment.start <= previous.end + 1) {
18195
+ previous.end = Math.max(previous.end, segment.end);
18196
+ } else {
18197
+ segments2.push(segment);
18198
+ }
18199
+ }
18200
+ return segments2;
18201
+ }
18139
18202
  let a = this.pointIndex(sel.anchor);
18140
18203
  let f = this.pointIndex(sel.focus);
18141
18204
  if (a === null || f === null) return [];
@@ -18303,6 +18366,7 @@ var _DocxEditor = class _DocxEditor {
18303
18366
  return;
18304
18367
  }
18305
18368
  this.hideCaret();
18369
+ this.selectedAll = false;
18306
18370
  this.selection = { anchor, focus };
18307
18371
  this.paintSelection();
18308
18372
  this.notifySelection();
@@ -18323,21 +18387,16 @@ var _DocxEditor = class _DocxEditor {
18323
18387
  }
18324
18388
  }
18325
18389
  selectAll() {
18326
- const handle = this.host.getHandle();
18327
- if (!handle) return;
18328
- if (handle._virtualized && !this.restoreSelectAllPages) {
18329
- this.restoreSelectAllPages = handle.materializeAll?.() ?? null;
18330
- }
18331
- const editable = handle.bindings.filter(
18332
- (b) => b.item.src?.t && this.regionOf(b.item.src.t) === (this.inHeaderFooter ? "hf" : "body")
18333
- );
18390
+ const editable = this.activeTextItems();
18334
18391
  if (editable.length === 0) return;
18335
- const first = editable[0].item.src;
18336
- const last = editable[editable.length - 1].item.src;
18392
+ const first = editable[0].src;
18393
+ const lastItem = editable[editable.length - 1];
18394
+ const last = lastItem.src;
18337
18395
  this.hideCaret();
18396
+ this.selectedAll = true;
18338
18397
  this.selection = {
18339
18398
  anchor: { t: first.t, offset: first.offset },
18340
- focus: { t: last.t, offset: last.offset + editable[editable.length - 1].item.text.length }
18399
+ focus: { t: last.t, offset: last.offset + lastItem.text.length }
18341
18400
  };
18342
18401
  this.paintSelection();
18343
18402
  this.notifySelection();
@@ -18345,6 +18404,7 @@ var _DocxEditor = class _DocxEditor {
18345
18404
  /** Select the given post-edit ranges (used after formatting to persist). */
18346
18405
  selectRanges(ranges) {
18347
18406
  if (ranges.length === 0) return;
18407
+ this.selectedAll = false;
18348
18408
  const first = ranges[0];
18349
18409
  const last = ranges[ranges.length - 1];
18350
18410
  this.selection = {
@@ -18360,10 +18420,19 @@ var _DocxEditor = class _DocxEditor {
18360
18420
  const sel = this.selection;
18361
18421
  const handle = this.host.getHandle();
18362
18422
  if (!sel || !handle) return;
18363
- let a = this.pointIndex(sel.anchor);
18364
- let f = this.pointIndex(sel.focus);
18423
+ const activeTexts = this.selectedAll ? new Set(this.activeTextItems().map((item) => item.src.t)) : null;
18424
+ const bindings = activeTexts ? handle.bindings.filter((binding) => !!binding.item.src?.t && activeTexts.has(binding.item.src.t)) : handle.bindings;
18425
+ if (bindings.length === 0) return;
18426
+ let a = this.selectedAll ? 0 : this.pointIndex(sel.anchor);
18427
+ let f = this.selectedAll ? (bindings.length - 1) * 1e6 + bindings[bindings.length - 1].item.text.length : this.pointIndex(sel.focus);
18365
18428
  if (a === null || f === null) return;
18366
- const [startPt, endPt] = a <= f ? [sel.anchor, sel.focus] : [sel.focus, sel.anchor];
18429
+ const [startPt, endPt] = this.selectedAll ? [
18430
+ { t: bindings[0].item.src.t, offset: bindings[0].item.src.offset },
18431
+ {
18432
+ t: bindings[bindings.length - 1].item.src.t,
18433
+ offset: bindings[bindings.length - 1].item.src.offset + bindings[bindings.length - 1].item.text.length
18434
+ }
18435
+ ] : a <= f ? [sel.anchor, sel.focus] : [sel.focus, sel.anchor];
18367
18436
  if (a > f) [a, f] = [f, a];
18368
18437
  const startIdx = Math.floor(a / 1e6);
18369
18438
  const endIdx = Math.floor(f / 1e6);
@@ -18378,7 +18447,7 @@ var _DocxEditor = class _DocxEditor {
18378
18447
  run = null;
18379
18448
  };
18380
18449
  for (let i = startIdx; i <= endIdx; i++) {
18381
- const b = handle.bindings[i];
18450
+ const b = bindings[i];
18382
18451
  const item = b.item;
18383
18452
  const src = item.src;
18384
18453
  if (!src?.t) continue;
@@ -18516,8 +18585,6 @@ var _DocxEditor = class _DocxEditor {
18516
18585
  c.removeEventListener("dragover", this.onDragOver);
18517
18586
  c.removeEventListener("drop", this.onDrop);
18518
18587
  this.dismissSuggestionPopover();
18519
- this.restoreSelectAllPages?.();
18520
- this.restoreSelectAllPages = null;
18521
18588
  this.hideCaret();
18522
18589
  }
18523
18590
  // ---------- clipboard ----------
@@ -18651,6 +18718,7 @@ var _DocxEditor = class _DocxEditor {
18651
18718
  }
18652
18719
  if (dragging) {
18653
18720
  this.hideCaret();
18721
+ this.selectedAll = false;
18654
18722
  this.selection = {
18655
18723
  anchor: { t: anchor.t, offset: anchor.offset },
18656
18724
  focus: { t: focus.t, offset: focus.offset }
@@ -18682,6 +18750,7 @@ var _DocxEditor = class _DocxEditor {
18682
18750
  const last = lastTextOf(pEl);
18683
18751
  if (!first || !last) return;
18684
18752
  this.hideCaret();
18753
+ this.selectedAll = false;
18685
18754
  this.selection = {
18686
18755
  anchor: { t: first, offset: 0 },
18687
18756
  focus: { t: last, offset: last.text.length }
@@ -18699,6 +18768,7 @@ var _DocxEditor = class _DocxEditor {
18699
18768
  while (e < text.length && isWord(text[e])) e++;
18700
18769
  if (e > s) {
18701
18770
  this.hideCaret();
18771
+ this.selectedAll = false;
18702
18772
  this.selection = { anchor: { t: caret.t, offset: s }, focus: { t: caret.t, offset: e } };
18703
18773
  this.paintSelection();
18704
18774
  this.notifySelection();
@@ -20081,9 +20151,10 @@ var _DocxEditor = class _DocxEditor {
20081
20151
  }
20082
20152
  deleteContents(direction) {
20083
20153
  if (direction === void 0) {
20154
+ const selectedAll = this.selectedAll;
20084
20155
  this.host.history?.checkpoint();
20085
20156
  this.removeSelectedText();
20086
- this.commit();
20157
+ this.commit(false, selectedAll ? "global" : "local");
20087
20158
  return;
20088
20159
  }
20089
20160
  const caret = this.caret;
@@ -20196,6 +20267,24 @@ var _DocxEditor = class _DocxEditor {
20196
20267
  }
20197
20268
  /** Delete the owned selection's text from the XML; caret → start. */
20198
20269
  removeSelectedText() {
20270
+ if (this.selectedAll && !this.inHeaderFooter && !this.suggesting) {
20271
+ const root = this.host.doc.editableRoots()[0];
20272
+ const body = localName(root.name) === "body" ? root : root.children.find((child3) => localName(child3.name) === "body");
20273
+ if (body) {
20274
+ const empty = emptyParagraphLike(body);
20275
+ const sectionProperties = body.children.filter(
20276
+ (child3) => localName(child3.name) === "sectPr"
20277
+ );
20278
+ body.children = [empty.paragraph, ...sectionProperties];
20279
+ this.clearSelection();
20280
+ this.caret = {
20281
+ t: empty.text,
20282
+ run: { type: "run", props: {}, content: [] },
20283
+ offset: 0
20284
+ };
20285
+ return;
20286
+ }
20287
+ }
20199
20288
  const segments = this.getSelectionSegments();
20200
20289
  if (this.suggesting) {
20201
20290
  const ranges = segments.filter((s) => s.t).map((s) => ({ t: s.t, start: s.start, end: s.end }));
@@ -20215,12 +20304,68 @@ var _DocxEditor = class _DocxEditor {
20215
20304
  list.push({ start: seg.start, end: seg.end });
20216
20305
  byT.set(t, list);
20217
20306
  }
20307
+ const fullySelected = /* @__PURE__ */ new Set();
20308
+ for (const [t, ranges] of byT) {
20309
+ const ordered = [...ranges].sort((a, b) => a.start - b.start);
20310
+ let end = 0;
20311
+ for (const range of ordered) {
20312
+ if (range.start > end) break;
20313
+ end = Math.max(end, range.end);
20314
+ }
20315
+ if (end >= t.text.length) fullySelected.add(t);
20316
+ }
20317
+ const paragraphs = /* @__PURE__ */ new Set();
20318
+ for (const t of fullySelected) {
20319
+ const paragraph = paragraphOf(this.host.doc, t);
20320
+ if (paragraph) paragraphs.add(paragraph);
20321
+ }
20322
+ const fullySelectedParagraphs = [...paragraphs].filter((paragraph) => {
20323
+ const texts = textElements(paragraph).filter((text) => text.text.length > 0);
20324
+ return texts.length > 0 && texts.every((text) => fullySelected.has(text));
20325
+ });
20326
+ const fullySelectedTables = /* @__PURE__ */ new Set();
20327
+ for (const paragraph of fullySelectedParagraphs) {
20328
+ const paragraphProperties = paragraph.children.find(
20329
+ (child3) => localName(child3.name) === "pPr"
20330
+ );
20331
+ const paragraphTexts = textElements(paragraph).filter((text) => text.text.length > 0);
20332
+ const style = paragraphProperties?.children.find((child3) => localName(child3.name) === "pStyle");
20333
+ const styleNumbering = resolveParagraphStyleChain(
20334
+ this.host.doc.styles,
20335
+ attr(style, "val"),
20336
+ false
20337
+ ).pPr.numbering;
20338
+ const isList = paragraphTexts.some((text) => listTypeAt(this.host.doc, text)) || !!styleNumbering;
20339
+ if (paragraphProperties && isList) {
20340
+ paragraphProperties.children = paragraphProperties.children.filter(
20341
+ (child3) => localName(child3.name) !== "numPr" && localName(child3.name) !== "pStyle"
20342
+ );
20343
+ }
20344
+ let ancestor = this.host.doc.findParentOf(paragraph);
20345
+ while (ancestor && localName(ancestor.name) !== "tbl") {
20346
+ ancestor = this.host.doc.findParentOf(ancestor);
20347
+ }
20348
+ if (!ancestor) continue;
20349
+ const tableTexts = textElements(ancestor).filter((text) => text.text.length > 0);
20350
+ if (tableTexts.length > 0 && tableTexts.every((text) => fullySelected.has(text))) {
20351
+ fullySelectedTables.add(ancestor);
20352
+ }
20353
+ }
20218
20354
  for (const [t, ranges] of byT) {
20219
20355
  ranges.sort((a, b) => b.start - a.start);
20220
20356
  for (const r of ranges) {
20221
20357
  t.text = t.text.slice(0, r.start) + t.text.slice(r.end);
20222
20358
  }
20223
20359
  }
20360
+ for (const table2 of fullySelectedTables) {
20361
+ const parent = this.host.doc.findParentOf(table2);
20362
+ if (!parent) continue;
20363
+ const empty = emptyParagraphLike(table2);
20364
+ parent.children.splice(parent.children.indexOf(table2), 1, empty.paragraph);
20365
+ if (first && textElements(table2).includes(first.t)) {
20366
+ first = { t: empty.text, run: first.run, offset: 0 };
20367
+ }
20368
+ }
20224
20369
  this.clearSelection();
20225
20370
  if (first) this.caret = first;
20226
20371
  }