@beyondwork/docx-react-component 1.0.41 → 1.0.43

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.
Files changed (118) hide show
  1. package/package.json +38 -37
  2. package/src/api/awareness-identity-types.ts +35 -0
  3. package/src/api/comment-negotiation-types.ts +130 -0
  4. package/src/api/comment-presentation-types.ts +106 -0
  5. package/src/api/editor-state-types.ts +110 -0
  6. package/src/api/external-custody-types.ts +74 -0
  7. package/src/api/participants-types.ts +18 -0
  8. package/src/api/public-types.ts +541 -5
  9. package/src/api/scope-metadata-resolver-types.ts +88 -0
  10. package/src/core/commands/formatting-commands.ts +1 -1
  11. package/src/core/commands/index.ts +601 -9
  12. package/src/core/search/search-text.ts +15 -2
  13. package/src/index.ts +131 -1
  14. package/src/io/docx-session.ts +672 -2
  15. package/src/io/export/escape-xml-attribute.ts +26 -0
  16. package/src/io/export/external-send.ts +188 -0
  17. package/src/io/export/serialize-comments.ts +13 -16
  18. package/src/io/export/serialize-footnotes.ts +17 -24
  19. package/src/io/export/serialize-headers-footers.ts +17 -24
  20. package/src/io/export/serialize-main-document.ts +59 -62
  21. package/src/io/export/serialize-numbering.ts +20 -27
  22. package/src/io/export/serialize-runtime-revisions.ts +2 -9
  23. package/src/io/export/serialize-tables.ts +8 -15
  24. package/src/io/export/table-properties-xml.ts +25 -32
  25. package/src/io/import/external-reimport.ts +40 -0
  26. package/src/io/load-scheduler.ts +230 -0
  27. package/src/io/normalize/normalize-text.ts +83 -0
  28. package/src/io/ooxml/bw-xml.ts +244 -0
  29. package/src/io/ooxml/canonicalize-payload.ts +301 -0
  30. package/src/io/ooxml/comment-negotiation-payload.ts +288 -0
  31. package/src/io/ooxml/comment-presentation-payload.ts +311 -0
  32. package/src/io/ooxml/external-custody-payload.ts +102 -0
  33. package/src/io/ooxml/participants-payload.ts +97 -0
  34. package/src/io/ooxml/payload-signature.ts +112 -0
  35. package/src/io/ooxml/workflow-payload-validator.ts +367 -0
  36. package/src/io/ooxml/workflow-payload.ts +317 -7
  37. package/src/runtime/awareness-identity.ts +173 -0
  38. package/src/runtime/collab/event-types.ts +27 -0
  39. package/src/runtime/collab-session-bridge.ts +157 -0
  40. package/src/runtime/collab-session-facet.ts +193 -0
  41. package/src/runtime/collab-session.ts +273 -0
  42. package/src/runtime/comment-negotiation-sync.ts +91 -0
  43. package/src/runtime/comment-negotiation.ts +158 -0
  44. package/src/runtime/comment-presentation.ts +223 -0
  45. package/src/runtime/document-runtime.ts +639 -124
  46. package/src/runtime/editor-state-channel.ts +544 -0
  47. package/src/runtime/editor-state-integration.ts +217 -0
  48. package/src/runtime/external-send-runtime.ts +117 -0
  49. package/src/runtime/layout/docx-font-loader.ts +11 -30
  50. package/src/runtime/layout/index.ts +2 -0
  51. package/src/runtime/layout/inert-layout-facet.ts +4 -0
  52. package/src/runtime/layout/layout-engine-instance.ts +139 -14
  53. package/src/runtime/layout/page-graph.ts +79 -7
  54. package/src/runtime/layout/paginated-layout-engine.ts +441 -48
  55. package/src/runtime/layout/public-facet.ts +585 -14
  56. package/src/runtime/layout/table-row-split.ts +316 -0
  57. package/src/runtime/markdown-sanitizer.ts +132 -0
  58. package/src/runtime/participants.ts +134 -0
  59. package/src/runtime/perf-counters.ts +28 -0
  60. package/src/runtime/render/render-frame-types.ts +17 -0
  61. package/src/runtime/render/render-kernel.ts +172 -29
  62. package/src/runtime/resign-payload.ts +120 -0
  63. package/src/runtime/surface-projection.ts +10 -5
  64. package/src/runtime/tamper-gate.ts +157 -0
  65. package/src/runtime/workflow-markup.ts +80 -16
  66. package/src/runtime/workflow-rail-segments.ts +244 -5
  67. package/src/ui/WordReviewEditor.tsx +654 -45
  68. package/src/ui/editor-command-bag.ts +14 -0
  69. package/src/ui/editor-runtime-boundary.ts +111 -11
  70. package/src/ui/editor-shell-view.tsx +21 -0
  71. package/src/ui/editor-surface-controller.tsx +5 -0
  72. package/src/ui/headless/selection-helpers.ts +10 -0
  73. package/src/ui-tailwind/chrome/chrome-preset-model.ts +28 -0
  74. package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +62 -2
  75. package/src/ui-tailwind/chrome/collab-audience-chip.tsx +73 -0
  76. package/src/ui-tailwind/chrome/collab-negotiation-action-bar.tsx +244 -0
  77. package/src/ui-tailwind/chrome/collab-presence-strip.tsx +150 -0
  78. package/src/ui-tailwind/chrome/collab-role-chip.tsx +62 -0
  79. package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +68 -0
  80. package/src/ui-tailwind/chrome/collab-send-to-supplier-modal.tsx +149 -0
  81. package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +68 -0
  82. package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +281 -0
  83. package/src/ui-tailwind/chrome/forward-non-drag-click.ts +104 -0
  84. package/src/ui-tailwind/chrome/tw-mode-dock.tsx +1 -0
  85. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +7 -1
  86. package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +1 -38
  87. package/src/ui-tailwind/chrome-overlay/index.ts +6 -0
  88. package/src/ui-tailwind/chrome-overlay/scope-card-role-model.ts +78 -0
  89. package/src/ui-tailwind/chrome-overlay/scope-keyboard-cycle.ts +49 -0
  90. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +106 -0
  91. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +527 -0
  92. package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +120 -22
  93. package/src/ui-tailwind/chrome-overlay/tw-scope-card.tsx +310 -32
  94. package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +93 -14
  95. package/src/ui-tailwind/editor-surface/paste-plain-text.ts +72 -0
  96. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +118 -8
  97. package/src/ui-tailwind/editor-surface/pm-decorations.ts +35 -1
  98. package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +86 -3
  99. package/src/ui-tailwind/editor-surface/pm-schema.ts +167 -17
  100. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +35 -7
  101. package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +20 -3
  102. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +265 -0
  103. package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +10 -256
  104. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +9 -0
  105. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +66 -0
  106. package/src/ui-tailwind/index.ts +37 -1
  107. package/src/ui-tailwind/page-stack/tw-endnote-area.tsx +57 -0
  108. package/src/ui-tailwind/page-stack/tw-footnote-area.tsx +71 -0
  109. package/src/ui-tailwind/page-stack/tw-page-footer-band.tsx +73 -0
  110. package/src/ui-tailwind/page-stack/tw-page-header-band.tsx +74 -0
  111. package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +477 -0
  112. package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +374 -0
  113. package/src/ui-tailwind/review/comment-markdown-renderer.tsx +155 -0
  114. package/src/ui-tailwind/review/tw-comment-sidebar.tsx +77 -16
  115. package/src/ui-tailwind/review/tw-review-rail-footer.tsx +29 -3
  116. package/src/ui-tailwind/status/tw-status-bar.tsx +52 -1
  117. package/src/ui-tailwind/theme/editor-theme.css +25 -0
  118. package/src/ui-tailwind/tw-review-workspace.tsx +455 -118
