Skip to content

feat(library): italic abstract classes/methods and lowercase UML class keywords - #799

Merged
FelixTJDietrich merged 10 commits into
mainfrom
feat/uml-abstract-and-keyword-casing
Jul 2, 2026
Merged

feat(library): italic abstract classes/methods and lowercase UML class keywords#799
FelixTJDietrich merged 10 commits into
mainfrom
feat/uml-abstract-and-keyword-casing

Conversation

@FelixTJDietrich

@FelixTJDietrich FelixTJDietrich commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

This makes UML class diagrams notation-correct and the class editor simpler to use.

  • Abstract classes show an italic name (UML 2.5.1 §9.2.4) instead of the invalid «Abstract» keyword — UML has no «abstract» keyword; abstractness is a property, not a stereotype.
  • Keywords use the exact lowercase UML spelling«interface» / «enumeration» (2.5.1 Table C.1), not the capitalized forms.
  • Methods can be marked abstract (italic signature) from the class editor. Attributes can't — UML forbids it — so the control isn't offered there.
  • One "Class type" picker replaces the old Abstract-checkbox + keyword-toggle pair: Class · Abstract Class · Interface · Enumeration. It mirrors the four palette tiles and every other node/edge "type" select, and — because the four options are a lossless projection of the underlying {stereotype, isAbstract} data — it makes the previously reachable invalid states (an italic «interface», an abstract enumeration) impossible to create.
  • Old diagrams migrate automatically on load, at every entry point.

The italic is a real shipped Inter italic face, so it renders the same in the editor and in PNG, PDF and PowerPoint exports. The editor's browser-synthesized slant can't be reproduced by the export renderers (resvg, jsPDF), so it was dropped on export — a real face fixes that at the source.

Release note

Abstract classes and methods now render in italics that survive PNG/PDF/PowerPoint export, interfaces and enumerations use the correct lowercase UML keywords, and you set all of it from a single "Class type" menu in the class editor. (Full user-facing note lives in the changeset.)

Implementation notes

Real italic, everywhere it's measured or rendered. gen:fonts subsets Inter Italic + Bold Italic (from the pinned Inter 4.0 release) into the three consumers that must agree byte-for-byte: the editor woff2, resvg's ttf fontBuffers (PNG), and the jsPDF VFS (PDF). Abstract text is now measured with italic metrics too, preserving the measured == rendered == exported invariant documented in fontStack.ts, so boxes still size correctly.

One deliberate, disclosed scope line — keeping the bundle flat. The italic faces are not base64-inlined into the self-contained SVG export (exportFonts.ts). Inlining them would roughly double that chunk (+180 KB gzip) to serve a single case: a raw .svg opened in a renderer that won't synthesize oblique (e.g. Inkscape). Browsers synthesize the slant from the embedded regular face, and our own PNG/PDF paths carry the real ttf, so the webapp bundle-size budget stays green with no ceiling bump. The only trade-off: abstract text is upright when a .svg is opened directly in a non-synthesizing external editor.

The picker is a projection, not a new data model. Storage stays orthogonal ({stereotype, isAbstract}); the popover just reads/writes a 4-way kind. Writing both fields on every change is what eliminates a real bug in the old two-control design — a stray isAbstract could survive a switch to Enumeration and paint an italic «enumeration» on canvas. A migration guard also clears such a stray modifier on load, and the header-height delta is derived from the LAYOUT constants instead of a magic 10.

Migration is idempotent and covers every hydration boundary — constructor, set model, importDiagram, and the off-screen SVG export — so no load path bypasses it.

Not a breaking change. The reshaped class types (ClassStereotype, ClassNodeProps) are not part of the published API — the package entry only re-exports typings.ts, and they're emitted as ambient declare, not export declare. The published JSON schema leaves node data open, so old and new models both validate. minor is correct. One known edge is out of scope: a peer joining a live Yjs collaboration room during a mixed-version rollout hydrates from the CRDT, which bypasses the load-time migration — a deployment-window concern no semver level addresses.

