Skip to content

Release v1.2.0 — themes, accessibility, exports, linked cursor, calendar heatmap#47

Merged
mortonanalytics merged 77 commits intomainfrom
develop
Apr 19, 2026
Merged

Release v1.2.0 — themes, accessibility, exports, linked cursor, calendar heatmap#47
mortonanalytics merged 77 commits intomainfrom
develop

Conversation

@mortonanalytics
Copy link
Copy Markdown
Owner

Summary

Cuts myIO v1.2.0 from develop into main. 76 commits since the v1.1.0 tag, covering the full v1.2 NEWS.md changelog. Brings the package up to 18+ chart types, a themeable dark-mode system, full ARIA/keyboard accessibility, a redesigned export pipeline, bidirectional linking (brush + cursor), and the new calendar heatmap.

Highlights (grouped, full list in NEWS.md)

  • New chart typescalendarHeatmap (GitHub-style daily grid), lollipop, dumbbell, waffle, beeswarm, bump, radar, funnel, parallel, survfit (Kaplan-Meier), histogram_fit (MLE distribution overlay).
  • Small multiples / facetingsetFacet(var, ncol, scales) with CSS-grid layout and responsive breakpoints.
  • Theme systemsetTheme(preset=) across 12 named presets + light/dark/auto mode; CSS-var-driven; WCAG AA dark palette; high-contrast and reduced-motion support.
  • Linked brushing + linked cursorlinkCharts() and setLinked() grow a cursor = TRUE arg; setLinkedCursor() retrofits. Crosstalk path extended to waffle, beeswarm, lollipop, dumbbell.
  • bslib + Quarto dashboards — widgets now declare a fill-aware sizing policy and carry html-fill-item; fit inside bslib::card() and Quarto {.fill} without boilerplate.
  • Export enhancementssetExportOptions() toolbar toggles, SVG download, PNG+SVG clipboard copy, CSS-var resolution in exported SVGs (dark mode exports correctly), lazy-loaded PDF via vendored jsPDF.
  • Accessibility — ARIA graphics roles on SVG; keyboard traversal across layers and points with live-region announcements; hidden data-table fallback; focus-ring styling.
  • Sparkline modemyIO(sparkline = TRUE) strips axes/legend for table-cell embedding.
  • Group-by auto-series — pipe a dplyr::group_by() tibble to addIoLayer() and it expands per-group with Okabe-Ito colors.
  • Infra — CRAN dev-artifact exclusion via .Rbuildignore; vite/brace-expansion security bumps; engine-bump-notify cross-repo workflow and AGENTS.md.

What changed in files

  • R surface: new exports include setFacet, setLinkedCursor, setExportOptions, setLayerOpacity, and the new type values. DESCRIPTION grows Suggests: dplyr, DT, reactable, htmltools, crosstalk (>= 1.2.0).
  • JS renderer layer: new classes (CalendarHeatmapRenderer, LollipopRenderer, DumbbellRenderer, WaffleRenderer, BeeswarmRenderer, BumpRenderer, RadarRenderer, FunnelRenderer, ParallelRenderer) and expanded export/tooltip/rollover/linked-cursor wiring.
  • Vignettes: chart-types, crosstalk-linking, accessibility/troubleshooting articles updated.

Test plan

  • JS suite: 257/257 passing (npm test)
  • R testthat suite: all pass (Rscript -e 'devtools::test()')
  • R CMD check: 0 errors, 0 warnings, 1 pre-existing NOTE (top-level files; addressed at release build time)
  • Real-browser Playwright smoke of linked cursor across two linked charts and of calendar heatmap cell hover → sibling crosshair sync
  • Reviewer: spot-check app/app.R Shiny gallery loads and each tab renders
  • Reviewer: spot-check bslib fill policy inside a bslib::card() dashboard
  • Reviewer: pre-release R CMD build . and inspect the tarball contents — confirm .Rbuildignore excludes md/, smoke PNGs, and other dev artifacts before any CRAN submission

Release notes

Primary source of truth: NEWS.md under # myIO 1.2.0 (development). Rename the header to # myIO 1.2.0 at tag time.

Requirements decision

No behavioral requirements doc gate applies — myIO does not maintain a separate md/requirements/ source-of-truth. Exported function roxygen docs + NEWS.md + vignettes are the contract. Those are updated in-tree.

Preflight gate

