FluentUI: Basis-Widget-Katalog
Zurück: FluentUI (Design-System-Bibliothek)
Status: Seit dem Vollausbau (2026-07-14) ist der
Katalog-Kernbestand durchgehend Tier 1 — Button, Dropdown, SelectBox,
SplitView (CSS-Primitive), ProgressBar, Hover/Tooltip, CountBadge,
DeclarativeTable und Card/Tile sind als helper_plugin_wkfluentui_widgets
bzw. CSS-/Attribut-Verträge umgesetzt (je Zeile vermerkt); verbindlicher
Methodenvertrag in FluentUI: Öffentliche Helper-API. Seit dem
Studio-Ausbau (2026-07-14) sind auch die vier
Studio-getriebenen Bausteine im Abschnitt unten (InputBox-Filter,
Editor-Tab-Strip, Command-Palette, Panel-Maximieren) Tier 1 —
Erstkonsument ist das SQLite Data Studio (wksqliteds).
Quellen: VSCode (https://github.com/microsoft/vscode, Pfad
src/vs/base/browser/ui/**, Basis-Widgets) und Azure Data Studio
(https://github.com/microsoft/azuredatastudio, Pfad src/sql/**,
Formular-/Dialog-/Grid-Erweiterungen, die es in Stock-VSCode nicht gibt) —
beide öffentliche, quelloffene Repositories.
Widget-Tabelle
| Widget | VSCode-Klasse | Kern-CSS-Klasse | Zustands-Vokabular | ARIA | Umsetzung |
|---|---|---|---|---|---|
| Button | Button, ButtonWithDropdown | .monaco-button (+.secondary/.small) | disabled, hover, focus, checked | role=„button“, aria-pressed, aria-disabled | Tier 1: widgets::button() (Varianten primary/secondary/outline/danger/link, confirm-Dialog) + .wk-btn-Basis-CSS — Vertiefung: Eingabefelder: Button |
| InputBox | InputBox, HistoryInputBox | .monaco-inputbox (+.idle/.info/.warning/.error) | idle/info/warning/error, disabled, empty | aria-label, aria-invalid | Tier 1: Feld-Metrik .wk-field__input + Zustands-/ARIA-Vertrag des Feld-Basiskontrakts; Freitext-mit-Liste über comboBox(allowUserInput) — Vertiefung: Eingabefelder-Demo-Portal |
| Dropdown | BaseDropdown, DropdownMenu | .monaco-dropdown | active (offen), disabled | aria-haspopup, aria-expanded | Tier 1: widgets::dropdown() (details/summary-Basis + Overlay-JS) — Vertiefung: Eingabefelder: Dropdown Editor |
| SelectBox | SelectBox (Native/Custom) | .monaco-select-box | disabled option, expanded | aria-label, role=„separator“ | Tier 1: widgets::comboBox() / widgets::listEditor() — Vertiefung: Eingabefelder: Combo Box |
| List/Tree | List<T>, ObjectTree/DataTree | .monaco-list, .monaco-list-row | focused, selected, hover, drop-target, dragging | role=„list“/„listbox“/„treeitem“, aria-activedescendant, aria-level | Tier 1: widgets::tree() — <details>/<summary>-Baum, mit Selection (Radio/Checkbox, role=tree-Set), Reorder (▲/▼ + Drag-Schicht) und Icon-Kollaps; Demo-Portal: treeview |
| ActionBar/Toolbar | ActionBar, ToolBar | .monaco-action-bar, .monaco-toolbar | disabled, vertical/horizontal, responsive-overflow | role=„toolbar“, Pfeiltasten-Roving-Tabindex | Tier 1: widgets::toolbar() + scripts/toolbar.js — mit Ribbon-Gruppen (groupLabel/size) und Opt-in-Overflow; Demo-Portal: toolbar |
| SplitView/Sash | SplitView, Sash | .monaco-split-view2, .monaco-sash | disabled, hover, active (Drag), orthogonal | role=„separator“, aria-valuenow/-min/-max | Tier 1: Workbench-Regionen nutzen die JS-Sash-Engine scripts/sash.js (.wk-workbench__sash: Drag + Pfeiltasten, Persistenz je data-wk-workbench-context, re-geklemmt — seit 2026-07-17, ersetzt dort das native resize); .wk-splitview + __pane--fixed (natives resize) bleibt für Nicht-Workbench-Konsumenten |
| ProgressBar | ProgressBar | .monaco-progress-container | active, done, infinite, discrete | role=„progressbar“, aria-valuenow | Tier 1: widgets::progressBar() + wkProgressBar.setValue() — Vertiefung: Eingabefelder: Progress Bar |
| Menu/ContextMenu | Menu, ContextView | .monaco-menu, .context-view | focused, checked | role=„menuitem“/„menuitemcheckbox“ | Tier 1 (Teilmenge): widgets::rowActions() + scripts/contextmenu.js — progressiv, re-triggert nur bereits vorhandene Elemente, kein neuer Schreib-Pfad |
| Hover/Tooltip | HoverWidget | .monaco-hover | fade-in, hidden, disabled (Action) | role=„tooltip“ | Tier 1: Attribut-Vertrag data-wk-tooltip + scripts/tooltip.js (Hover und Fokus, aria-describedby-Kopplung, Escape) |
| CountBadge | CountBadge | .monaco-count-badge (Pill, radius 11px) | long-Variante | — | Tier 1: widgets::countBadge() (Pill + –long, Pflicht-Screenreader-Text) — die eine Badge-Quelle, navBar() delegiert hierher |
| Modal/Dialog (ADS) | Modal-Basisklasse | .modal.normal-dialog (640px) / .modal.flyout-dialog (500/800/1200px) | — | Standard-Dialog-ARIA | Tier 1 (640px-Variante): widgets::drawer() (seitlich) + widgets::modal() (wk-modal–normal, zentriert) |
| FormLayout (ADS ModelView) | formContainer/groupContainer | .form-table/.form-row/.form-cell-title (Label-Spalte 129px) | required (rotes Sternchen), collapsible Group | <fieldset>-artig | Tier 1 (Kernraster): widgets::propertyGrid() — CSS-Grid fit-content(22rem) minmax(0, 1fr), ohne required-Sternchen/Collapsible-Group |
| DeclarativeTable (ADS) | declarativeTable | .declarative-table | editierbare Zellen | — | Tier 1: widgets::declarativeTable() — native Formularfelder je Zelle ({name}[{i}][{key}]), postet ohne JavaScript |
| Card/Tile (ADS) | card-Komponente | .model-card (radius 8px, einzige rundere Ausnahme im sonst 2px-flachen System) | Status-/Auswahl-Badge (radius 50%) | — | Tier 1: widgets::card() (.wk-card, radius-lg, Status-Badge, Footer-Zeile) |
| Table/Designer (ADS) | Table(SlickGrid) + designer.ts | .monaco-table, .components-grid | Sortierpfeile, Spalten-Filter-Menü | bester Fund für „Formular+Datengrid-Hybrid“ | Tier 2 (Konzept) — Konsument wksqliteds-Table-Designer baut auf propertyGrid() + tabs() auf; Demo-Portale: property-grid, tabcontrol, treelist |
| InputBox-Filter (ADS/VSCode) | InputBox als List-Filter | .wk-listfilter | empty, focused, no-match | aria-controls + Live-Region | Tier 1: widgets::listFilter() + scripts/listfilter.js — Vertrag unten: inputbox-filter |
| Editor-Tab-Strip (ADS/VSCode) | EditorTabsControl | .wk-editortabs | active, dirty, disabled | role=„tablist“ | Tier 1: widgets::editorTabs() + scripts/editortabs.js — Vertrag unten: editor-tab-strip |
| Command-Palette (VSCode) | QuickInput/QuickOpen | .wk-cmdpalette | empty, filtered, no-match | Dialog + Listbox | Tier 1: widgets::commandPalette() + scripts/cmdpalette.js — Vertrag unten: command-palette |
| Panel-Maximieren (VSCode) | maximized-Layoutklasse | .wk-shell-panel--max | maximiert/normal | Toggle-Button | Tier 1: Attribut-Vertrag data-wk-panelmax + scripts/panelmax.js — Vertrag unten: panel-maximieren |
| Workbench-Grid (VSCode/ADS Workbench-Layout) | workbench.ts-Grid-Parts | .wk-workbench (+--flat/--no-sidebar/--no-auxbar/--auxbar-collapsed) | overlays, has-sidebar/-auxbar, is-open (Region) | Regionen-Landmarks der Konsumenten | Tier 1: Grid-Komposition mit Track-Wrapper-Properties + widgets::workbench() + scripts/workbench.js (Degradation 1280/1024/768, Overlay+Scrim) — Regeln: FluentUI: Admin-Bereich (vertieft) |
| Statusbar-Items (VSCode StatusBar) | statusbarPart (priority-basierter Abwurf) | .wk-shell-statusbar__group/__item | priorisiert/verzichtbar (unter 1024px) | role=„status“ | Tier 1: widgets::statusbar() + Attribut-Vertrag data-wk-priority — Vertrag: FluentUI: Öffentliche Helper-API |
| Toast/Notification (VSCode Notifications) | notificationsToasts | .wk-toast-host, .wk-toast--{info,success,warning,error} | auto-dismiss, sticky (error), hover-pause | aria-live=„polite“ | Tier 1: JS-API wkToast(type, text, opts) (scripts/toast.js) — nur asynchrone Rückmeldungen, msg() bleibt für Roundtrips; Vertrag: FluentUI: Öffentliche Helper-API |
| Dichte (ADS density) | — (WDX-Referenz: data-*-density) | Wirkschicht Sektion DENSITY (body[data-wk-density="compact"]) | compact/standard | Umschalter mit aria-pressed (Template) | Tier 1: Token-/Override-Schicht in wkfluentui; Umschalter + Persistenz je Login im Template — Regeln: FluentUI: Admin-Bereich (vertieft) |
| Accordion (progressive disclosure) | — (WDX-Referenz: WdxAccordion, expandMode=„Single“) | .wk-accordion / __item / __summary / __body | offen/geschlossen, exklusiv je Gruppe | natives <details>-Verhalten (kein eigenes ARIA-Pattern nötig) | Tier 1: widgets::accordion() — Vertrag: accordion, Anatomie unten: accordion |
Studio-getriebene Bausteine (Tier 1)
Vier Bausteine, die das SQLite-Data-Studio-Aktionsinventar
(Studio-Bereichsseite) referenziert — ursprünglich als
[T2]-Vertrag spezifiziert, seit dem Studio-Ausbau (2026-07-14) implementiert und im Studio
verdrahtet. Die früher als „Vorschlag„ markierten wk-*-Klassennamen sind
mit der Implementierung verbindlich geworden. Die je Baustein offen gelassenen
Spezifikationsfragen sind entschieden und im jeweiligen Abschnitt dokumentiert.
Mechanik-Referenz Azure Data Studio
(https://github.com/microsoft/azuredatastudio) / VS Code
(https://github.com/microsoft/vscode): als rekonstruierte
Mechanik zitiert, keine Code-Übernahme.
InputBox-Filter
Tier 1 (widgets::listFilter($targetId, $opts) + scripts/listfilter.js) ·
Referenz: src/vs/base/browser/ui/tree/abstractTree.ts (Baum-Filter über eine
InputBox), src/vs/base/browser/ui/list/listWidget.ts.
Zweck + Abgrenzung. Einzeiliges Filterfeld unter der Objekt-Explorer-Titelleiste, das die sichtbaren Knoten des Baums auf Treffer eingrenzt (Substring, Groß-/Kleinschreibung egal). Es ist kein Suchdialog (kein Ergebnis-Panel, keine Volltextsuche über Inhalte) und kein Ersatz für eine Server-Suche — es blendet nur bereits geladene Baumknoten ein/aus.
Anatomie.
<div class="wk-listfilter"> <input type="search" class="wk-listfilter__input" aria-controls="objtree" placeholder="Filtern …"> <span class="wk-listfilter__count" role="status" aria-live="polite">7 von 20</span> </div> <ul id="objtree" class="wk-tree"> … gefilterter Baum … </ul>
Zustände. leer (kein Filter, alle Knoten sichtbar) · fokussiert · aktiv-filternd (Nicht-Treffer ausgeblendet) · no-match (leerer Baum + gedämpfte „Keine Treffer“-Zeile).
Tastatur + ARIA. Feld als <input type=„search“> mit aria-controls auf die
Baum-id; die Trefferzahl liegt in einer role=„status“ aria-live=„polite“-Region, damit
die Reduktion angesagt wird. Esc leert den Filter und gibt den Fokus an den Baum,
Pfeil-runter springt aus dem Feld in den ersten Treffer. Der Baum behält seine
treeitem-Semantik — der Filter ändert nur hidden.
No-JS-Fallback. Degradiert zu nichts (ohne JavaScript nicht gerendert bzw. wirkungslos) — „Knoten finden„ bleibt über das Aufklappen des Baums erreichbar. Ein Filter ist nie die einzige Möglichkeit, einen Knoten zu erreichen.
Entschiedene Fragen. (a) Keine Treffer-Hervorhebung im Knotentext in v1
(bewusst schlank; nachrüstbar ohne Vertragsbruch). (b) Der Filter wirkt auf den gesamten
per aria-controls verknüpften Baum; gematcht wird das Eigen-Label jedes Knotens
(direkter Link bzw. Gruppen-Summary), nicht der Teilbaum-Text — sonst zählte jeder Vorfahre
als Treffer. © Konsumenten, die das Ziel-DOM austauschen (z. B. Auxbar-Nachladen), lösen
ein wk-listfilter-rescan-Event auf dem Wrapper aus; der aktuelle Filter wird dann neu
angewandt.
Editor-Tab-Strip
Tier 1 (widgets::editorTabs($tabs, $opts) + scripts/editortabs.js;
Studio-Puffer-Verwaltung: wksqliteds/script.js) · Referenz:
src/vs/workbench/browser/parts/editor/ (editorTabsControl.ts,
tabsTitleControl.ts — Tab-Leiste, Dirty-Indikator, Schließen).
Zweck + Abgrenzung. Mehrere gleichzeitig offene Abfragen in der Workbench als Editor-Tabs
mit Dirty-State-Punkt (ungespeicherte Änderung). Abzugrenzen von den View-Tabs des
Table Designers (Spalten/Indizes/Fremdschlüssel/Trigger — das ist ein tabs()-role=tablist
zum Sichtwechsel, siehe tabcontrol): der Editor-Tab-Strip
wechselt Dokumente (je Tab ein eigener SQL-Puffer), nicht Sichten desselben Objekts.
Anatomie.
<div class="wk-editortabs" role="tablist" aria-label="Offene Abfragen"> <div class="wk-editortabs__tab is-active" role="tab" aria-selected="true"> <span class="wk-editortabs__title">abfrage1.sql</span> <span class="wk-editortabs__dirty" aria-hidden="true">•</span> <button class="wk-editortabs__close" aria-label="Schließen">×</button> </div> <div class="wk-editortabs__tab" role="tab" aria-selected="false"> … </div> </div>
Zustände. active (im Vordergrund) · dirty (ungespeichert — Punkt statt/über dem Schließen-×) · disabled (nicht wechselbar, z. B. während einer laufenden Ausführung).
Tastatur + ARIA. role=„tablist“ mit role=„tab“-Kindern, aria-selected;
Roving-Tabindex, Pfeil-links/-rechts wechselt, Entf/Mittelklick schließt. Bewusst
abgegrenzt vom View-Tabs-tablist des Designers, damit Screenreader „Dokument-Tabs“ nicht
mit „Sicht-Tabs„ verwechseln (unterschiedliche aria-label).
No-JS-Fallback. Degradiert zu einer Abfrage (der Strip verschwindet, die Workbench zeigt einen einzelnen SQL-Puffer) — die POST-Roundtrip-Ausführung einer einzelnen Abfrage bleibt unverändert erreichbar.
Entschiedene Fragen (Persistenz: Nutzer-Entscheid 2026-07-14).
(a) localStorage pro Login unter wk-editortabs:<login>
(kanonischer Schlüssel via wkEditorTabs.storageKey()): reine Anzeige-Präferenz, der
Server bleibt zustandslos und sieht weiterhin nur den einen geposteten Puffer — die
Puffer-Inhalte verwaltet der Konsument (die Bibliothek verwaltet den Strip und feuert
wk-tabchange/wk-tabclose-Events, Letzteres abbrechbar per preventDefault).
(b) Keine harte Obergrenze; der Strip scrollt horizontal (overflow-x).
© Pro Verbindung (Studio-Verdrahtung: Schlüssel-Suffix :<conn>) — SQL-Puffer
sind verbindungsspezifisch. Der letzte verbleibende Tab ist nicht schließbar.
Command-Palette
Tier 1 (widgets::commandPalette($opts) + scripts/cmdpalette.js) ·
Referenz: src/vs/platform/quickinput/browser/ (quickInput.ts),
src/vs/workbench/contrib/quickaccess/.
Zweck + Abgrenzung. Globales Aktions-/Navigations-Overlay (Muster Strg+Umschalt+P): ein zentrales Eingabefeld filtert eine Liste aller erreichbaren Aktionen/Sprungziele. Es ist kein Ersatz für Menüs/Command-Bar (die bleiben die primäre, sichtbare Bedienung) und keine Datensuche — es adressiert Aktionen, nicht Inhalte.
Anatomie.
<div class="wk-cmdpalette" role="dialog" aria-modal="true" aria-label="Befehle"> <input class="wk-cmdpalette__input" role="combobox" aria-expanded="true" aria-controls="cmdlist" aria-activedescendant="cmd-3"> <ul id="cmdlist" class="wk-cmdpalette__list" role="listbox"> <li id="cmd-3" role="option" aria-selected="true">Tabelle exportieren …</li> <li role="option">Verbindung wählen …</li> </ul> </div>
Zustände. leer (alle Aktionen) · gefiltert · no-match („Keine passende Aktion“).
Tastatur + ARIA. Dialog + Listbox-Kombination: role=„dialog“ aria-modal=„true“ um
ein role=„combobox“-Feld, das über aria-activedescendant die aktive
role=„option“-Zeile der role=„listbox“ referenziert. Pfeil-hoch/-runter wandert,
Enter löst aus, Esc schließt und gibt den Fokus an den Auslöser zurück; Fokus bleibt im
Overlay gefangen. Vorschlag für die Öffnen-Taste: Strg+Umschalt+P — als Vorschlag markiert
(mögliche Browser-/Erweiterungs-Kollision, in der Implementierung zu prüfen).
No-JS-Fallback. Degradiert zu nichts — jede Aktion der Palette ist außerdem über Menü, Command-Bar oder Modul-Rail erreichbar (die Palette ist reine Beschleunigung, nie einziger Weg).
Entschiedene Fragen. (a) Öffnen-Taste Strg+Umschalt+P wie vorgeschlagen —
die dokumentierte Kollision (Firefox: privates Fenster) bleibt bestehen, deshalb ist der
sichtbare Auslöser (data-wk-palette-trigger-Button, im Studio per script.js in
die Command-Bar injiziert) der kollisionsfreie Weg. (b) Die Aktions-Registry entsteht
dynamisch aus dem DOM bei jedem Öffnen: jedes sichtbare Element mit data-wk-cmd
wird eine Option (Attributwert = Label, leerer Wert = Elementtext); Enter re-triggert das
Original-Element per .click() — kein zweiter Code-Pfad, serverseitige ACL-/
Readonly-Filterung des sichtbaren Markups bleibt maßgeblich. © Scope = die aktive View
(nur dort existiert sichtbares, getaggtes Markup) — modulübergreifende Aktionen sind damit
bewusst außen vor.
Panel-Maximieren
Tier 1 (Attribut-Vertrag data-wk-panelmax + scripts/panelmax.js
+ CSS-Region .wk-shell-panel) · Referenz: src/vs/workbench/browser/layout.ts
(maximized-Layoutklasse, Panel-Toggle), Sichtbarkeits-Klassen siehe
FluentUI: Basic Layout (vertieft).
Zweck + Abgrenzung. Das Results-Panel der Workbench temporär auf die volle
Content-Höhe schalten (mehr Zeilen ohne Scrollen). Es ist kein Vollbild (kein
fullscreen über die Shell hinaus) und kein neues Fenster — nur die Panel-Region
wächst, Command-Bar/Statusbar/Rail bleiben.
Anatomie.
<div class="wk-shell-panel wk-shell-panel--max"> <div class="wk-shell-panel__header"> <span>Ergebnisse</span> <button class="wk-shell-panel__maximize is-active" aria-pressed="true" aria-label="Panel maximieren">⤢</button> </div> <div class="wk-shell-panel__body"> … Ergebnis-Grid … </div> </div>
Zustände. normal · maximiert (Modifikator .wk-shell-panel--max auf der
Panel-Region; Toggle-Button .is-active).
Tastatur + ARIA. Toggle-Button mit aria-pressed (An/Aus eines beibehaltenen
Zustands) — bewusst nicht aria-expanded (das beschriebe Ein-/Ausklappen von verstecktem
Inhalt; hier wird sichtbarer Inhalt nur vergrößert). Enter/Space schaltet um, der Fokus
bleibt auf dem Button.
No-JS-Fallback. Entfällt — ohne JavaScript keine Maximierung; das Panel bleibt in Normalgröße (voll funktionsfähig, nur ohne die Vergrößerung).
Entschiedene Fragen. (a) aria-pressed bestätigt — der Toggle hält
einen An/Aus-Zustand sichtbaren Inhalts, aria-expanded beschriebe das Aufdecken
versteckten Inhalts. (b) Ja, als Anzeige-Präferenz je Kontext: localStorage
wk-panelmax:<context> (Kontext = Attributwert des Buttons; leerer Wert = keine
Persistenz) — dasselbe Muster wie die Workbench-Dialog-Größe. © Das maximierte Panel füllt
seinen Positionierungskontext (.wk-shell-content, dafür position:relative im
Bibliotheks-CSS) und überdeckt die Innen-Scroll-Aufteilung temporär; Command-Bar,
Statusbar und Rails bleiben sichtbar — die Viewport-Fit-Richtlinie gilt unverändert, sobald
der Toggle zurückgenommen ist.
Progressive-Disclosure-Bausteine (Tier 1)
Ein Baustein, generisch für jedes Admin-Plugin mit AdminPlugin::getTOC()
(nicht Studio-spezifisch, anders als der vorige Abschnitt) — eingeführt bei der
Design-System-Vereinheitlichung (2026-07-17).
Accordion
Tier 1 (widgets::accordion($items, $opts), s.
API-Referenz; Erstkonsument
wkfluentui/action/admintoc.php) · Referenz: WDX WdxNavigationControl-Familie
(D:\Workspace\repos\sources\WvdS\php\packages\WvdS.Wdx.Ui\src\Navigation''),
konkret ''WdxAccordions expandMode=„Single“ — Konzept übernommen (exklusives
Auf-/Zuklappen), kein Code-Transfer (WDX ist ein Props-Serialisierungs-Framework
für eine JS-Runtime, dieses Widget ist serverseitig gerendertes, natives HTML).
Zweck + Abgrenzung. Zerlegt einen langen, flachen Admin-Screen (z. B. der
Konfigurations-Manager mit ~45–60 Formular-Abschnitten) in exklusiv auf-/zuklappbare
Blöcke — ein Klick zeigt genau einen Abschnitt, andere schließen automatisch. Es ist
kein Tab-Control (kein role=„tablist“, keine horizontale Kopfzeile — die
Abschnitte bleiben vertikal gestapelt) und kein Ersatz für tree() (das bleibt
die Navigation zu einem Abschnitt; Accordion ist die Darstellung des
Abschnitts-Inhalts selbst).
Anatomie.
<div class="wk-accordion"> <details class="wk-accordion__item" name="wk-accordion-admintoc" id="lang" open> <summary class="wk-accordion__summary">Sprache</summary> <div class="wk-accordion__body"> … Formularfelder … </div> </details> <details class="wk-accordion__item" name="wk-accordion-admintoc" id="title"> <summary class="wk-accordion__summary">Titel</summary> <div class="wk-accordion__body"> … Formularfelder … </div> </details> </div>
Zustände. offen/geschlossen je Abschnitt; exklusiv innerhalb derselben
name-Gruppe (das native <details name="…">-Verhalten des Browsers —
kein JavaScript nötig).
Tastatur + ARIA. Kein eigenes ARIA-Pattern erforderlich — <summary> ist
nativ fokussierbar und per Enter/Space bedienbar, der Browser verwaltet
Auf-/Zuklapp-Zustand und Exklusivität selbst.
No-JS-Fallback. Kein Funktionsverlust — <details> funktioniert vollständig
ohne JavaScript. Einzige Einschränkung bei fehlender name-Exklusivitäts-Unterstützung
(Browser älter als Chrome/Edge 120, Firefox 122, Safari 17.2, ~2023/24): alle Abschnitte
bleiben gleichzeitig offen — identisch zum Zustand vor Einführung dieses Bausteins, keine
Regression.
Entschiedene Fragen. (a) Exklusivität seitenweit, nicht nur je Formular-Abschnitts-Gruppe:
wkfluentui/action/admintoc.php vergibt allen Akkordeon-Blöcken derselben Seite denselben
context (admintoc), auch wenn sie durch nicht-akkordierte Zwischenüberschriften
(<h1> je getTOC()-Sektion) optisch getrennt sind — ein einzelner offener Abschnitt
über die ganze Seite hinweg, nicht nur innerhalb einer Sektion. (b) Standard-offener Abschnitt:
der erste in Dokumentreihenfolge, außer ein ?section=<id>-Query-Parameter (nur für den
Initial-Zustand beim Laden relevant) wählt einen anderen — Folge-Klicks laufen rein clientseitig
über <details name>, ohne weiteren Request.
Zustands-Vokabular (durchgängig)
disabled, hover, focus/focused, active, checked/selected,
error/warning/info, expanded/collapsed, dragging/drop-target.
Klassennamens-Konvention: monaco-<widget>-Wurzel mit Modifikator-Klassen (kein formales
BEM –modifier). Für wkfluentui analog vorgeschlagen: wk-<widget>-Wurzel mit
denselben Modifikator-Namen, um das etablierte Zustands-Vokabular 1:1 zu übernehmen.
Theming-Mechanik (Referenz für ein künftiges Token-Registry-Modul)
Drei-Schichten-Modell: (1) zentrale Farb-/Größen-Registry mit Light/Dark/High-Contrast-Defaults
(registerColor()/registerSize()), (2) mechanische Namensableitung domain.property →
–vscode-domain-property, (3) EIN generiertes, auf den Root-Container skopiertes Stylesheet,
das die aktive Theme-Werte materialisiert. Konsumiert wird entweder direkt über CSS var()
oder über ein typisiertes „Styles-Objekt“, das dem Widget-Konstruktor übergeben wird (nützlich,
wenn dasselbe Widget in unterschiedlichen Farbräumen rendern muss). Siehe
FluentUI: Design-Tokens für die konkret in wkfluentui umgesetzte, einfachere
Variante (statische –wk-*-Tokens ohne Registry-Ebene, Tier 1).