Steps for testing

  1. Add a Class, open its editor (double-click, or the pencil in the toolbar). Cycle Class type through Class → Abstract Class → Interface → Enumeration. Confirm: Abstract Class → italic name, no keyword line; Interface/Enumeration → a «interface» / «enumeration» line; height only changes when a keyword line appears or disappears.
  2. In the same editor, toggle a method to abstract → its signature renders italic. Note attributes offer no such control.
  3. Export to PNG and PDF → abstract class names and method signatures are italic in both files.
  4. Open an older diagram (e.g. a bundled template with "stereotype": "Abstract" / "Interface") → it loads as an italic abstract class / lowercase «interface» with no manual step.

Screenshots / screencasts

The class editor's classifier control changes from a checkbox + two-button toggle to a single Class type dropdown (each option previews its notation — italic name for Abstract Class, a «keyword» chip for Interface/Enumeration). The new popover and the exported-diagram rendering are both captured by the refreshed Playwright visual baselines in this PR (node-edit.png and the class-diagram snapshots). A maintainer can attach a quick screencast if desired.

Checklist

  • Linked to a related issue (if applicable) — implements User wants to make method abstract #105 (already closed)
  • Added a changeset whose summary is written in the user's voice (@tumaet/apollon, minor)
  • PR title's Conventional Commit type (feat) matches the kind of change
  • Tests added or updated
  • Ran pnpm lint && pnpm format:check && pnpm build && pnpm test locally — green (library 1221, ui 42, webapp 263)
  • Documentation updated (if applicable) — n/a; behavior is covered by the changeset
  • Screenshots or screencasts attached — captured via the refreshed visual baselines; optional screencast left for a maintainer

FelixTJDietrich and others added 2 commits July 2, 2026 16:33
Split the conflated `ClassType` enum into orthogonal UML concepts and fix
how the class diagram renders them:

- Abstract is a modifier, not a keyword: an abstract class shows an italic
  name + the standard `{abstract}` annotation instead of the invalid
  `«Abstract»` guillemet. Italic renders in the editor; `{abstract}` carries
  the cue through export (which strips italic — no italic face is shipped).
- Interface/Enumeration are metaclass keywords, now rendered lowercase
  (`«interface»`/`«enumeration»`) per UML 2.5.1 Table C.1.
- New: mark a method abstract from the class editor (per-method toggle) →
  italic + `{abstract}` signature. Attributes are excluded — UML attributes
  cannot be abstract.

Model: `ClassType` → `ClassStereotype` ({interface, enumeration}), plus an
`isAbstract` boolean on the class and on class members. A shared
`stereotypeLabel`/`withAbstractMarker` pair keeps both SVG renderers and the
width measurement in sync. Existing diagrams migrate on load via an
idempotent normalizer wired at every hydration boundary (editor load bypasses
the public `importDiagram`); serialized version bumped to 4.1.0.

Closes #105.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…picker

Ship real Inter Italic + Bold Italic faces so abstract classes and methods
render italic across the editor and the PNG, PDF and PowerPoint exports,
instead of a browser-only synthetic slant the exporters silently dropped.
Removes the `{abstract}` text fallback and the italic-stripping export pass;
the italic faces are subset by `gen:fonts` and threaded through resvg and
jsPDF, with abstract text measured in italic metrics so boxes still fit.

Replace the class editor's Abstract checkbox + Interface/Enumeration toggle
with one "Class type" Select (Class / Abstract Class / Interface /
Enumeration) — the popover mirror of the palette tiles and the other node/edge
kind selects. Its four options are a lossless projection of the orthogonal
{stereotype, isAbstract} model, so the previously reachable invalid states
(an italic «interface», an abstract enumeration) are unrepresentable, and any
older diagram carrying one self-heals on load.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cut over-explaining and history/temporal references ('now', 'previously',
'older two-control editor') from the abstract-italic + class-type-picker work;
keep only durable rationale.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FelixTJDietrich The implementation pieces I checked look coherent and the focused library tests pass, but this still needs changes: the visual baselines/assets were not regenerated for the changed class UI/rendering, and the title lint check is currently failing. Please update the affected PNG baselines/assets and fix the PR title casing.

