[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-microsoft-reactor-docking":3,"mdc--d3l603-key":31,"related-org-microsoft-reactor-docking":1409,"related-repo-microsoft-reactor-docking":1606},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":20,"repoUrl":21,"updatedAt":22,"license":23,"forks":24,"topics":25,"repo":26,"sourceUrl":29,"mdContent":30},"reactor-docking","build IDE-style docking window layouts","Reactor docking windows — `DockManager`, `DockSplit`\u002F`DockTabGroup`\u002F`Document`\u002F`ToolWindow`, drag-to-float\u002Fredock, roles (`DocumentArea`\u002F`ToolWindowStrip`), persistence. Use when building IDE-\u002FOffice-shaped layouts with dockable, tear-out tool windows and document wells. READ THIS BEFORE wiring `DockManager` — the content-vs-shape ownership model is the #1 thing people get wrong.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"microsoft","Microsoft","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fmicrosoft.png",[12,14,17],{"name":9,"slug":8,"type":13},"tag",{"name":15,"slug":16,"type":13},"Desktop","desktop",{"name":18,"slug":19,"type":13},"UI Components","ui-components",591,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor","2026-07-03T16:32:06.396776",null,39,[],{"repoUrl":21,"stars":20,"forks":24,"topics":27,"description":28},[],"Reactor is an experimental set of extensions to WinUI","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fmicrosoft-ui-reactor\u002Ftree\u002FHEAD\u002Fplugins\u002Freactor\u002Fskills\u002Freactor-docking","---\nname: reactor-docking\ndescription: \"Reactor docking windows — `DockManager`, `DockSplit`\u002F`DockTabGroup`\u002F`Document`\u002F`ToolWindow`, drag-to-float\u002Fredock, roles (`DocumentArea`\u002F`ToolWindowStrip`), persistence. Use when building IDE-\u002FOffice-shaped layouts with dockable, tear-out tool windows and document wells. READ THIS BEFORE wiring `DockManager` — the content-vs-shape ownership model is the #1 thing people get wrong.\"\n---\n\n# Docking in Reactor\n\n`DockManager` hosts a tree of dockable panes that the user can drag, split,\ntear out into floating windows, re-dock, pin to a side, and persist. It is the\nfoundation for IDE-\u002FOffice-shaped apps (solution explorer + editor well +\ntool panes).\n\n```csharp\nconfigure: host => DockingNativeInterop.Register(host.Reconciler)  \u002F\u002F required once at startup\n```\n\n## The ownership model — READ THIS FIRST\n\nThis is the single most important rule, and the easiest to get wrong:\n\n> **The app owns CONTENT. The host owns SHAPE.**\n\n- **Content** = which panes exist, their `Title`\u002F`Content`\u002F`Key`, which document\n  is active. The app declares this via `manager.Layout`, fresh every render,\n  derived from its own `UseState`.\n- **Shape** = the user's drag-modified arrangement: split orientations\u002Fratios,\n  which group a tab lives in, floating windows. The **host owns this\n  internally** (spec 045 §2.30) and resolves the effective layout each render\n  by matching your content to its shape *by `Key`*.\n\n### ❌ The anti-pattern that breaks everything\n\nDo **NOT** round-trip the host's live layout back into your own state:\n\n```csharp\n\u002F\u002F ❌ WRONG — feeds the host's shape back into the content prop.\nvar (layout, setLayout) = UseState\u003CDockNode?>(BuildLayout());\nnew DockManager {\n    Layout = layout,\n    OnLiveLayoutChanged = next => setLayout(next),   \u002F\u002F ⛔ double-owns the shape\n};\n```\n\nThis double-owns the shape. Symptoms (all of these at once):\n- **Drag-out-to-float works, but you can't drag back to re-dock.**\n- **Clicking tabs doesn't switch** \u002F selection resets.\n- Splitter drags snap back.\n\n`OnLiveLayoutChanged` is for **observation only** (e.g. a layout inspector). It\nis never a setter for `manager.Layout`.\n\n### ✅ The correct pattern\n\nThe app holds *which documents are open* (content), not the live tree. Opening\nor closing a pane changes the **set of `Key`s** in `manager.Layout`; the host\ndetects the key-set change and merges it into its shape. Reset is a\n`.WithKey(...)` remount.\n\n```csharp\nvar (openDocs, setOpenDocs) = UseState(ImmutableList.Create(File.AppCs));\nvar (activeKey, setActiveKey) = UseState\u003Cobject?>(File.AppCs.Key);\nvar (epoch, bumpEpoch) = UseReducer(0);\n\nvoid Open(ProjectFile f) {\n    if (!openDocs.Any(d => Equals(d.Key, f.Key))) setOpenDocs(openDocs.Add(f));\n    setActiveKey(f.Key);                       \u002F\u002F focus it (drives SelectedIndex)\n}\n\nvar editorWell = new DockTabGroup(\n    openDocs.Select(MakeDoc).ToArray(),\n    SelectedIndex: openDocs.FindIndex(d => Equals(d.Key, activeKey)),\n    ShowWhenEmpty: true,\n    Role: DockGroupRole.DocumentArea);\n\nnew DockManager {\n    Layout = BuildLayout(editorWell),\n    \u002F\u002F Sync state when the host closes a tab via its X button. The host already\n    \u002F\u002F removed it from its shape; drop it from openDocs so the key sets converge.\n    OnDocumentClosing = args =>\n        setOpenDocs(openDocs.RemoveAll(d => Equals(d.Key, args.Document.Key))),\n}.WithKey($\"dock-{epoch}\");   \u002F\u002F View ▸ Reset Layout: bumpEpoch + reset openDocs\n```\n\nRules of thumb:\n- Derive `manager.Layout` from app state every render. Never store the host's tree.\n- Add\u002Fremove a pane ⇒ the `Key` set changes ⇒ the host picks it up.\n- Model-mutator additions (drag, `DockHostModel.Dock`) keep the same app key set,\n  so the host preserves them. That's why round-tripping is both unnecessary and harmful.\n- Reset \u002F discard drag state ⇒ `.WithKey($\"dock-{epoch}\")` bump remounts the host.\n- Layout persistence across launches ⇒ `PersistenceId`, not `OnLiveLayoutChanged`.\n\n\n> **Controlled prop note:** `SelectedIndex`-style element properties are\n> `Optional\u003Cint>` under the hood. Factory parameters such as `SelectedIndex:`\n> still accept `int`, but if you read an element record directly use\n> `.Value` or `.GetValueOrDefault(-1)`. See\n> [`migration\u002F050-optional-t.md`](..\u002F..\u002F..\u002F..\u002Fdocs\u002Fguide\u002Fmigration\u002F050-optional-t.md).\n\n## Building a layout\n\n```csharp\nnew DockSplit(Orientation.Vertical, new DockNode[] {\n    new DockSplit(Orientation.Horizontal, new DockNode[] {\n        new DockTabGroup(new DockableContent[]{ solutionTool }, Width: 260,\n            Role: DockGroupRole.ToolWindowStrip),\n        editorWell,                                              \u002F\u002F DocumentArea\n        new DockTabGroup(new DockableContent[]{ propsTool, gitTool }, Width: 300,\n            TabPosition: TabPosition.Bottom, CompactTabs: true,\n            Role: DockGroupRole.ToolWindowStrip),\n    }),\n    new DockTabGroup(new DockableContent[]{ output, terminal, errors },\n        Height: 220, TabPosition: TabPosition.Bottom, CompactTabs: true,\n        Role: DockGroupRole.ToolWindowStrip),\n});\n```\n\n- `Document` (closable, not pinnable) vs `ToolWindow` (hideable, side-pinnable,\n  `AllowedSides` mask). Both reconcile through `DockableContent`.\n- **Roles** (spec 046): `DocumentArea` is the preferred `Dock(Center)` target and\n  **survives empty** (the well stays a visible drop target). `ToolWindowStrip` is\n  the preferred target for tool-window drops. Use object-initializer syntax for\n  `Document`\u002F`ToolWindow` so you opt into permission flags additively.\n- Every pane needs a **stable, equatable `Key`** — it's how the host preserves\n  pane state across reorders, tear-out, and re-dock. No fallback to title-keying.\n\n## Pane content gotchas\n\n### Make pane bodies fill the pane\n\nA docked pane body is **content-sized** by default — a plain `Border`\u002F`TextBox`\ncollapses to its desired height at the top of the pane. To fill, put it in a\nflex container with `grow`:\n\n```csharp\nFlexColumn(\n    editorTextBox.Flex(grow: 1, basis: 0)\n).Flex(grow: 1);\n```\n\n### Multi-line TextBox: `AcceptsReturn` must be an element prop, not `.Set`\n\nThe `TextBox` descriptor applies `AcceptsReturn`\u002F`TextWrapping` **before** `Text`\non purpose — single-line mode truncates `Text` at the first newline. A\n`.Set(tb => tb.AcceptsReturn = true)` lambda runs *after* `Text` is assigned, so\nthe body collapses to one line. Use the first-class modifiers:\n\n```csharp\n\u002F\u002F ✅ ordered before Text by the descriptor\nTextBox(text, setText).AcceptsReturn().TextWrapping(TextWrapping.NoWrap)\n\n\u002F\u002F ❌ runs after Text → multi-line content truncated to the first line\nTextBox(text, setText).Set(tb => tb.AcceptsReturn = true)\n```\n\nGenerally: any prop whose *ordering relative to another prop matters* belongs on\nthe element (`.AcceptsReturn()`, `.TextWrapping()`), not in a `.Set(...)` escape\nhatch — `.Set` always runs last.\n\n## Key APIs\n\n| API | Purpose |\n|-----|---------|\n| `DockManager { Layout, PersistenceId, ... }` | The host element |\n| `DockSplit(Orientation, children)` | Resizable split (ratios owned by host) |\n| `DockTabGroup(docs, TabPosition, CompactTabs, SelectedIndex, Width\u002FHeight, Role)` | A tab group |\n| `Document { Title, Key, Content, CanClose }` | Closable document pane |\n| `ToolWindow { Title, Key, Content, CanPin, AllowedSides, ... }` | Hideable\u002Fpinnable tool pane |\n| `.WithKey($\"dock-{epoch}\")` | Remount to reset\u002Fdiscard drag shape |\n| `OnDocumentClosing` | Sync app state when the host closes a tab |\n| `OnLiveLayoutChanged` | **Observe** the resolved layout (never feed back to `Layout`) |\n| `DockingNativeInterop.Register(host.Reconciler)` | One-time startup registration |\n\nSee `samples\u002Fapps\u002Freactor-ide` for a complete IDE-shaped app exercising all of this.\n",{"data":32,"body":33},{"name":4,"description":6},{"type":34,"children":35},"root",[36,45,58,79,86,91,104,186,193,205,265,270,296,320,326,367,564,569,641,714,720,830,938,944,950,985,1016,1036,1103,1149,1192,1198,1390,1403],{"type":37,"tag":38,"props":39,"children":41},"element","h1",{"id":40},"docking-in-reactor",[42],{"type":43,"value":44},"text","Docking in Reactor",{"type":37,"tag":46,"props":47,"children":48},"p",{},[49,56],{"type":37,"tag":50,"props":51,"children":53},"code",{"className":52},[],[54],{"type":43,"value":55},"DockManager",{"type":43,"value":57}," hosts a tree of dockable panes that the user can drag, split,\ntear out into floating windows, re-dock, pin to a side, and persist. It is the\nfoundation for IDE-\u002FOffice-shaped apps (solution explorer + editor well +\ntool panes).",{"type":37,"tag":59,"props":60,"children":65},"pre",{"className":61,"code":62,"language":63,"meta":64,"style":64},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","configure: host => DockingNativeInterop.Register(host.Reconciler)  \u002F\u002F required once at startup\n","csharp","",[66],{"type":37,"tag":50,"props":67,"children":68},{"__ignoreMap":64},[69],{"type":37,"tag":70,"props":71,"children":74},"span",{"class":72,"line":73},"line",1,[75],{"type":37,"tag":70,"props":76,"children":77},{},[78],{"type":43,"value":62},{"type":37,"tag":80,"props":81,"children":83},"h2",{"id":82},"the-ownership-model-read-this-first",[84],{"type":43,"value":85},"The ownership model — READ THIS FIRST",{"type":37,"tag":46,"props":87,"children":88},{},[89],{"type":43,"value":90},"This is the single most important rule, and the easiest to get wrong:",{"type":37,"tag":92,"props":93,"children":94},"blockquote",{},[95],{"type":37,"tag":46,"props":96,"children":97},{},[98],{"type":37,"tag":99,"props":100,"children":101},"strong",{},[102],{"type":43,"value":103},"The app owns CONTENT. The host owns SHAPE.",{"type":37,"tag":105,"props":106,"children":107},"ul",{},[108,157],{"type":37,"tag":109,"props":110,"children":111},"li",{},[112,117,119,125,127,132,133,139,141,147,149,155],{"type":37,"tag":99,"props":113,"children":114},{},[115],{"type":43,"value":116},"Content",{"type":43,"value":118}," = which panes exist, their ",{"type":37,"tag":50,"props":120,"children":122},{"className":121},[],[123],{"type":43,"value":124},"Title",{"type":43,"value":126},"\u002F",{"type":37,"tag":50,"props":128,"children":130},{"className":129},[],[131],{"type":43,"value":116},{"type":43,"value":126},{"type":37,"tag":50,"props":134,"children":136},{"className":135},[],[137],{"type":43,"value":138},"Key",{"type":43,"value":140},", which document\nis active. The app declares this via ",{"type":37,"tag":50,"props":142,"children":144},{"className":143},[],[145],{"type":43,"value":146},"manager.Layout",{"type":43,"value":148},", fresh every render,\nderived from its own ",{"type":37,"tag":50,"props":150,"children":152},{"className":151},[],[153],{"type":43,"value":154},"UseState",{"type":43,"value":156},".",{"type":37,"tag":109,"props":158,"children":159},{},[160,165,167,172,174,185],{"type":37,"tag":99,"props":161,"children":162},{},[163],{"type":43,"value":164},"Shape",{"type":43,"value":166}," = the user's drag-modified arrangement: split orientations\u002Fratios,\nwhich group a tab lives in, floating windows. The ",{"type":37,"tag":99,"props":168,"children":169},{},[170],{"type":43,"value":171},"host owns this\ninternally",{"type":43,"value":173}," (spec 045 §2.30) and resolves the effective layout each render\nby matching your content to its shape ",{"type":37,"tag":175,"props":176,"children":177},"em",{},[178,180],{"type":43,"value":179},"by ",{"type":37,"tag":50,"props":181,"children":183},{"className":182},[],[184],{"type":43,"value":138},{"type":43,"value":156},{"type":37,"tag":187,"props":188,"children":190},"h3",{"id":189},"the-anti-pattern-that-breaks-everything",[191],{"type":43,"value":192},"❌ The anti-pattern that breaks everything",{"type":37,"tag":46,"props":194,"children":195},{},[196,198,203],{"type":43,"value":197},"Do ",{"type":37,"tag":99,"props":199,"children":200},{},[201],{"type":43,"value":202},"NOT",{"type":43,"value":204}," round-trip the host's live layout back into your own state:",{"type":37,"tag":59,"props":206,"children":208},{"className":61,"code":207,"language":63,"meta":64,"style":64},"\u002F\u002F ❌ WRONG — feeds the host's shape back into the content prop.\nvar (layout, setLayout) = UseState\u003CDockNode?>(BuildLayout());\nnew DockManager {\n    Layout = layout,\n    OnLiveLayoutChanged = next => setLayout(next),   \u002F\u002F ⛔ double-owns the shape\n};\n",[209],{"type":37,"tag":50,"props":210,"children":211},{"__ignoreMap":64},[212,220,229,238,247,256],{"type":37,"tag":70,"props":213,"children":214},{"class":72,"line":73},[215],{"type":37,"tag":70,"props":216,"children":217},{},[218],{"type":43,"value":219},"\u002F\u002F ❌ WRONG — feeds the host's shape back into the content prop.\n",{"type":37,"tag":70,"props":221,"children":223},{"class":72,"line":222},2,[224],{"type":37,"tag":70,"props":225,"children":226},{},[227],{"type":43,"value":228},"var (layout, setLayout) = UseState\u003CDockNode?>(BuildLayout());\n",{"type":37,"tag":70,"props":230,"children":232},{"class":72,"line":231},3,[233],{"type":37,"tag":70,"props":234,"children":235},{},[236],{"type":43,"value":237},"new DockManager {\n",{"type":37,"tag":70,"props":239,"children":241},{"class":72,"line":240},4,[242],{"type":37,"tag":70,"props":243,"children":244},{},[245],{"type":43,"value":246},"    Layout = layout,\n",{"type":37,"tag":70,"props":248,"children":250},{"class":72,"line":249},5,[251],{"type":37,"tag":70,"props":252,"children":253},{},[254],{"type":43,"value":255},"    OnLiveLayoutChanged = next => setLayout(next),   \u002F\u002F ⛔ double-owns the shape\n",{"type":37,"tag":70,"props":257,"children":259},{"class":72,"line":258},6,[260],{"type":37,"tag":70,"props":261,"children":262},{},[263],{"type":43,"value":264},"};\n",{"type":37,"tag":46,"props":266,"children":267},{},[268],{"type":43,"value":269},"This double-owns the shape. Symptoms (all of these at once):",{"type":37,"tag":105,"props":271,"children":272},{},[273,281,291],{"type":37,"tag":109,"props":274,"children":275},{},[276],{"type":37,"tag":99,"props":277,"children":278},{},[279],{"type":43,"value":280},"Drag-out-to-float works, but you can't drag back to re-dock.",{"type":37,"tag":109,"props":282,"children":283},{},[284,289],{"type":37,"tag":99,"props":285,"children":286},{},[287],{"type":43,"value":288},"Clicking tabs doesn't switch",{"type":43,"value":290}," \u002F selection resets.",{"type":37,"tag":109,"props":292,"children":293},{},[294],{"type":43,"value":295},"Splitter drags snap back.",{"type":37,"tag":46,"props":297,"children":298},{},[299,305,307,312,314,319],{"type":37,"tag":50,"props":300,"children":302},{"className":301},[],[303],{"type":43,"value":304},"OnLiveLayoutChanged",{"type":43,"value":306}," is for ",{"type":37,"tag":99,"props":308,"children":309},{},[310],{"type":43,"value":311},"observation only",{"type":43,"value":313}," (e.g. a layout inspector). It\nis never a setter for ",{"type":37,"tag":50,"props":315,"children":317},{"className":316},[],[318],{"type":43,"value":146},{"type":43,"value":156},{"type":37,"tag":187,"props":321,"children":323},{"id":322},"the-correct-pattern",[324],{"type":43,"value":325},"✅ The correct pattern",{"type":37,"tag":46,"props":327,"children":328},{},[329,331,336,338,350,352,357,359,365],{"type":43,"value":330},"The app holds ",{"type":37,"tag":175,"props":332,"children":333},{},[334],{"type":43,"value":335},"which documents are open",{"type":43,"value":337}," (content), not the live tree. Opening\nor closing a pane changes the ",{"type":37,"tag":99,"props":339,"children":340},{},[341,343,348],{"type":43,"value":342},"set of ",{"type":37,"tag":50,"props":344,"children":346},{"className":345},[],[347],{"type":43,"value":138},{"type":43,"value":349},"s",{"type":43,"value":351}," in ",{"type":37,"tag":50,"props":353,"children":355},{"className":354},[],[356],{"type":43,"value":146},{"type":43,"value":358},"; the host\ndetects the key-set change and merges it into its shape. Reset is a\n",{"type":37,"tag":50,"props":360,"children":362},{"className":361},[],[363],{"type":43,"value":364},".WithKey(...)",{"type":43,"value":366}," remount.",{"type":37,"tag":59,"props":368,"children":370},{"className":61,"code":369,"language":63,"meta":64,"style":64},"var (openDocs, setOpenDocs) = UseState(ImmutableList.Create(File.AppCs));\nvar (activeKey, setActiveKey) = UseState\u003Cobject?>(File.AppCs.Key);\nvar (epoch, bumpEpoch) = UseReducer(0);\n\nvoid Open(ProjectFile f) {\n    if (!openDocs.Any(d => Equals(d.Key, f.Key))) setOpenDocs(openDocs.Add(f));\n    setActiveKey(f.Key);                       \u002F\u002F focus it (drives SelectedIndex)\n}\n\nvar editorWell = new DockTabGroup(\n    openDocs.Select(MakeDoc).ToArray(),\n    SelectedIndex: openDocs.FindIndex(d => Equals(d.Key, activeKey)),\n    ShowWhenEmpty: true,\n    Role: DockGroupRole.DocumentArea);\n\nnew DockManager {\n    Layout = BuildLayout(editorWell),\n    \u002F\u002F Sync state when the host closes a tab via its X button. The host already\n    \u002F\u002F removed it from its shape; drop it from openDocs so the key sets converge.\n    OnDocumentClosing = args =>\n        setOpenDocs(openDocs.RemoveAll(d => Equals(d.Key, args.Document.Key))),\n}.WithKey($\"dock-{epoch}\");   \u002F\u002F View ▸ Reset Layout: bumpEpoch + reset openDocs\n",[371],{"type":37,"tag":50,"props":372,"children":373},{"__ignoreMap":64},[374,382,390,398,407,415,423,432,441,449,458,467,476,485,494,502,510,519,528,537,546,555],{"type":37,"tag":70,"props":375,"children":376},{"class":72,"line":73},[377],{"type":37,"tag":70,"props":378,"children":379},{},[380],{"type":43,"value":381},"var (openDocs, setOpenDocs) = UseState(ImmutableList.Create(File.AppCs));\n",{"type":37,"tag":70,"props":383,"children":384},{"class":72,"line":222},[385],{"type":37,"tag":70,"props":386,"children":387},{},[388],{"type":43,"value":389},"var (activeKey, setActiveKey) = UseState\u003Cobject?>(File.AppCs.Key);\n",{"type":37,"tag":70,"props":391,"children":392},{"class":72,"line":231},[393],{"type":37,"tag":70,"props":394,"children":395},{},[396],{"type":43,"value":397},"var (epoch, bumpEpoch) = UseReducer(0);\n",{"type":37,"tag":70,"props":399,"children":400},{"class":72,"line":240},[401],{"type":37,"tag":70,"props":402,"children":404},{"emptyLinePlaceholder":403},true,[405],{"type":43,"value":406},"\n",{"type":37,"tag":70,"props":408,"children":409},{"class":72,"line":249},[410],{"type":37,"tag":70,"props":411,"children":412},{},[413],{"type":43,"value":414},"void Open(ProjectFile f) {\n",{"type":37,"tag":70,"props":416,"children":417},{"class":72,"line":258},[418],{"type":37,"tag":70,"props":419,"children":420},{},[421],{"type":43,"value":422},"    if (!openDocs.Any(d => Equals(d.Key, f.Key))) setOpenDocs(openDocs.Add(f));\n",{"type":37,"tag":70,"props":424,"children":426},{"class":72,"line":425},7,[427],{"type":37,"tag":70,"props":428,"children":429},{},[430],{"type":43,"value":431},"    setActiveKey(f.Key);                       \u002F\u002F focus it (drives SelectedIndex)\n",{"type":37,"tag":70,"props":433,"children":435},{"class":72,"line":434},8,[436],{"type":37,"tag":70,"props":437,"children":438},{},[439],{"type":43,"value":440},"}\n",{"type":37,"tag":70,"props":442,"children":444},{"class":72,"line":443},9,[445],{"type":37,"tag":70,"props":446,"children":447},{"emptyLinePlaceholder":403},[448],{"type":43,"value":406},{"type":37,"tag":70,"props":450,"children":452},{"class":72,"line":451},10,[453],{"type":37,"tag":70,"props":454,"children":455},{},[456],{"type":43,"value":457},"var editorWell = new DockTabGroup(\n",{"type":37,"tag":70,"props":459,"children":461},{"class":72,"line":460},11,[462],{"type":37,"tag":70,"props":463,"children":464},{},[465],{"type":43,"value":466},"    openDocs.Select(MakeDoc).ToArray(),\n",{"type":37,"tag":70,"props":468,"children":470},{"class":72,"line":469},12,[471],{"type":37,"tag":70,"props":472,"children":473},{},[474],{"type":43,"value":475},"    SelectedIndex: openDocs.FindIndex(d => Equals(d.Key, activeKey)),\n",{"type":37,"tag":70,"props":477,"children":479},{"class":72,"line":478},13,[480],{"type":37,"tag":70,"props":481,"children":482},{},[483],{"type":43,"value":484},"    ShowWhenEmpty: true,\n",{"type":37,"tag":70,"props":486,"children":488},{"class":72,"line":487},14,[489],{"type":37,"tag":70,"props":490,"children":491},{},[492],{"type":43,"value":493},"    Role: DockGroupRole.DocumentArea);\n",{"type":37,"tag":70,"props":495,"children":497},{"class":72,"line":496},15,[498],{"type":37,"tag":70,"props":499,"children":500},{"emptyLinePlaceholder":403},[501],{"type":43,"value":406},{"type":37,"tag":70,"props":503,"children":505},{"class":72,"line":504},16,[506],{"type":37,"tag":70,"props":507,"children":508},{},[509],{"type":43,"value":237},{"type":37,"tag":70,"props":511,"children":513},{"class":72,"line":512},17,[514],{"type":37,"tag":70,"props":515,"children":516},{},[517],{"type":43,"value":518},"    Layout = BuildLayout(editorWell),\n",{"type":37,"tag":70,"props":520,"children":522},{"class":72,"line":521},18,[523],{"type":37,"tag":70,"props":524,"children":525},{},[526],{"type":43,"value":527},"    \u002F\u002F Sync state when the host closes a tab via its X button. The host already\n",{"type":37,"tag":70,"props":529,"children":531},{"class":72,"line":530},19,[532],{"type":37,"tag":70,"props":533,"children":534},{},[535],{"type":43,"value":536},"    \u002F\u002F removed it from its shape; drop it from openDocs so the key sets converge.\n",{"type":37,"tag":70,"props":538,"children":540},{"class":72,"line":539},20,[541],{"type":37,"tag":70,"props":542,"children":543},{},[544],{"type":43,"value":545},"    OnDocumentClosing = args =>\n",{"type":37,"tag":70,"props":547,"children":549},{"class":72,"line":548},21,[550],{"type":37,"tag":70,"props":551,"children":552},{},[553],{"type":43,"value":554},"        setOpenDocs(openDocs.RemoveAll(d => Equals(d.Key, args.Document.Key))),\n",{"type":37,"tag":70,"props":556,"children":558},{"class":72,"line":557},22,[559],{"type":37,"tag":70,"props":560,"children":561},{},[562],{"type":43,"value":563},"}.WithKey($\"dock-{epoch}\");   \u002F\u002F View ▸ Reset Layout: bumpEpoch + reset openDocs\n",{"type":37,"tag":46,"props":565,"children":566},{},[567],{"type":43,"value":568},"Rules of thumb:",{"type":37,"tag":105,"props":570,"children":571},{},[572,584,596,609,622],{"type":37,"tag":109,"props":573,"children":574},{},[575,577,582],{"type":43,"value":576},"Derive ",{"type":37,"tag":50,"props":578,"children":580},{"className":579},[],[581],{"type":43,"value":146},{"type":43,"value":583}," from app state every render. Never store the host's tree.",{"type":37,"tag":109,"props":585,"children":586},{},[587,589,594],{"type":43,"value":588},"Add\u002Fremove a pane ⇒ the ",{"type":37,"tag":50,"props":590,"children":592},{"className":591},[],[593],{"type":43,"value":138},{"type":43,"value":595}," set changes ⇒ the host picks it up.",{"type":37,"tag":109,"props":597,"children":598},{},[599,601,607],{"type":43,"value":600},"Model-mutator additions (drag, ",{"type":37,"tag":50,"props":602,"children":604},{"className":603},[],[605],{"type":43,"value":606},"DockHostModel.Dock",{"type":43,"value":608},") keep the same app key set,\nso the host preserves them. That's why round-tripping is both unnecessary and harmful.",{"type":37,"tag":109,"props":610,"children":611},{},[612,614,620],{"type":43,"value":613},"Reset \u002F discard drag state ⇒ ",{"type":37,"tag":50,"props":615,"children":617},{"className":616},[],[618],{"type":43,"value":619},".WithKey($\"dock-{epoch}\")",{"type":43,"value":621}," bump remounts the host.",{"type":37,"tag":109,"props":623,"children":624},{},[625,627,633,635,640],{"type":43,"value":626},"Layout persistence across launches ⇒ ",{"type":37,"tag":50,"props":628,"children":630},{"className":629},[],[631],{"type":43,"value":632},"PersistenceId",{"type":43,"value":634},", not ",{"type":37,"tag":50,"props":636,"children":638},{"className":637},[],[639],{"type":43,"value":304},{"type":43,"value":156},{"type":37,"tag":92,"props":642,"children":643},{},[644],{"type":37,"tag":46,"props":645,"children":646},{},[647,652,654,660,662,668,670,676,678,684,686,692,694,700,702,713],{"type":37,"tag":99,"props":648,"children":649},{},[650],{"type":43,"value":651},"Controlled prop note:",{"type":43,"value":653}," ",{"type":37,"tag":50,"props":655,"children":657},{"className":656},[],[658],{"type":43,"value":659},"SelectedIndex",{"type":43,"value":661},"-style element properties are\n",{"type":37,"tag":50,"props":663,"children":665},{"className":664},[],[666],{"type":43,"value":667},"Optional\u003Cint>",{"type":43,"value":669}," under the hood. Factory parameters such as ",{"type":37,"tag":50,"props":671,"children":673},{"className":672},[],[674],{"type":43,"value":675},"SelectedIndex:",{"type":43,"value":677},"\nstill accept ",{"type":37,"tag":50,"props":679,"children":681},{"className":680},[],[682],{"type":43,"value":683},"int",{"type":43,"value":685},", but if you read an element record directly use\n",{"type":37,"tag":50,"props":687,"children":689},{"className":688},[],[690],{"type":43,"value":691},".Value",{"type":43,"value":693}," or ",{"type":37,"tag":50,"props":695,"children":697},{"className":696},[],[698],{"type":43,"value":699},".GetValueOrDefault(-1)",{"type":43,"value":701},". See\n",{"type":37,"tag":703,"props":704,"children":706},"a",{"href":705},"..\u002F..\u002F..\u002F..\u002Fdocs\u002Fguide\u002Fmigration\u002F050-optional-t.md",[707],{"type":37,"tag":50,"props":708,"children":710},{"className":709},[],[711],{"type":43,"value":712},"migration\u002F050-optional-t.md",{"type":43,"value":156},{"type":37,"tag":80,"props":715,"children":717},{"id":716},"building-a-layout",[718],{"type":43,"value":719},"Building a layout",{"type":37,"tag":59,"props":721,"children":723},{"className":61,"code":722,"language":63,"meta":64,"style":64},"new DockSplit(Orientation.Vertical, new DockNode[] {\n    new DockSplit(Orientation.Horizontal, new DockNode[] {\n        new DockTabGroup(new DockableContent[]{ solutionTool }, Width: 260,\n            Role: DockGroupRole.ToolWindowStrip),\n        editorWell,                                              \u002F\u002F DocumentArea\n        new DockTabGroup(new DockableContent[]{ propsTool, gitTool }, Width: 300,\n            TabPosition: TabPosition.Bottom, CompactTabs: true,\n            Role: DockGroupRole.ToolWindowStrip),\n    }),\n    new DockTabGroup(new DockableContent[]{ output, terminal, errors },\n        Height: 220, TabPosition: TabPosition.Bottom, CompactTabs: true,\n        Role: DockGroupRole.ToolWindowStrip),\n});\n",[724],{"type":37,"tag":50,"props":725,"children":726},{"__ignoreMap":64},[727,735,743,751,759,767,775,783,790,798,806,814,822],{"type":37,"tag":70,"props":728,"children":729},{"class":72,"line":73},[730],{"type":37,"tag":70,"props":731,"children":732},{},[733],{"type":43,"value":734},"new DockSplit(Orientation.Vertical, new DockNode[] {\n",{"type":37,"tag":70,"props":736,"children":737},{"class":72,"line":222},[738],{"type":37,"tag":70,"props":739,"children":740},{},[741],{"type":43,"value":742},"    new DockSplit(Orientation.Horizontal, new DockNode[] {\n",{"type":37,"tag":70,"props":744,"children":745},{"class":72,"line":231},[746],{"type":37,"tag":70,"props":747,"children":748},{},[749],{"type":43,"value":750},"        new DockTabGroup(new DockableContent[]{ solutionTool }, Width: 260,\n",{"type":37,"tag":70,"props":752,"children":753},{"class":72,"line":240},[754],{"type":37,"tag":70,"props":755,"children":756},{},[757],{"type":43,"value":758},"            Role: DockGroupRole.ToolWindowStrip),\n",{"type":37,"tag":70,"props":760,"children":761},{"class":72,"line":249},[762],{"type":37,"tag":70,"props":763,"children":764},{},[765],{"type":43,"value":766},"        editorWell,                                              \u002F\u002F DocumentArea\n",{"type":37,"tag":70,"props":768,"children":769},{"class":72,"line":258},[770],{"type":37,"tag":70,"props":771,"children":772},{},[773],{"type":43,"value":774},"        new DockTabGroup(new DockableContent[]{ propsTool, gitTool }, Width: 300,\n",{"type":37,"tag":70,"props":776,"children":777},{"class":72,"line":425},[778],{"type":37,"tag":70,"props":779,"children":780},{},[781],{"type":43,"value":782},"            TabPosition: TabPosition.Bottom, CompactTabs: true,\n",{"type":37,"tag":70,"props":784,"children":785},{"class":72,"line":434},[786],{"type":37,"tag":70,"props":787,"children":788},{},[789],{"type":43,"value":758},{"type":37,"tag":70,"props":791,"children":792},{"class":72,"line":443},[793],{"type":37,"tag":70,"props":794,"children":795},{},[796],{"type":43,"value":797},"    }),\n",{"type":37,"tag":70,"props":799,"children":800},{"class":72,"line":451},[801],{"type":37,"tag":70,"props":802,"children":803},{},[804],{"type":43,"value":805},"    new DockTabGroup(new DockableContent[]{ output, terminal, errors },\n",{"type":37,"tag":70,"props":807,"children":808},{"class":72,"line":460},[809],{"type":37,"tag":70,"props":810,"children":811},{},[812],{"type":43,"value":813},"        Height: 220, TabPosition: TabPosition.Bottom, CompactTabs: true,\n",{"type":37,"tag":70,"props":815,"children":816},{"class":72,"line":469},[817],{"type":37,"tag":70,"props":818,"children":819},{},[820],{"type":43,"value":821},"        Role: DockGroupRole.ToolWindowStrip),\n",{"type":37,"tag":70,"props":823,"children":824},{"class":72,"line":478},[825],{"type":37,"tag":70,"props":826,"children":827},{},[828],{"type":43,"value":829},"});\n",{"type":37,"tag":105,"props":831,"children":832},{},[833,867,921],{"type":37,"tag":109,"props":834,"children":835},{},[836,842,844,850,852,858,860,866],{"type":37,"tag":50,"props":837,"children":839},{"className":838},[],[840],{"type":43,"value":841},"Document",{"type":43,"value":843}," (closable, not pinnable) vs ",{"type":37,"tag":50,"props":845,"children":847},{"className":846},[],[848],{"type":43,"value":849},"ToolWindow",{"type":43,"value":851}," (hideable, side-pinnable,\n",{"type":37,"tag":50,"props":853,"children":855},{"className":854},[],[856],{"type":43,"value":857},"AllowedSides",{"type":43,"value":859}," mask). Both reconcile through ",{"type":37,"tag":50,"props":861,"children":863},{"className":862},[],[864],{"type":43,"value":865},"DockableContent",{"type":43,"value":156},{"type":37,"tag":109,"props":868,"children":869},{},[870,875,877,883,885,891,893,898,900,906,908,913,914,919],{"type":37,"tag":99,"props":871,"children":872},{},[873],{"type":43,"value":874},"Roles",{"type":43,"value":876}," (spec 046): ",{"type":37,"tag":50,"props":878,"children":880},{"className":879},[],[881],{"type":43,"value":882},"DocumentArea",{"type":43,"value":884}," is the preferred ",{"type":37,"tag":50,"props":886,"children":888},{"className":887},[],[889],{"type":43,"value":890},"Dock(Center)",{"type":43,"value":892}," target and\n",{"type":37,"tag":99,"props":894,"children":895},{},[896],{"type":43,"value":897},"survives empty",{"type":43,"value":899}," (the well stays a visible drop target). ",{"type":37,"tag":50,"props":901,"children":903},{"className":902},[],[904],{"type":43,"value":905},"ToolWindowStrip",{"type":43,"value":907}," is\nthe preferred target for tool-window drops. Use object-initializer syntax for\n",{"type":37,"tag":50,"props":909,"children":911},{"className":910},[],[912],{"type":43,"value":841},{"type":43,"value":126},{"type":37,"tag":50,"props":915,"children":917},{"className":916},[],[918],{"type":43,"value":849},{"type":43,"value":920}," so you opt into permission flags additively.",{"type":37,"tag":109,"props":922,"children":923},{},[924,926,936],{"type":43,"value":925},"Every pane needs a ",{"type":37,"tag":99,"props":927,"children":928},{},[929,931],{"type":43,"value":930},"stable, equatable ",{"type":37,"tag":50,"props":932,"children":934},{"className":933},[],[935],{"type":43,"value":138},{"type":43,"value":937}," — it's how the host preserves\npane state across reorders, tear-out, and re-dock. No fallback to title-keying.",{"type":37,"tag":80,"props":939,"children":941},{"id":940},"pane-content-gotchas",[942],{"type":43,"value":943},"Pane content gotchas",{"type":37,"tag":187,"props":945,"children":947},{"id":946},"make-pane-bodies-fill-the-pane",[948],{"type":43,"value":949},"Make pane bodies fill the pane",{"type":37,"tag":46,"props":951,"children":952},{},[953,955,960,962,968,969,975,977,983],{"type":43,"value":954},"A docked pane body is ",{"type":37,"tag":99,"props":956,"children":957},{},[958],{"type":43,"value":959},"content-sized",{"type":43,"value":961}," by default — a plain ",{"type":37,"tag":50,"props":963,"children":965},{"className":964},[],[966],{"type":43,"value":967},"Border",{"type":43,"value":126},{"type":37,"tag":50,"props":970,"children":972},{"className":971},[],[973],{"type":43,"value":974},"TextBox",{"type":43,"value":976},"\ncollapses to its desired height at the top of the pane. To fill, put it in a\nflex container with ",{"type":37,"tag":50,"props":978,"children":980},{"className":979},[],[981],{"type":43,"value":982},"grow",{"type":43,"value":984},":",{"type":37,"tag":59,"props":986,"children":988},{"className":61,"code":987,"language":63,"meta":64,"style":64},"FlexColumn(\n    editorTextBox.Flex(grow: 1, basis: 0)\n).Flex(grow: 1);\n",[989],{"type":37,"tag":50,"props":990,"children":991},{"__ignoreMap":64},[992,1000,1008],{"type":37,"tag":70,"props":993,"children":994},{"class":72,"line":73},[995],{"type":37,"tag":70,"props":996,"children":997},{},[998],{"type":43,"value":999},"FlexColumn(\n",{"type":37,"tag":70,"props":1001,"children":1002},{"class":72,"line":222},[1003],{"type":37,"tag":70,"props":1004,"children":1005},{},[1006],{"type":43,"value":1007},"    editorTextBox.Flex(grow: 1, basis: 0)\n",{"type":37,"tag":70,"props":1009,"children":1010},{"class":72,"line":231},[1011],{"type":37,"tag":70,"props":1012,"children":1013},{},[1014],{"type":43,"value":1015},").Flex(grow: 1);\n",{"type":37,"tag":187,"props":1017,"children":1019},{"id":1018},"multi-line-textbox-acceptsreturn-must-be-an-element-prop-not-set",[1020,1022,1028,1030],{"type":43,"value":1021},"Multi-line TextBox: ",{"type":37,"tag":50,"props":1023,"children":1025},{"className":1024},[],[1026],{"type":43,"value":1027},"AcceptsReturn",{"type":43,"value":1029}," must be an element prop, not ",{"type":37,"tag":50,"props":1031,"children":1033},{"className":1032},[],[1034],{"type":43,"value":1035},".Set",{"type":37,"tag":46,"props":1037,"children":1038},{},[1039,1041,1046,1048,1053,1054,1060,1061,1066,1067,1073,1075,1080,1082,1088,1090,1095,1096,1101],{"type":43,"value":1040},"The ",{"type":37,"tag":50,"props":1042,"children":1044},{"className":1043},[],[1045],{"type":43,"value":974},{"type":43,"value":1047}," descriptor applies ",{"type":37,"tag":50,"props":1049,"children":1051},{"className":1050},[],[1052],{"type":43,"value":1027},{"type":43,"value":126},{"type":37,"tag":50,"props":1055,"children":1057},{"className":1056},[],[1058],{"type":43,"value":1059},"TextWrapping",{"type":43,"value":653},{"type":37,"tag":99,"props":1062,"children":1063},{},[1064],{"type":43,"value":1065},"before",{"type":43,"value":653},{"type":37,"tag":50,"props":1068,"children":1070},{"className":1069},[],[1071],{"type":43,"value":1072},"Text",{"type":43,"value":1074},"\non purpose — single-line mode truncates ",{"type":37,"tag":50,"props":1076,"children":1078},{"className":1077},[],[1079],{"type":43,"value":1072},{"type":43,"value":1081}," at the first newline. A\n",{"type":37,"tag":50,"props":1083,"children":1085},{"className":1084},[],[1086],{"type":43,"value":1087},".Set(tb => tb.AcceptsReturn = true)",{"type":43,"value":1089}," lambda runs ",{"type":37,"tag":175,"props":1091,"children":1092},{},[1093],{"type":43,"value":1094},"after",{"type":43,"value":653},{"type":37,"tag":50,"props":1097,"children":1099},{"className":1098},[],[1100],{"type":43,"value":1072},{"type":43,"value":1102}," is assigned, so\nthe body collapses to one line. Use the first-class modifiers:",{"type":37,"tag":59,"props":1104,"children":1106},{"className":61,"code":1105,"language":63,"meta":64,"style":64},"\u002F\u002F ✅ ordered before Text by the descriptor\nTextBox(text, setText).AcceptsReturn().TextWrapping(TextWrapping.NoWrap)\n\n\u002F\u002F ❌ runs after Text → multi-line content truncated to the first line\nTextBox(text, setText).Set(tb => tb.AcceptsReturn = true)\n",[1107],{"type":37,"tag":50,"props":1108,"children":1109},{"__ignoreMap":64},[1110,1118,1126,1133,1141],{"type":37,"tag":70,"props":1111,"children":1112},{"class":72,"line":73},[1113],{"type":37,"tag":70,"props":1114,"children":1115},{},[1116],{"type":43,"value":1117},"\u002F\u002F ✅ ordered before Text by the descriptor\n",{"type":37,"tag":70,"props":1119,"children":1120},{"class":72,"line":222},[1121],{"type":37,"tag":70,"props":1122,"children":1123},{},[1124],{"type":43,"value":1125},"TextBox(text, setText).AcceptsReturn().TextWrapping(TextWrapping.NoWrap)\n",{"type":37,"tag":70,"props":1127,"children":1128},{"class":72,"line":231},[1129],{"type":37,"tag":70,"props":1130,"children":1131},{"emptyLinePlaceholder":403},[1132],{"type":43,"value":406},{"type":37,"tag":70,"props":1134,"children":1135},{"class":72,"line":240},[1136],{"type":37,"tag":70,"props":1137,"children":1138},{},[1139],{"type":43,"value":1140},"\u002F\u002F ❌ runs after Text → multi-line content truncated to the first line\n",{"type":37,"tag":70,"props":1142,"children":1143},{"class":72,"line":249},[1144],{"type":37,"tag":70,"props":1145,"children":1146},{},[1147],{"type":43,"value":1148},"TextBox(text, setText).Set(tb => tb.AcceptsReturn = true)\n",{"type":37,"tag":46,"props":1150,"children":1151},{},[1152,1154,1159,1161,1167,1169,1175,1177,1183,1185,1190],{"type":43,"value":1153},"Generally: any prop whose ",{"type":37,"tag":175,"props":1155,"children":1156},{},[1157],{"type":43,"value":1158},"ordering relative to another prop matters",{"type":43,"value":1160}," belongs on\nthe element (",{"type":37,"tag":50,"props":1162,"children":1164},{"className":1163},[],[1165],{"type":43,"value":1166},".AcceptsReturn()",{"type":43,"value":1168},", ",{"type":37,"tag":50,"props":1170,"children":1172},{"className":1171},[],[1173],{"type":43,"value":1174},".TextWrapping()",{"type":43,"value":1176},"), not in a ",{"type":37,"tag":50,"props":1178,"children":1180},{"className":1179},[],[1181],{"type":43,"value":1182},".Set(...)",{"type":43,"value":1184}," escape\nhatch — ",{"type":37,"tag":50,"props":1186,"children":1188},{"className":1187},[],[1189],{"type":43,"value":1035},{"type":43,"value":1191}," always runs last.",{"type":37,"tag":80,"props":1193,"children":1195},{"id":1194},"key-apis",[1196],{"type":43,"value":1197},"Key APIs",{"type":37,"tag":1199,"props":1200,"children":1201},"table",{},[1202,1221],{"type":37,"tag":1203,"props":1204,"children":1205},"thead",{},[1206],{"type":37,"tag":1207,"props":1208,"children":1209},"tr",{},[1210,1216],{"type":37,"tag":1211,"props":1212,"children":1213},"th",{},[1214],{"type":43,"value":1215},"API",{"type":37,"tag":1211,"props":1217,"children":1218},{},[1219],{"type":43,"value":1220},"Purpose",{"type":37,"tag":1222,"props":1223,"children":1224},"tbody",{},[1225,1243,1260,1277,1294,1311,1327,1344,1373],{"type":37,"tag":1207,"props":1226,"children":1227},{},[1228,1238],{"type":37,"tag":1229,"props":1230,"children":1231},"td",{},[1232],{"type":37,"tag":50,"props":1233,"children":1235},{"className":1234},[],[1236],{"type":43,"value":1237},"DockManager { Layout, PersistenceId, ... }",{"type":37,"tag":1229,"props":1239,"children":1240},{},[1241],{"type":43,"value":1242},"The host element",{"type":37,"tag":1207,"props":1244,"children":1245},{},[1246,1255],{"type":37,"tag":1229,"props":1247,"children":1248},{},[1249],{"type":37,"tag":50,"props":1250,"children":1252},{"className":1251},[],[1253],{"type":43,"value":1254},"DockSplit(Orientation, children)",{"type":37,"tag":1229,"props":1256,"children":1257},{},[1258],{"type":43,"value":1259},"Resizable split (ratios owned by host)",{"type":37,"tag":1207,"props":1261,"children":1262},{},[1263,1272],{"type":37,"tag":1229,"props":1264,"children":1265},{},[1266],{"type":37,"tag":50,"props":1267,"children":1269},{"className":1268},[],[1270],{"type":43,"value":1271},"DockTabGroup(docs, TabPosition, CompactTabs, SelectedIndex, Width\u002FHeight, Role)",{"type":37,"tag":1229,"props":1273,"children":1274},{},[1275],{"type":43,"value":1276},"A tab group",{"type":37,"tag":1207,"props":1278,"children":1279},{},[1280,1289],{"type":37,"tag":1229,"props":1281,"children":1282},{},[1283],{"type":37,"tag":50,"props":1284,"children":1286},{"className":1285},[],[1287],{"type":43,"value":1288},"Document { Title, Key, Content, CanClose }",{"type":37,"tag":1229,"props":1290,"children":1291},{},[1292],{"type":43,"value":1293},"Closable document pane",{"type":37,"tag":1207,"props":1295,"children":1296},{},[1297,1306],{"type":37,"tag":1229,"props":1298,"children":1299},{},[1300],{"type":37,"tag":50,"props":1301,"children":1303},{"className":1302},[],[1304],{"type":43,"value":1305},"ToolWindow { Title, Key, Content, CanPin, AllowedSides, ... }",{"type":37,"tag":1229,"props":1307,"children":1308},{},[1309],{"type":43,"value":1310},"Hideable\u002Fpinnable tool pane",{"type":37,"tag":1207,"props":1312,"children":1313},{},[1314,1322],{"type":37,"tag":1229,"props":1315,"children":1316},{},[1317],{"type":37,"tag":50,"props":1318,"children":1320},{"className":1319},[],[1321],{"type":43,"value":619},{"type":37,"tag":1229,"props":1323,"children":1324},{},[1325],{"type":43,"value":1326},"Remount to reset\u002Fdiscard drag shape",{"type":37,"tag":1207,"props":1328,"children":1329},{},[1330,1339],{"type":37,"tag":1229,"props":1331,"children":1332},{},[1333],{"type":37,"tag":50,"props":1334,"children":1336},{"className":1335},[],[1337],{"type":43,"value":1338},"OnDocumentClosing",{"type":37,"tag":1229,"props":1340,"children":1341},{},[1342],{"type":43,"value":1343},"Sync app state when the host closes a tab",{"type":37,"tag":1207,"props":1345,"children":1346},{},[1347,1355],{"type":37,"tag":1229,"props":1348,"children":1349},{},[1350],{"type":37,"tag":50,"props":1351,"children":1353},{"className":1352},[],[1354],{"type":43,"value":304},{"type":37,"tag":1229,"props":1356,"children":1357},{},[1358,1363,1365,1371],{"type":37,"tag":99,"props":1359,"children":1360},{},[1361],{"type":43,"value":1362},"Observe",{"type":43,"value":1364}," the resolved layout (never feed back to ",{"type":37,"tag":50,"props":1366,"children":1368},{"className":1367},[],[1369],{"type":43,"value":1370},"Layout",{"type":43,"value":1372},")",{"type":37,"tag":1207,"props":1374,"children":1375},{},[1376,1385],{"type":37,"tag":1229,"props":1377,"children":1378},{},[1379],{"type":37,"tag":50,"props":1380,"children":1382},{"className":1381},[],[1383],{"type":43,"value":1384},"DockingNativeInterop.Register(host.Reconciler)",{"type":37,"tag":1229,"props":1386,"children":1387},{},[1388],{"type":43,"value":1389},"One-time startup registration",{"type":37,"tag":46,"props":1391,"children":1392},{},[1393,1395,1401],{"type":43,"value":1394},"See ",{"type":37,"tag":50,"props":1396,"children":1398},{"className":1397},[],[1399],{"type":43,"value":1400},"samples\u002Fapps\u002Freactor-ide",{"type":43,"value":1402}," for a complete IDE-shaped app exercising all of this.",{"type":37,"tag":1404,"props":1405,"children":1406},"style",{},[1407],{"type":43,"value":1408},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1410,"total":1605},[1411,1433,1454,1475,1490,1507,1518,1531,1546,1561,1580,1593],{"slug":1412,"name":1412,"fn":1413,"description":1414,"org":1415,"tags":1416,"stars":1430,"repoUrl":1431,"updatedAt":1432},"rushstack-best-practices","manage Rush monorepos with best practices","Provides best practices and guidance for working with Rush monorepos. Use when the user is working in a Rush-based repository, asks about Rush commands (install, update, build, rebuild), needs help with project selection, dependency management, build caching, subspace configuration, or troubleshooting Rush-specific issues.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1417,1420,1423,1424,1427],{"name":1418,"slug":1419,"type":13},"Engineering","engineering",{"name":1421,"slug":1422,"type":13},"Local Development","local-development",{"name":9,"slug":8,"type":13},{"name":1425,"slug":1426,"type":13},"Project Management","project-management",{"name":1428,"slug":1429,"type":13},"Rush","rush",6484,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frushstack","2026-04-06T18:34:44.965032",{"slug":1434,"name":1434,"fn":1435,"description":1436,"org":1437,"tags":1438,"stars":1451,"repoUrl":1452,"updatedAt":1453},"azure-ai-agents-persistent-dotnet","build AI agents with Azure .NET SDK","Azure AI Agents Persistent SDK for .NET. Low-level SDK for creating and managing AI agents with threads, messages, runs, and tools. Use for agent CRUD, conversation threads, streaming responses, function calling, file search, and code interpreter. Triggers: \"PersistentAgentsClient\", \"persistent agents\", \"agent threads\", \"agent runs\", \"streaming agents\", \"function calling agents .NET\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1439,1442,1445,1448],{"name":1440,"slug":1441,"type":13},".NET","net",{"name":1443,"slug":1444,"type":13},"Agents","agents",{"name":1446,"slug":1447,"type":13},"Azure","azure",{"name":1449,"slug":1450,"type":13},"LLM","llm",2804,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fskills","2026-07-03T16:32:10.297433",{"slug":1455,"name":1455,"fn":1456,"description":1457,"org":1458,"tags":1459,"stars":1451,"repoUrl":1452,"updatedAt":1474},"azure-ai-anomalydetector-java","build anomaly detection applications with Java","Build anomaly detection applications with Azure AI Anomaly Detector SDK for Java. Use when implementing univariate\u002Fmultivariate anomaly detection, time-series analysis, or AI-powered monitoring.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1460,1463,1464,1467,1470,1471],{"name":1461,"slug":1462,"type":13},"Analytics","analytics",{"name":1446,"slug":1447,"type":13},{"name":1465,"slug":1466,"type":13},"Data Analysis","data-analysis",{"name":1468,"slug":1469,"type":13},"Java","java",{"name":9,"slug":8,"type":13},{"name":1472,"slug":1473,"type":13},"Monitoring","monitoring","2026-05-13T06:14:16.261754",{"slug":1476,"name":1476,"fn":1477,"description":1478,"org":1479,"tags":1480,"stars":1451,"repoUrl":1452,"updatedAt":1489},"azure-ai-contentsafety-java","build content moderation applications with Azure AI","Build content moderation applications with Azure AI Content Safety SDK for Java. Use when implementing text\u002Fimage analysis, blocklist management, or harm detection for hate, violence, sexual content, and self-harm.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1481,1484,1485,1486],{"name":1482,"slug":1483,"type":13},"AI Infrastructure","ai-infrastructure",{"name":1446,"slug":1447,"type":13},{"name":1468,"slug":1469,"type":13},{"name":1487,"slug":1488,"type":13},"Security","security","2026-07-07T06:53:31.293235",{"slug":1491,"name":1491,"fn":1492,"description":1493,"org":1494,"tags":1495,"stars":1451,"repoUrl":1452,"updatedAt":1506},"azure-ai-contentsafety-py","detect harmful content with Azure AI Content Safety","Azure AI Content Safety SDK for Python. Use for detecting harmful content in text and images with multi-severity classification.\nTriggers: \"azure-ai-contentsafety\", \"ContentSafetyClient\", \"content moderation\", \"harmful content\", \"text analysis\", \"image analysis\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1496,1497,1500,1501,1502,1505],{"name":1446,"slug":1447,"type":13},{"name":1498,"slug":1499,"type":13},"Compliance","compliance",{"name":1449,"slug":1450,"type":13},{"name":9,"slug":8,"type":13},{"name":1503,"slug":1504,"type":13},"Python","python",{"name":1487,"slug":1488,"type":13},"2026-07-18T05:14:23.017504",{"slug":1508,"name":1508,"fn":1509,"description":1510,"org":1511,"tags":1512,"stars":1451,"repoUrl":1452,"updatedAt":1517},"azure-ai-language-conversations-py","implement conversational language understanding with Python","Implement Conversational Language Understanding (CLU) using the azure-ai-language-conversations Python SDK. Use when working with ConversationAnalysisClient to analyze conversation intent and entities, building NLP features, or integrating language understanding into applications.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1513,1514,1515,1516],{"name":1461,"slug":1462,"type":13},{"name":1446,"slug":1447,"type":13},{"name":1449,"slug":1450,"type":13},{"name":1503,"slug":1504,"type":13},"2026-07-31T05:54:29.068751",{"slug":1519,"name":1519,"fn":1520,"description":1521,"org":1522,"tags":1523,"stars":1451,"repoUrl":1452,"updatedAt":1530},"azure-ai-translation-text-py","translate text using Azure AI services","Azure AI Text Translation SDK for real-time text translation, transliteration, language detection, and dictionary lookup. Use for translating text content in applications.\nTriggers: \"text translation\", \"translator\", \"translate text\", \"transliterate\", \"TextTranslationClient\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1524,1527,1528,1529],{"name":1525,"slug":1526,"type":13},"API Development","api-development",{"name":1446,"slug":1447,"type":13},{"name":9,"slug":8,"type":13},{"name":1503,"slug":1504,"type":13},"2026-07-18T05:14:16.988376",{"slug":1532,"name":1532,"fn":1533,"description":1534,"org":1535,"tags":1536,"stars":1451,"repoUrl":1452,"updatedAt":1545},"azure-ai-vision-imageanalysis-py","analyze images with Azure AI Vision","Azure AI Vision Image Analysis SDK for captions, tags, objects, OCR, people detection, and smart cropping. Use for computer vision and image understanding tasks.\nTriggers: \"image analysis\", \"computer vision\", \"OCR\", \"object detection\", \"ImageAnalysisClient\", \"image caption\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1537,1538,1541,1544],{"name":1446,"slug":1447,"type":13},{"name":1539,"slug":1540,"type":13},"Computer Vision","computer-vision",{"name":1542,"slug":1543,"type":13},"Images","images",{"name":1503,"slug":1504,"type":13},"2026-07-18T05:14:18.007737",{"slug":1547,"name":1547,"fn":1548,"description":1549,"org":1550,"tags":1551,"stars":1451,"repoUrl":1452,"updatedAt":1560},"azure-appconfiguration-java","manage configuration with Azure App Configuration","Azure App Configuration SDK for Java. Centralized application configuration management with key-value settings, feature flags, and snapshots.\nTriggers: \"ConfigurationClient java\", \"app configuration java\", \"feature flag java\", \"configuration setting java\", \"azure config java\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1552,1553,1556,1559],{"name":1446,"slug":1447,"type":13},{"name":1554,"slug":1555,"type":13},"Configuration","configuration",{"name":1557,"slug":1558,"type":13},"Feature Flags","feature-flags",{"name":1468,"slug":1469,"type":13},"2026-07-03T16:32:01.278468",{"slug":1562,"name":1562,"fn":1563,"description":1564,"org":1565,"tags":1566,"stars":1451,"repoUrl":1452,"updatedAt":1579},"azure-cosmos-rust","build applications with Azure Cosmos DB","Azure Cosmos DB library for Rust (NoSQL API). Document CRUD, containers, and globally distributed data.\nTriggers: \"cosmos db rust\", \"CosmosClient rust\", \"document crud rust\", \"NoSQL rust\", \"partition key rust\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1567,1570,1573,1576],{"name":1568,"slug":1569,"type":13},"Cosmos DB","cosmos-db",{"name":1571,"slug":1572,"type":13},"Database","database",{"name":1574,"slug":1575,"type":13},"NoSQL","nosql",{"name":1577,"slug":1578,"type":13},"Rust","rust","2026-07-31T05:54:27.021432",{"slug":1581,"name":1581,"fn":1563,"description":1582,"org":1583,"tags":1584,"stars":1451,"repoUrl":1452,"updatedAt":1592},"azure-cosmos-ts","Azure Cosmos DB JavaScript\u002FTypeScript SDK (@azure\u002Fcosmos) for data plane operations. Use for CRUD operations on documents, queries, bulk operations, and container management. Triggers: \"Cosmos DB\", \"@azure\u002Fcosmos\", \"CosmosClient\", \"document CRUD\", \"NoSQL queries\", \"bulk operations\", \"partition key\", \"container.items\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1585,1586,1587,1588,1589],{"name":1568,"slug":1569,"type":13},{"name":1571,"slug":1572,"type":13},{"name":9,"slug":8,"type":13},{"name":1574,"slug":1575,"type":13},{"name":1590,"slug":1591,"type":13},"TypeScript","typescript","2026-07-03T16:31:19.368382",{"slug":1594,"name":1594,"fn":1595,"description":1596,"org":1597,"tags":1598,"stars":1451,"repoUrl":1452,"updatedAt":1604},"azure-data-tables-java","build table storage applications with Java","Build table storage applications with Azure Tables SDK for Java. Use when working with Azure Table Storage or Cosmos DB Table API for NoSQL key-value data, schemaless storage, or structured data at scale.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1599,1600,1601,1602,1603],{"name":1446,"slug":1447,"type":13},{"name":1568,"slug":1569,"type":13},{"name":1571,"slug":1572,"type":13},{"name":1468,"slug":1469,"type":13},{"name":1574,"slug":1575,"type":13},"2026-05-13T06:14:17.582229",267,{"items":1607,"total":222},[1608,1628],{"slug":1609,"name":1609,"fn":1610,"description":1611,"org":1612,"tags":1613,"stars":20,"repoUrl":21,"updatedAt":1627},"reactor-design","design Windows 11 user interfaces with Reactor","Windows 11 design rules for Reactor — theme tokens, High Contrast, typography (`Heading`\u002F`SubHeading`\u002F`Caption`), 4px grid, acrylic surfaces, accessibility, animation, and a code-review checklist. Use when authoring, reviewing, or fixing visual styling.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1614,1617,1620,1623,1624],{"name":1615,"slug":1616,"type":13},"Accessibility","accessibility",{"name":1618,"slug":1619,"type":13},"Animation","animation",{"name":1621,"slug":1622,"type":13},"Design","design",{"name":18,"slug":19,"type":13},{"name":1625,"slug":1626,"type":13},"Windows","windows","2026-07-31T05:54:53.086222",{"slug":4,"name":4,"fn":5,"description":6,"org":1629,"tags":1630,"stars":20,"repoUrl":21,"updatedAt":22},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1631,1632,1633],{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13},{"name":18,"slug":19,"type":13}]