@beyondwork/docx-react-component 1.0.53 → 1.0.55
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 +1 -1
- package/src/api/public-types.ts +125 -7
- package/src/index.ts +5 -0
- package/src/io/docx-session.ts +27 -3
- package/src/io/normalize/normalize-text.ts +1 -0
- package/src/io/ooxml/parse-field-switches.ts +134 -0
- package/src/io/ooxml/parse-fields.ts +28 -2
- package/src/model/canonical-document.ts +13 -2
- package/src/runtime/chart/chart-model-store.ts +88 -0
- package/src/runtime/chart/chart-snapshot.ts +239 -0
- package/src/runtime/collab/checkpoint-store.ts +1 -1
- package/src/runtime/collab/event-types.ts +4 -0
- package/src/runtime/collab/runtime-collab-sync.ts +1 -2
- package/src/runtime/document-runtime.ts +115 -13
- package/src/runtime/layout/inert-layout-facet.ts +1 -0
- package/src/runtime/layout/layout-engine-version.ts +58 -1
- package/src/runtime/layout/layout-invalidation.ts +150 -30
- package/src/runtime/layout/page-graph.ts +19 -0
- package/src/runtime/layout/paginated-layout-engine.ts +128 -19
- package/src/runtime/layout/project-block-fragments.ts +27 -0
- package/src/runtime/layout/public-facet.ts +27 -0
- package/src/runtime/page-number-format.ts +207 -0
- package/src/runtime/render/render-frame-diff.ts +38 -2
- package/src/runtime/surface-projection.ts +32 -3
- package/src/ui/WordReviewEditor.tsx +57 -3
- package/src/ui/headless/comment-decoration-model.ts +60 -5
- package/src/ui/headless/revision-decoration-model.ts +94 -6
- package/src/ui/shared/revision-filters.ts +16 -6
- package/src/ui-tailwind/chart/ChartSurface.tsx +236 -0
- package/src/ui-tailwind/chart/layout/axis-layout.ts +17 -9
- package/src/ui-tailwind/chart/layout/legend-layout.ts +231 -0
- package/src/ui-tailwind/chart/layout/plot-area.ts +152 -59
- package/src/ui-tailwind/chart/layout/title-layout.ts +184 -0
- package/src/ui-tailwind/chart/render/area.tsx +277 -0
- package/src/ui-tailwind/chart/render/bar-column.tsx +356 -0
- package/src/ui-tailwind/chart/render/bubble.tsx +134 -0
- package/src/ui-tailwind/chart/render/combo.tsx +85 -0
- package/src/ui-tailwind/chart/render/data-labels.tsx +513 -0
- package/src/ui-tailwind/chart/render/font-metrics.ts +298 -0
- package/src/ui-tailwind/chart/render/gridlines.ts +228 -0
- package/src/ui-tailwind/chart/render/line.tsx +363 -0
- package/src/ui-tailwind/chart/render/number-format.ts +120 -16
- package/src/ui-tailwind/chart/render/pie.tsx +275 -0
- package/src/ui-tailwind/chart/render/progressive-render.ts +103 -0
- package/src/ui-tailwind/chart/render/scatter.tsx +228 -0
- package/src/ui-tailwind/chart/render/smooth-curve.ts +101 -0
- package/src/ui-tailwind/chart/render/svg-primitives.ts +378 -0
- package/src/ui-tailwind/chart/render/unsupported.tsx +126 -0
- package/src/ui-tailwind/chrome/collab-audience-chip.tsx +11 -0
- package/src/ui-tailwind/chrome/collab-negotiation-action-bar.tsx +44 -18
- package/src/ui-tailwind/chrome/collab-presence-strip.tsx +68 -7
- package/src/ui-tailwind/chrome/collab-role-chip.tsx +21 -2
- package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +20 -3
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +102 -37
- package/src/ui-tailwind/chrome/tw-command-palette.tsx +358 -0
- package/src/ui-tailwind/chrome/tw-comment-preview.tsx +108 -0
- package/src/ui-tailwind/chrome/tw-context-menu.tsx +227 -0
- package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +136 -0
- package/src/ui-tailwind/chrome/tw-empty-state.tsx +76 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +30 -16
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +23 -4
- package/src/ui-tailwind/chrome/tw-paste-drop-toast.tsx +113 -0
- package/src/ui-tailwind/chrome/tw-revision-hover-preview.tsx +150 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +2 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +38 -2
- package/src/ui-tailwind/chrome/tw-selection-tool-placement.ts +15 -3
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +32 -20
- package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +68 -0
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +10 -10
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +26 -5
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +29 -22
- package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +72 -10
- package/src/ui-tailwind/chrome-overlay/tw-scope-card.tsx +33 -18
- package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +94 -0
- package/src/ui-tailwind/editor-surface/chart-node-view.tsx +90 -0
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +20 -7
- package/src/ui-tailwind/editor-surface/pm-schema.ts +4 -0
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +14 -0
- package/src/ui-tailwind/editor-surface/scroll-anchor.ts +93 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +2 -1
- package/src/ui-tailwind/index.ts +11 -0
- package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +52 -2
- package/src/ui-tailwind/page-stack/tw-page-footer-band.tsx +13 -0
- package/src/ui-tailwind/page-stack/tw-page-header-band.tsx +13 -0
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +8 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +83 -32
- package/src/ui-tailwind/review/tw-health-panel.tsx +174 -109
- package/src/ui-tailwind/review/tw-rail-card.tsx +9 -1
- package/src/ui-tailwind/review/tw-review-rail.tsx +36 -42
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +189 -101
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +11 -1
- package/src/ui-tailwind/status/tw-status-bar.tsx +114 -46
- package/src/ui-tailwind/theme/editor-theme.css +249 -22
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +14 -1
- package/src/ui-tailwind/toolbar/tw-shell-header.tsx +73 -32
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +49 -9
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +178 -14
- package/src/ui-tailwind/tw-review-workspace.tsx +39 -6
- package/src/ui-tailwind/chrome/review-queue-bar.tsx +0 -85
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bubble chart renderer (Stage 4 Slice 4E).
|
|
3
|
+
*
|
|
4
|
+
* Each data point is drawn as a circle whose radius is proportional to
|
|
5
|
+
* `sqrt(|size|)` (the classic bubble scaling that maps size → area).
|
|
6
|
+
* Null x/y/size values skip the point. Negative sizes use |size|
|
|
7
|
+
* (matching Excel's observed behavior).
|
|
8
|
+
*
|
|
9
|
+
* `bubble3D` is collapsed to 2D per the lane non-goal.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import React from "react";
|
|
13
|
+
import { composeSeriesColor } from "../../../io/ooxml/chart/compose-series-color.ts";
|
|
14
|
+
import type {
|
|
15
|
+
BubbleChartModel,
|
|
16
|
+
BubbleSeries,
|
|
17
|
+
} from "../../../io/ooxml/chart/types.ts";
|
|
18
|
+
import type { ResolvedTheme } from "../../../model/canonical-document.ts";
|
|
19
|
+
import type { PlotAreaLayout } from "../layout/plot-area.ts";
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Public API
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
export interface BubbleChartProps {
|
|
26
|
+
model: BubbleChartModel;
|
|
27
|
+
layout: PlotAreaLayout;
|
|
28
|
+
theme: ResolvedTheme | undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function BubbleChartImpl({ model, layout, theme }: BubbleChartProps): React.ReactElement {
|
|
32
|
+
const plot = layout.plotRect;
|
|
33
|
+
const { xMin, xMax, yMin, yMax, maxSize } = computeRange(model);
|
|
34
|
+
const xSpan = Math.max(1e-9, xMax - xMin);
|
|
35
|
+
const ySpan = Math.max(1e-9, yMax - yMin);
|
|
36
|
+
|
|
37
|
+
// Max bubble radius = ~6% of the smaller plot dimension so bubbles
|
|
38
|
+
// don't dominate. Scale radius linearly with sqrt(size).
|
|
39
|
+
const maxRadius = Math.max(4, Math.min(plot.w, plot.h) * 0.06);
|
|
40
|
+
const sizeScaleFactor = maxSize > 0 ? maxRadius / Math.sqrt(maxSize) : 0;
|
|
41
|
+
|
|
42
|
+
const bubbles: React.ReactElement[] = [];
|
|
43
|
+
|
|
44
|
+
for (let s = 0; s < model.series.length; s++) {
|
|
45
|
+
const series = model.series[s]!;
|
|
46
|
+
const color = composeSeriesColor(model, theme ?? { colors: {} }, s);
|
|
47
|
+
const n = Math.min(series.xValues.length, series.yValues.length, series.sizes.length);
|
|
48
|
+
for (let i = 0; i < n; i++) {
|
|
49
|
+
const x = series.xValues[i];
|
|
50
|
+
const y = series.yValues[i];
|
|
51
|
+
const size = series.sizes[i];
|
|
52
|
+
if (
|
|
53
|
+
x === null || y === null || size === null ||
|
|
54
|
+
!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(size)
|
|
55
|
+
) continue;
|
|
56
|
+
const cx = plot.x + ((x - xMin) / xSpan) * plot.w;
|
|
57
|
+
const cy = plot.y + plot.h - ((y - yMin) / ySpan) * plot.h;
|
|
58
|
+
const r = Math.sqrt(Math.abs(size)) * sizeScaleFactor * (series.bubbleScale ?? 1);
|
|
59
|
+
bubbles.push(
|
|
60
|
+
<circle
|
|
61
|
+
key={`bubble-${s}-${i}`}
|
|
62
|
+
cx={cx}
|
|
63
|
+
cy={cy}
|
|
64
|
+
r={Math.max(1, r)}
|
|
65
|
+
fill={color}
|
|
66
|
+
fillOpacity={0.7}
|
|
67
|
+
stroke={color}
|
|
68
|
+
strokeWidth={1}
|
|
69
|
+
data-role="bubble"
|
|
70
|
+
data-series-index={s}
|
|
71
|
+
data-point-index={i}
|
|
72
|
+
/>,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<g data-role="bubble-chart" data-bubble3d={model.bubble3D}>
|
|
79
|
+
<g data-role="bubbles">{bubbles}</g>
|
|
80
|
+
<g data-role="data-labels" />
|
|
81
|
+
</g>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const BubbleChart = React.memo(
|
|
86
|
+
BubbleChartImpl,
|
|
87
|
+
(prev, next) =>
|
|
88
|
+
prev.model.rawXml === next.model.rawXml &&
|
|
89
|
+
prev.layout.plotRect.w === next.layout.plotRect.w &&
|
|
90
|
+
prev.layout.plotRect.h === next.layout.plotRect.h &&
|
|
91
|
+
prev.theme === next.theme,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Range computation
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
function computeRange(model: BubbleChartModel): {
|
|
99
|
+
xMin: number; xMax: number; yMin: number; yMax: number; maxSize: number;
|
|
100
|
+
} {
|
|
101
|
+
const ax = model.xAxis;
|
|
102
|
+
const ay = model.yAxis;
|
|
103
|
+
let xMin = ax.min ?? Infinity;
|
|
104
|
+
let xMax = ax.max ?? -Infinity;
|
|
105
|
+
let yMin = ay.min ?? Infinity;
|
|
106
|
+
let yMax = ay.max ?? -Infinity;
|
|
107
|
+
let maxSize = 0;
|
|
108
|
+
const dataFillX = ax.min === undefined || ax.max === undefined;
|
|
109
|
+
const dataFillY = ay.min === undefined || ay.max === undefined;
|
|
110
|
+
|
|
111
|
+
for (const s of model.series) {
|
|
112
|
+
for (let i = 0; i < s.xValues.length; i++) {
|
|
113
|
+
const x = s.xValues[i];
|
|
114
|
+
const y = s.yValues[i];
|
|
115
|
+
const size = s.sizes[i];
|
|
116
|
+
if (x === null || y === null || size === null) continue;
|
|
117
|
+
if (dataFillX) {
|
|
118
|
+
if (x < xMin) xMin = x;
|
|
119
|
+
if (x > xMax) xMax = x;
|
|
120
|
+
}
|
|
121
|
+
if (dataFillY) {
|
|
122
|
+
if (y < yMin) yMin = y;
|
|
123
|
+
if (y > yMax) yMax = y;
|
|
124
|
+
}
|
|
125
|
+
const absSize = Math.abs(size);
|
|
126
|
+
if (absSize > maxSize) maxSize = absSize;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (!Number.isFinite(xMin)) xMin = 0;
|
|
130
|
+
if (!Number.isFinite(xMax)) xMax = 1;
|
|
131
|
+
if (!Number.isFinite(yMin)) yMin = 0;
|
|
132
|
+
if (!Number.isFinite(yMax)) yMax = 1;
|
|
133
|
+
return { xMin, xMax, yMin, yMax, maxSize };
|
|
134
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combo chart renderer (Stage 4 Slice 4F).
|
|
3
|
+
*
|
|
4
|
+
* Combo charts pack multiple chart-type groups (bar/line/area) into a
|
|
5
|
+
* single plot area. Each group is a full `BarChartModel`,
|
|
6
|
+
* `LineChartModel`, or `AreaChartModel` that was produced by the
|
|
7
|
+
* parser with per-group axis objects (already cloned by
|
|
8
|
+
* `parse-chart-space.ts` so mutation in one group doesn't bleed into
|
|
9
|
+
* another).
|
|
10
|
+
*
|
|
11
|
+
* Draw order: groups render in declaration order so later groups
|
|
12
|
+
* visually stack on top. The convention is bar → line (line renders
|
|
13
|
+
* atop bar), which matches Word's observed behavior when a combo's
|
|
14
|
+
* type-group nodes appear in XML order.
|
|
15
|
+
*
|
|
16
|
+
* Secondary axes: when a group has `secondaryValueAxis`, its bars /
|
|
17
|
+
* lines project onto the secondary scale. Because per-group renderers
|
|
18
|
+
* already honor `valueAxis.min/max` when computing their range, this
|
|
19
|
+
* works without special wiring — the combo just hands each group its
|
|
20
|
+
* own layout and model.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import React from "react";
|
|
24
|
+
import type { ComboChartModel } from "../../../io/ooxml/chart/types.ts";
|
|
25
|
+
import type { ResolvedTheme } from "../../../model/canonical-document.ts";
|
|
26
|
+
import type { PlotAreaLayout } from "../layout/plot-area.ts";
|
|
27
|
+
import { BarColumnChart } from "./bar-column.tsx";
|
|
28
|
+
import { LineChart } from "./line.tsx";
|
|
29
|
+
import { AreaChart } from "./area.tsx";
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Public API
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
export interface ComboChartProps {
|
|
36
|
+
model: ComboChartModel;
|
|
37
|
+
layout: PlotAreaLayout;
|
|
38
|
+
theme: ResolvedTheme | undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function ComboChartImpl({ model, layout, theme }: ComboChartProps): React.ReactElement {
|
|
42
|
+
// Groups render in declaration order → last group paints on top.
|
|
43
|
+
return (
|
|
44
|
+
<g
|
|
45
|
+
data-role="combo-chart"
|
|
46
|
+
data-group-count={model.groups.length}
|
|
47
|
+
data-has-secondary-axis={model.hasSecondaryAxis}
|
|
48
|
+
>
|
|
49
|
+
{model.groups.map((group, i) => (
|
|
50
|
+
<g key={`combo-group-${i}`} data-role="combo-group" data-group-index={i}>
|
|
51
|
+
{renderGroup(group, layout, theme)}
|
|
52
|
+
</g>
|
|
53
|
+
))}
|
|
54
|
+
<g data-role="data-labels" />
|
|
55
|
+
</g>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const ComboChart = React.memo(
|
|
60
|
+
ComboChartImpl,
|
|
61
|
+
(prev, next) =>
|
|
62
|
+
prev.model.rawXml === next.model.rawXml &&
|
|
63
|
+
prev.layout.plotRect.w === next.layout.plotRect.w &&
|
|
64
|
+
prev.layout.plotRect.h === next.layout.plotRect.h &&
|
|
65
|
+
prev.theme === next.theme,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Group dispatch
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
function renderGroup(
|
|
73
|
+
group: ComboChartModel["groups"][number],
|
|
74
|
+
layout: PlotAreaLayout,
|
|
75
|
+
theme: ResolvedTheme | undefined,
|
|
76
|
+
): React.ReactElement {
|
|
77
|
+
switch (group.kind) {
|
|
78
|
+
case "bar":
|
|
79
|
+
return <BarColumnChart model={group} layout={layout} theme={theme} />;
|
|
80
|
+
case "line":
|
|
81
|
+
return <LineChart model={group} layout={layout} theme={theme} />;
|
|
82
|
+
case "area":
|
|
83
|
+
return <AreaChart model={group} layout={layout} theme={theme} />;
|
|
84
|
+
}
|
|
85
|
+
}
|