Insert > Line or Area and the All Charts list offer 100% Stacked Area,
and insert.chart and chart.set take it as type area with subtype
stacked100. Each series' area stacks on the ones before it as its
share of the category's total. When every series on the value axis is
100% stacked and no value is negative, the axis runs from 0% to 100%.
A blank cell counts as zero, and a category whose total is zero stays
on the baseline.
An XLSX area chart with percentStacked grouping now opens as 100%
stacked and is saved back as percentStacked. It used to open as a
stacked area and was saved as stacked.
Home > Format as Table on a cell or range inside an existing table
failed with "A table can't overlap another table." Excel applies the
picked style to that table instead. The command now returns that table
and its range, as it does for a new table. A range crossing a table's
edge is still rejected.
Without a range, the active area of the selection decides, as it does
for Insert > Table. The native Format menu's Format as Table now runs
home.formatAsTable instead of insert.table.
crates/engine/src/cmd/insert.rs: kept both sides: PR #884's is_string_literal and cf_style_json, and PR #2022's check_cf_* before edit(); 884's kept string literals parse
The reader took only <x:Visible/> from a note's VML shape and vml_xml
wrote every note with a fixed anchor (two columns right of the cell,
four rows tall) and a 108 x 59.25 pt style, so a plain open and save
moved and resized every note box Excel had stored.
Comment gets an optional NoteBox: the <x:Anchor> corners relative to the
note's cell (so the box follows the note when rows or columns move) and
the shape's width and height. The writer puts it back, clamped to the
sheet; notes made here, and boxes equal to the default, keep the
default box.
Every edit copies the workbook for its undo step (copy-on-write: sheets
and 64-row bands of cells are shared). A floating picture's bytes
(Image.data) and the VBA project (Workbook.vba_project) were plain
Vec<u8>, so each edit on a sheet with a picture, and every edit in a
workbook with macros, kept another full copy of them, up to the 100
steps of the history. They are Arc<Vec<u8>> now, as cell pictures
already are, with base64 helpers for serde (b64::shared, b64::opt). JSON
and XLSX are unchanged.
Measured on macOS 27 (Apple M3 Max), gridcraft-cli, kernel peak
footprint: a 19 MB picture and 50 cell edits on its sheet, 992 -> 22 MB;
10 edits, 215 -> 21 MB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/insert.rs:477
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`style: {fill: "none"}` (or "auto") went through the colour pass and came out as a solid
fill in the automatic colour. `home.fillColor` reads the same word as no fill, so the rule
style does too now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
home.conditionalFormat deserialized `style` straight into the model's
Style, so a programmatic caller had to write colours as {"Rgb": 16773836}:
"#FFF2CC", which format_range, colorScale and dataBar take, was refused
with a serde message naming internal types. A key the struct doesn't have
(`style: {preset: …}`, `fillColor`) was dropped, which saved a rule with an
empty format that matches and shows nothing. And a cellIs `value` already
written as a string literal ("\"Closed\"", as in the file and openpyxl)
was quoted again into the text "Closed" with its quotes, so it never
matched.
`style` colours (font, fill fg/bg, borders) may now be "#RRGGBB",
{theme, tint} or "auto", and `fill` may be a colour alone (a solid fill);
a fill colour with no pattern is solid. Unknown keys and a non-object
`style` are refused. A cellIs value that is one string literal is kept.
The model's own shape keeps working.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
home.manageRules took the number of rules once, before deleting, so
{"delete":0,"moveUp":1} with two rules swapped past the end of the
shortened list and panicked (index out of bounds; the session's guard
kept the workbook). The count is now taken after each step.
Model: Series.trendlines (Vec<Trendline>, serde default) with kind
(linear, exponential, logarithmic, polynomial 2..6, power, moving
average 2..255), name, forward/backward forecast, set intercept,
equation / R² display and line colour, width and dash.
XLSX: read and write <c:trendline> in CT_Trendline child order, placed
after dLbls and before the data references in line, bar, area, scatter,
bubble and stock series; unknown types are skipped.
Chart: least-squares fits (transformed for exp/log/power, skipping
non-positive values; polynomials via normal equations on centred,
scaled x with partial pivoting), moving averages, forecasts that widen
the category or x axis, clipping to the plot, equation and R² labels and
legend entries ("Linear (Sales)"). Degenerate data draws nothing.
Engine: chart.addElement element="trendline" adds (type, series, order,
period, forward, backward, displayEquation, displayRSquared) or removes
trendlines; document.inspect lists each chart's trendlines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Text boxes ignored a:rPr (size, bold, italic, typeface, fill, outline),
a:pPr algn, a:bodyPr anchor and spPr/a:ln/a:noFill. They are now read into
Shape::format, drawn on screen and in PDF, and written back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>