@@ -17,11 +17,36 @@ export interface TwReviewRailFooterProps {
17
17
  const focusRingClass =
18
18
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1 focus-visible:ring-offset-canvas";
19
19
 
20
+ /**
21
+ * Accept only http(s) and mailto help links. Rejects javascript:, data:,
22
+ * and any other scheme that could execute code when a reviewer clicks the
23
+ * help button. Host-supplied; treated as untrusted.
24
+ */
25
+ function safeHelpHref(raw: string | undefined): string | undefined {
26
+ if (typeof raw !== "string") return undefined;
27
+ const value = raw.trim();
28
+ if (value.length === 0) return undefined;
29
+ // Allow relative paths (no scheme) — hosts often use `/docs/help`.
30
+ if (value.startsWith("/") || value.startsWith("#") || value.startsWith("?")) {
31
+ return value;
32
+ }
33
+ try {
34
+ const url = new URL(value, "https://placeholder.invalid/");
35
+ if (url.protocol === "https:" || url.protocol === "http:" || url.protocol === "mailto:") {
36
+ return value;
37
+ }
38
+ } catch {
39
+ // fall through
40
+ }
41
+ return undefined;
42
+ }
43
+
20
44
  export function TwReviewRailFooter(props: TwReviewRailFooterProps) {
21
45
  const searchLabel = props.searchLabel ?? "SEARCH";
22
46
  const helpLabel = props.helpLabel ?? "HELP";
47
+ const helpHref = safeHelpHref(props.helpHref);
23
48
 
24
- if (!props.onSearch && !props.helpHref) {
49
+ if (!props.onSearch && !helpHref) {
25
50
  return null;
26
51
  }
27
52
 
@@ -38,9 +63,10 @@ export function TwReviewRailFooter(props: TwReviewRailFooterProps) {
38
63
  </button>
39
64
  ) : null}
40
65
 
41
- {props.helpHref ? (
66
+ {helpHref ? (
42
67
  <a
43
- href={props.helpHref}
68
+ href={helpHref}
69
+ rel="noopener noreferrer"
44
70
  className={`inline-flex items-center gap-1.5 rounded-sm px-2 py-1 text-[10px] font-semibold uppercase tracking-[0.14em] text-tertiary transition-colors hover:text-secondary ${focusRingClass}`}
45
71
  >
46
72
  <HelpCircle aria-hidden="true" className="h-3 w-3" />
@@ -1,6 +1,9 @@
1
1
  import React from "react";
2
2
 
3
- import type { RuntimeContextAnalyticsSnapshot } from "../../api/public-types";
3
+ import type {
4
+ PublicMeasurementFidelity,
5
+ RuntimeContextAnalyticsSnapshot,
6
+ } from "../../api/public-types";
4
7
 
5
8
  export interface TwStatusBarProps {
6
9
  isDirty: boolean;
@@ -10,6 +13,26 @@ export interface TwStatusBarProps {
10
13
  changeCount: number;
11
14
  sessionId: string;
12
15
  contextAnalytics?: RuntimeContextAnalyticsSnapshot | null;
16
+ /**
17
+ * P5b: **displayed** page number for the selection head. When the
18
+ * active section restarts page numbering (roman front matter → arabic
19
+ * body), this reflects what Word would print on the page — not the
20
+ * raw 0-based document-order index. Pass `null` when the facet has
21
+ * no resolved page (e.g., during initial load).
22
+ */
23
+ displayPageNumber?: number | null;
24
+ /**
25
+ * P5b: total **content** page count (excludes evenPage / oddPage
26
+ * blank fillers). Matches `facet.getPageCount()` — same quantity a
27
+ * `NUMPAGES` field resolves to on every page.
28
+ */
29
+ pageCount?: number | null;
30
+ /**
31
+ * P5b: measurement fidelity the layout engine is computing against.
32
+ * Surfaced as a compact badge so harness operators can see when the
33
+ * canvas backend is live vs. the empirical fallback. Absent = skip.
34
+ */
35
+ measurementFidelity?: PublicMeasurementFidelity;
13
36
  }
14
37
 
15
38
  export function TwStatusBar(props: TwStatusBarProps) {
@@ -56,10 +79,38 @@ export function TwStatusBar(props: TwStatusBarProps) {
56
79
  {props.commentCount} comment{props.commentCount !== 1 ? "s" : ""} ·{" "}
57
80
  {props.changeCount} change{props.changeCount !== 1 ? "s" : ""}
58
81
  </span>
82
+ {props.displayPageNumber != null && props.pageCount != null ? (
83
+ <span data-testid="status-bar-page-count">
84
+ Page {props.displayPageNumber} of {props.pageCount}
85
+ </span>
86
+ ) : null}
59
87
  <span className="flex-1" />
88
+ {props.measurementFidelity ? (
89
+ <span
90
+ data-testid="status-bar-measurement-fidelity"
91
+ data-fidelity={props.measurementFidelity}
92
+ className="uppercase tracking-[0.12em] text-tertiary/70"
93
+ title={`Measurement fidelity: ${props.measurementFidelity}`}
94
+ >
95
+ {formatFidelityBadge(props.measurementFidelity)}
96
+ </span>
97
+ ) : null}
60
98
  <span className="truncate text-[10px] uppercase tracking-[0.12em] text-tertiary/80">
61
99
  Session active
62
100
  </span>
63
101
  </footer>
64
102
  );
65
103
  }
104
+
105
+ function formatFidelityBadge(fidelity: PublicMeasurementFidelity): string {
106
+ switch (fidelity) {
107
+ case "empirical":
108
+ return "E";
109
+ case "canvas":
110
+ return "C";
111
+ case "canvas-with-font-loading":
112
+ return "C+F";
113
+ default:
114
+ return String(fidelity);
115
+ }
116
+ }
@@ -488,6 +488,31 @@
488
488
  outline-offset: -1px;
489
489
  }
490
490
 
491
+ /*
492
+ * ─── Agent-pending shimmer (K2 / scope-card-overlay P2) ───
493
+ *
494
+ * Painted on every scope tint that overlaps a WorkflowCandidateRange
495
+ * with `source: "ai"`. A soft 1.8s pulse signals the agent is
496
+ * thinking without competing with the active outline. Reduced-
497
+ * motion disables the animation and holds a static 60% opacity
498
+ * border so the posture is still readable.
499
+ */
500
+ @keyframes wre-agent-pulse {
501
+ 0%, 100% { opacity: 0.4; }
502
+ 50% { opacity: 0.85; }
503
+ }
504
+
505
+ .wre-scope-rail-tint-agent-pending {
506
+ outline: 1px solid color-mix(in srgb, var(--color-workflow) 70%, transparent);
507
+ outline-offset: -1px;
508
+ animation: wre-agent-pulse 1.8s ease-in-out infinite;
509
+ }
510
+
511
+ [data-reduced-motion="true"] .wre-scope-rail-tint-agent-pending {
512
+ animation: none;
513
+ opacity: 0.6;
514
+ }
515
+
491
516
  /*
492
517
  * ─── Scope rail stripe ───
493
518
  *