The /pr skill template's per-feature preflight gate (.claude/state/preflight-{slug}.txt) does not apply here: this is a release-cut PR from develop, not a single-feature branch. Feature-level verification happened at each commit's merge to develop during the v1.2 cycle.

Pipeline docs archived locally

Two completed v1.2 plans moved to md/archive/ in this session (local only; md/ is gitignored):

  • md/archive/calendar-heatmap-plan.md
  • md/archive/bslib-fill-and-crosstalk-expansion-plan.md

🤖 Generated with Claude Code

mortonanalytics and others added 30 commits March 26, 2026 19:02
Exclude the auto-generated CRAN-SUBMISSION file from package builds.
Document strict semver and backward-compatibility requirements for
all minor/patch releases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds `sparkline = TRUE` parameter to `myIO()` that renders compact,
axes-free charts at 20px height — suitable for embedding in reactable,
DT, and gt table cells. Strips legend, interactions, and reference lines.
Supports line, bar, and area layer types.

R: sparkline param on myIO(), type validation in addIoLayer()
JS: applySparklineOverrides() in Chart constructor, sparkline CSS
Tests: 12 R tests, 7 JS vitest tests (19 total)
Docs: sparklines.Rmd vignette, NEWS.md v1.2.0 entry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add sparkline mode for compact table-cell charts
Adds mode-based theming to setTheme(): "light", "dark", and "auto" modes
with WCAG AA-verified palettes. Auto mode detects OS preference and
Quarto/Bootstrap data-bs-theme via MutationObserver + matchMedia.

R: setTheme() gains mode/preset/overrides params (backward compatible)
JS: ThemeManager class with palettes, auto-detection, lifecycle cleanup
CSS: high-contrast and reduced-motion media queries
Tests: 18 R tests, 7 JS vitest tests (25 total)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add dark mode / theme system with auto-detection
…(v1.2)

Adds SVG download button, clipboard copy (SVG + PNG via Clipboard API),
and CSS custom property resolution for theme-correct exported SVGs.
New setExportOptions() R function controls toolbar button visibility.

R: setExportOptions() with png/svg/pdf/clipboard/csv/title flags
JS: resolve-css-vars.js, export-clipboard.js, downloadSVG(), SVG button
    in toolbar with config.export-aware filtering
Tests: 15 R tests, 5 JS vitest tests (20 total)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add export enhancements: SVG download, clipboard, CSS var resolution
Adds setFacet() to split charts into a CSS grid of panels, one per unique
value of the faceting variable. FacetController manages lifecycle and
FacetPanel renders mini-charts with own SVG, scales, and axes.

R: setFacet(var, ncol, min_width, scales, label_position)
JS: FacetController + FacetPanel classes, Chart.js integration,
    htmlwidgets resize handling for faceted mode
CSS: facet grid layout, panel labels, responsive breakpoints
Tests: 17 R tests, existing JS suite passes

Phases 3-5 (free scales, cross-panel interactions, performance) deferred.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add small multiples / faceting with CSS grid layout
Adds two new chart types to the myIO renderer registry:
- lollipop: vertical stem + circle head, categorical x-axis, supports
  mean/summary transforms
- dumbbell: connected dots showing low_y to high_y range

Both support flipAxis, themed colors, and standard tooltip formatting.

R: types added to ALLOWED_TYPES, COMPATIBILITY_GROUPS, VALID_COMBINATIONS
JS: LollipopRenderer + DumbbellRenderer with full renderer interface
CSS: crisp stems, hover enlargement on heads/dots
Tests: 5 lollipop + 6 dumbbell R contract tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Completes the new chart types roadmap:
- waffle: 10x10 grid of colored squares for proportions (standalone)
- beeswarm: dodge-positioned points with inline collision detection
- bump: smooth S-curves for rank/value changes over time (grouped)

R: types added to ALLOWED_TYPES, COMPATIBILITY_GROUPS, VALID_COMBINATIONS
JS: WaffleRenderer + BeeswarmRenderer + BumpRenderer
CSS: hover effects for all three types
Tests: 6 waffle + 4 beeswarm + 4 bump R contract tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds cross-cutting accessibility features:
- ARIA roles (graphics-document, graphics-object, graphics-symbol) on SVG
  structure with auto-generated labels from axis config
- Keyboard navigation state machine: arrow keys traverse layers/points,
  live region announcements with 150ms debounce, focus ring styling
