@duro-app/cli 5.21.0 → 5.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +5 -5
  2. package/registry.json +68 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duro-app/cli",
3
- "version": "5.21.0",
3
+ "version": "5.23.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Machine-queryable docs for the Duro design system: components, props, recipes, tokens and rules as CLI output, JSON, or an MCP server.",
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@modelcontextprotocol/sdk": ">=1.0.0",
49
- "@duro-app/ui": "^5.21.0"
49
+ "@duro-app/ui": "^5.23.0"
50
50
  },
51
51
  "peerDependenciesMeta": {
52
52
  "@duro-app/ui": {
@@ -61,9 +61,9 @@
61
61
  "@types/node": "^24.0.0",
62
62
  "ts-morph": "^26.0.0",
63
63
  "typescript": "^5.7.0",
64
- "@duro-app/eslint-plugin": "^5.21.0",
65
- "@duro-app/ui": "^5.21.0",
66
- "@duro-app/tokens": "^5.21.0"
64
+ "@duro-app/tokens": "^5.23.0",
65
+ "@duro-app/ui": "^5.23.0",
66
+ "@duro-app/eslint-plugin": "^5.23.0"
67
67
  },
68
68
  "scripts": {
69
69
  "registry": "node scripts/build-registry.mjs",
package/registry.json CHANGED
@@ -190,7 +190,7 @@
190
190
  "Main"
191
191
  ]
192
192
  },
193
- "description": "An application's frame: a navigation rail (a labelled nav, the brand at its top, an optional footer at its foot) beside the main content (main), with an optional Header. Below collapseBelow (sm default, md or lg), measured on the shell's own width, the rail is hidden and one sticky bar (a banner, appBarH tall) holds a Menu button that opens the same navigation in a left Drawer, the brand, and the Header's content when there is one — a shell without a Header still has its navigation on a phone. Above it the Header is a row that scrolls with the page and the rail stays sticky. CSS makes the switch: the server renders one HTML for every width with the brand in both places, and display: none hides the inactive copy, so nothing moves after hydration. A skip link (the first tab stop) focuses Main; an Aside inside Main sticks below the bar. Labels come from props. Compound component — Root is required. On React Native it is always the narrow shape: the bar below the status bar, Main under it, and the Rail in a left Drawer; there is no skip link.",
193
+ "description": "An application's frame: a navigation rail (a labelled nav, the brand at its top, an optional footer at its foot) beside the main content (main), with an optional Header. Below collapseBelow (sm default, md or lg), measured on the shell's own width, the rail is hidden and one sticky bar (a banner, appBarH tall) holds a Menu button that opens the same navigation in a left Drawer, the brand, and the Header's content when there is one — a shell without a Header still has its navigation on a phone. Above it the Header is a row that scrolls with the page and the rail stays sticky. CSS makes the switch: the server renders one HTML for every width with the brand in both places, and display: none hides the inactive copy, so nothing moves after hydration. A skip link (the first tab stop) focuses Main; an Aside inside Main sticks below the bar. Labels come from props. Compound component — Root is required. On React Native it is always the narrow shape: the bar below the status bar, Main under it, and the Rail in a left Drawer; there is no skip link. scroll=\"main\" makes it an app frame rather than a page: the shell is the viewport's height and Main scrolls on its own, so a SplitPane or VirtualList inside it fills Main and scrolls its own panes.",
194
194
  "example": "<AppShell.Root\n menuLabel=\"Menu\"\n closeLabel=\"Close navigation\"\n skipLabel=\"Skip to content\"\n brand={<TextLink href=\"/\">Acme</TextLink>}\n collapseBelow=\"md\"\n>\n <AppShell.Rail aria-label=\"Navigation\" footer={<Text variant=\"bodySm\">{user.name}</Text>}>\n {({close}) => (\n <SideNav.Root value={pathname} onValueChange={(v) => { close(); navigate(v) }}>\n <SideNav.Item value=\"/docs\">Docs</SideNav.Item>\n </SideNav.Root>\n )}\n </AppShell.Rail>\n <AppShell.Header>{search}</AppShell.Header>\n <AppShell.Main>{children}</AppShell.Main>\n</AppShell.Root>",
195
195
  "relatedTo": [
196
196
  {
@@ -325,6 +325,17 @@
325
325
  "lg"
326
326
  ]
327
327
  },
328
+ {
329
+ "default": "'page'",
330
+ "description": "What scrolls. `page` (default): the document, a page that grows with its content. `main`: the shell is exactly the viewport's height and Main scrolls on its own, so a SplitPane or VirtualList inside it can fill Main and scroll its own panes (an app such as a chat or a mail client).",
331
+ "name": "scroll",
332
+ "required": false,
333
+ "type": "AppShellScroll",
334
+ "union": [
335
+ "page",
336
+ "main"
337
+ ]
338
+ },
328
339
  {
329
340
  "description": "`AppShell.Rail`, `AppShell.Main` and an optional `AppShell.Header`, as direct children (Root places the Header's content in its bar).",
330
341
  "name": "children",
@@ -1182,7 +1193,7 @@
1182
1193
  "importPath": "@duro-app/ui",
1183
1194
  "kind": "component",
1184
1195
  "meta": {
1185
- "description": "A block of code with a copy button: a pre that scrolls sideways when a line is long, and a Button that copies its text, shows the copied label for copiedDuration ms and announces it through a polite LiveRegion. Labels come from props.",
1196
+ "description": "A block of code with a copy button: a pre that scrolls sideways when a line is long, and a Button that copies its text, shows the copied label for copiedDuration ms and announces it through a polite LiveRegion. Labels come from props. With language=\"diff\", added, removed and hunk lines are coloured from tokens. On native the text is selectable and scrolls sideways; there is no copy button.",
1186
1197
  "example": "<CodeBlock copyLabel=\"Copy\" copiedLabel=\"Copied\">\n <code>pnpm add @duro-app/ui</code>\n</CodeBlock>",
1187
1198
  "relatedTo": [
1188
1199
  {
@@ -1206,7 +1217,7 @@
1206
1217
  ]
1207
1218
  },
1208
1219
  "name": "CodeBlock",
1209
- "native": false,
1220
+ "native": true,
1210
1221
  "props": [
1211
1222
  {
1212
1223
  "description": "The code: text, or the `<code>` element a Markdown renderer produced (highlighted spans included). What is copied is its text content.",
@@ -1214,6 +1225,12 @@
1214
1225
  "required": true,
1215
1226
  "type": "ReactNode"
1216
1227
  },
1228
+ {
1229
+ "description": "The code's language (\"diff\", \"ts\"), exposed as `data-language` on the `pre`. `\"diff\"` also gives each added (`+`), removed (`-`) and hunk (`@@`) line its own colour; what is copied stays the raw text. Diff rendering works on the text content, so highlighted spans inside `children` are flattened to plain text. The language is a data attribute only: it is not announced to assistive technology.",
1230
+ "name": "language",
1231
+ "required": false,
1232
+ "type": "string"
1233
+ },
1217
1234
  {
1218
1235
  "description": "The copy button's label (\"Copy\"), from your text catalog.",
1219
1236
  "name": "copyLabel",
@@ -5238,7 +5255,7 @@
5238
5255
  "importPath": "@duro-app/ui",
5239
5256
  "kind": "component",
5240
5257
  "meta": {
5241
- "description": "The container for HTML Duro does not author — rendered Markdown, CMS output: headings, paragraphs, lists, tables, blockquotes, inline code, links and images are styled from tokens by descendant rules scoped to it (plain CSS in dist/index.css, :where() and its own cascade layer). Duro components inside it keep their styles, and an app's own CSS wins over every Prose rule. Web only.",
5258
+ "description": "The container for HTML Duro does not author — rendered Markdown, CMS output: headings, paragraphs, lists, tables, blockquotes, inline code, links and images are styled from tokens by descendant rules scoped to it (plain CSS in dist/index.css, :where() and its own cascade layer). Duro components inside it keep their styles, and an app's own CSS wins over every Prose rule. On native it is a reading-width column with a token gap; the renderer maps Markdown to Duro primitives.",
5242
5259
  "example": "<Prose>\n <ReactMarkdown components={{pre: ({children}) => <CodeBlock copyLabel=\"Copy\" copiedLabel=\"Copied\">{children}</CodeBlock>}}>\n {body}\n </ReactMarkdown>\n</Prose>",
5243
5260
  "relatedTo": [
5244
5261
  {
@@ -5262,7 +5279,7 @@
5262
5279
  ]
5263
5280
  },
5264
5281
  "name": "Prose",
5265
- "native": false,
5282
+ "native": true,
5266
5283
  "props": [
5267
5284
  {
5268
5285
  "description": "HTML Duro does not author: the output of a Markdown renderer.",
@@ -5938,7 +5955,7 @@
5938
5955
  "Pane"
5939
5956
  ]
5940
5957
  },
5941
- "description": "Two panes side by side with a resizable separator: the first Pane is sized by the Handle (pointer drag, arrow keys, Shift for larger steps, Home and End), the second takes the rest. Min, max and starting widths are size tokens. Below collapseBelow, measured on its own width, the panes stack in one column and the handle goes; on native they always stack. The Handle is a hairline that thickens to the accent on hover, keyboard focus or drag.",
5958
+ "description": "Two panes side by side with a resizable separator: the first Pane is sized by the Handle (pointer drag, arrow keys, Shift for larger steps, Home and End), the second takes the rest. Min, max and starting widths are size tokens. Below collapseBelow, measured on its own width, the panes stack in one column and the handle goes; on native they always stack. A controlled collapsed prop shrinks the first pane to a strip (the iconButton size) that shows collapsedContent, removes the Handle, and keeps the first pane’s own children mounted but inert and hidden (state kept, no tab stops, out of the accessibility tree); the prior width returns when it turns false. Native ignores both. The Handle is a hairline that thickens to the accent on hover, keyboard focus or drag.",
5942
5959
  "example": "<SplitPane.Root aria-label=\"Resize the session list\" minSize=\"sidebarW\" maxSize=\"panelLg\">\n <SplitPane.Pane>\n <List.Root aria-label=\"Sessions\">…</List.Root>\n </SplitPane.Pane>\n <SplitPane.Handle />\n <SplitPane.Pane>\n <Panel.Root>…</Panel.Root>\n </SplitPane.Pane>\n</SplitPane.Root>",
5943
5960
  "relatedTo": [
5944
5961
  {
@@ -6036,6 +6053,19 @@
6036
6053
  "xl"
6037
6054
  ]
6038
6055
  },
6056
+ {
6057
+ "default": "false",
6058
+ "description": "Controlled: shrink the primary pane to a strip (the `iconButton` size), show `collapsedContent` in it and remove the handle. The pane's own children stay mounted (their state is kept) but are inert and hidden. When it turns false the pane returns to its prior width. Ignored when stacked.",
6059
+ "name": "collapsed",
6060
+ "required": false,
6061
+ "type": "boolean"
6062
+ },
6063
+ {
6064
+ "description": "What the strip shows while `collapsed` (an expand button, icons).",
6065
+ "name": "collapsedContent",
6066
+ "required": false,
6067
+ "type": "ReactNode"
6068
+ },
6039
6069
  {
6040
6070
  "description": "The handle's accessible name (\"Resize list\").",
6041
6071
  "name": "aria-label",
@@ -7489,7 +7519,7 @@
7489
7519
  "importPath": "@duro-app/ui",
7490
7520
  "kind": "component",
7491
7521
  "meta": {
7492
- "description": "Multi-line text input with automatic Field/Form integration. Same Field binding behavior as Input.",
7522
+ "description": "Multi-line text input with automatic Field/Form integration. Same Field binding behavior as Input. autoGrow makes the height follow the content from rows up to maxRows, then it scrolls (CSS field-sizing, with a scrollHeight fallback; native grows with the content and caps at maxRows). The anchor props of Listbox.getAnchorProps() (role combobox, aria-controls, aria-expanded, aria-activedescendant) are forwarded as ARIA attributes on web and as the matching accessibility props on native, so a Listbox can be anchored to it while the editor keeps focus.",
7493
7523
  "example": "<Field.Root name=\"message\">\n <Field.Label>Message</Field.Label>\n <Textarea placeholder=\"Tell us what you think...\" rows={4} />\n <Field.Description>At least 10 characters</Field.Description>\n <Field.Error />\n</Field.Root>",
7494
7524
  "relatedTo": [
7495
7525
  {
@@ -7507,12 +7537,26 @@
7507
7537
  "Single-line input — use Input"
7508
7538
  ],
7509
7539
  "whenToUse": [
7510
- "Multi-line text entry (comments, messages, descriptions)"
7540
+ "Multi-line text entry (comments, messages, descriptions)",
7541
+ "A composer that grows with its text (autoGrow, maxRows)",
7542
+ "An editor a Listbox is anchored to for mentions or slash commands (spread Listbox.getAnchorProps())"
7511
7543
  ]
7512
7544
  },
7513
7545
  "name": "Textarea",
7514
7546
  "native": true,
7515
7547
  "props": [
7548
+ {
7549
+ "description": "The height follows the content, from `rows` up to `maxRows`, then it scrolls.",
7550
+ "name": "autoGrow",
7551
+ "required": false,
7552
+ "type": "true | false"
7553
+ },
7554
+ {
7555
+ "description": "The most rows the field shows before it scrolls. Default: no limit",
7556
+ "name": "maxRows",
7557
+ "required": false,
7558
+ "type": "number"
7559
+ },
7516
7560
  {
7517
7561
  "default": "'default'",
7518
7562
  "name": "variant",
@@ -8159,7 +8203,7 @@
8159
8203
  "aria-label"
8160
8204
  ]
8161
8205
  },
8162
- "description": "A row of controls with one tab stop (the WAI-ARIA toolbar pattern): Tab enters at the last focused control, Left/Right move across every control inside — through attached ButtonGroups too — and Home/End jump to the ends. A Select or Menu trigger keeps its own keys, and a control whose popup is open keeps Left/Right.",
8206
+ "description": "A row of controls with one tab stop (the WAI-ARIA toolbar pattern): Tab enters at the last focused control, Left/Right move across every control inside — through attached ButtonGroups too — and Home/End jump to the ends. A Select or Menu trigger keeps its own keys, and a control whose popup is open keeps Left/Right. On native it is the same row of controls without the roving tab stop and arrow keys.",
8163
8207
  "example": "<Toolbar aria-label=\"Formatting\">\n <ButtonGroup attached aria-label=\"Text style\">\n <Toggle aria-label=\"Bold\" pressed={bold} onPressedChange={setBold}>B</Toggle>\n <Toggle aria-label=\"Italic\" pressed={italic} onPressedChange={setItalic}>I</Toggle>\n </ButtonGroup>\n <Menu.Root>\n <Menu.Trigger>Insert</Menu.Trigger>\n <Menu.Popup>…</Menu.Popup>\n </Menu.Root>\n</Toolbar>",
8164
8208
  "relatedTo": [
8165
8209
  {
@@ -8189,7 +8233,7 @@
8189
8233
  ]
8190
8234
  },
8191
8235
  "name": "Toolbar",
8192
- "native": false,
8236
+ "native": true,
8193
8237
  "props": [
8194
8238
  {
8195
8239
  "description": "Names the toolbar (\"Formatting\"). Required: a toolbar is a landmark-like widget.",
@@ -8452,7 +8496,7 @@
8452
8496
  "optional": [],
8453
8497
  "required": []
8454
8498
  },
8455
- "description": "A windowed list on @tanstack/react-virtual: only the rows in view (plus overscan) are mounted, and rows are measured so they may differ in height. role=\"list\" with listitem rows carrying aria-setsize and aria-posinset. anchor=\"end\" opens at the last item and stays pinned to the bottom while new items arrive and the reader is at the bottom (a transcript, a log). It fills its parent, or stops at maxHeight. Web only: on native, host FlashList or Legend List behind your own .native.tsx leaf.",
8499
+ "description": "A windowed list on @tanstack/react-virtual: only the rows in view (plus overscan) are mounted, and rows are measured so they may differ in height. role=\"list\" with listitem rows carrying aria-setsize and aria-posinset. anchor=\"end\" opens at the last item and stays pinned to the bottom while new items arrive and the reader is at the bottom (a transcript, a log). It fills its parent, or stops at maxHeight. onStartReached fires once each time the reader scrolls to the start (load older history), and prepending items keeps the first visible row in place. On native it is a FlatList with the same props (role list; rows carry no listitem role, which React Native lacks) (maintainVisibleContentPosition for prepend). The scroll region is a tab stop with a focus ring, so the keyboard can scroll rows that hold no control.",
8456
8500
  "example": "<VirtualList\n aria-label=\"Transcript\"\n items={messages}\n getKey={(m) => m.id}\n estimateSize=\"controlLg\"\n anchor=\"end\"\n renderItem={(m) => <Text>{m.text}</Text>}\n/>",
8457
8501
  "relatedTo": [
8458
8502
  {
@@ -8473,11 +8517,12 @@
8473
8517
  ],
8474
8518
  "whenToUse": [
8475
8519
  "Hundreds to tens of thousands of rows: sessions, a chat transcript, log lines",
8476
- "A list that grows at the bottom while the reader follows it (anchor=\"end\")"
8520
+ "A list that grows at the bottom while the reader follows it (anchor=\"end\")",
8521
+ "A transcript that pages older history in at the top (onStartReached, then prepend items)"
8477
8522
  ]
8478
8523
  },
8479
8524
  "name": "VirtualList",
8480
- "native": false,
8525
+ "native": true,
8481
8526
  "props": [
8482
8527
  {
8483
8528
  "name": "items",
@@ -8515,6 +8560,12 @@
8515
8560
  "required": false,
8516
8561
  "type": "'start' | 'end'"
8517
8562
  },
8563
+ {
8564
+ "description": "Called once each time the reader scrolls to within 44px (touchTarget) of the start (load older history). It fires again only after they move away. A list too short to scroll calls it once for each new first item or length, until it fills. Prepending items keeps the first visible row where it was on screen.",
8565
+ "name": "onStartReached",
8566
+ "required": false,
8567
+ "type": "() => void"
8568
+ },
8518
8569
  {
8519
8570
  "description": "Cap the list's height; without it, it fills its parent.",
8520
8571
  "name": "maxHeight",
@@ -10926,6 +10977,10 @@
10926
10977
  "md",
10927
10978
  "lg"
10928
10979
  ],
10980
+ "AppShellScroll": [
10981
+ "page",
10982
+ "main"
10983
+ ],
10929
10984
  "BadgeSize": [
10930
10985
  "sm",
10931
10986
  "md"