@duro-app/cli 3.0.0 → 3.2.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 +195 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duro-app/cli",
3
- "version": "3.0.0",
3
+ "version": "3.2.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.",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@modelcontextprotocol/sdk": ">=1.0.0",
48
- "@duro-app/ui": "^3.0.0"
48
+ "@duro-app/ui": "^3.2.0"
49
49
  },
50
50
  "peerDependenciesMeta": {
51
51
  "@duro-app/ui": {
@@ -60,9 +60,9 @@
60
60
  "@types/node": "^24.0.0",
61
61
  "ts-morph": "^26.0.0",
62
62
  "typescript": "^5.7.0",
63
- "@duro-app/eslint-plugin": "^3.0.0",
64
- "@duro-app/tokens": "^3.0.0",
65
- "@duro-app/ui": "^3.0.0"
63
+ "@duro-app/eslint-plugin": "^3.2.0",
64
+ "@duro-app/ui": "^3.2.0",
65
+ "@duro-app/tokens": "^3.2.0"
66
66
  },
67
67
  "scripts": {
68
68
  "registry": "node scripts/build-registry.mjs",
package/registry.json CHANGED
@@ -1743,6 +1743,152 @@
1743
1743
  "props": null,
1744
1744
  "sourcePath": "packages/ui/src/components/Dialog/Dialog.tsx"
1745
1745
  },
1746
+ "DragDrop": {
1747
+ "importPath": "@duro-app/ui",
1748
+ "kind": "compound",
1749
+ "meta": {
1750
+ "anatomy": {
1751
+ "required": [
1752
+ "Root",
1753
+ "Zone",
1754
+ "Item"
1755
+ ]
1756
+ },
1757
+ "description": "Move items between zones with one pointer — mouse, pen and touch through the same pointer-event path (touch holds briefly, then drags; a moving touch stays a scroll). A ghost follows the pointer, the zone under it lights up, and the Root announces picks and drops to screen readers. Dragging is pointer-only by design: keep a button or remove affordance that does the same thing.",
1758
+ "example": "<DragDrop.Root onDrop={({item, target}) => move(item.id, target.zone, target.index)}>\n <DragDrop.Zone id=\"roster\" label=\"Roster\">\n <Cluster gap=\"sm\">\n {people.map((p) => (\n <DragDrop.Item key={p.id} id={p.id} zone=\"roster\" label={p.name} data={p}>\n <Button variant=\"secondary\" size=\"small\" onClick={() => slot(p)}>{p.name}</Button>\n </DragDrop.Item>\n ))}\n </Cluster>\n </DragDrop.Zone>\n <DragDrop.Zone id=\"gates\" label=\"Gates\" orientation=\"horizontal\">\n <Inline gap=\"sm\">\n {gates.map((g) => (\n <DragDrop.Item key={g.id} id={g.id} zone=\"gates\" label={g.name} data={g}>\n <Tag removable onRemove={() => unslot(g)}>{g.name}</Tag>\n </DragDrop.Item>\n ))}\n </Inline>\n </DragDrop.Zone>\n</DragDrop.Root>",
1759
+ "relatedTo": [
1760
+ {
1761
+ "component": "Tag",
1762
+ "kind": "composition",
1763
+ "relationship": "A removable Tag inside an Item gives the drop target its non-drag remove path"
1764
+ },
1765
+ {
1766
+ "component": "ScrollArea",
1767
+ "kind": "contrast",
1768
+ "relationship": "ScrollArea drags a thumb along one axis; DragDrop moves items between zones"
1769
+ }
1770
+ ],
1771
+ "whenNotToUse": [
1772
+ "As the ONLY way to do something — every drag needs a tap/click equivalent (WCAG 2.5.7); this component does not provide one",
1773
+ "Long lists that scroll while dragging — the ghost follows the pointer but zones do not auto-scroll",
1774
+ "Sorting tabular data — sort the Table instead",
1775
+ "React Native — Item renders its children without drag behaviour there"
1776
+ ],
1777
+ "whenToUse": [
1778
+ "Slotting things into places — people into approval gates, cards into columns, files into folders",
1779
+ "Reordering a short row or list when the order is visible and meaningful"
1780
+ ]
1781
+ },
1782
+ "name": "DragDrop",
1783
+ "parts": {
1784
+ "Item": {
1785
+ "name": "Item",
1786
+ "props": [
1787
+ {
1788
+ "name": "id",
1789
+ "required": true,
1790
+ "type": "string"
1791
+ },
1792
+ {
1793
+ "description": "The zone this item currently lives in.",
1794
+ "name": "zone",
1795
+ "required": true,
1796
+ "type": "string"
1797
+ },
1798
+ {
1799
+ "description": "Read to screen readers when picked up or dropped.",
1800
+ "name": "label",
1801
+ "required": true,
1802
+ "type": "string"
1803
+ },
1804
+ {
1805
+ "description": "Carried to onDrop untouched.",
1806
+ "name": "data",
1807
+ "required": false,
1808
+ "type": "T"
1809
+ },
1810
+ {
1811
+ "description": "What follows the pointer; defaults to the children.",
1812
+ "name": "preview",
1813
+ "required": false,
1814
+ "type": "ReactNode"
1815
+ },
1816
+ {
1817
+ "default": "false",
1818
+ "name": "disabled",
1819
+ "required": false,
1820
+ "type": "boolean"
1821
+ },
1822
+ {
1823
+ "name": "children",
1824
+ "required": true,
1825
+ "type": "ReactNode"
1826
+ }
1827
+ ],
1828
+ "sourcePath": "packages/ui/src/components/DragDrop/DragDrop.tsx"
1829
+ },
1830
+ "Root": {
1831
+ "name": "Root",
1832
+ "props": [
1833
+ {
1834
+ "description": "Called when an item is released over a zone that accepts it. Reordering inside the item's own zone arrives here too, with the new index.",
1835
+ "name": "onDrop",
1836
+ "required": true,
1837
+ "type": "(event: DragDropEvent<T>) => void"
1838
+ },
1839
+ {
1840
+ "description": "Overrides the default screen-reader announcements.",
1841
+ "name": "announce",
1842
+ "required": false,
1843
+ "type": "(event: {kind: 'pick' | 'drop' | 'cancel'; item: string; zone?: string}) => string"
1844
+ },
1845
+ {
1846
+ "name": "children",
1847
+ "required": true,
1848
+ "type": "ReactNode"
1849
+ }
1850
+ ],
1851
+ "sourcePath": "packages/ui/src/components/DragDrop/DragDrop.tsx"
1852
+ },
1853
+ "Zone": {
1854
+ "name": "Zone",
1855
+ "props": [
1856
+ {
1857
+ "name": "id",
1858
+ "required": true,
1859
+ "type": "string"
1860
+ },
1861
+ {
1862
+ "description": "Read to screen readers when an item is dropped here.",
1863
+ "name": "label",
1864
+ "required": true,
1865
+ "type": "string"
1866
+ },
1867
+ {
1868
+ "default": "'horizontal'",
1869
+ "description": "Which axis items flow along; decides how the insertion index is read from the pointer.",
1870
+ "name": "orientation",
1871
+ "required": false,
1872
+ "type": "'horizontal' | 'vertical'"
1873
+ },
1874
+ {
1875
+ "description": "Refuse an item; the zone then never lights up for it.",
1876
+ "name": "accepts",
1877
+ "required": false,
1878
+ "type": "(item: DragDropItemData<T>) => boolean"
1879
+ },
1880
+ {
1881
+ "name": "children",
1882
+ "required": true,
1883
+ "type": "ReactNode"
1884
+ }
1885
+ ],
1886
+ "sourcePath": "packages/ui/src/components/DragDrop/DragDrop.tsx"
1887
+ }
1888
+ },
1889
+ "props": null,
1890
+ "sourcePath": "packages/ui/src/components/DragDrop/DragDrop.tsx"
1891
+ },
1746
1892
  "Drawer": {
1747
1893
  "importPath": "@duro-app/ui",
1748
1894
  "kind": "compound",
@@ -2294,8 +2440,8 @@
2294
2440
  "importPath": "@duro-app/ui",
2295
2441
  "kind": "component",
2296
2442
  "meta": {
2297
- "description": "CSS grid layout. Fixed column count (1-6), responsive auto-fit via minColumnWidth, or a named split layout (list/detail, nav/content) that collapses below the md breakpoint.",
2298
- "example": "// Split: list ≥ 240px beside a detail pane, one column below md\n<Grid layout=\"split\" gap=\"lg\">\n <List.Root>…</List.Root>\n <Panel.Root>…</Panel.Root>\n</Grid>\n\n// Responsive: columns auto-fit based on min width\n<Grid minColumnWidth=\"280px\" gap=\"md\">\n <Card>A</Card>\n <Card>B</Card>\n <Card>C</Card>\n</Grid>\n\n// Fixed: always 3 columns\n<Grid columns={3} gap=\"md\">\n <Card>A</Card>\n <Card>B</Card>\n <Card>C</Card>\n</Grid>",
2443
+ "description": "Grid layout. Columns are a count (1-6), a list of weights ([1, 2] for one-third / two-thirds), responsive auto-fit via minColumnWidth, or a named split layout (list/detail, nav/content) that collapses to one column on the width of its own container, so it is safe to nest and to place beside a DetailPanel. Weights rather than CSS template strings, so the same props render as CSS grid on web and as a wrapping flex row on native.",
2444
+ "example": "// Split: list ≥ 240px beside a detail pane, one column below md\n<Grid layout=\"split\" gap=\"lg\">\n <List.Root>…</List.Root>\n <Panel.Root>…</Panel.Root>\n</Grid>\n\n// Responsive: columns auto-fit based on min width\n<Grid minColumnWidth=\"280px\" gap=\"md\">\n <Card>A</Card>\n <Card>B</Card>\n <Card>C</Card>\n</Grid>\n\n// Fixed: always 3 columns\n<Grid columns={3} gap=\"md\">\n <Card>A</Card>\n <Card>B</Card>\n <Card>C</Card>\n</Grid>\n\n// Weighted: a one-third / two-thirds split (works on native too)\n<Grid columns={[1, 2]} gap=\"md\">\n <Card>Sidebar</Card>\n <Card>Content</Card>\n</Grid>",
2299
2445
  "relatedTo": [
2300
2446
  {
2301
2447
  "component": "Stack",
@@ -2315,7 +2461,7 @@
2315
2461
  "whenToUse": [
2316
2462
  "Card grids, dashboard layouts, multi-column forms",
2317
2463
  "Responsive layouts that should auto-adjust column count",
2318
- "A list/detail or nav/content screen — layout=\"split\" | \"split-wide\", never a hand-rolled gridTemplateColumns with its own @media"
2464
+ "A list/detail or nav/content screen — layout=\"split\" | \"split-wide\", never a hand-rolled gridTemplateColumns with its own @media; a split inside a split is fine, each collapses on its own room"
2319
2465
  ]
2320
2466
  },
2321
2467
  "name": "Grid",
@@ -2337,17 +2483,19 @@
2337
2483
  ]
2338
2484
  },
2339
2485
  {
2486
+ "description": "A column count (equal columns) or weights: `[1, 2]` gives a one-third / two-thirds split. Weights are the portable form of a track list — a CSS template string would be silently ignored on native.",
2340
2487
  "name": "columns",
2341
2488
  "required": false,
2342
- "type": "1 | 2 | 3 | 4 | 5 | 6"
2489
+ "type": "GridColumns"
2343
2490
  },
2344
2491
  {
2492
+ "description": "Responsive auto-fit: as many columns of at least this width as fit. Wins over `columns` when both are set. On native this approximates to cells of that minimum width that grow and wrap.",
2345
2493
  "name": "minColumnWidth",
2346
2494
  "required": false,
2347
2495
  "type": "string"
2348
2496
  },
2349
2497
  {
2350
- "description": "A named responsive layout. `split` is list/detail (1:2, list ≥ 240px), `split-wide` is nav/content (1:3, nav ≥ 280px); both collapse to one column below the `md` breakpoint. Wins over `columns` / `minColumnWidth`.",
2498
+ "description": "A named responsive layout. `split` is list/detail (1:2, list ≥ 240px), `split-wide` is nav/content (1:3, nav ≥ 280px). Each collapses to one column on the width of its OWN container — `split` below `sm` (640px), `split-wide` below `md` (768px) — so a split nested inside another split, or beside an open DetailPanel, collapses when it runs out of room rather than when the window does. Wins over `columns` / `minColumnWidth`.",
2351
2499
  "name": "layout",
2352
2500
  "required": false,
2353
2501
  "type": "GridLayout"
@@ -5876,6 +6024,46 @@
5876
6024
  "props": [],
5877
6025
  "sourcePath": "packages/ui/src/components/Table/useDataTable.ts"
5878
6026
  },
6027
+ "useDragDrop": {
6028
+ "importPath": "@duro-app/ui",
6029
+ "kind": "hook",
6030
+ "meta": {
6031
+ "anatomy": {
6032
+ "required": [
6033
+ "Root",
6034
+ "Zone",
6035
+ "Item"
6036
+ ]
6037
+ },
6038
+ "description": "Move items between zones with one pointer — mouse, pen and touch through the same pointer-event path (touch holds briefly, then drags; a moving touch stays a scroll). A ghost follows the pointer, the zone under it lights up, and the Root announces picks and drops to screen readers. Dragging is pointer-only by design: keep a button or remove affordance that does the same thing.",
6039
+ "example": "<DragDrop.Root onDrop={({item, target}) => move(item.id, target.zone, target.index)}>\n <DragDrop.Zone id=\"roster\" label=\"Roster\">\n <Cluster gap=\"sm\">\n {people.map((p) => (\n <DragDrop.Item key={p.id} id={p.id} zone=\"roster\" label={p.name} data={p}>\n <Button variant=\"secondary\" size=\"small\" onClick={() => slot(p)}>{p.name}</Button>\n </DragDrop.Item>\n ))}\n </Cluster>\n </DragDrop.Zone>\n <DragDrop.Zone id=\"gates\" label=\"Gates\" orientation=\"horizontal\">\n <Inline gap=\"sm\">\n {gates.map((g) => (\n <DragDrop.Item key={g.id} id={g.id} zone=\"gates\" label={g.name} data={g}>\n <Tag removable onRemove={() => unslot(g)}>{g.name}</Tag>\n </DragDrop.Item>\n ))}\n </Inline>\n </DragDrop.Zone>\n</DragDrop.Root>",
6040
+ "relatedTo": [
6041
+ {
6042
+ "component": "Tag",
6043
+ "kind": "composition",
6044
+ "relationship": "A removable Tag inside an Item gives the drop target its non-drag remove path"
6045
+ },
6046
+ {
6047
+ "component": "ScrollArea",
6048
+ "kind": "contrast",
6049
+ "relationship": "ScrollArea drags a thumb along one axis; DragDrop moves items between zones"
6050
+ }
6051
+ ],
6052
+ "whenNotToUse": [
6053
+ "As the ONLY way to do something — every drag needs a tap/click equivalent (WCAG 2.5.7); this component does not provide one",
6054
+ "Long lists that scroll while dragging — the ghost follows the pointer but zones do not auto-scroll",
6055
+ "Sorting tabular data — sort the Table instead",
6056
+ "React Native — Item renders its children without drag behaviour there"
6057
+ ],
6058
+ "whenToUse": [
6059
+ "Slotting things into places — people into approval gates, cards into columns, files into folders",
6060
+ "Reordering a short row or list when the order is visible and meaningful"
6061
+ ]
6062
+ },
6063
+ "name": "useDragDrop",
6064
+ "props": [],
6065
+ "sourcePath": "packages/ui/src/components/DragDrop/DragDrop.tsx"
6066
+ },
5879
6067
  "usePortalMount": {
5880
6068
  "importPath": "@duro-app/ui",
5881
6069
  "kind": "hook",
@@ -6218,7 +6406,7 @@
6218
6406
  "page-with-sidenav": {
6219
6407
  "export": "PageWithSideNavRecipe",
6220
6408
  "meta": {
6221
- "description": "Page with a side navigation rail: SideNav in the narrow column of Grid layout=\"split-wide\", the routed content in the wide one; the rail stacks above the content below the md breakpoint.",
6409
+ "description": "Page with a side navigation rail: SideNav in the narrow column of Grid layout=\"split-wide\", the routed content in the wide one; the rail stacks above the content when the page is narrower than md.",
6222
6410
  "example": "<PageWithSideNavRecipe />",
6223
6411
  "whenNotToUse": [
6224
6412
  "Three or four destinations — Tabs inside a PageShell read better than a rail",
@@ -6284,7 +6472,7 @@
6284
6472
  "split-pane": {
6285
6473
  "export": "SplitPaneRecipe",
6286
6474
  "meta": {
6287
- "description": "List/detail split: a selectable List beside a Panel showing the selection, on Grid layout=\"split\" (list ≥ 240px, one column below the md breakpoint).",
6475
+ "description": "List/detail split: a selectable List beside a Panel showing the selection, on Grid layout=\"split\" (list ≥ 240px, one column when the board is narrower than sm).",
6288
6476
  "example": "<SplitPaneRecipe />",
6289
6477
  "whenNotToUse": [
6290
6478
  "The detail is a short-lived inspection — use DetailPanel over the list instead",