- Hidden data table fallback for screen reader access (500-row cap)
- Screen-reader-only utility class, focus ring CSS

All features skip sparkline mode. Existing functionality preserved.

JS: a11y/aria.js, descriptions.js, keyboard-nav.js, data-table.js
CSS: focus ring, sr-only, data table styles
Tests: 6 JS a11y contract tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add SVG accessibility: ARIA roles, keyboard nav, data table
… Session 1)

Three new features completing the statistical visualization story:

- Kaplan-Meier survival curves: transform_survfit computes KM estimator +
  Greenwood CI using base R only. composite_survfit expands to step-curve
  line + CI band + censored markers. Group stratification supported.
- Distribution fitting: transform_fit_distribution fits normal/lognormal/
  exponential via MLE. composite_histogram_fit overlays fitted density on
  histogram.
- Layer opacity: setLayerOpacity(label, opacity) for per-layer transparency.
  Applied in Chart.js routeLayers().

Tests: 23 survfit + 7 histogram_fit + 6 opacity = 36 new R tests
Total: 770 R tests, 194 JS tests, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add survival curves, distribution fitting, and layer opacity
Side-by-side code comparisons for 8 common patterns: scatter, line, bar,
histogram, box, regression+CI, statistical annotations, and dark mode.
Addresses the plotly documentation retirement and broken features (#1472,
#1687) as migration motivators.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…guide

Add plotly migration guide vignette
Two adoption features to close the gap with ggiraph and echarts4r:

- linkCharts(): cross-chart selection with bidirectional mode and
  aggregation-to-source-row key resolution
- Group-by auto-series: pass a grouped tibble to addIoLayer() and it
  auto-creates one layer per group with Okabe-Ito colors. Soft dplyr dep.

Tests: 7 grouped_df + 13 linkCharts = 20 new R tests
Total: 790 R tests, 194 JS tests, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add linked brushing and group-by auto-series
12 named theme presets: midnight, ocean, forest, sunset, monochrome,
neon, corporate, academic, nature, minimal, retro, warm. Applied via
setTheme(preset = "name"). Presets override the base light/dark palette
but user CSS custom property overrides still take highest priority.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ion 4)

Three new standalone chart types bringing the total to 30+:

- radar: spider/radar chart with radial axes and polygon data fill
- funnel: narrowing horizontal bars for conversion pipelines
- parallel: parallel coordinates for multivariate exploration

R: types registered in ALLOWED_TYPES, COMPATIBILITY_GROUPS, VALID_COMBINATIONS
JS: RadarRenderer, FunnelRenderer, ParallelRenderer with standalone rendering
CSS: hover effects for all three types
Tests: 4 radar + 4 funnel + 3 parallel R tests, 4 JS render tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add radar, funnel, and parallel coordinates chart types
Adds tabs for 11 new chart types (lollipop, dumbbell, waffle, beeswarm,
bump, radar, funnel, survival curves, distribution fit, sparklines,
small multiples) and theme preset selector. Updates home page to reflect
30 chart types and 12 theme presets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update gallery app with all v1.2 features
- Bump chart: add defineCategoricalAxis() so x-axis renders Q1-Q4
- Beeswarm: swap to point chart (beeswarm needs categorical y-axis,
  demo data uses numeric y — will fix renderer in follow-up)
- Sparklines: use sparkline = TRUE parameter instead of manual suppress
- Survival curve: add setAxisLimits(ylim = 0-1)

Known remaining issues (renderer-level, not app-level):
- Survival curve: x-axis scale derivation compresses time values
- Distribution fit: JS error "undefined is not iterable" in composite
- Sparklines: axes/FAB still faintly visible (CSS specificity issue)
- Bump: all lines same color (colorScale not applied per group)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix gallery app visual issues from review
Three root-cause fixes:

1. Distribution fit composite: changed histogram sublayer from type
   "histogram" to "bar" with pre-binned data. HistogramRenderer expects
   layer.bins from the derive pipeline, which composites bypass.

2. Survival curve composite: fixed scaleHints to include x_var/y_var
   in extent fields so the derive pipeline computes correct x/y domains
   instead of normalizing to [-1, 1].

3. Scaffold: add "myIO-container" CSS class to the widget element so
   CSS selectors for sparkline hiding, high-contrast, and reduced-motion
   actually match. This was preventing sparkline FAB/axis suppression.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mortonanalytics and others added 28 commits March 30, 2026 21:43