Comment thread standalone/webapp/tests/visual/how-to-use.visual.spec.ts
@github-project-automation github-project-automation Bot moved this from Backlog to In progress in Apollon Development Jul 2, 2026
FelixTJDietrich and others added 2 commits July 2, 2026 19:03
The container ran the commit/push script under dash, which rejects
`set -o pipefail` and failed the step before it could push refreshed
snapshots. Pin the step to bash.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FelixTJDietrich The title/CI issue is fixed and most visual baselines are refreshed, but one requested asset is still missing: standalone/webapp/assets/images/how-to-use-node-edit.png was not regenerated. Leaving changes requested until that modal image is committed.

@FelixTJDietrich FelixTJDietrich changed the title feat(library): UML-correct class notation with italic abstract and abstract methods feat(library): italic abstract classes/methods and lowercase UML class keywords Jul 2, 2026
The howto-assets Playwright project regenerates the modal images under
assets/images/, but the commit step only staged tests/**/*-snapshots — so a
UI change left those doc images stale. Stage them too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FelixTJDietrich The latest commit fixes the title and refreshes the Playwright snapshots, but standalone/webapp/assets/images/how-to-use-node-edit.png is still missing from the diff. Keeping this as changes requested until that generated modal asset is regenerated and committed.

FelixTJDietrich and others added 3 commits July 2, 2026 19:30
test:visual:update used the default --update-snapshots (=changed), which
skips snapshots that still pass within tolerance. A sub-threshold UI change
(e.g. the class editor's new Class type select) therefore left the how-to-use
modal images stale — they rendered old UI but never got rewritten. Use
--update-snapshots=all so the baseline job is authoritative.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The export path explicitly warms the Inter faces before its one-shot measure/
render, but only loaded 400/700 upright. Abstract classes/methods are italic,
so that text could be measured and rendered in a fallback family until the
italic face loaded — drifting box sizes in the exported SVG. Load the italic
400/700 faces too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FelixTJDietrich All feedback addressed, nice work.

--update-snapshots=all rewrote every snapshot, churning 32 diagram baselines
that only differ from CI's render sub-tolerance (visual-regression-tests stays
green on them). Restore those to keep the diff scoped to this change: the four
class-diagram baselines (lowercase keywords, italic abstract) and the four
how-to-use modal images (new Class type select). Revert the update script to the
default --update-snapshots.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@FelixTJDietrich
FelixTJDietrich merged commit 8905b71 into main Jul 2, 2026
32 of 34 checks passed
@github-project-automation github-project-automation Bot moved this from In progress to Done in Apollon Development Jul 2, 2026
@FelixTJDietrich
FelixTJDietrich deleted the feat/uml-abstract-and-keyword-casing branch July 2, 2026 17:52
@FelixTJDietrich

Copy link
Copy Markdown
Contributor Author

Two commits landed after the approval — flagging them for the record since one is a genuine behavior change:

  • 39f899a3 fix(library): preload the italic faces before off-screen SVG export. The static export path explicitly warms the Inter faces before its one-shot measure/render, but only loaded the upright 400/700. Abstract classes/methods are italic, so that text could be measured and rendered in a fallback family until the italic face loaded — drifting box sizes in the exported SVG. Now the italic 400/700 faces are preloaded too. (Build + full library suite green.)
  • 84bd0d45 chore(webapp): scope visual-baseline refresh to the changed diagrams. While chasing the modal-asset regen I briefly switched the baseline job to --update-snapshots=all, which rewrote 32 unrelated diagram baselines that differ from CI only sub-tolerance. Reverted those and the script change; the diff is now scoped to the 4 class-diagram baselines + 4 how-to-use modal images that this change actually affects.

CI is green on the new head (the earlier e2e-tests miss was an unrelated flake in activity-swimlane.spec.ts's keyboard drag-reorder poll — green on re-run).

@github-actions github-actions Bot mentioned this pull request Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants