enhancement
major
minor
major
minor
major
#29914
Design System wave 5d: foundation pieces and foreign stylesheets read the design system package; tlReactControls.css is removed
Continues #29906 (wave 5c, planning and drag). Wave 5 is cut into four parts with a ticket each (5a inputs, 5b media, 5c planning and drag, 5d foundation and removal of tlReactControls.css), so that a release between the merges does not close the ticket of an open part.
Problem
After wave 5c, the old stylesheet tlReactControls.css still holds about 200 lines that belong to no single control, plus two blocks not yet counted. The design system package's forecast (docs/migration/altlast.md, "Welle 5", V13, V15, V16, V21) found:
- Foundation pieces in the old sheet: the tooltip (tl-tooltip-popover, old tokens, defines --tl-tt-padding in the package's name space), the fill contract (tlFill), the viewport and mount point rules, repeated items, the drag shield, touch drag, the element picker, the anchor flash, the compact field.
- Layers above everything as literals: drag shield 12000, touch drag image 12500, element picker 10000, Wysiwyg popups 10000 — above the package's layer scale.
- Foreign stylesheets (Wysiwyg, script editor, code editor, flow diagram, Chart.js, demo, tlReactBase.css) read the old theme tokens: other focus blue, other surfaces.
- The element picker handles Escape with its own capture listener, outside the keyboard dispatcher.
Solution
Spec in the package: docs/superpowers/specs/2026-10-20-welle-5d-fundament-design.md. No new interaction concept; the only new setting is the density.
- tlReactControls.css is deleted. A test in the package fails if it comes back; a gate keeps the old class names out of react-src, stylesheets, Java, docs and views.
- Package: layers layer-tooltip (1300) and layer-drag (1400); roles surface-inverse/`text-inverse` (computed by derive for customer themes); blocks tl-tooltip, tl-rich-text, tl-compact-field, tl-chart; one rule for actions shown on hover (tl-reveal-on-hover); tl-toolbar--wrap; menuitemradio in the menu contract.
- Fill, anchor flash, drag shield, touch drag image, element picker read the package. Touch drag marks "armed" with its own attribute data-tl-armed; the refused-drop hint lies above the drag image. The picker's Escape goes through the keyboard dispatcher, so Escape inside an open dialog ends only the picker. Viewport and mount point stay the engine's page frame in tlReactBase.css.
- The tooltip is the package block, inverted (dark in light mode, light in dark mode); it follows the anchor the pointer moves to (pinned by a test).
- User menu: a group "Density" with "Normal" and "Compact", stored per person (react.density in the personal configuration); the first HTML already carries data-tl-density, switching takes effect without reload.
- Bridge API: Menu, MenuItem, MenuHeader, MenuSeparator, useRovingMenu, menuItemClassName are exported from tl-react-bridge; <ButtonDefaults appearance="menu-item" radio> gives menuitemradio entries; useTokenSwitch re-reads tokens on mode, theme and density changes.
- Rich text editor: toolbar, menus and link popup are built from the package's parts (Enter and Space on toolbar buttons work again, focus returns to the text); Radix is gone. An error is announced at the textbox (aria-invalid).
- Charts: series colours come from the theme's categories category-1..8, grid, axes, ticks and titles from roles; re-read on mode and theme change without reload; the server's own colours win; Chart.js's Colors plugin is off.
- Code editor, script editor, flow diagram, demo stylesheet and the MUI text read the package's roles instead of the old theme tokens. The editors are fields of the package (frame and fill, also read-only); their keyboard focus ring lies over CodeMirror's sticky line numbers.
The old theme tokens and UIThemeService stay as a bridge (decision V17); their future is decided with #29850 and #29909.
Migration
The foundation pieces and the editors now draw with the design system package; tlReactControls.css no longer exists. Application stylesheets and configurations that address the old names must move to the new ones.
Stylesheet registration: the stylesheet tl-react-controls-css is gone. An application stylesheet that requires it must require tl-design-system-components (or tl-react-base) instead. The stylesheet tl-react-chartjs.css of the Chart.js module is gone as well (the package block tl-chart replaces it).
States are attributes, not classes: picking body[data-tl-state~="picking"], anchor flash [data-tl-anchor][data-tl-state~="flash"], dragging [data-tl-state~="dragging"], armed for touch drag [data-tl-armed], interactive tooltip [data-tl-state~="interactive"], editable compact field [data-tl-state~="edit"], editor error [aria-invalid="true"].
Old → new:
| = Old = | = New = |
| .tlFill | .tl-fill |
| body.tlPick--active, #tl-pick-highlight | body[data-tl-state~="picking"], .tl-pick-highlight |
| .tlAnchor, .tlAnchor--flash | [data-tl-anchor], [data-tl-anchor][data-tl-state~="flash"] |
| .tlDragShield, .tlTouchDragImage, [data-touch-drag] | .tl-drag-shield, .tl-drag-image, [data-tl-state~="dragging"] / [data-tl-armed] |
| .tl-tooltip-popover, -caption, -body, -arrow, --interactive; custom property --tl-tt-padding | .tl-tooltip, __caption, __body, __arrow, [data-tl-state~="interactive"]; no custom property |
| .tlCompactField*, --edit, --view | .tl-compact-field, __preview, __opener; editable: .tl-field with [data-tl-state~="edit"] |
| .tlWysiwygEditor*, .tlWysiwygToolbar*, custom properties --tl-wysiwyg-* | .tl-field.tl-rich-text, content .tl-prose, toolbar .tl-toolbar.tl-toolbar--wrap |
| .tlReactChart* | .tl-chart, .tl-chart__tooltip, .tl-chart__zoom-reset |
| .tlCodeEditor--error, .tlScriptEditor--error | [aria-invalid="true"] (the root classes tlCodeEditor, tlCodeEditorSurface, tlScriptEditor stay) |
The complete table is in the design system repository, docs/migration/altlast.md, section "Welle 5d".
Java API: the Chart.js module drops its colour palette (com.top_logic.layout.react.chartjs.Icons) and the themeColors state of ReactChartJsControl; series colours come from the theme. ReactStackControl gets setStateWords(String) to put state words on the stack's root (data-tl-state).
Visible changes: the tooltip is light in dark mode; charts follow light and dark mode, with eight category colours instead of ten fixed ones; the rich text editor's toolbar wraps, its menus are package menus (the list kind is a toggle, choosing the current heading level keeps it); the link button no longer shows that the cursor stands in a link; code and script editors have the field fill of the package; the selection in the flow diagram uses the interactive border instead of the focus colour.