Resolved merge conflict in buttons.js data2Use logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- T1: Simplified icon set (iconLegend, iconDownload, iconImage), stroke-width
  1.5→2 at 16px, data-first labels, removed dead addButtons()
- T3: FAB responsive position (top-right desktop, bottom-right mobile), close
  button styles, circle swatches, divider, Show All reset, adaptive grid,
  action row layout, removed .buttonDiv styles
- T4: Removed .buttonDiv from scaffold.js and Chart.js cleanup selectors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Header row with close button (X) replacing bare handle
- Section wrapper holds legend body + divider (hides together)
- Removed section titles (h2) and On/Off state text
- Circle swatches (no border), adaptive grid for 5+ items on mobile
- Show All reset button rendered outside grid in section wrapper
- Swipe-to-dismiss on mobile (header-only, 80px threshold)
- Data-first action order with visible labels
- FAB icon: iconLegend(), aria-label: "Legend and actions"
- try/finally on toggleOrdinalSegment suppress flag

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- T5: Updated bottom-sheet tests for new DOM structure (13 tests)
  - Close button, Show All reset, no On/Off text, visible labels,
    Escape-to-close, initial focus, suppressLegend hides divider
- T6: Added resetLegendVisibility tests for layer and ordinal reset

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Regenerated myIOapi.js via esbuild with all legend redesign changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cross-agent review found that toggleOrdinalSegment and
resetLegendVisibility("ordinal") suppressed the legend rebuild but
never re-rendered the panel legend items. Added renderSheetLegend(chart)
after both finally blocks so aria-checked and Show All stay in sync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create export-pdf.js with lazy jsPDF loading and A4 page fitting
- Add PDF and clipboard handlers to buttons.js handleAction
- Add PDF, SVG, clipboard actions to bottom-sheet buildActionData
- Fix SVG default: all export buttons visible unless explicitly disabled
- Add export CSS (copy menu, success feedback, sr-announce)
- Update contract tests and bottom-sheet tests for new action count

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New tab with toggleable PNG/SVG/PDF/CSV/clipboard controls and theme
selector to test CSS variable resolution in exports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Legend UI: FAB + bottom-sheet panel replacing old buttonDiv toolbar.
Export enhancements: PDF export (lazy jsPDF), clipboard copy (SVG/PNG),
expanded CSS var resolution, all 5 export buttons default visible.
Gallery: new Export Demo tab.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add missing svg branch to handleAction; Save as SVG was a silent no-op
- Move jspdf.umd.min.js into the widget dir so Shiny htmlwidgets serves it;
  switch load-jspdf.js to URL-based path resolution instead of string trim
- Fix resolve-css-vars regex to handle var(--x, fallback) syntax
- Inject resolved chart vars as inline style on SVG root so embedded CSS
  rules inherit the active theme in standalone exports

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The single "Copy to clipboard" action hardcoded PNG; splitting gives users
a discoverable way to copy vector SVG without reaching for R config. Both
entries are controlled by the existing export.clipboard flag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
linkCharts() and setLinked() gain a cursor=TRUE argument (default FALSE
for strict-semver). When enabled, hovering any element with an x-value in
one chart draws a vertical crosshair at the matching x on every sibling
chart in the same link group. New setLinkedCursor() composes onto a
pre-linked widget.

Architecture:
- linked-cursor.js owns a module-level Map<group, Set<chart>> registry.
- Charts register on mount from Chart.js when config.interactions.linked
  .cursor===true; unregister from cleanupLinked in linked.js.
- rollover.js emits a CursorEvent at the three hover tails (showElementHover,
  showGroupedBar, showOverlayTooltip) and a clear event from their mouseout
  paths. Receivers map xValue through their own xScale (not source pixels).
- Out-of-domain xValues clear rather than drawing off-canvas.
- Echo suppression (self-receive skipped), stale-ts drop, and teardown
  cleanup are all covered by tests.

Covers design criteria 1-7 and 9. Criterion 8 (config round-trip) is
verified by R tests. rAF throttling deferred to v1.3 if profiling shows
need. Donut/treemap excluded — no x-axis to sync on.

Design: docs/linked-cursor-design.md
Contract: docs/linked-cursor-contract.md
Plan: md/todo/linked-cursor.md

Tests: 29 R assertions + 10 JS unit + 13 JS integration = 52 new.
Total suite: 248 JS tests, 822 R tests, all passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
drawCrosshair appended line.myIO-hover-rule to chart.svg (root) but
used xPx from chart.xScale, which is in plot-area-local coordinates.
On real charts the plot group is translated by (margin.left, margin.top),
so the crosshair rendered 30-50px left of the actual data. The JSDOM
integration tests didn't catch this because their fixture mounts skip
the plot group.

Attach to chart.plot when present, fall back to chart.svg for tests.
Clamp y-extent to inner plot height so the rule doesn't extend past
the x-axis into the margin band.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
expand_grouped_df() calls dplyr::group_vars() and dplyr::ungroup()
behind a requireNamespace guard, and test_grouped_df.R uses
dplyr::group_by() for fixtures via skip_if_not_installed. Both call
sites are optional, so Suggests is the correct declaration. Resolves
two WARNINGs: undeclared :: import and undeclared requireNamespace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitHub-contributions-style grid: 7 rows (weekdays) x ~52 week columns,
month labels across the top. Single calendar year per layer; multi-year
data is rejected with a pointer to a future setFacet() path. Default
week start is Sunday; Monday is available via options$weekStart.

Piping grouped data just works:
  addIoLayer(type = "calendarHeatmap",
             mapping = list(date = "day", value = "x"))

Participates in the shared pipeline for free — theming, PNG/SVG/PDF/CSV
export, tooltips, and cross-chart linked-cursor sync on the date key.
Two new hooks were needed: rollover.js now recognizes calendarHeatmap as
an element-bound layer and derives its xValue from mapping.date as a
Date, so linked cursor maps through each receiver's own week-column
scale. Three CSS vars theme the grid: --chart-calendar-cell-gap,
--chart-calendar-cell-stroke, --chart-calendar-empty-fill.

Tests: 6 testthat cases (mapping, numeric, coercion, multi-year,
empty, composition) and 9 vitest cases (registration, cell count,
both week-start conventions, color scale, month labels, tooltip,
linked-cursor emit + receive).

Design: md/design/calendar-heatmap.md. Plan: md/todo/calendar-heatmap.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Slice A (bslib): myIO() widgets now declare a sizing policy with
fill = TRUE so they render as bslib fill items inside card(),
Quarto Dashboard {.fill} cards, and flexdashboard layouts. Added
a resize guard against zero-dimension containers that appear
briefly during fill-layout transitions.

Slice B (crosstalk): LINKABLE_TYPES extended from 5 to 9 entries,
adding waffle, beeswarm, lollipop, and dumbbell (all four already
stamp _source_key in their renderers). New crosstalk-linking
vignette demonstrates linking myIO with DT and reactable, with
plotly and leaflet shown as static code listings.

Suggests: add DT, reactable, htmltools for the vignette and tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Transitive dev dependency via glob. npm audit fix bumps
brace-expansion from 2.0.2 -> 2.1.0 and 5.0.4 -> 5.0.5,
resolving GHSA-f886-m6hf-6m8v (zero-step sequence hang).
Dev-only; not shipped to users.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Documents the myIO↔pymyIO boundary for AI coding agents and auto-opens
a tracking issue in pymyIO whenever engine files change on main.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Also Rbuildignores AGENTS.md so dev-only guidance stays out of the
package build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Enables manual firing for smoke tests and for backfilling tracking
issues after a missed sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
gh issue create routes through GraphQL, which fine-grained PATs don't
fully support and returns 401. Using the REST POST /issues endpoint
directly with jq-built payload works with a fine-grained token scoped
to Issues: Read and write.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both gh api and gh issue create probe GraphQL during token verification
and reject fine-grained PATs with 401 even for pure REST calls. Plain
curl with a Bearer header works.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Temporarily probe /user before POST /issues to isolate whether the
workflow's 401 is a token-storage issue or a token-permission issue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The diagnostic surfaced a secret-install bug (gh secret set --body -
stored literal "-" instead of stdin); that's now fixed. The workflow
runs cleanly against a correctly-installed fine-grained PAT.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mortonanalytics mortonanalytics merged commit 64e7481 into main Apr 19, 2026
7 of 8 checks passed
mortonanalytics added a commit that referenced this pull request Apr 19, 2026
v1.2.0 merged into main (PR #47, merge commit 64e7481). Open the 1.3.0
dev cycle on develop. NEWS header for 1.2.0 loses its (development)
marker here since that version is shipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant