@agentero/design-system 0.8.2 → 0.8.3

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.
@@ -576,13 +576,13 @@
576
576
  <header>
577
577
  <div class="wrap">
578
578
  <h1>Manifest Debugger</h1>
579
- <div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><span class="filter-pill ok" aria-disabled="true">9 components ok</span><span class="filter-pill ok" aria-disabled="true">104 stories ok</span></div>
579
+ <div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><span class="filter-pill ok" aria-disabled="true">9 components ok</span><span class="filter-pill ok" aria-disabled="true">109 stories ok</span></div>
580
580
  </div>
581
581
  </header>
582
582
  <main>
583
583
  <div class="wrap">
584
584
  <div class="note ok" style="margin-bottom: 16px;">
585
- Using <code>react-docgen-typescript</code>. Generation took <strong>2.2s</strong>.
585
+ Using <code>react-docgen-typescript</code>. Generation took <strong>2.4s</strong>.
586
586
  </div>
587
587
  <h2 class="section-title">Components</h2>
588
588
  <div class="grid" role="list">
@@ -1153,15 +1153,15 @@ size?: AlertSizeType = sm</code></pre>
1153
1153
  <div class="title">
1154
1154
  <h2><span class="status-dot dot-ok"></span> Avatar</h2>
1155
1155
  <div class="badges">
1156
- <label for="c-1-components-avatar-props" class="badge ok as-toggle">7 prop types</label>
1156
+ <label for="c-1-components-avatar-props" class="badge ok as-toggle">8 prop types</label>
1157
1157
 
1158
- <label for="c-1-components-avatar-stories" class="badge ok as-toggle">17 stories</label>
1158
+ <label for="c-1-components-avatar-stories" class="badge ok as-toggle">22 stories</label>
1159
1159
 
1160
1160
  </div>
1161
1161
  </div>
1162
1162
  <div class="meta" title="./src/avatar/avatar.stories.tsx">components-avatar · ./src/avatar/avatar.stories.tsx</div>
1163
1163
 
1164
- <div class="hint">Avatar displays a user&#39;s profile image, initials, or a fallback icon. Use for user identification in lists, headers, cards, and comment threads. Supports multiple shapes (`circle`, `square`, `pillow`, `pentagon`) and sizes from `xs` (24px) to `4xl` (128px).</div>
1164
+ <div class="hint">Avatar displays a user&#39;s profile image, initials, or a fallback icon. Use for user identification in lists, headers, cards, and comment threads. Supports multiple shapes (`circle`, `square`, `pillow`, `pentagon`), content types (`photo`, `initials`, `isotype`), and sizes from `xs` (24px) to `4xl` (128px).</div>
1165
1165
 
1166
1166
  </div>
1167
1167
 
@@ -1180,7 +1180,7 @@ size?: AlertSizeType = sm</code></pre>
1180
1180
  <div class="note ok">
1181
1181
  <div class="row">
1182
1182
  <span class="ex-name">Prop types <small>(react-docgen-typescript)</small></span>
1183
- <span class="badge ok">7 prop types</span>
1183
+ <span class="badge ok">8 prop types</span>
1184
1184
  </div>
1185
1185
  <pre><code>Component: src/avatar/avatar.tsx::Avatar</code></pre>
1186
1186
  <pre><code>Props:</code></pre>
@@ -1219,6 +1219,15 @@ size?: &quot;sm&quot; | &quot;md&quot; | &quot;xs&quot; | &quot;lg&quot; | &quot
1219
1219
  */
1220
1220
  src?: string
1221
1221
 
1222
+ /**
1223
+ * Content type the avatar represents. Defaults to `&#39;photo&#39;`.
1224
+ * - `photo` — a user&#39;s profile photograph filling the avatar shape
1225
+ * - `initials` — text initials standing in for a missing photo
1226
+ * - `isotype` — a brand or organization icon rendered smaller than the avatar
1227
+ * so it sits centered inside the shape instead of filling it
1228
+ */
1229
+ type?: &quot;isotype&quot; | &quot;photo&quot; | &quot;initials&quot;
1230
+
1222
1231
  /**
1223
1232
  * Shape of the avatar container. Defaults to `&#39;circle&#39;`.
1224
1233
  * - `circle` — standard round avatar for user photos
@@ -1249,7 +1258,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1249
1258
  </div>
1250
1259
  <div>Default avatar with fallback initials</div>
1251
1260
  <div class="hint">The default avatar with fallback initials. Renders as a medium circle when no image source is provided.</div>
1252
- <pre><code>const Default = () =&gt; &lt;Avatar fallback=&quot;JD&quot; size=&quot;md&quot; variant=&quot;circle&quot; /&gt;;</code></pre>
1261
+ <pre><code>const Default = () =&gt; &lt;Avatar fallback=&quot;JD&quot; size=&quot;md&quot; variant=&quot;circle&quot; type=&quot;photo&quot; /&gt;;</code></pre>
1253
1262
  </div>
1254
1263
  <div class="note ok">
1255
1264
  <div class="row">
@@ -1262,6 +1271,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1262
1271
  fallback=&quot;JD&quot;
1263
1272
  size=&quot;md&quot;
1264
1273
  variant=&quot;circle&quot;
1274
+ type=&quot;photo&quot;
1265
1275
  src=&quot;https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&amp;w=256&amp;h=256&amp;q=70&amp;crop=focalpoint&amp;fp-x=0.5&amp;fp-y=0.3&amp;fp-z=1&amp;fit=crop&quot;
1266
1276
  alt=&quot;Alex Morgan&quot; /&gt;;</code></pre>
1267
1277
  </div>
@@ -1276,6 +1286,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1276
1286
  fallback=&quot;AM&quot;
1277
1287
  size=&quot;md&quot;
1278
1288
  variant=&quot;circle&quot;
1289
+ type=&quot;photo&quot;
1279
1290
  src=&quot;https://broken-url.example/photo.jpg&quot; /&gt;;</code></pre>
1280
1291
  </div>
1281
1292
  <div class="note ok">
@@ -1285,7 +1296,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1285
1296
  </div>
1286
1297
  <div>Circle-shaped avatar (default)</div>
1287
1298
  <div class="hint">The circle variant is the default shape, ideal for user profile photos.</div>
1288
- <pre><code>const Circle = () =&gt; &lt;Avatar fallback=&quot;CR&quot; size=&quot;md&quot; variant=&quot;circle&quot; /&gt;;</code></pre>
1299
+ <pre><code>const Circle = () =&gt; &lt;Avatar fallback=&quot;CR&quot; size=&quot;md&quot; variant=&quot;circle&quot; type=&quot;photo&quot; /&gt;;</code></pre>
1289
1300
  </div>
1290
1301
  <div class="note ok">
1291
1302
  <div class="row">
@@ -1294,7 +1305,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1294
1305
  </div>
1295
1306
  <div>Square-shaped avatar for workspaces</div>
1296
1307
  <div class="hint">The square variant uses a rounded rectangle, suitable for workspace, team, or organization icons.</div>
1297
- <pre><code>const Square = () =&gt; &lt;Avatar fallback=&quot;WS&quot; size=&quot;md&quot; variant=&quot;square&quot; /&gt;;</code></pre>
1308
+ <pre><code>const Square = () =&gt; &lt;Avatar fallback=&quot;WS&quot; size=&quot;md&quot; variant=&quot;square&quot; type=&quot;photo&quot; /&gt;;</code></pre>
1298
1309
  </div>
1299
1310
  <div class="note ok">
1300
1311
  <div class="row">
@@ -1303,7 +1314,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1303
1314
  </div>
1304
1315
  <div>Pillow-shaped avatar with organic squircle</div>
1305
1316
  <div class="hint">The pillow variant uses a soft, organic squircle shape for a friendly and distinctive appearance.</div>
1306
- <pre><code>const Pillow = () =&gt; &lt;Avatar fallback=&quot;PL&quot; size=&quot;md&quot; variant=&quot;pillow&quot; /&gt;;</code></pre>
1317
+ <pre><code>const Pillow = () =&gt; &lt;Avatar fallback=&quot;PL&quot; size=&quot;md&quot; variant=&quot;pillow&quot; type=&quot;photo&quot; /&gt;;</code></pre>
1307
1318
  </div>
1308
1319
  <div class="note ok">
1309
1320
  <div class="row">
@@ -1312,7 +1323,97 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1312
1323
  </div>
1313
1324
  <div>Pentagon-shaped avatar for unique identity</div>
1314
1325
  <div class="hint">The pentagon variant uses a five-sided mask for a unique visual identity. Note: the border is hidden in this variant due to the mask shape.</div>
1315
- <pre><code>const Pentagon = () =&gt; &lt;Avatar fallback=&quot;PT&quot; size=&quot;md&quot; variant=&quot;pentagon&quot; /&gt;;</code></pre>
1326
+ <pre><code>const Pentagon = () =&gt; &lt;Avatar fallback=&quot;PT&quot; size=&quot;md&quot; variant=&quot;pentagon&quot; type=&quot;photo&quot; /&gt;;</code></pre>
1327
+ </div>
1328
+ <div class="note ok">
1329
+ <div class="row">
1330
+ <span class="ex-name">Type Photo</span>
1331
+ <span class="badge ok">story ok</span>
1332
+ </div>
1333
+ <div>Photo type fills the avatar shape edge-to-edge</div>
1334
+ <div class="hint">The `photo` type is the default. The image fills the avatar shape edge-to-edge, which is ideal for user profile photographs.</div>
1335
+ <pre><code>const TypePhoto = () =&gt; &lt;Avatar
1336
+ fallback=&quot;AM&quot;
1337
+ size=&quot;md&quot;
1338
+ variant=&quot;circle&quot;
1339
+ type=&quot;photo&quot;
1340
+ src=&quot;https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&amp;w=256&amp;h=256&amp;q=70&amp;crop=focalpoint&amp;fp-x=0.5&amp;fp-y=0.3&amp;fp-z=1&amp;fit=crop&quot;
1341
+ alt=&quot;Alex Morgan&quot; /&gt;;</code></pre>
1342
+ </div>
1343
+ <div class="note ok">
1344
+ <div class="row">
1345
+ <span class="ex-name">Type Initials</span>
1346
+ <span class="badge ok">story ok</span>
1347
+ </div>
1348
+ <div>Initials type for users without a profile photo</div>
1349
+ <div class="hint">The `initials` type is intended when no image is available and the avatar stands in for a user with their initials. The fallback text is centered within the avatar shape.</div>
1350
+ <pre><code>const TypeInitials = () =&gt; &lt;Avatar fallback=&quot;JD&quot; size=&quot;md&quot; variant=&quot;circle&quot; type=&quot;initials&quot; /&gt;;</code></pre>
1351
+ </div>
1352
+ <div class="note ok">
1353
+ <div class="row">
1354
+ <span class="ex-name">Type Isotype</span>
1355
+ <span class="badge ok">story ok</span>
1356
+ </div>
1357
+ <div>Isotype type centers a brand icon inside the shape</div>
1358
+ <div class="hint">The `isotype` type renders the image smaller than the avatar shape so a brand or organization icon sits centered inside the container rather than filling it. Use for workspace, team, or company avatars where a logo should remain legible inside the bounding shape.</div>
1359
+ <pre><code>const TypeIsotype = () =&gt; &lt;Avatar
1360
+ fallback=&quot;FG&quot;
1361
+ size=&quot;md&quot;
1362
+ variant=&quot;square&quot;
1363
+ type=&quot;isotype&quot;
1364
+ src=&quot;https://cdn.simpleicons.org/figma&quot;
1365
+ alt=&quot;Figma&quot; /&gt;;</code></pre>
1366
+ </div>
1367
+ <div class="note ok">
1368
+ <div class="row">
1369
+ <span class="ex-name">All Types</span>
1370
+ <span class="badge ok">story ok</span>
1371
+ </div>
1372
+ <div>Visual comparison of all avatar content types</div>
1373
+ <div class="hint">All content types shown side by side: `photo` fills the shape, `initials` centers text, and `isotype` shrinks a brand icon inside the bounding shape.</div>
1374
+ <pre><code>const AllTypes = () =&gt; (
1375
+ &lt;div style={{ display: &#39;flex&#39;, alignItems: &#39;center&#39;, gap: &#39;1rem&#39; }}&gt;
1376
+ &lt;Avatar
1377
+ size=&quot;lg&quot;
1378
+ type=&quot;photo&quot;
1379
+ src=&quot;https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&amp;w=256&amp;h=256&amp;q=70&amp;crop=focalpoint&amp;fp-x=0.5&amp;fp-y=0.3&amp;fp-z=1&amp;fit=crop&quot;
1380
+ alt=&quot;Alex Morgan&quot;
1381
+ fallback=&quot;AM&quot;
1382
+ /&gt;
1383
+ &lt;Avatar size=&quot;lg&quot; type=&quot;initials&quot; fallback=&quot;JD&quot; /&gt;
1384
+ &lt;Avatar
1385
+ size=&quot;lg&quot;
1386
+ type=&quot;isotype&quot;
1387
+ variant=&quot;square&quot;
1388
+ src=&quot;https://cdn.simpleicons.org/figma&quot;
1389
+ alt=&quot;Figma&quot;
1390
+ fallback=&quot;FG&quot;
1391
+ /&gt;
1392
+ &lt;/div&gt;
1393
+ );</code></pre>
1394
+ </div>
1395
+ <div class="note ok">
1396
+ <div class="row">
1397
+ <span class="ex-name">All Sizes Isotype</span>
1398
+ <span class="badge ok">story ok</span>
1399
+ </div>
1400
+ <div>Isotype scaling across all avatar sizes</div>
1401
+ <div class="hint">The isotype icon scales proportionally smaller than the avatar shape at every size, keeping a consistent inset around the logo from `xs` (24px) to `4xl` (128px).</div>
1402
+ <pre><code>const AllSizesIsotype = () =&gt; (
1403
+ &lt;div style={{ display: &#39;flex&#39;, alignItems: &#39;center&#39;, gap: &#39;1rem&#39; }}&gt;
1404
+ {([&#39;xs&#39;, &#39;sm&#39;, &#39;md&#39;, &#39;lg&#39;, &#39;xl&#39;, &#39;2xl&#39;, &#39;3xl&#39;, &#39;4xl&#39;] as const).map(size =&gt; (
1405
+ &lt;Avatar
1406
+ key={size}
1407
+ size={size}
1408
+ type=&quot;isotype&quot;
1409
+ variant=&quot;square&quot;
1410
+ src=&quot;https://cdn.simpleicons.org/figma&quot;
1411
+ alt=&quot;Figma&quot;
1412
+ fallback=&quot;FG&quot;
1413
+ /&gt;
1414
+ ))}
1415
+ &lt;/div&gt;
1416
+ );</code></pre>
1316
1417
  </div>
1317
1418
  <div class="note ok">
1318
1419
  <div class="row">
@@ -1321,7 +1422,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1321
1422
  </div>
1322
1423
  <div>Extra-small 24px avatar</div>
1323
1424
  <div class="hint">Extra-small avatar (24px) for dense lists and inline indicators.</div>
1324
- <pre><code>const SizeXs = () =&gt; &lt;Avatar fallback=&quot;XS&quot; size=&quot;xs&quot; variant=&quot;circle&quot; /&gt;;</code></pre>
1425
+ <pre><code>const SizeXs = () =&gt; &lt;Avatar fallback=&quot;XS&quot; size=&quot;xs&quot; variant=&quot;circle&quot; type=&quot;photo&quot; /&gt;;</code></pre>
1325
1426
  </div>
1326
1427
  <div class="note ok">
1327
1428
  <div class="row">
@@ -1330,7 +1431,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1330
1431
  </div>
1331
1432
  <div>Small 32px avatar</div>
1332
1433
  <div class="hint">Small avatar (32px) for compact layouts and table rows.</div>
1333
- <pre><code>const SizeSm = () =&gt; &lt;Avatar fallback=&quot;SM&quot; size=&quot;sm&quot; variant=&quot;circle&quot; /&gt;;</code></pre>
1434
+ <pre><code>const SizeSm = () =&gt; &lt;Avatar fallback=&quot;SM&quot; size=&quot;sm&quot; variant=&quot;circle&quot; type=&quot;photo&quot; /&gt;;</code></pre>
1334
1435
  </div>
1335
1436
  <div class="note ok">
1336
1437
  <div class="row">
@@ -1339,7 +1440,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1339
1440
  </div>
1340
1441
  <div>Large 48px avatar</div>
1341
1442
  <div class="hint">Large avatar (48px) for profile sections and detail views.</div>
1342
- <pre><code>const SizeLg = () =&gt; &lt;Avatar fallback=&quot;LG&quot; size=&quot;lg&quot; variant=&quot;circle&quot; /&gt;;</code></pre>
1443
+ <pre><code>const SizeLg = () =&gt; &lt;Avatar fallback=&quot;LG&quot; size=&quot;lg&quot; variant=&quot;circle&quot; type=&quot;photo&quot; /&gt;;</code></pre>
1343
1444
  </div>
1344
1445
  <div class="note ok">
1345
1446
  <div class="row">
@@ -1348,7 +1449,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1348
1449
  </div>
1349
1450
  <div>Extra-large 64px avatar</div>
1350
1451
  <div class="hint">Extra-large avatar (64px) for hero sections and prominent display.</div>
1351
- <pre><code>const SizeXl = () =&gt; &lt;Avatar fallback=&quot;XL&quot; size=&quot;xl&quot; variant=&quot;circle&quot; /&gt;;</code></pre>
1452
+ <pre><code>const SizeXl = () =&gt; &lt;Avatar fallback=&quot;XL&quot; size=&quot;xl&quot; variant=&quot;circle&quot; type=&quot;photo&quot; /&gt;;</code></pre>
1352
1453
  </div>
1353
1454
  <div class="note ok">
1354
1455
  <div class="row">
@@ -1357,7 +1458,7 @@ variant?: &quot;circle&quot; | &quot;square&quot; | &quot;pillow&quot; | &quot;p
1357
1458
  </div>
1358
1459
  <div>Colorized avatar based on user name</div>
1359
1460
  <div class="hint">The `colorize` prop deterministically maps a string (typically a user name) to a color from the palette, applying a tinted background and matching text color. Useful for distinguishing users in lists without profile photos.</div>
1360
- <pre><code>const Colorized = () =&gt; &lt;Avatar fallback=&quot;JD&quot; size=&quot;md&quot; variant=&quot;circle&quot; colorize=&quot;jane doe&quot; /&gt;;</code></pre>
1461
+ <pre><code>const Colorized = () =&gt; &lt;Avatar fallback=&quot;JD&quot; size=&quot;md&quot; variant=&quot;circle&quot; type=&quot;photo&quot; colorize=&quot;jane doe&quot; /&gt;;</code></pre>
1361
1462
  </div>
1362
1463
  <div class="note ok">
1363
1464
  <div class="row">
@@ -1 +1 @@
1
- {"v":0,"components":{"components-alert":{"id":"components-alert","name":"Alert","path":"./src/alert/alert.stories.tsx","stories":[{"id":"components-alert--default","name":"Default","snippet":"const Default = () => <Alert\n color=\"neutral\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Args-controlled playground. Toggle `color`, `size`, `ghost`, `hasIcon`, and `onDismiss` from the Controls panel to explore every visual combination.","summary":"Default args playground for Alert"},{"id":"components-alert--neutral","name":"Neutral","snippet":"const Neutral = () => <Alert\n color=\"neutral\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Neutral color is the default and carries no strong semantic signal — use it for generic inline information.","summary":"Neutral color (default)"},{"id":"components-alert--success","name":"Success","snippet":"const Success = () => <Alert\n color=\"success\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Success color confirms a positive outcome — saved record, completed task, healthy state.","summary":"Success color for positive outcomes"},{"id":"components-alert--danger","name":"Danger","snippet":"const Danger = () => <Alert\n color=\"danger\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Danger color flags errors and destructive outcomes that require the user's attention.","summary":"Danger color for errors and destructive outcomes"},{"id":"components-alert--warning","name":"Warning","snippet":"const Warning = () => <Alert\n color=\"warning\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Warning color signals caution — the user should review before proceeding.","summary":"Warning color for cautionary feedback"},{"id":"components-alert--info","name":"Info","snippet":"const Info = () => <Alert\n color=\"info\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Info color highlights tips, hints, or secondary informational content.","summary":"Info color for informational highlights"},{"id":"components-alert--creative","name":"Creative","snippet":"const Creative = () => <Alert\n color=\"creative\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Creative color uses a brand-aligned purple accent for marketing or onboarding moments.","summary":"Creative brand accent color"},{"id":"components-alert--dynamic","name":"Dynamic","snippet":"const Dynamic = () => <Alert\n color=\"dynamic\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Dynamic color uses a brand-aligned orange accent for activity or momentum-focused content.","summary":"Dynamic brand accent color"},{"id":"components-alert--playful","name":"Playful","snippet":"const Playful = () => <Alert\n color=\"playful\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Playful color uses a brand-aligned pink accent for lighter or celebratory content.","summary":"Playful brand accent color"},{"id":"components-alert--ghost","name":"Ghost","snippet":"const Ghost = () => <Alert\n color=\"danger\"\n size=\"sm\"\n ghost\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Ghost mode removes the background and padding so the alert blends inline with surrounding text (e.g., form field errors). Colors switch to the ghost token ramp for lower visual weight.","summary":"Ghost mode for inline, low-emphasis alerts"},{"id":"components-alert--small-size","name":"Small Size","snippet":"const SmallSize = () => <Alert\n color=\"neutral\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Small size (default) uses compact padding and 14/12px typography — suitable for inline alerts inside forms, tables, or cards.","summary":"Small size (default, compact)"},{"id":"components-alert--medium-size","name":"Medium Size","snippet":"const MediumSize = () => <Alert\n color=\"neutral\"\n size=\"md\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Medium size uses larger padding and 18/14px typography — suitable for standalone alerts in empty states, modals, or dedicated feedback regions.","summary":"Medium size (prominent, standalone)"},{"id":"components-alert--with-dismiss","name":"With Dismiss","snippet":"const WithDismiss = () => <Alert color=\"warning\" size=\"sm\" ghost={false} hasIcon onDismiss={fn()}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Dismissible alert. Providing `onDismiss` shows an icon-only close button with `aria-label=\"Dismiss\"` that inherits the alert's color.","summary":"Alert with a dismiss button"},{"id":"components-alert--with-actions","name":"With Actions","snippet":"const WithActions = () => <Alert\n color=\"info\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Update available</Alert.Title>\n <Alert.Paragraph>Reload to apply the latest version.</Alert.Paragraph>\n </Alert.Content>\n <Alert.Actions>\n <Alert.Button onClick={() => {}}>Reload</Alert.Button>\n </Alert.Actions>\n</Alert>;","description":"Alert with a trailing action pinned to the right edge. Use `Alert.Actions` + `Alert.Button` for the common \"message + action\" pattern.","summary":"Alert with a trailing action button"},{"id":"components-alert--with-dismiss-and-action","name":"With Dismiss And Action","snippet":"const WithDismissAndAction = () => <Alert\n color=\"warning\"\n size=\"md\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Session expiring</Alert.Title>\n <Alert.Paragraph>Renew to continue editing.</Alert.Paragraph>\n </Alert.Content>\n <Alert.Actions>\n <Alert.Button onClick={() => {}}>Renew session</Alert.Button>\n </Alert.Actions>\n</Alert>;","description":"Alert combining a dismiss button with a trailing action. Dismiss is pinned to the right edge after the actions.","summary":"Alert with both dismiss and action"},{"id":"components-alert--without-icon","name":"Without Icon","snippet":"const WithoutIcon = () => <Alert\n color=\"info\"\n size=\"sm\"\n ghost={false}\n hasIcon={false}\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Alert rendered without the built-in color icon. Use `hasIcon={false}` when the surrounding context already conveys the semantic intent.","summary":"Alert without the default icon"},{"id":"components-alert--with-custom-icon","name":"With Custom Icon","snippet":"const WithCustomIcon = () => <Alert\n color=\"creative\"\n size=\"sm\"\n ghost={false}\n hasIcon\n icon={IconLightbulb}\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Alert with a caller-supplied icon that replaces the default color icon. The custom icon receives the slot-computed className so color tokens still apply.","summary":"Alert with a custom icon override"},{"id":"components-alert--with-paragraph-html","name":"With Paragraph Html","snippet":"const WithParagraphHtml = () => <Alert\n color=\"success\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Formatted content</Alert.Title>\n <Alert.ParagraphHtml\n html=\"Review the <strong>terms</strong> or <a href='https://example.com'>read the docs</a>.\" />\n </Alert.Content>\n</Alert>;","description":"Alert rendering a paragraph from pre-sanitized HTML via `Alert.ParagraphHtml`. The caller is responsible for sanitizing the HTML string before passing it in.","summary":"Alert paragraph rendered from HTML"},{"id":"components-alert--with-pictograms","name":"With Pictograms","snippet":"const WithPictograms = () => <Alert\n color=\"info\"\n size=\"md\"\n ghost={false}\n hasIcon={false}\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Pictograms>\n <svg viewBox=\"0 0 64 64\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden>\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.15\" />\n <circle cx=\"32\" cy=\"32\" r=\"14\" fill=\"currentColor\" />\n </svg>\n </Alert.Pictograms>\n <Alert.Content>\n <Alert.Title>Pictogram example</Alert.Title>\n <Alert.Paragraph>Pictograms scale to 64×64px regardless of the configured size.\n </Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Alert with a 64×64 pictogram in place of the inline icon. Use `Alert.Pictograms` when the message benefits from a richer illustration.","summary":"Alert with a pictogram illustration"},{"id":"components-alert--only-paragraph","name":"Only Paragraph","snippet":"const OnlyParagraph = () => <Alert\n color=\"neutral\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Paragraph>This field is required.</Alert.Paragraph>\n</Alert>;","description":"Alert rendered with only a paragraph — no title. The root omits `aria-labelledby` since there is no title to reference.","summary":"Alert with only a paragraph body"},{"id":"components-alert--with-actions-below","name":"With Actions Below","snippet":"const WithActionsBelow = () => <Alert\n color=\"success\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Upload complete</Alert.Title>\n <Alert.Paragraph>12 documents were added to the policy.</Alert.Paragraph>\n <div>\n <Alert.Button onClick={() => {}}>View documents</Alert.Button>\n </div>\n </Alert.Content>\n</Alert>;","description":"Action button rendered inline below the paragraphs, inside `Alert.Content`, rather than pinned to the right via `Alert.Actions`.","summary":"Alert with actions placed below the content"},{"id":"components-alert--all-colors","name":"All Colors","snippet":"const AllColors = () => (\n <Stack>\n {COLORS.map(color => (\n <Alert key={color} color={color}>\n <Alert.Content>\n <Alert.Title>{color}</Alert.Title>\n <Alert.Paragraph>\n This is a {color} alert variant with the default icon.\n </Alert.Paragraph>\n </Alert.Content>\n </Alert>\n ))}\n </Stack>\n);","description":"All eight colors in their primary (non-ghost) treatment, stacked for comparison. Each alert uses the built-in icon mapping for its color.","summary":"Visual comparison of all Alert colors"},{"id":"components-alert--all-ghost-colors","name":"All Ghost Colors","snippet":"const AllGhostColors = () => (\n <Stack>\n {COLORS.map(color => (\n <Alert key={color} color={color} ghost>\n <Alert.Content>\n <Alert.Title>{color} (ghost)</Alert.Title>\n <Alert.Paragraph>\n This is a {color} ghost alert variant with the ghost icon color.\n </Alert.Paragraph>\n </Alert.Content>\n </Alert>\n ))}\n </Stack>\n);","description":"All eight colors in ghost mode, stacked for comparison. Ghost alerts use a lower-weight token ramp and omit background + padding.","summary":"Visual comparison of all Alert colors in ghost mode"}],"import":"import { Alert } from \"@agentero/design-system\";","jsDocTags":{},"description":"Alert surfaces feedback about outcomes or state changes — success, danger, warning, or info. Compose it from `Alert.Content`, `Alert.Title`, `Alert.Paragraph`, `Alert.Actions`, and `Alert.Button` to build the layout your flow needs. Eight colors, two sizes, and a ghost mode cover most feedback scenarios.","reactDocgenTypescript":{"tags":{"summary":"Feedback banner with color variants, optional icon, and dismiss","example":"<Alert color=\"success\" size=\"sm\">\n <Alert.Content>\n <Alert.Title>Policy saved</Alert.Title>\n <Alert.Paragraph>Your changes are live.</Alert.Paragraph>\n </Alert.Content>\n</Alert>\n<Alert color=\"warning\" onDismiss={() => setOpen(false)}>\n <Alert.Content>\n <Alert.Title>Session expiring</Alert.Title>\n <Alert.Paragraph>Renew to continue editing.</Alert.Paragraph>\n </Alert.Content>\n <Alert.Actions>\n <Alert.Button onClick={renew}>Renew session</Alert.Button>\n </Alert.Actions>\n</Alert>\n<Alert color=\"danger\" ghost>\n <Alert.Paragraph>This field is required.</Alert.Paragraph>\n</Alert>"},"filePath":"/home/runner/work/design-system/design-system/src/alert/alert.tsx","description":"Alert surfaces feedback about an outcome or state change — success, error,\nwarning, or informational. Compose it from the exposed sub-components to\nbuild the layout you need: `Alert.Content` groups a `Alert.Title` and any\nnumber of `Alert.Paragraph` / `Alert.ParagraphHtml`; `Alert.Actions` adds\ntrailing buttons; `Alert.Pictograms` renders a 64px illustration. Pass\n`onDismiss` to show a close button; `hasIcon={false}` to hide the default\nicon; `icon` to substitute a custom icon component.\n\nAccessibility: the root carries `role=\"alert\"`; `aria-labelledby` points at\nthe rendered `Alert.Title` (when present) and `aria-describedby` at the\nparagraph wrapper. Multiple Alerts on the same page receive unique ids via\n`useId()`. The dismiss control has an accessible name of `Dismiss`.\n\nDo **not** use Alert for transient toast notifications (use a Toast\ncomponent) or for large error pages (use a dedicated empty-state).","displayName":"Alert","methods":[],"props":{"onDismiss":{"defaultValue":null,"description":"Fires when the dismiss button is clicked. When provided, renders an `iconOnly` close button with `aria-label=\"Dismiss\"`.","name":"onDismiss","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"(() => void)"}},"hasIcon":{"defaultValue":{"value":"true"},"description":"When `true` (default), renders the built-in icon for the current `color`. Set to `false` to omit the icon entirely.","name":"hasIcon","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"icon":{"defaultValue":null,"description":"Overrides the default icon for the current `color`. Receives the slot-computed className so color tokens still apply.","name":"icon","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"ComponentType<SVGProps<SVGSVGElement>>"}},"color":{"defaultValue":{"value":"neutral"},"description":"Semantic color. Defaults to `'neutral'`.\n- `neutral` — generic info; no strong signal.\n- `success` — positive confirmation.\n- `danger` — error or destructive outcome.\n- `warning` — caution; user attention needed.\n- `info` — informational highlight.\n- `creative`, `dynamic`, `playful` — brand-aligned accents.","name":"color","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"},{"fileName":"design-system/node_modules/@types/react/index.d.ts","name":"HTMLAttributes"}],"required":false,"type":{"name":"enum","raw":"\"neutral\" | \"success\" | \"danger\" | \"warning\" | \"info\" | \"creative\" | \"dynamic\" | \"playful\"","value":[{"value":"\"neutral\""},{"value":"\"success\""},{"value":"\"danger\""},{"value":"\"warning\""},{"value":"\"info\""},{"value":"\"creative\""},{"value":"\"dynamic\""},{"value":"\"playful\""}]}},"size":{"defaultValue":{"value":"sm"},"description":"Size treatment. Defaults to `'sm'`.\n- `sm` — compact inline alerts (1rem padding, 14/12px typography).\n- `md` — prominent standalone alerts (2rem padding, 18/14px typography).","name":"size","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"AlertSizeType","value":[{"value":"\"sm\""},{"value":"\"md\""}]}},"ghost":{"defaultValue":{"value":"false"},"description":"When `true`, removes background and padding so the alert blends inline\nwith surrounding text (e.g., inline form field errors). Colors switch\nto the ghost token ramp for lower visual weight.","name":"ghost","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}}},"exportName":"Alert"}},"components-avatar":{"id":"components-avatar","name":"Avatar","path":"./src/avatar/avatar.stories.tsx","stories":[{"id":"components-avatar--default","name":"Default","snippet":"const Default = () => <Avatar fallback=\"JD\" size=\"md\" variant=\"circle\" />;","description":"The default avatar with fallback initials. Renders as a medium circle when no image source is provided.","summary":"Default avatar with fallback initials"},{"id":"components-avatar--with-image","name":"With Image","snippet":"const WithImage = () => <Avatar\n fallback=\"JD\"\n size=\"md\"\n variant=\"circle\"\n src=\"https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&w=256&h=256&q=70&crop=focalpoint&fp-x=0.5&fp-y=0.3&fp-z=1&fit=crop\"\n alt=\"Alex Morgan\" />;","description":"Avatar displaying a user profile photo. The image fills the avatar shape and the fallback is hidden while the image loads successfully.","summary":"Avatar with a profile image"},{"id":"components-avatar--with-fallback-initials","name":"With Fallback Initials","snippet":"const WithFallbackInitials = () => <Avatar\n fallback=\"AM\"\n size=\"md\"\n variant=\"circle\"\n src=\"https://broken-url.example/photo.jpg\" />;","description":"When the image fails to load, the fallback content is displayed. Pass initials, an icon, or any ReactNode as the `fallback` prop.","summary":"Fallback content shown when image is unavailable"},{"id":"components-avatar--circle","name":"Circle","snippet":"const Circle = () => <Avatar fallback=\"CR\" size=\"md\" variant=\"circle\" />;","description":"The circle variant is the default shape, ideal for user profile photos.","summary":"Circle-shaped avatar (default)"},{"id":"components-avatar--square","name":"Square","snippet":"const Square = () => <Avatar fallback=\"WS\" size=\"md\" variant=\"square\" />;","description":"The square variant uses a rounded rectangle, suitable for workspace, team, or organization icons.","summary":"Square-shaped avatar for workspaces"},{"id":"components-avatar--pillow","name":"Pillow","snippet":"const Pillow = () => <Avatar fallback=\"PL\" size=\"md\" variant=\"pillow\" />;","description":"The pillow variant uses a soft, organic squircle shape for a friendly and distinctive appearance.","summary":"Pillow-shaped avatar with organic squircle"},{"id":"components-avatar--pentagon","name":"Pentagon","snippet":"const Pentagon = () => <Avatar fallback=\"PT\" size=\"md\" variant=\"pentagon\" />;","description":"The pentagon variant uses a five-sided mask for a unique visual identity. Note: the border is hidden in this variant due to the mask shape.","summary":"Pentagon-shaped avatar for unique identity"},{"id":"components-avatar--size-xs","name":"Size Xs","snippet":"const SizeXs = () => <Avatar fallback=\"XS\" size=\"xs\" variant=\"circle\" />;","description":"Extra-small avatar (24px) for dense lists and inline indicators.","summary":"Extra-small 24px avatar"},{"id":"components-avatar--size-sm","name":"Size Sm","snippet":"const SizeSm = () => <Avatar fallback=\"SM\" size=\"sm\" variant=\"circle\" />;","description":"Small avatar (32px) for compact layouts and table rows.","summary":"Small 32px avatar"},{"id":"components-avatar--size-lg","name":"Size Lg","snippet":"const SizeLg = () => <Avatar fallback=\"LG\" size=\"lg\" variant=\"circle\" />;","description":"Large avatar (48px) for profile sections and detail views.","summary":"Large 48px avatar"},{"id":"components-avatar--size-xl","name":"Size Xl","snippet":"const SizeXl = () => <Avatar fallback=\"XL\" size=\"xl\" variant=\"circle\" />;","description":"Extra-large avatar (64px) for hero sections and prominent display.","summary":"Extra-large 64px avatar"},{"id":"components-avatar--colorized","name":"Colorized","snippet":"const Colorized = () => <Avatar fallback=\"JD\" size=\"md\" variant=\"circle\" colorize=\"jane doe\" />;","description":"The `colorize` prop deterministically maps a string (typically a user name) to a color from the palette, applying a tinted background and matching text color. Useful for distinguishing users in lists without profile photos.","summary":"Colorized avatar based on user name"},{"id":"components-avatar--all-colorized","name":"All Colorized","snippet":"const AllColorized = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {['alice', 'bob', 'carol', 'dave', 'eve', 'frank', 'grace', 'henry', 'iris'].map(name => (\n <Avatar key={name} size=\"lg\" colorize={name} fallback={name.slice(0, 2).toUpperCase()} />\n ))}\n </div>\n);","description":"Multiple colorized avatars showing how different names map to different colors from the palette for visual distinction.","summary":"Multiple colorized avatars for visual distinction"},{"id":"components-avatar--all-sizes","name":"All Sizes","snippet":"const AllSizes = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {(['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'] as const).map(size => (\n <Avatar key={size} size={size} fallback={size.toUpperCase()} />\n ))}\n </div>\n);","description":"All available sizes displayed together for visual comparison. Sizes range from `xs` (24px) to `4xl` (128px).","summary":"Visual comparison of all avatar sizes"},{"id":"components-avatar--all-sizes-with-image","name":"All Sizes With Image","snippet":"const AllSizesWithImage = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {(['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'] as const).map(size => (\n <Avatar\n key={size}\n size={size}\n src=\"https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&w=256&h=256&q=70&crop=focalpoint&fp-x=0.5&fp-y=0.3&fp-z=1&fit=crop\"\n alt=\"Alex Morgan\"\n fallback=\"AM\"\n />\n ))}\n </div>\n);","description":"All sizes with a profile image to verify image scaling and quality across the full size range from `xs` (24px) to `4xl` (128px).","summary":"All avatar sizes with a profile image"},{"id":"components-avatar--all-variants","name":"All Variants","snippet":"const AllVariants = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {(['circle', 'square', 'pillow', 'pentagon'] as const).map(variant => (\n <Avatar\n key={variant}\n size=\"lg\"\n variant={variant}\n fallback={variant.slice(0, 2).toUpperCase()}\n />\n ))}\n </div>\n);","description":"All available shape variants displayed together for visual comparison. Each variant serves a different use case: user photos, workspaces, friendly branding, and unique identity.","summary":"Visual comparison of all avatar shapes"},{"id":"components-avatar--all-variants-with-image","name":"All Variants With Image","snippet":"const AllVariantsWithImage = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {(['circle', 'square', 'pillow', 'pentagon'] as const).map(variant => (\n <Avatar\n key={variant}\n size=\"lg\"\n variant={variant}\n src=\"https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&w=256&h=256&q=70&crop=focalpoint&fp-x=0.5&fp-y=0.3&fp-z=1&fit=crop\"\n alt=\"Alex Morgan\"\n fallback=\"AM\"\n />\n ))}\n </div>\n);","description":"All shape variants with a profile image to show how each mask clips the photo. Particularly useful for verifying the pentagon mask and pillow shape render correctly with real imagery.","summary":"All avatar shapes with a profile image"}],"import":"import { Avatar } from \"@agentero/design-system\";","jsDocTags":{},"description":"Avatar displays a user's profile image, initials, or a fallback icon. Use for user identification in lists, headers, cards, and comment threads. Supports multiple shapes (`circle`, `square`, `pillow`, `pentagon`) and sizes from `xs` (24px) to `4xl` (128px).","reactDocgenTypescript":{"tags":{"summary":"Displays a user's profile image, initials, or fallback icon","example":"<Avatar src=\"/photos/jane.jpg\" alt=\"Jane Doe\" size=\"md\" variant=\"circle\" />\n<Avatar fallback=\"JD\" size=\"lg\" variant=\"square\" />"},"filePath":"/home/runner/work/design-system/design-system/src/avatar/avatar.tsx","description":"Avatar displays a user's profile image, initials, or a fallback icon.\nUse Avatar for user identification in lists, headers, cards, and comment threads.\n\nDo **not** use Avatar for decorative images or thumbnails unrelated to a person\nor entity — use a standard `<img>` or a Thumbnail component instead.\n\nRenders an image when `src` is provided; otherwise displays `fallback` content\n(typically initials or an icon). Built on Radix UI Avatar primitives.\n\nAvailable shapes: `circle` (default), `square`, `pillow`, and `pentagon`.\nSizes range from `xs` (24px) to `4xl` (128px), defaulting to `md` (40px).","displayName":"Avatar","methods":[],"props":{"asChild":{"defaultValue":null,"description":"","name":"asChild","declarations":[{"fileName":"design-system/node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive/dist/index.d.mts","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"alt":{"defaultValue":null,"description":"Accessible alt text describing the avatar image. Required when `src` is provided.","name":"alt","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}},"src":{"defaultValue":null,"description":"Image URL to display. When unavailable or loading fails, `fallback` content is shown instead.","name":"src","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}},"fallback":{"defaultValue":null,"description":"Content rendered when `src` is missing or fails to load. Typically user initials (e.g., \"JD\") or an icon.","name":"fallback","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"ReactNode"}},"colorize":{"defaultValue":null,"description":"When provided, deterministically maps the string (typically a user name) to a\ncolor from the palette, applying a light background, matching text color, and\nborder color. Useful for distinguishing users in lists without profile photos.","name":"colorize","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}},"size":{"defaultValue":null,"description":"Controls the avatar dimensions. Defaults to `'md'` (40px).\n- `xs` (24px) — inline indicators, dense lists\n- `sm` (32px) — compact layouts, table rows\n- `md` (40px) — standard usage, cards, headers\n- `lg` (48px) — profile sections, detail views\n- `xl` (64px) — hero sections, prominent display\n- `2xl` (80px), `3xl` (96px), `4xl` (128px) — large feature areas, profile pages","name":"size","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"sm\" | \"md\" | \"xs\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" | \"4xl\"","value":[{"value":"\"sm\""},{"value":"\"md\""},{"value":"\"xs\""},{"value":"\"lg\""},{"value":"\"xl\""},{"value":"\"2xl\""},{"value":"\"3xl\""},{"value":"\"4xl\""}]}},"variant":{"defaultValue":null,"description":"Shape of the avatar container. Defaults to `'circle'`.\n- `circle` — standard round avatar for user photos\n- `square` — rounded rectangle, suitable for workspace or team icons\n- `pillow` — soft, organic squircle shape\n- `pentagon` — distinctive five-sided shape for unique visual identity","name":"variant","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"circle\" | \"square\" | \"pillow\" | \"pentagon\"","value":[{"value":"\"circle\""},{"value":"\"square\""},{"value":"\"pillow\""},{"value":"\"pentagon\""}]}}},"exportName":"Avatar"}},"components-button":{"id":"components-button","name":"Button","path":"./src/button/button.stories.tsx","stories":[{"id":"components-button--default","name":"Default","snippet":"const Default = () => <Button variant=\"primary\" size=\"sm\">{TEXT}</Button>;","description":"Args-controlled playground. Toggle `variant`, `size`, `status`, `loading`, `disabled`, and `rounded` from the Controls panel to explore every visual combination of the Button.","summary":"Default args playground for Button"},{"id":"components-button--variants","name":"Variants","snippet":"const Variants = () => (\n <Row>\n {VARIANTS.map(variant => (\n <Button key={variant} variant={variant}>\n {TEXT}\n </Button>\n ))}\n </Row>\n);","description":"All five variants at the default `sm` size. Variants express visual hierarchy: `primary` for the main CTA, `secondary` / `tertiary` for supporting actions, `ghost` for low-emphasis inline actions, and `link` for text-only actions.","summary":"All Button variants at default size"},{"id":"components-button--sizes","name":"Sizes","snippet":"const Sizes = () => (\n <Row>\n {SIZES.map(size => (\n <Button key={size} size={size}>\n {TEXT}\n </Button>\n ))}\n </Row>\n);","description":"All four sizes at the default `primary` variant. Sizes scale from `xs` (24px) for dense toolbars up to `lg` (48px) for hero CTAs.","summary":"All Button sizes at default variant"},{"id":"components-button--disabled","name":"Disabled","snippet":"const Disabled = () => (\n <Row>\n {VARIANTS.map(variant => (\n <Button asChild key={variant} variant={variant} disabled>\n <a>{TEXT}</a>\n </Button>\n ))}\n </Row>\n);","description":"Disabled state across all variants. Rendered via `asChild` with `<a>` children to show the disabled treatment applied via className — native anchors ignore the `disabled` attribute, so Button emits `aria-disabled` and `data-disabled` on the child instead.","summary":"Disabled treatment for every variant"},{"id":"components-button--with-icons","name":"With Icons","snippet":"const WithIcons = () => (\n <Stack>\n {VARIANTS.map(variant => (\n <Row key={variant}>\n {SIZES.map(size => (\n <Button key={size} variant={variant} size={size}>\n <IconAdd />\n {TEXT}\n <IconAdd />\n </Button>\n ))}\n </Row>\n ))}\n </Stack>\n);","description":"Variant × size grid with leading and trailing icons.","summary":"Variant × size grid with leading + trailing icons"},{"id":"components-button--only-icon","name":"Only Icon","snippet":"const OnlyIcon = () => (\n <Stack>\n {NON_LINK_VARIANTS.map(variant => (\n <Row key={variant}>\n {SIZES.map(size => (\n <Button key={size} variant={variant} size={size} aria-label=\"Close\">\n <IconClose />\n </Button>\n ))}\n </Row>\n ))}\n </Stack>\n);","description":"Icon-only buttons across the variant × size grid. Excludes `variant=\"link\"` — combining `link` with icon-only children logs a dev-only warning because the link treatment has no padding to accommodate an icon alone.","summary":"Icon-only Button across variant × size (excluding `link`)"},{"id":"components-button--loading","name":"Loading","snippet":"const Loading = () => (\n <Stack>\n {NON_LINK_VARIANTS.map(variant => (\n <Row key={variant}>\n {SIZES.map(size => (\n <div key={size} style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>\n <Button variant={variant} size={size} loading aria-label=\"Loading\">\n <IconAdd />\n </Button>\n <Button variant={variant} size={size} loading>\n {TEXT}\n </Button>\n </div>\n ))}\n </Row>\n ))}\n </Stack>\n);","description":"Loading state across the variant × size grid. Each row shows two buttons per size: one icon-only, one with text. Loading forces `disabled` and overlays a spinner that inherits the variant's text color. Excludes `variant=\"link\"` — combining `link` with `loading` logs a dev-only warning.","summary":"Loading state across variant × size (excluding `link`)"},{"id":"components-button--status","name":"Status","snippet":"const Status = () => (\n <Stack>\n <Row>\n {VARIANTS.map(variant => (\n <Button key={variant} variant={variant} status=\"danger\">\n <IconAdd />\n {TEXT}\n <IconAdd />\n </Button>\n ))}\n </Row>\n <Row>\n {VARIANTS.map(variant => (\n <Button asChild key={variant} variant={variant} status=\"danger\" disabled>\n <a>\n <IconAdd />\n {TEXT}\n <IconAdd />\n </a>\n </Button>\n ))}\n </Row>\n </Stack>\n);","description":"Destructive treatment via `status=\"danger\"`. The top row shows every variant enabled; the bottom row shows every variant disabled. Use `status=\"danger\"` for delete, remove, or disconnect actions regardless of variant.","summary":"`status=\"danger\"` across every variant, enabled + disabled"},{"id":"components-button--rounded","name":"Rounded","snippet":"const Rounded = () => (\n <Stack>\n {NON_LINK_VARIANTS.map(variant => (\n <Row key={variant}>\n {SIZES.map(size => (\n <Button key={size} variant={variant} size={size} rounded>\n <IconAdd />\n {TEXT}\n <IconAdd />\n </Button>\n ))}\n </Row>\n ))}\n </Stack>\n);","description":"Fully pill-shaped buttons across the variant × size grid. Excludes `variant=\"link\"` since the link treatment has no background to round.","summary":"`rounded` pill shape across variant × size (excluding `link`)"},{"id":"components-button--as-child","name":"As Child","snippet":"const AsChild = () => (\n <Row>\n <Button asChild variant=\"primary\">\n <a href=\"/dashboard\">Go to dashboard</a>\n </Button>\n <Button asChild variant=\"secondary\">\n <a href=\"https://agentero.com\" target=\"_blank\" rel=\"noreferrer\">\n Visit Agentero\n </a>\n </Button>\n </Row>\n);","description":"`asChild` renders Button's styles on the nested child element rather than on a `<button>` — the child receives Button's `className`, `ref`, and merged props via Radix's `Slot` primitive. Use it to turn any anchor or framework `Link` into a Button without coupling the design system to a router. In app code, swap the plain `<a>` below for your framework's Link (`next/link`, `react-router`, `@tanstack/react-router`, etc.).","summary":"`asChild` composes Button's styles onto any element"}],"import":"import { Button } from \"@agentero/design-system\";","jsDocTags":{},"description":"Button is the design system's primary actionable control. Pick `variant` to express hierarchy, `size` for prominence, and `status=\"danger\"` for destructive actions. Pass `asChild` to render Button's styles on any nested element — a plain `<a>`, a framework `<Link>`, or a custom component — without Button binding to any particular framework.","reactDocgenTypescript":{"tags":{"summary":"Primary actionable control; renders a `<button>` or, with `asChild`, any nested element","example":"<Button variant=\"primary\" size=\"sm\" onClick={handleSave}>\n Save changes\n</Button>\n<Button asChild variant=\"secondary\">\n <a href=\"https://agentero.com\" target=\"_blank\" rel=\"noreferrer\">Visit Agentero</a>\n</Button>\n// Framework-agnostic: wrap any Link implementation\n<Button asChild variant=\"primary\">\n <Link href=\"/dashboard\">Go to dashboard</Link>\n</Button>\n<Button variant=\"primary\" status=\"danger\" loading={isDeleting} onClick={handleDelete}>\n Delete account\n</Button>"},"filePath":"/home/runner/work/design-system/design-system/src/button/button.tsx","description":"Button is the design system's primary actionable control. Use it for any\ninteraction that triggers behavior, submits a form, or navigates the user.\nBy default Button renders a `<button>`; pass `asChild` to render its single\nchild element as the underlying tag instead — Button merges its styles,\n`className`, `ref`, and props onto whatever the consumer nests. This keeps\nthe design system framework-agnostic: route a plain `<a>`, a Next.js\n`<Link>`, a React Router `<Link>`, or any custom element through the same\nvisual treatment.\n\nPick `variant` to express hierarchy (`primary` for the main CTA,\n`secondary` / `tertiary` for supporting actions, `ghost` for low-emphasis\ninline actions, `link` for text-only actions). Use `status=\"danger\"` for\ndestructive actions and `loading` to block interaction while async work\nresolves.\n\nDo **not** use Button for toggle states (prefer a Switch or ToggleButton),\nfor passive decorative anchors without action intent (use a plain `<a>`),\nor with `variant=\"link\"` when loading or when the button has no text\nchildren — both combinations log a dev-only warning (silent in production).","displayName":"Button","methods":[],"props":{"children":{"defaultValue":null,"description":"Content rendered inside the Button. Accepts a text label, icon elements,\nor any mix of both. Icon-only children switch the Button to a square\naspect ratio and trigger the icon-only layout.\n\nWhen `asChild` is set, the single child element is merged with Button's\nprops and styles; auto-detection of icon-only children is skipped — use\nthe `iconOnly` prop to opt into the square icon-only layout.\n\nNot supported with `variant=\"link\"` when children resolve to icons only\n— passing both logs a dev-only warning (silent in production).","name":"children","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"},{"fileName":"design-system/node_modules/@types/react/index.d.ts","name":"DOMAttributes"}],"required":false,"type":{"name":"ReactNode"}},"variant":{"defaultValue":null,"description":"Visual hierarchy. Defaults to `'primary'`.\n- `primary` — main call-to-action; use once per view.\n- `secondary` — alternative action alongside a primary button.\n- `tertiary` — low-emphasis action, subtle background.\n- `ghost` — minimal background; low-emphasis action in dense layouts.\n- `link` — inline text-style action; no padding or background.","name":"variant","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"ButtonVariantType","value":[{"value":"\"ghost\""},{"value":"\"link\""},{"value":"\"primary\""},{"value":"\"secondary\""},{"value":"\"tertiary\""}]}},"size":{"defaultValue":null,"description":"Control size. Defaults to `'sm'`.\n- `xs` (24px) — dense toolbars, compact inline actions.\n- `sm` (32px) — standard usage in forms and cards.\n- `md` (40px) — prominent actions in modals or feature rows.\n- `lg` (48px) — hero CTAs and full-width mobile actions.","name":"size","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"ButtonSizeType","value":[{"value":"\"sm\""},{"value":"\"md\""},{"value":"\"xs\""},{"value":"\"lg\""}]}},"status":{"defaultValue":null,"description":"Semantic status override. Set to `'danger'` for destructive actions\n(delete, remove, disconnect) — applies the destructive color treatment\nacross all variants.","name":"status","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"danger\"","value":[{"value":"\"danger\""}]}},"loading":{"defaultValue":null,"description":"When `true`, shows a spinner overlay and forces the button into a disabled\nstate to block further interaction. Not supported with `variant=\"link\"` —\npassing both logs a dev-only warning (silent in production).","name":"loading","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"disabled":{"defaultValue":null,"description":"Disables interaction and applies the disabled color treatment. Applied\nvia className so it still affects anchors rendered via `asChild`, which\nignore the native `disabled` attribute — in that case `aria-disabled`\nand `data-disabled` are forwarded to the child element instead.","name":"disabled","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"},{"fileName":"design-system/node_modules/@types/react/index.d.ts","name":"ButtonHTMLAttributes"}],"required":false,"type":{"name":"boolean"}},"iconOnly":{"defaultValue":null,"description":"Forces the icon-only layout (square aspect ratio, no min-width). Useful\nwith `asChild` where the single wrapper child prevents auto-detection.\nFor non-`asChild` usage, prefer passing icon elements as children — the\nicon-only layout is applied automatically.","name":"iconOnly","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"rounded":{"defaultValue":null,"description":"When `true`, renders a fully pill-shaped button (rounded-full). Otherwise\nuses the variant's default corner radius.","name":"rounded","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"align":{"defaultValue":null,"description":"Justifies children along the main axis. Defaults to `'center'`.\nUse `'justify'` to push leading and trailing icons to the edges.","name":"align","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"center\" | \"start\" | \"end\" | \"justify\"","value":[{"value":"\"center\""},{"value":"\"start\""},{"value":"\"end\""},{"value":"\"justify\""}]}},"fitContent":{"defaultValue":null,"description":"When `true`, removes the per-size `min-width` floor so the button hugs\nits content. Useful for inline actions inside tight containers.","name":"fitContent","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"ref":{"defaultValue":null,"description":"Ref forwarded to the underlying element. Typed as a union covering both\n`<button>` and `<a>` because `asChild` lets consumers render either tag\n(or any forwardRef component) through Radix's `Slot`.","name":"ref","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"Ref<HTMLButtonElement | HTMLAnchorElement>"}},"asChild":{"defaultValue":null,"description":"When `true`, Button clones its single child element and merges\nButton's `className`, `ref`, and event handlers onto it rather than\nrendering a `<button>`. Use this to style any element (a plain `<a>`,\na framework `Link`, a `React.forwardRef` component) as a Button.\n\nWhen combined with `disabled`, Button emits `aria-disabled` and\n`data-disabled` on the child instead of the native `disabled`\nattribute (which is ignored by non-form-control elements).","name":"asChild","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}}},"exportName":"Button"}},"components-divider":{"id":"components-divider","name":"Divider","path":"./src/divider/divider.stories.tsx","stories":[{"id":"components-divider--default","name":"Default","snippet":"const Default = () => <div\n className={cn(\n 'flex gap-4 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary p-6',\n args.orientation === 'vertical' ? 'h-40 w-lg items-stretch' : 'w-80 flex-col'\n )}>\n <div className=\"flex flex-1 flex-col justify-center gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">First section</h3>\n <p className=\"text-sm text-text-default-base-secondary\">Content on one side of the divider, visually separated from the other.\n </p>\n </div>\n <Divider orientation=\"horizontal\" decorative />\n <div className=\"flex flex-1 flex-col justify-center gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Second section</h3>\n <p className=\"text-sm text-text-default-base-secondary\">Content on the other side of the divider, clearly separated from the first.\n </p>\n </div>\n</div>;","description":"The default horizontal, decorative divider — a 1px line that spans the parent width. Use this form between stacked content blocks.","summary":"Default horizontal decorative divider"},{"id":"components-divider--horizontal","name":"Horizontal","snippet":"const Horizontal = () => (\n <div className=\"w-80\">\n <Divider />\n </div>\n);","description":"Horizontal divider — a 1px line spanning the parent's full width. The default orientation; use to separate stacked content.","summary":"Horizontal 1px line spanning the parent width"},{"id":"components-divider--vertical","name":"Vertical","snippet":"const Vertical = () => (\n <div className=\"flex h-24 items-stretch\">\n <Divider orientation=\"vertical\" />\n </div>\n);","description":"Vertical divider — a 1px line spanning the parent's full height. Parent must establish a height (via `h-*` or an intrinsic flex item height) for the line to be visible.","summary":"Vertical 1px line spanning the parent height"},{"id":"components-divider--with-label","name":"With Label","snippet":"const WithLabel = () => <div className=\"flex w-80 flex-col gap-2\">\n <Button variant=\"primary\">Continue with email</Button>\n <Divider orientation=\"horizontal\" decorative label=\"or\" />\n <Button variant=\"secondary\">Continue with SSO</Button>\n</div>;","description":"Labelled divider. The label sits centered between two flanking 1px lines — a common pattern for \"or\" breaks between authentication options.","summary":"Horizontal divider with a centered \"or\" label"},{"id":"components-divider--vertical-with-label","name":"Vertical With Label","snippet":"const VerticalWithLabel = () => <div\n className=\"flex h-40 items-stretch gap-4 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary p-6\">\n <div className=\"flex flex-col justify-center gap-1\">\n <h3 className=\"text-sm font-semibold text-text-default-base-primary\">Left panel</h3>\n <p className=\"text-xs text-text-default-base-secondary\">Content on the left side</p>\n </div>\n <Divider orientation=\"vertical\" decorative label=\"OR\" />\n <div className=\"flex flex-col justify-center gap-1\">\n <h3 className=\"text-sm font-semibold text-text-default-base-primary\">Right panel</h3>\n <p className=\"text-xs text-text-default-base-secondary\">Content on the right side</p>\n </div>\n</div>;","description":"Vertical divider with a label. The label sits between two stacked 1px line segments; use sparingly — horizontal labelled dividers are more common.","summary":"Vertical divider with a centered label"},{"id":"components-divider--semantic","name":"Semantic","snippet":"const Semantic = () => <div\n className=\"flex w-80 flex-col gap-4 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary p-6\">\n <section className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Section one</h3>\n <p className=\"text-sm text-text-default-base-secondary\">Semantically separated from the next section for screen readers.\n </p>\n </section>\n <Divider orientation=\"horizontal\" decorative={false} />\n <section className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Section two</h3>\n <p className=\"text-sm text-text-default-base-secondary\">Screen readers will announce this as a separate section.\n </p>\n </section>\n</div>;","description":"Semantic divider (`decorative={false}`). Exposes `role=\"separator\"` and `aria-orientation` to assistive technologies, marking a meaningful section break rather than a purely visual one.","summary":"Semantic separator announced to assistive technologies"},{"id":"components-divider--in-list","name":"In List","snippet":"const InList = () => (\n <div className=\"w-80 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary\">\n <div className=\"flex flex-col gap-1 px-4 py-3\">\n <h4 className=\"text-sm text-text-default-base-primary\">Notification 1</h4>\n <p className=\"text-xs text-text-default-base-secondary\">\n You have a new message from Jane.\n </p>\n </div>\n <Divider />\n <div className=\"flex flex-col gap-1 px-4 py-3\">\n <h4 className=\"text-sm text-text-default-base-primary\">Notification 2</h4>\n <p className=\"text-xs text-text-default-base-secondary\">\n Your report is ready to download.\n </p>\n </div>\n <Divider />\n <div className=\"flex flex-col gap-1 px-4 py-3\">\n <h4 className=\"text-sm text-text-default-base-primary\">Notification 3</h4>\n <p className=\"text-xs text-text-default-base-secondary\">\n System maintenance is scheduled for tonight.\n </p>\n </div>\n </div>\n);","description":"Divider between list rows. Dividers delineate each item without the visual weight of a full border on every row.","summary":"Horizontal dividers between stacked list rows"},{"id":"components-divider--in-toolbar","name":"In Toolbar","snippet":"const InToolbar = () => (\n <div className=\"inline-flex h-10 items-center gap-1 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary px-2 shadow-1\">\n <Button variant=\"ghost\" size=\"xs\">\n Cut\n </Button>\n <Button variant=\"ghost\" size=\"xs\">\n Copy\n </Button>\n <Button variant=\"ghost\" size=\"xs\">\n Paste\n </Button>\n <Divider orientation=\"vertical\" className=\"mx-1 h-6\" />\n <Button variant=\"ghost\" size=\"xs\">\n Undo\n </Button>\n <Button variant=\"ghost\" size=\"xs\">\n Redo\n </Button>\n <Divider orientation=\"vertical\" className=\"mx-1 h-6\" />\n <Button variant=\"ghost\" size=\"xs\">\n Settings\n </Button>\n </div>\n);","description":"Vertical dividers grouping related toolbar actions. Use to separate logical clusters of buttons (editing vs. history vs. settings) without visual weight.","summary":"Vertical dividers grouping toolbar actions"},{"id":"components-divider--horizontal-in-content","name":"Horizontal In Content","snippet":"const HorizontalInContent = () => (\n <div className=\"flex w-96 flex-col gap-4 p-6\">\n <div className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Section title</h3>\n <p className=\"text-sm text-text-default-base-secondary\">\n Descriptive content for the first section. The divider below separates it from the next.\n </p>\n </div>\n <Divider />\n <div className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Another section</h3>\n <p className=\"text-sm text-text-default-base-secondary\">\n The second section is clearly separated from the previous one.\n </p>\n </div>\n <Divider />\n <div className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Final section</h3>\n <p className=\"text-sm text-text-default-base-secondary\">\n Dividers help establish visual hierarchy in content-heavy layouts.\n </p>\n </div>\n </div>\n);","description":"Horizontal dividers between content sections in a long-form layout. Helps create visual hierarchy in content-heavy pages.","summary":"Horizontal dividers between content sections"},{"id":"components-divider--vertical-between-elements","name":"Vertical Between Elements","snippet":"const VerticalBetweenElements = () => (\n <div className=\"flex items-stretch gap-3\">\n <Button variant=\"primary\" size=\"sm\">\n Button 1\n </Button>\n <Divider orientation=\"vertical\" />\n <Button variant=\"primary\" size=\"sm\">\n Button 2\n </Button>\n <Divider orientation=\"vertical\" />\n <Button variant=\"primary\" size=\"sm\">\n Button 3\n </Button>\n </div>\n);","description":"Vertical dividers between inline elements. Common for separating a row of related controls or inline links without visual weight.","summary":"Vertical dividers separating inline elements"}],"import":"import { Button, Divider } from \"@agentero/design-system\";","jsDocTags":{},"description":"Divider separates content visually along either a horizontal or vertical axis. Use between page or card sections, between inline items in a toolbar or list, or — with the `label` prop — to render an \"or\"-style break between options. Set `decorative={false}` when the separator carries semantic meaning so it's announced to assistive technologies.","reactDocgenTypescript":{"tags":{"summary":"Visual or semantic separator that optionally renders a centered label","param":"orientation - Axis along which the separator renders. Defaults to `'horizontal'`.\n- `horizontal` — 1px line spanning the parent width.\n- `vertical` — 1px line spanning the parent height; parent must establish a height.\ndecorative - When `true` (default), the separator is purely visual and hidden\nfrom assistive technologies. Set to `false` to expose `role=\"separator\"` plus\n`aria-orientation` for meaningful section breaks.\nlabel - Optional inline content rendered between two flanking 1px lines.\nWhen omitted, Divider renders a single line.","example":"<Divider />\n<Divider orientation=\"vertical\" />\n<Divider label=\"or\" />\n<Divider decorative={false} />"},"filePath":"/home/runner/work/design-system/design-system/src/divider/divider.tsx","description":"Divider separates content visually (or semantically, via `decorative={false}`)\nalong either a horizontal or vertical axis. Use Divider between page or card\nsections, between inline items in a toolbar or list, or to break up long\ncontent regions. Pass a `label` to render the \"or\"-style divider with text\ncentered between two line segments — useful for auth flows and step breaks.\n\nBuilt on Radix UI's Separator primitive for the unlabelled case; the\nlabelled case renders a `<div>` that still forwards the correct\n`role`/`aria-orientation` when `decorative={false}`.\n\nDo **not** use Divider as a bare horizontal rule to add vertical rhythm —\nreach for margin utilities or a layout wrapper instead. Divider should carry\nmeaning (visual or semantic section break), not whitespace.","displayName":"Divider","methods":[],"props":{"asChild":{"defaultValue":null,"description":"","name":"asChild","declarations":[{"fileName":"design-system/node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive/dist/index.d.mts","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"label":{"defaultValue":null,"description":"Optional label rendered inline between two flanking 1px lines. When set,\nDivider renders a styled `<div>` (rather than the underlying separator\nprimitive) so the label can sit centered between the two line segments.","name":"label","declarations":[{"fileName":"design-system/src/divider/divider.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"ReactNode"}}},"exportName":"Divider"}},"components-dropdownmenu":{"id":"components-dropdownmenu","name":"DropdownMenu.Root","path":"./src/dropdown-menu/dropdown-menu.stories.tsx","stories":[{"id":"components-dropdownmenu--default","name":"Default","snippet":"const Default = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Click me\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('Edit clicked')}>Edit</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Duplicate clicked')}>\n Duplicate\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Archive clicked')}>\n Archive\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item onSelect={() => console.log('Delete clicked')}>\n <span className=\"text-red-500\">Delete</span>\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"A minimal DropdownMenu with four `Item`s — edit/duplicate/archive plus a separator before a destructive delete. Use this as the starting point for most overflow menus.","summary":"Basic menu with item rows and a separated destructive action"},{"id":"components-dropdownmenu--with-groups-and-dividers","name":"With Groups And Dividers","snippet":"const WithGroupsAndDividers = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n More Options\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('Undo')}>Undo</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Redo')}>Redo</DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item onSelect={() => console.log('Copy')}>Copy</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Cut')}>Cut</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Paste')}>Paste</DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item disabled>Print (disabled)</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Export')}>Export</DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"Multiple clusters of `Item`s split by `Separator` rules — mirrors an \"edit history / clipboard / export\" overflow menu. Demonstrates the `disabled` state on a menu row.","summary":"Menu with multiple `Separator`-split groups and a disabled item"},{"id":"components-dropdownmenu--with-icons","name":"With Icons","snippet":"const WithIcons = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Actions\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('Copy')}>\n <IconContentCopy />\n Copy\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n onSelect={() => console.log('Delete')}\n className=\"data-[highlighted]:bg-red-100\">\n <IconDelete className=\"[&>path]:fill-red-500\" />\n <span className=\"text-red-500\">Delete</span>\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"Menu items with leading icons and a destructive row using the `data-[highlighted]:bg-red-100` + `text-red-500` escape hatch. Use this pattern when a row should read as destructive.","summary":"Icon-leading items with a destructive delete row"},{"id":"components-dropdownmenu--with-group-titles","name":"With Group Titles","snippet":"const WithGroupTitles = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Account Menu\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Label>Profile</DropdownMenu.Label>\n <DropdownMenu.Item onSelect={() => console.log('View Profile')}>\n View Profile\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Edit Profile')}>\n Edit Profile\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Label>Settings</DropdownMenu.Label>\n <DropdownMenu.Item onSelect={() => console.log('Preferences')}>\n Preferences\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Privacy')}>Privacy</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Notifications')}>\n Notifications\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Label>Account</DropdownMenu.Label>\n <DropdownMenu.Item onSelect={() => console.log('Billing')}>Billing</DropdownMenu.Item>\n <DropdownMenu.Item\n onSelect={() => console.log('Logout')}\n className=\"data-[highlighted]:bg-red-100\">\n <span className=\"text-red-500\">Logout</span>\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"`Label`-segmented Profile / Settings / Account sections with a destructive Logout row. Use `Label` to name groups that would otherwise be ambiguous from the item text alone.","summary":"Menu with `Label`-titled sections and a destructive logout row"},{"id":"components-dropdownmenu--with-submenu","name":"With Submenu","snippet":"const WithSubmenu = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n File Options\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('New File')}>New File</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Open')}>Open</DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n <IconIosShare />\n Share\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('Email')}>Email</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Slack')}>Slack</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Copy Link')}>\n Copy Link\n </DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n <IconDriveFileMove />\n Move to\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('Archive')}>\n Archive\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Projects')}>\n Projects\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Drafts')}>Drafts</DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n onSelect={() => console.log('Delete')}\n className=\"data-[highlighted]:bg-red-100\">\n <IconDelete className=\"[&>path]:fill-red-500\" />\n <span className=\"text-red-500\">Delete</span>\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"One level of nesting: Share and Move-to submenus wired via `Sub` / `SubTrigger` / `SubContent`. Each submenu is portaled independently so it escapes the parent's stacking context.","summary":"Single-level submenus for Share and Move-to flows"},{"id":"components-dropdownmenu--nested-submenus","name":"Nested Submenus","snippet":"const NestedSubmenus = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Organization Menu\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Label>Organization</DropdownMenu.Label>\n <DropdownMenu.Item onSelect={() => console.log('Dashboard')}>Dashboard</DropdownMenu.Item>\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n <IconPeople />\n Teams\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('View All Teams')}>\n View All Teams\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>Engineering</DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('Frontend')}>\n Frontend\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Backend')}>\n Backend\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('DevOps')}>\n DevOps\n </DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>Design</DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('Product Design')}>\n Product Design\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Brand')}>\n Brand\n </DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Item onSelect={() => console.log('Marketing')}>\n Marketing\n </DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Separator />\n <DropdownMenu.Item onSelect={() => console.log('Settings')}>Settings</DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"Two levels of nesting: Organization → Teams → (Engineering, Design). Deeper nesting is rarely a good UX — prefer splitting into separate screens once the tree grows past two levels.","summary":"Two-level nested submenus inside a parent menu"},{"id":"components-dropdownmenu--submenu-with-disabled-items","name":"Submenu With Disabled Items","snippet":"const SubmenuWithDisabledItems = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Document Actions\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('View')}>View</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Edit')}>Edit</DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n <IconContentCopy />\n Export as\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('PDF')}>PDF</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Word')}>\n Word Document\n </DropdownMenu.Item>\n <DropdownMenu.Item disabled>Excel (Premium only)</DropdownMenu.Item>\n <DropdownMenu.Item disabled>PowerPoint (Premium only)</DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger disabled>\n <IconIosShare />\n Share (Sign in required)\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item>Email</DropdownMenu.Item>\n <DropdownMenu.Item>Link</DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"Submenu that contains `disabled` `Item`s alongside a fully-disabled `SubTrigger`. Use `disabled` sparingly — prefer hiding unavailable actions outright unless the user needs to see them and understand why.","summary":"Submenu with `disabled` items and a disabled `SubTrigger`"}],"import":"import { Button, DropdownMenu } from \"@agentero/design-system\";","jsDocTags":{},"description":"DropdownMenu is a compound overlay for secondary actions, bulk operations, or navigation shortcuts triggered off a button or icon. Compose it from `Root` / `Trigger` / `Portal` / `Content` and fill the menu with `Item`, `Separator`, `Label`, and — for nested flows — `Sub` / `SubTrigger` / `SubContent`. Built on Radix UI's DropdownMenu primitive, so keyboard navigation, focus trapping, typeahead, and collision detection come for free.","reactDocgenTypescript":{"tags":{"summary":"Compound overlay menu for secondary actions, grouped items, and submenus","see":"{@link https://www.radix-ui.com/primitives/docs/components/dropdown-menu Radix UI DropdownMenu}","example":"```tsx\nimport { DropdownMenu } from '@agentero/design-system/dropdown-menu';\n\n<DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconMoreVert />\n </DropdownMenu.Trigger>\n\n <DropdownMenu.Portal>\n <DropdownMenu.Content side=\"bottom\" align=\"end\">\n <DropdownMenu.Label>Actions</DropdownMenu.Label>\n\n <DropdownMenu.Item onSelect={() => handleEdit()}>\n <IconEdit />\n Edit\n </DropdownMenu.Item>\n\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>Share</DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item>Email</DropdownMenu.Item>\n <DropdownMenu.Item>Slack</DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n\n <DropdownMenu.Separator />\n\n <DropdownMenu.Item\n onSelect={() => handleDelete()}\n disabled={!canDelete}\n >\n <IconDelete />\n Delete\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n</DropdownMenu.Root>\n```","component":"","namespace":"DropdownMenu"},"filePath":"/home/runner/work/design-system/design-system/src/dropdown-menu/dropdown-menu.tsx","description":"DropdownMenu is the compound component for attaching a menu of secondary\nactions to a button or icon trigger — edit/duplicate/delete rows, account\nmenus, overflow affordances, and nested submenus. Built on Radix UI's\nDropdownMenu primitive, so keyboard navigation, focus trapping, typeahead,\nand viewport-collision detection come for free.\n\nCompose it from `Root` / `Trigger` / `Portal` / `Content` and fill the\nmenu with `Item`, `Separator`, `Label`, and — for nested flows — `Sub` /\n`SubTrigger` / `SubContent`. Wrap content in `Portal` so the menu escapes\nancestor `overflow:hidden` and z-index stacking contexts.\n\nDo **not** use DropdownMenu for primary navigation (use a real nav menu),\nfor single-choice form input (use a `Select`), or for command palettes\n(use a dedicated command component). For radio/checkbox-style toggles,\nuse Radix's `CheckboxItem` / `RadioItem` primitives directly — those\nparts are not exposed here yet.","displayName":"DropdownMenu","methods":[],"props":{},"exportName":"DropdownMenu"}},"components-loading":{"id":"components-loading","name":"Loading","path":"./src/loading/loading.stories.tsx","stories":[{"id":"components-loading--default","name":"Default","snippet":"const Default = () => <Loading size=\"sm\" />;","description":"The default spinner at `size=\"sm\"` (1em diameter), inheriting the current text color. Matches the out-of-the-box behavior when Loading is dropped into any layout.","summary":"Default spinner at the `sm` size"},{"id":"components-loading--size-sm","name":"Size Sm","snippet":"const SizeSm = () => <Loading size=\"sm\" />;","description":"Small spinner (1em diameter) — the default. Ideal for inline indicators, buttons, and compact layouts where the spinner needs to sit next to text.","summary":"Small 1em spinner for inline indicators"},{"id":"components-loading--size-md","name":"Size Md","snippet":"const SizeMd = () => <Loading size=\"md\" />;","description":"Medium spinner (1.5em diameter). Use for cards, panels, and standalone loading states where the spinner is the primary visual signal.","summary":"Medium 1.5em spinner for cards and panels"},{"id":"components-loading--size-lg","name":"Size Lg","snippet":"const SizeLg = () => <Loading size=\"lg\" />;","description":"Large spinner (2em diameter). Use for page-level or section-level loading where the spinner needs more visual weight.","summary":"Large 2em spinner for page or section loading"},{"id":"components-loading--sizes","name":"Sizes","snippet":"const Sizes = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '2rem' }}>\n {(['sm', 'md', 'lg'] as const).map(size => (\n <Loading key={size} size={size} />\n ))}\n </div>\n);","description":"All three sizes rendered side by side for visual comparison of the `em`-based scaling. Each spinner inherits the same parent text color.","summary":"Visual comparison of all three spinner sizes"},{"id":"components-loading--inherits-color","name":"Inherits Color","snippet":"const InheritsColor = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '2rem' }}>\n <div className=\"text-text-default-base-primary\">\n <Loading size=\"md\" />\n </div>\n <div className=\"text-text-default-brand-primary\">\n <Loading size=\"md\" />\n </div>\n <div className=\"text-text-default-danger-primary\">\n <Loading size=\"md\" />\n </div>\n </div>\n);","description":"The spinner color tracks the parent `color` (text color) via `border-current`. Wrap Loading in any element with a text color utility — or set `color` on Loading itself — and the spinner adopts that color without extra props.","summary":"Spinner color inherits from the parent text color"},{"id":"components-loading--on-dark-surface","name":"On Dark Surface","snippet":"const OnDarkSurface = () => (\n <div className=\"flex items-center gap-8 rounded-lg bg-bg-button-primary-enable p-8 text-text-default-base-inverse-primary\">\n <Loading size=\"sm\" />\n <Loading size=\"md\" />\n <Loading size=\"lg\" />\n </div>\n);","description":"Spinner on a dark surface to verify `border-current` contrast. The parent sets a light text color, which the spinner inherits so it remains visible against the dark background.","summary":"Spinner on a dark-background surface"}],"import":"import { Loading } from \"@agentero/design-system\";","jsDocTags":{},"description":"Loading displays a circular spinner that indicates an in-progress operation. Use for inline fetch, form submission, or asynchronous task indicators. The spinner inherits its color from the parent `color` and scales with the parent font size via `em`-based size variants (`sm`, `md`, `lg`).","reactDocgenTypescript":{"tags":{"summary":"Circular spinner for in-progress and loading states","example":"<Loading />\n<Loading size=\"lg\" className=\"text-text-default-brand-primary\" />"},"filePath":"/home/runner/work/design-system/design-system/src/loading/loading.tsx","description":"Loading displays a circular spinner that indicates an in-progress operation.\nUse Loading to signal that content is being fetched, a form is submitting,\nor any asynchronous task is running inline with surrounding content.\n\nThe spinner inherits its color from the parent `color` (text color) via\n`border-current`, so it adapts to the surrounding context without extra\nprops. It fades in on mount and spins continuously until unmounted.\n\nAvailable sizes: `sm` (1em, default), `md` (1.5em), and `lg` (2em). Each\nsize is expressed in `em` units so the spinner scales with the parent\nfont size — wrap the Loading (or its ancestor) with the appropriate\n`text-[size]` utility to override the absolute diameter.\n\nExposes `role=\"status\"` and `aria-label=\"Loading\"` for screen readers, and\n`data-slot=\"loading\"` for styling hooks.\n\nDo **not** use Loading as the busy indicator for a button — the Button\ncomponent has its own built-in loading overlay ([Button](?path=/docs/button--docs)).\nFor full-page or skeleton loading states prefer a dedicated skeleton\nplaceholder instead of a spinner.","displayName":"Loading","methods":[],"props":{"size":{"defaultValue":null,"description":"Controls the spinner diameter in `em` units relative to the parent font size.\nDefaults to `'sm'`.\n- `sm` (1em) — inline indicators, buttons, and compact layouts\n- `md` (1.5em) — cards, panels, and standalone loading states\n- `lg` (2em) — page-level or section-level loading","name":"size","declarations":[{"fileName":"design-system/src/loading/loading.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"sm\" | \"md\" | \"lg\"","value":[{"value":"\"sm\""},{"value":"\"md\""},{"value":"\"lg\""}]}}},"exportName":"Loading"}},"components-pagination":{"id":"components-pagination","name":"Pagination","path":"./src/pagination/pagination.stories.tsx","stories":[{"id":"components-pagination--default","name":"Default","snippet":"const Default = () => <Pagination currentPage={1} totalCount={1000} pageSize={10} onPageChange={fn()} />;","description":"Default args playground. The first page of a 1,000-item list paged 10 at a time — renders pages 1–5, an ellipsis, and the last page (100), with the previous-page button disabled because we're on page 1.","summary":"Default args playground for Pagination"},{"id":"components-pagination--few-pages","name":"Few Pages","snippet":"const FewPages = () => <Pagination\n currentPage={2}\n totalCount={30}\n pageSize={10}\n onPageChange={(page: number) => console.log('onPageChange', page)} />;","description":"Short list whose total pages fit in the visible window — no ellipsis is rendered. Exercises the `totalPageNumbers >= totalPageCount` branch in `getPages`.","summary":"Short page list with no ellipsis collapse"},{"id":"components-pagination--dots-right","name":"Dots Right","snippet":"const DotsRight = () => <Pagination\n currentPage={2}\n totalCount={1000}\n pageSize={10}\n onPageChange={(page: number) => console.log('onPageChange', page)} />;","description":"Current page sits near the start of the range — left ellipsis is hidden, right ellipsis is shown, and the last page button anchors the right edge.","summary":"Right-side ellipsis only (current page near start)"},{"id":"components-pagination--dots-left","name":"Dots Left","snippet":"const DotsLeft = () => <Pagination\n currentPage={99}\n totalCount={1000}\n pageSize={10}\n onPageChange={(page: number) => console.log('onPageChange', page)} />;","description":"Current page sits near the end of the range — left ellipsis is shown, right ellipsis is hidden, and the first page button anchors the left edge.","summary":"Left-side ellipsis only (current page near end)"},{"id":"components-pagination--dots-both","name":"Dots Both","snippet":"const DotsBoth = () => <Pagination\n currentPage={50}\n totalCount={1000}\n pageSize={10}\n onPageChange={(page: number) => console.log('onPageChange', page)} />;","description":"Current page sits in the middle of the range — both ellipses are visible, with the first and last page buttons anchoring each edge.","summary":"Both ellipses visible (current page in middle)"},{"id":"components-pagination--last-page","name":"Last Page","snippet":"const LastPage = () => <Pagination currentPage={100} totalCount={1000} pageSize={10} onPageChange={fn()} />;","description":"Last page selected — the next-page button is disabled and the active page indicator sits on the trailing number.","summary":"Last page selected with disabled next button"},{"id":"components-pagination--controlled","name":"Controlled","snippet":"const Controlled = ({ totalCount, pageSize }) => {\n const [page, setPage] = useState(1);\n\n return (\n <Pagination\n currentPage={page}\n totalCount={totalCount}\n pageSize={pageSize}\n onPageChange={setPage}\n />\n );\n};","description":"Interactive controlled example. Local `useState` owns the page; clicking a page, previous, or next button updates it so the active page indicator and entries summary follow along.","summary":"Interactive controlled example backed by `useState`"}],"import":"import { Pagination } from \"@agentero/design-system\";","jsDocTags":{},"description":"Pagination is a 1-indexed paged navigation control with previous/next icon buttons, numeric page buttons, and a leading \"X - Y of Z\" entries summary. The page list collapses long ranges with `…` ellipses so the control stays compact regardless of total page count. Use it for lists, tables, or grids that are split across pages.","reactDocgenTypescript":{"tags":{"summary":"1-indexed paged navigation control with prev/next, numeric pages, and entries summary","example":"```tsx\nimport { useState } from 'react';\nimport { Pagination } from '@agentero/design-system/pagination';\n\nconst [page, setPage] = useState(1);\n\n<Pagination\n currentPage={page}\n pageSize={10}\n totalCount={1000}\n onPageChange={setPage}\n/>\n```"},"filePath":"/home/runner/work/design-system/design-system/src/pagination/pagination.tsx","description":"Pagination is a 1-indexed paged navigation control with previous/next icon\nbuttons, numeric page buttons, and a leading \"X - Y of Z\" entries summary.\nThe page list collapses long ranges with `…` ellipses, keeping at most a\nhandful of buttons in view regardless of total page count. Use it whenever\na list, table, or grid is split across pages and the user needs direct\naccess to specific pages (not just prev/next).\n\nThe control short-circuits to `null` when `currentPage === 0` (legacy \"off\"\nsentinel) or when there are no pages to show, so it's safe to mount\nunconditionally above a list that may be empty.\n\nDo **not** use Pagination for infinite-scroll feeds, sub-page-1 indexing\n(the `0` value is reserved as the off-switch), or as a tab/segmented\ncontrol — it's strictly a page-of-pages affordance.","displayName":"Pagination","methods":[],"props":{"onPageChange":{"defaultValue":null,"description":"","name":"onPageChange","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":true,"type":{"name":"(page: number) => void"}},"totalCount":{"defaultValue":null,"description":"","name":"totalCount","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":true,"type":{"name":"number"}},"currentPage":{"defaultValue":null,"description":"","name":"currentPage","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":true,"type":{"name":"number"}},"pageSize":{"defaultValue":null,"description":"","name":"pageSize","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":true,"type":{"name":"number"}},"className":{"defaultValue":null,"description":"","name":"className","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}}},"exportName":"Pagination"}},"components-statusball":{"id":"components-statusball","name":"StatusBall","path":"./src/status-ball/status-ball.stories.tsx","stories":[{"id":"components-statusball--default","name":"Default","snippet":"const Default = () => <div className=\"flex items-center gap-2\">\n <StatusBall color=\"neutral\" />\n</div>;","description":"The default dot — `color=\"neutral\"` for an unknown or inactive status. Drop next to a text label to surface state at a glance.","summary":"Default neutral dot representing an inactive status"},{"id":"components-statusball--intents","name":"Intents","snippet":"const Intents = () => {\n const samples: { color: (typeof INTENTS)[number]; label: string }[] = [\n { color: 'success', label: 'Active' },\n { color: 'info', label: 'Scheduled' },\n { color: 'warning', label: 'Pending' },\n { color: 'danger', label: 'Expired' },\n { color: 'creative', label: 'In review' },\n { color: 'playful', label: 'Flagged' },\n { color: 'dynamic', label: 'Needs attention' },\n { color: 'neutral', label: 'Inactive' }\n ];\n\n return (\n <div className=\"grid grid-cols-2 gap-x-8 gap-y-3\">\n {samples.map(({ color, label }) => (\n <div key={color} className=\"flex items-center gap-2\">\n <StatusBall color={color} />\n <span className=\"text-sm text-text-default-base-primary\">{label}</span>\n </div>\n ))}\n </div>\n );\n};","description":"All 8 semantic intents rendered in a single grid, each paired with a sample label. Consumers typically drive the `color` prop from a domain-specific status → intent lookup table.","summary":"Every intent paired with a representative status label"},{"id":"components-statusball--success","name":"Success","snippet":"const Success = () => <StatusBall color=\"success\" data-testid=\"status-ball-success\" />;","description":"Success dot for positive / active states — the most common pairing for \"live\" records such as active licenses or confirmed appointments.","summary":"Success dot for positive or active statuses"},{"id":"components-statusball--info","name":"Info","snippet":"const Info = () => <StatusBall color=\"info\" />;","description":"Info dot for informational or neutral-positive states — e.g., scheduled or queued records that are progressing normally.","summary":"Info dot for informational statuses"},{"id":"components-statusball--warning","name":"Warning","snippet":"const Warning = () => <StatusBall color=\"warning\" />;","description":"Warning dot for pending states or records approaching a deadline — e.g., a license nearing expiration or an appointment awaiting confirmation.","summary":"Warning dot for pending or approaching-deadline statuses"},{"id":"components-statusball--danger","name":"Danger","snippet":"const Danger = () => <StatusBall color=\"danger\" />;","description":"Danger dot for error / expired / blocking states — e.g., an expired license or a failed payment that blocks progress.","summary":"Danger dot for error or expired statuses"},{"id":"components-statusball--creative","name":"Creative","snippet":"const Creative = () => <StatusBall color=\"creative\" />;","description":"Creative dot for category-specific statuses without a direct success/info/ warning/danger mapping — often used for \"in review\" or \"under assessment\" domain states.","summary":"Creative dot for category-specific statuses"},{"id":"components-statusball--dynamic","name":"Dynamic","snippet":"const Dynamic = () => <StatusBall color=\"dynamic\" />;","description":"Dynamic dot for attention-worthy states that sit between warning and danger — e.g., records that need action soon but are not yet failed.","summary":"Dynamic dot for attention-needed statuses"},{"id":"components-statusball--playful","name":"Playful","snippet":"const Playful = () => <StatusBall color=\"playful\" />;","description":"Playful dot for flagged or priority domain states that need to stand out from warnings with a distinct hue.","summary":"Playful dot for flagged or priority statuses"},{"id":"components-statusball--neutral","name":"Neutral","snippet":"const Neutral = () => <StatusBall color=\"neutral\" />;","description":"Neutral dot for inactive, unknown, or default states — the fallback when no other intent applies.","summary":"Neutral dot for inactive or unknown statuses"},{"id":"components-statusball--in-list","name":"In List","snippet":"const InList = () => {\n const rows = [\n { color: 'success', name: 'Ada Lovelace', status: 'Active' },\n { color: 'warning', name: 'Grace Hopper', status: 'Pending renewal' },\n { color: 'danger', name: 'Alan Turing', status: 'Expired' },\n { color: 'neutral', name: 'Katherine Johnson', status: 'Inactive' }\n ] as const;\n\n return (\n <ul className=\"w-80 divide-y divide-border-default-base-primary rounded-lg border border-border-default-base-primary bg-bg-default-base-primary\">\n {rows.map(row => (\n <li key={row.name} className=\"flex items-center gap-3 px-4 py-3\">\n <StatusBall color={row.color} />\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-medium text-text-default-base-primary\">{row.name}</span>\n <span className=\"text-xs text-text-default-base-secondary\">{row.status}</span>\n </div>\n </li>\n ))}\n </ul>\n );\n};","description":"StatusBall inside a list row — the canonical production usage, mirroring the appointment and license list patterns in `producerflow/mono`. Each row pairs a dot with a label and supporting text.","summary":"StatusBall paired with labels inside a list"},{"id":"components-statusball--in-pill","name":"In Pill","snippet":"const InPill = () => (\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default-base-primary bg-bg-default-base-primary px-2.5 py-1 text-xs text-text-default-base-primary\">\n <StatusBall color=\"success\" />\n Active\n </span>\n <span className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default-base-primary bg-bg-default-base-primary px-2.5 py-1 text-xs text-text-default-base-primary\">\n <StatusBall color=\"warning\" />\n Pending\n </span>\n <span className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default-base-primary bg-bg-default-base-primary px-2.5 py-1 text-xs text-text-default-base-primary\">\n <StatusBall color=\"danger\" />\n Expired\n </span>\n </div>\n);","description":"StatusBall inside a status pill — a tinted badge that pairs the dot with a label in a single rounded container. Use when the status needs more visual weight than a bare list row provides.","summary":"StatusBall inside a rounded status pill"}],"import":"import { StatusBall } from \"@agentero/design-system\";","jsDocTags":{},"description":"StatusBall renders a small colored dot that marks the state of an adjacent label — appointment confirmation, license validity, availability, or any list row where a single glyph of color communicates status. Pair it with text; the dot alone is not announced to assistive technologies, so the surrounding label must carry the meaning.","reactDocgenTypescript":{"tags":{"summary":"Small colored dot that signals the status of an adjacent label","example":"<div className=\"flex items-center gap-2\">\n <StatusBall color=\"success\" />\n <span>Active</span>\n</div>\n<StatusBall color={statusToIntent[appointment.status]} />"},"filePath":"/home/runner/work/design-system/design-system/src/status-ball/status-ball.tsx","description":"StatusBall renders a small colored dot used to mark the state of an adjacent\nlabel — things like an appointment's confirmation state, a license's validity,\nor any list-row entry where a single glyph of color conveys the status at a\nglance. Pair it with text; the dot alone is not announced to assistive\ntechnologies, so the surrounding label must carry the meaning.\n\nThe 8 intents (`success`, `info`, `warning`, `danger`, `creative`,\n`dynamic`, `playful`, `neutral`) map to semantic tokens\n(`--color-bg-status-ball-*`) and mirror the convention used by\n[Alert](?path=/docs/components-alert--docs). Consumers typically resolve a\ndomain-specific status to an intent via their own lookup table\n(e.g., `active → success`, `expired → danger`).\n\nDo **not** use StatusBall as a progress or loading indicator — reach for\n[Loading](?path=/docs/components-loading--docs) for async state. For\nsection-level alerts with copy, use [Alert](?path=/docs/components-alert--docs)\ninstead.","displayName":"StatusBall","methods":[],"props":{},"exportName":"StatusBall"}},"components-toast":{"id":"components-toast","name":"Toast","path":"./src/toast/toast.stories.tsx","stories":[{"id":"components-toast--default","name":"Default","snippet":"const Default = () => (\n <div style={{ minHeight: '240px' }}>\n <Button variant=\"secondary\" onClick={() => toast('Hello from Toast')}>\n Show toast\n </Button>\n </div>\n);","description":"Args-controlled playground. Click the button to fire a neutral toast; tweak `position` and `duration` from the Controls panel to preview the provider defaults.","summary":"Default playground for the Toast provider"},{"id":"components-toast--inline","name":"Inline","snippet":"const Inline = () => (\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>\n <Button\n variant=\"secondary\"\n onClick={() => toast('Something happened', { description: 'Additional context.' })}>\n Neutral\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() => toast.success('Policy saved', { description: 'Your edits are live.' })}>\n Success\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.error('Failed to save', { description: 'The file could not be processed.' })\n }>\n Error\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.warning('License expiring soon', { description: 'Renew before end of month.' })\n }>\n Warning\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.info('Sync in progress', { description: 'Please wait while we sync your data.' })\n }>\n Info\n </Button>\n </div>\n);","description":"Inline layout (default). Compact treatment — title with an optional description stacked directly below it. The `type` drives the icon color. Use for short acknowledgments that don't need a colored rail.","summary":"Inline layout across all five semantic types"},{"id":"components-toast--expanded","name":"Expanded","snippet":"const Expanded = () => (\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast('Something happened', {\n variant: 'expanded',\n description: 'Additional context for the user.'\n })\n }>\n Neutral\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.success('Policy saved', {\n variant: 'expanded',\n description: 'Your changes have been saved successfully.'\n })\n }>\n Success\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.error('Failed to save', {\n variant: 'expanded',\n description: 'The file could not be processed.'\n })\n }>\n Error\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.warning('License expiring soon', {\n variant: 'expanded',\n description: 'Renew before the end of the month to avoid interruption.'\n })\n }>\n Warning\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.info('Sync in progress', {\n variant: 'expanded',\n description: 'Please wait while we sync your data.'\n })\n }>\n Info\n </Button>\n </div>\n);","description":"Expanded layout. Multi-line treatment with a 0.375rem colored left rail that tracks the toast's `type`. Use for feedback that benefits from a description on its own line or a trailing action button.","summary":"Expanded layout across all five semantic types"},{"id":"components-toast--with-action-object","name":"With Action Object","snippet":"const WithActionObject = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.error('Upload failed', {\n variant: 'expanded',\n description: 'The file could not be processed.',\n action: { label: 'Retry', onClick: () => {} }\n })\n }>\n Show toast with action\n </Button>\n);","description":"Toast with a structured `action` object. Passing `{ label, onClick }` renders the built-in secondary Button; the handler runs and the toast auto-dismisses afterward.","summary":"Toast with a structured action button"},{"id":"components-toast--with-action-node","name":"With Action Node","snippet":"const WithActionNode = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast('File uploaded', {\n description: 'document.pdf is ready.',\n action: (\n <Button variant=\"link\" onClick={() => {}}>\n View file\n </Button>\n )\n })\n }>\n Show toast with link action\n </Button>\n);","description":"Toast with a raw-ReactNode `action`. Pass any JSX to render a custom trailing control — a link, a pair of buttons, etc. — when the default secondary Button doesn't fit.","summary":"Toast with a custom ReactNode action"},{"id":"components-toast--with-action-and-cancel","name":"With Action And Cancel","snippet":"const WithActionAndCancel = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.success('Record archived', {\n variant: 'expanded',\n description: 'The record is hidden from the default view.',\n action: { label: 'Undo', onClick: () => {} },\n cancel: { label: 'Dismiss', onClick: () => {} }\n })\n }>\n Show toast with action + cancel\n </Button>\n);","description":"Toast with both `action` and `cancel`. Cancel renders as a ghost Button next to the action; its handler runs and the toast auto-dismisses.","summary":"Toast with an action and a cancel control"},{"id":"components-toast--non-dismissible","name":"Non Dismissible","snippet":"const NonDismissible = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.info('Sync in progress', {\n dismissible: false,\n description: 'Please wait while we sync your data.'\n })\n }>\n Show non-dismissible toast\n </Button>\n);","description":"Non-dismissible toast. Setting `dismissible: false` hides the close button; the toast still auto-dismisses when its `duration` elapses, or programmatically via `toast.dismiss(id)`.","summary":"Non-dismissible toast (no close button)"},{"id":"components-toast--long-duration","name":"Long Duration","snippet":"const LongDuration = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.info('Uploading documents', {\n description: 'This may take a moment.',\n duration: 10_000\n })\n }>\n Show 10s toast\n </Button>\n);","description":"Long-duration toast. `duration` (in ms) overrides the provider default so long-running operations stay visible until they're relevant.","summary":"Toast with a custom `duration`"},{"id":"components-toast--programmatic-dismiss","name":"Programmatic Dismiss","snippet":"const ProgrammaticDismiss = () => {\n let toastId: string | number | undefined;\n return (\n <div style={{ display: 'flex', gap: '0.5rem' }}>\n <Button\n variant=\"secondary\"\n onClick={() => {\n toastId = toast.info('Uploading...', { duration: 60_000 });\n }}>\n Start\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => {\n if (toastId !== undefined) toast.dismiss(toastId);\n }}>\n Dismiss\n </Button>\n </div>\n );\n};","description":"Programmatic dismissal. `toast()` returns the toast id, which you can pass to `toast.dismiss(id)` to clear it before its duration elapses.","summary":"Dismiss a toast programmatically via its id"},{"id":"components-toast--with-promise","name":"With Promise","snippet":"const WithPromise = () => {\n const fakeFetch = () =>\n new Promise<string>((resolve, reject) => {\n window.setTimeout(\n () => (Math.random() > 0.5 ? resolve('ok') : reject(new globalThis.Error('nope'))),\n 1500\n );\n });\n return (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.promise(fakeFetch(), {\n loading: 'Saving document…',\n success: 'Document saved',\n error: 'Save failed'\n })\n }>\n Run promise\n </Button>\n );\n};","description":"`toast.promise` wires a toast to an async operation — loading while the promise is pending, success or error when it settles. Useful for save/submit flows where the outcome feeds back into the same toast.","summary":"Wire a toast to an async operation via `toast.promise`"},{"id":"components-toast--custom-icon","name":"Custom Icon","snippet":"const CustomIcon = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.success('Sync started', {\n description: 'Data sync is in progress.',\n icon: (\n <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"currentColor\" aria-hidden>\n <path d=\"M12 4V1L8 5l4 4V6c3.3 0 6 2.7 6 6 0 1-.3 2-.7 2.8l1.5 1.5C19.5 15 20 13.6 20 12c0-4.4-3.6-8-8-8zm0 14c-3.3 0-6-2.7-6-6 0-1 .3-2 .7-2.8L5.2 7.7C4.5 9 4 10.4 4 12c0 4.4 3.6 8 8 8v3l4-4-4-4v3z\" />\n </svg>\n )\n })\n }>\n Show toast with custom icon\n </Button>\n);","description":"Custom `icon` override. Pass any ReactNode as `icon` to replace the type-based default — helpful when the toast reflects a domain-specific action (e.g., a sync icon for a sync-in-progress toast).","summary":"Override the default type-based icon"}],"import":"import { Button, Toast } from \"@agentero/design-system\";","jsDocTags":{},"description":"Toast renders transient feedback about an outcome — saved, failed, warning, info — without interrupting the user's flow. Mount `<Toast />` once near the app root to register the provider, then call the imperative `toast()` API from anywhere in the tree. Five semantic types (`neutral`, `success`, `error`, `warning`, `info`) × two layouts (`inline`, `expanded`) cover the common feedback patterns.","reactDocgenTypescript":{"tags":{"summary":"Toast provider; mount once near the app root","example":"<Toast />\n<Toast position=\"top-center\" duration={4000} />"},"filePath":"/home/runner/work/design-system/design-system/src/toast/toast.tsx","description":"Toast provider. Renders the sonner `<Toaster />` configured for the\n{@link toast} imperative API. Mount it once near the root of your React\ntree (below any context providers that the toasts need, and above the\nrest of the app) so every call to `toast()` from anywhere in the tree\nrenders into the same surface.\n\nDefaults: `position='bottom-right'`, `duration=5000`. The Toaster is sized\nto `23.75rem` (`[--width:23.75rem]`) and each list item stretches to that\nwidth (`[&>li]:w-full`) so the DS Toast fills the Toaster row rather than\nsonner's 356px default. The provider disables sonner's built-in close\nbutton (`closeButton={false}`) — dismissal is rendered inside each Toast\nby the DS component itself.\n\nDo **not** use Toast for persistent feedback — mount an `Alert` with\n`color=\"success|danger\"` instead. Do **not** use Toast for form\nvalidation errors — render those inline with the form field.","displayName":"Toast","methods":[],"props":{"position":{"defaultValue":{"value":"bottom-right"},"description":"Placement of the toaster on the screen. Defaults to `'bottom-right'`.","name":"position","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"ToastPosition","value":[{"value":"\"top-left\""},{"value":"\"top-center\""},{"value":"\"top-right\""},{"value":"\"bottom-left\""},{"value":"\"bottom-center\""},{"value":"\"bottom-right\""}]}},"duration":{"defaultValue":{"value":"5000"},"description":"Default auto-dismiss duration in ms for toasts fired against this provider. Defaults to `5000`.","name":"duration","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"number"}},"dir":{"defaultValue":null,"description":"Text direction. Sonner forwards this to the rendered toaster root.","name":"dir","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"auto\" | \"ltr\" | \"rtl\"","value":[{"value":"\"auto\""},{"value":"\"ltr\""},{"value":"\"rtl\""}]}},"gap":{"defaultValue":null,"description":"Gap between stacked toasts, in pixels.","name":"gap","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"number"}},"offset":{"defaultValue":null,"description":"Offset from the screen edge, in pixels or as a CSS length.","name":"offset","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string | number"}},"expand":{"defaultValue":null,"description":"When `true`, stack expands on hover instead of auto-collapsing.","name":"expand","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"visibleToasts":{"defaultValue":null,"description":"Maximum number of toasts rendered at once before earlier ones dismiss.","name":"visibleToasts","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"number"}},"hotkey":{"defaultValue":null,"description":"Keyboard shortcut used to focus the toaster.","name":"hotkey","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string[]"}},"richColors":{"defaultValue":null,"description":"When `true`, sonner paints colored backgrounds per type (DS uses its own icon tokens by default).","name":"richColors","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"invert":{"defaultValue":null,"description":"When `true`, flips light/dark theme on the toaster root.","name":"invert","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"className":{"defaultValue":null,"description":"Additional className merged onto the sonner `<Toaster>` root.","name":"className","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}}},"exportName":"Toast"}}},"meta":{"docgen":"react-docgen-typescript","durationMs":2229}}
1
+ {"v":0,"components":{"components-alert":{"id":"components-alert","name":"Alert","path":"./src/alert/alert.stories.tsx","stories":[{"id":"components-alert--default","name":"Default","snippet":"const Default = () => <Alert\n color=\"neutral\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Args-controlled playground. Toggle `color`, `size`, `ghost`, `hasIcon`, and `onDismiss` from the Controls panel to explore every visual combination.","summary":"Default args playground for Alert"},{"id":"components-alert--neutral","name":"Neutral","snippet":"const Neutral = () => <Alert\n color=\"neutral\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Neutral color is the default and carries no strong semantic signal — use it for generic inline information.","summary":"Neutral color (default)"},{"id":"components-alert--success","name":"Success","snippet":"const Success = () => <Alert\n color=\"success\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Success color confirms a positive outcome — saved record, completed task, healthy state.","summary":"Success color for positive outcomes"},{"id":"components-alert--danger","name":"Danger","snippet":"const Danger = () => <Alert\n color=\"danger\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Danger color flags errors and destructive outcomes that require the user's attention.","summary":"Danger color for errors and destructive outcomes"},{"id":"components-alert--warning","name":"Warning","snippet":"const Warning = () => <Alert\n color=\"warning\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Warning color signals caution — the user should review before proceeding.","summary":"Warning color for cautionary feedback"},{"id":"components-alert--info","name":"Info","snippet":"const Info = () => <Alert\n color=\"info\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Info color highlights tips, hints, or secondary informational content.","summary":"Info color for informational highlights"},{"id":"components-alert--creative","name":"Creative","snippet":"const Creative = () => <Alert\n color=\"creative\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Creative color uses a brand-aligned purple accent for marketing or onboarding moments.","summary":"Creative brand accent color"},{"id":"components-alert--dynamic","name":"Dynamic","snippet":"const Dynamic = () => <Alert\n color=\"dynamic\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Dynamic color uses a brand-aligned orange accent for activity or momentum-focused content.","summary":"Dynamic brand accent color"},{"id":"components-alert--playful","name":"Playful","snippet":"const Playful = () => <Alert\n color=\"playful\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Playful color uses a brand-aligned pink accent for lighter or celebratory content.","summary":"Playful brand accent color"},{"id":"components-alert--ghost","name":"Ghost","snippet":"const Ghost = () => <Alert\n color=\"danger\"\n size=\"sm\"\n ghost\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Ghost mode removes the background and padding so the alert blends inline with surrounding text (e.g., form field errors). Colors switch to the ghost token ramp for lower visual weight.","summary":"Ghost mode for inline, low-emphasis alerts"},{"id":"components-alert--small-size","name":"Small Size","snippet":"const SmallSize = () => <Alert\n color=\"neutral\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Small size (default) uses compact padding and 14/12px typography — suitable for inline alerts inside forms, tables, or cards.","summary":"Small size (default, compact)"},{"id":"components-alert--medium-size","name":"Medium Size","snippet":"const MediumSize = () => <Alert\n color=\"neutral\"\n size=\"md\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Medium size uses larger padding and 18/14px typography — suitable for standalone alerts in empty states, modals, or dedicated feedback regions.","summary":"Medium size (prominent, standalone)"},{"id":"components-alert--with-dismiss","name":"With Dismiss","snippet":"const WithDismiss = () => <Alert color=\"warning\" size=\"sm\" ghost={false} hasIcon onDismiss={fn()}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Dismissible alert. Providing `onDismiss` shows an icon-only close button with `aria-label=\"Dismiss\"` that inherits the alert's color.","summary":"Alert with a dismiss button"},{"id":"components-alert--with-actions","name":"With Actions","snippet":"const WithActions = () => <Alert\n color=\"info\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Update available</Alert.Title>\n <Alert.Paragraph>Reload to apply the latest version.</Alert.Paragraph>\n </Alert.Content>\n <Alert.Actions>\n <Alert.Button onClick={() => {}}>Reload</Alert.Button>\n </Alert.Actions>\n</Alert>;","description":"Alert with a trailing action pinned to the right edge. Use `Alert.Actions` + `Alert.Button` for the common \"message + action\" pattern.","summary":"Alert with a trailing action button"},{"id":"components-alert--with-dismiss-and-action","name":"With Dismiss And Action","snippet":"const WithDismissAndAction = () => <Alert\n color=\"warning\"\n size=\"md\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Session expiring</Alert.Title>\n <Alert.Paragraph>Renew to continue editing.</Alert.Paragraph>\n </Alert.Content>\n <Alert.Actions>\n <Alert.Button onClick={() => {}}>Renew session</Alert.Button>\n </Alert.Actions>\n</Alert>;","description":"Alert combining a dismiss button with a trailing action. Dismiss is pinned to the right edge after the actions.","summary":"Alert with both dismiss and action"},{"id":"components-alert--without-icon","name":"Without Icon","snippet":"const WithoutIcon = () => <Alert\n color=\"info\"\n size=\"sm\"\n ghost={false}\n hasIcon={false}\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Alert rendered without the built-in color icon. Use `hasIcon={false}` when the surrounding context already conveys the semantic intent.","summary":"Alert without the default icon"},{"id":"components-alert--with-custom-icon","name":"With Custom Icon","snippet":"const WithCustomIcon = () => <Alert\n color=\"creative\"\n size=\"sm\"\n ghost={false}\n hasIcon\n icon={IconLightbulb}\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Title</Alert.Title>\n <Alert.Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Alert with a caller-supplied icon that replaces the default color icon. The custom icon receives the slot-computed className so color tokens still apply.","summary":"Alert with a custom icon override"},{"id":"components-alert--with-paragraph-html","name":"With Paragraph Html","snippet":"const WithParagraphHtml = () => <Alert\n color=\"success\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Formatted content</Alert.Title>\n <Alert.ParagraphHtml\n html=\"Review the <strong>terms</strong> or <a href='https://example.com'>read the docs</a>.\" />\n </Alert.Content>\n</Alert>;","description":"Alert rendering a paragraph from pre-sanitized HTML via `Alert.ParagraphHtml`. The caller is responsible for sanitizing the HTML string before passing it in.","summary":"Alert paragraph rendered from HTML"},{"id":"components-alert--with-pictograms","name":"With Pictograms","snippet":"const WithPictograms = () => <Alert\n color=\"info\"\n size=\"md\"\n ghost={false}\n hasIcon={false}\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Pictograms>\n <svg viewBox=\"0 0 64 64\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden>\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.15\" />\n <circle cx=\"32\" cy=\"32\" r=\"14\" fill=\"currentColor\" />\n </svg>\n </Alert.Pictograms>\n <Alert.Content>\n <Alert.Title>Pictogram example</Alert.Title>\n <Alert.Paragraph>Pictograms scale to 64×64px regardless of the configured size.\n </Alert.Paragraph>\n </Alert.Content>\n</Alert>;","description":"Alert with a 64×64 pictogram in place of the inline icon. Use `Alert.Pictograms` when the message benefits from a richer illustration.","summary":"Alert with a pictogram illustration"},{"id":"components-alert--only-paragraph","name":"Only Paragraph","snippet":"const OnlyParagraph = () => <Alert\n color=\"neutral\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Paragraph>This field is required.</Alert.Paragraph>\n</Alert>;","description":"Alert rendered with only a paragraph — no title. The root omits `aria-labelledby` since there is no title to reference.","summary":"Alert with only a paragraph body"},{"id":"components-alert--with-actions-below","name":"With Actions Below","snippet":"const WithActionsBelow = () => <Alert\n color=\"success\"\n size=\"sm\"\n ghost={false}\n hasIcon\n onDismiss={onDismiss ? () => {} : undefined}>\n <Alert.Content>\n <Alert.Title>Upload complete</Alert.Title>\n <Alert.Paragraph>12 documents were added to the policy.</Alert.Paragraph>\n <div>\n <Alert.Button onClick={() => {}}>View documents</Alert.Button>\n </div>\n </Alert.Content>\n</Alert>;","description":"Action button rendered inline below the paragraphs, inside `Alert.Content`, rather than pinned to the right via `Alert.Actions`.","summary":"Alert with actions placed below the content"},{"id":"components-alert--all-colors","name":"All Colors","snippet":"const AllColors = () => (\n <Stack>\n {COLORS.map(color => (\n <Alert key={color} color={color}>\n <Alert.Content>\n <Alert.Title>{color}</Alert.Title>\n <Alert.Paragraph>\n This is a {color} alert variant with the default icon.\n </Alert.Paragraph>\n </Alert.Content>\n </Alert>\n ))}\n </Stack>\n);","description":"All eight colors in their primary (non-ghost) treatment, stacked for comparison. Each alert uses the built-in icon mapping for its color.","summary":"Visual comparison of all Alert colors"},{"id":"components-alert--all-ghost-colors","name":"All Ghost Colors","snippet":"const AllGhostColors = () => (\n <Stack>\n {COLORS.map(color => (\n <Alert key={color} color={color} ghost>\n <Alert.Content>\n <Alert.Title>{color} (ghost)</Alert.Title>\n <Alert.Paragraph>\n This is a {color} ghost alert variant with the ghost icon color.\n </Alert.Paragraph>\n </Alert.Content>\n </Alert>\n ))}\n </Stack>\n);","description":"All eight colors in ghost mode, stacked for comparison. Ghost alerts use a lower-weight token ramp and omit background + padding.","summary":"Visual comparison of all Alert colors in ghost mode"}],"import":"import { Alert } from \"@agentero/design-system\";","jsDocTags":{},"description":"Alert surfaces feedback about outcomes or state changes — success, danger, warning, or info. Compose it from `Alert.Content`, `Alert.Title`, `Alert.Paragraph`, `Alert.Actions`, and `Alert.Button` to build the layout your flow needs. Eight colors, two sizes, and a ghost mode cover most feedback scenarios.","reactDocgenTypescript":{"tags":{"summary":"Feedback banner with color variants, optional icon, and dismiss","example":"<Alert color=\"success\" size=\"sm\">\n <Alert.Content>\n <Alert.Title>Policy saved</Alert.Title>\n <Alert.Paragraph>Your changes are live.</Alert.Paragraph>\n </Alert.Content>\n</Alert>\n<Alert color=\"warning\" onDismiss={() => setOpen(false)}>\n <Alert.Content>\n <Alert.Title>Session expiring</Alert.Title>\n <Alert.Paragraph>Renew to continue editing.</Alert.Paragraph>\n </Alert.Content>\n <Alert.Actions>\n <Alert.Button onClick={renew}>Renew session</Alert.Button>\n </Alert.Actions>\n</Alert>\n<Alert color=\"danger\" ghost>\n <Alert.Paragraph>This field is required.</Alert.Paragraph>\n</Alert>"},"filePath":"/home/runner/work/design-system/design-system/src/alert/alert.tsx","description":"Alert surfaces feedback about an outcome or state change — success, error,\nwarning, or informational. Compose it from the exposed sub-components to\nbuild the layout you need: `Alert.Content` groups a `Alert.Title` and any\nnumber of `Alert.Paragraph` / `Alert.ParagraphHtml`; `Alert.Actions` adds\ntrailing buttons; `Alert.Pictograms` renders a 64px illustration. Pass\n`onDismiss` to show a close button; `hasIcon={false}` to hide the default\nicon; `icon` to substitute a custom icon component.\n\nAccessibility: the root carries `role=\"alert\"`; `aria-labelledby` points at\nthe rendered `Alert.Title` (when present) and `aria-describedby` at the\nparagraph wrapper. Multiple Alerts on the same page receive unique ids via\n`useId()`. The dismiss control has an accessible name of `Dismiss`.\n\nDo **not** use Alert for transient toast notifications (use a Toast\ncomponent) or for large error pages (use a dedicated empty-state).","displayName":"Alert","methods":[],"props":{"onDismiss":{"defaultValue":null,"description":"Fires when the dismiss button is clicked. When provided, renders an `iconOnly` close button with `aria-label=\"Dismiss\"`.","name":"onDismiss","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"(() => void)"}},"hasIcon":{"defaultValue":{"value":"true"},"description":"When `true` (default), renders the built-in icon for the current `color`. Set to `false` to omit the icon entirely.","name":"hasIcon","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"icon":{"defaultValue":null,"description":"Overrides the default icon for the current `color`. Receives the slot-computed className so color tokens still apply.","name":"icon","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"ComponentType<SVGProps<SVGSVGElement>>"}},"color":{"defaultValue":{"value":"neutral"},"description":"Semantic color. Defaults to `'neutral'`.\n- `neutral` — generic info; no strong signal.\n- `success` — positive confirmation.\n- `danger` — error or destructive outcome.\n- `warning` — caution; user attention needed.\n- `info` — informational highlight.\n- `creative`, `dynamic`, `playful` — brand-aligned accents.","name":"color","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"},{"fileName":"design-system/node_modules/@types/react/index.d.ts","name":"HTMLAttributes"}],"required":false,"type":{"name":"enum","raw":"\"neutral\" | \"success\" | \"danger\" | \"warning\" | \"info\" | \"creative\" | \"dynamic\" | \"playful\"","value":[{"value":"\"neutral\""},{"value":"\"success\""},{"value":"\"danger\""},{"value":"\"warning\""},{"value":"\"info\""},{"value":"\"creative\""},{"value":"\"dynamic\""},{"value":"\"playful\""}]}},"size":{"defaultValue":{"value":"sm"},"description":"Size treatment. Defaults to `'sm'`.\n- `sm` — compact inline alerts (1rem padding, 14/12px typography).\n- `md` — prominent standalone alerts (2rem padding, 18/14px typography).","name":"size","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"AlertSizeType","value":[{"value":"\"sm\""},{"value":"\"md\""}]}},"ghost":{"defaultValue":{"value":"false"},"description":"When `true`, removes background and padding so the alert blends inline\nwith surrounding text (e.g., inline form field errors). Colors switch\nto the ghost token ramp for lower visual weight.","name":"ghost","declarations":[{"fileName":"design-system/src/alert/alert.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}}},"exportName":"Alert"}},"components-avatar":{"id":"components-avatar","name":"Avatar","path":"./src/avatar/avatar.stories.tsx","stories":[{"id":"components-avatar--default","name":"Default","snippet":"const Default = () => <Avatar fallback=\"JD\" size=\"md\" variant=\"circle\" type=\"photo\" />;","description":"The default avatar with fallback initials. Renders as a medium circle when no image source is provided.","summary":"Default avatar with fallback initials"},{"id":"components-avatar--with-image","name":"With Image","snippet":"const WithImage = () => <Avatar\n fallback=\"JD\"\n size=\"md\"\n variant=\"circle\"\n type=\"photo\"\n src=\"https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&w=256&h=256&q=70&crop=focalpoint&fp-x=0.5&fp-y=0.3&fp-z=1&fit=crop\"\n alt=\"Alex Morgan\" />;","description":"Avatar displaying a user profile photo. The image fills the avatar shape and the fallback is hidden while the image loads successfully.","summary":"Avatar with a profile image"},{"id":"components-avatar--with-fallback-initials","name":"With Fallback Initials","snippet":"const WithFallbackInitials = () => <Avatar\n fallback=\"AM\"\n size=\"md\"\n variant=\"circle\"\n type=\"photo\"\n src=\"https://broken-url.example/photo.jpg\" />;","description":"When the image fails to load, the fallback content is displayed. Pass initials, an icon, or any ReactNode as the `fallback` prop.","summary":"Fallback content shown when image is unavailable"},{"id":"components-avatar--circle","name":"Circle","snippet":"const Circle = () => <Avatar fallback=\"CR\" size=\"md\" variant=\"circle\" type=\"photo\" />;","description":"The circle variant is the default shape, ideal for user profile photos.","summary":"Circle-shaped avatar (default)"},{"id":"components-avatar--square","name":"Square","snippet":"const Square = () => <Avatar fallback=\"WS\" size=\"md\" variant=\"square\" type=\"photo\" />;","description":"The square variant uses a rounded rectangle, suitable for workspace, team, or organization icons.","summary":"Square-shaped avatar for workspaces"},{"id":"components-avatar--pillow","name":"Pillow","snippet":"const Pillow = () => <Avatar fallback=\"PL\" size=\"md\" variant=\"pillow\" type=\"photo\" />;","description":"The pillow variant uses a soft, organic squircle shape for a friendly and distinctive appearance.","summary":"Pillow-shaped avatar with organic squircle"},{"id":"components-avatar--pentagon","name":"Pentagon","snippet":"const Pentagon = () => <Avatar fallback=\"PT\" size=\"md\" variant=\"pentagon\" type=\"photo\" />;","description":"The pentagon variant uses a five-sided mask for a unique visual identity. Note: the border is hidden in this variant due to the mask shape.","summary":"Pentagon-shaped avatar for unique identity"},{"id":"components-avatar--type-photo","name":"Type Photo","snippet":"const TypePhoto = () => <Avatar\n fallback=\"AM\"\n size=\"md\"\n variant=\"circle\"\n type=\"photo\"\n src=\"https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&w=256&h=256&q=70&crop=focalpoint&fp-x=0.5&fp-y=0.3&fp-z=1&fit=crop\"\n alt=\"Alex Morgan\" />;","description":"The `photo` type is the default. The image fills the avatar shape edge-to-edge, which is ideal for user profile photographs.","summary":"Photo type fills the avatar shape edge-to-edge"},{"id":"components-avatar--type-initials","name":"Type Initials","snippet":"const TypeInitials = () => <Avatar fallback=\"JD\" size=\"md\" variant=\"circle\" type=\"initials\" />;","description":"The `initials` type is intended when no image is available and the avatar stands in for a user with their initials. The fallback text is centered within the avatar shape.","summary":"Initials type for users without a profile photo"},{"id":"components-avatar--type-isotype","name":"Type Isotype","snippet":"const TypeIsotype = () => <Avatar\n fallback=\"FG\"\n size=\"md\"\n variant=\"square\"\n type=\"isotype\"\n src=\"https://cdn.simpleicons.org/figma\"\n alt=\"Figma\" />;","description":"The `isotype` type renders the image smaller than the avatar shape so a brand or organization icon sits centered inside the container rather than filling it. Use for workspace, team, or company avatars where a logo should remain legible inside the bounding shape.","summary":"Isotype type centers a brand icon inside the shape"},{"id":"components-avatar--all-types","name":"All Types","snippet":"const AllTypes = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n <Avatar\n size=\"lg\"\n type=\"photo\"\n src=\"https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&w=256&h=256&q=70&crop=focalpoint&fp-x=0.5&fp-y=0.3&fp-z=1&fit=crop\"\n alt=\"Alex Morgan\"\n fallback=\"AM\"\n />\n <Avatar size=\"lg\" type=\"initials\" fallback=\"JD\" />\n <Avatar\n size=\"lg\"\n type=\"isotype\"\n variant=\"square\"\n src=\"https://cdn.simpleicons.org/figma\"\n alt=\"Figma\"\n fallback=\"FG\"\n />\n </div>\n);","description":"All content types shown side by side: `photo` fills the shape, `initials` centers text, and `isotype` shrinks a brand icon inside the bounding shape.","summary":"Visual comparison of all avatar content types"},{"id":"components-avatar--all-sizes-isotype","name":"All Sizes Isotype","snippet":"const AllSizesIsotype = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {(['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'] as const).map(size => (\n <Avatar\n key={size}\n size={size}\n type=\"isotype\"\n variant=\"square\"\n src=\"https://cdn.simpleicons.org/figma\"\n alt=\"Figma\"\n fallback=\"FG\"\n />\n ))}\n </div>\n);","description":"The isotype icon scales proportionally smaller than the avatar shape at every size, keeping a consistent inset around the logo from `xs` (24px) to `4xl` (128px).","summary":"Isotype scaling across all avatar sizes"},{"id":"components-avatar--size-xs","name":"Size Xs","snippet":"const SizeXs = () => <Avatar fallback=\"XS\" size=\"xs\" variant=\"circle\" type=\"photo\" />;","description":"Extra-small avatar (24px) for dense lists and inline indicators.","summary":"Extra-small 24px avatar"},{"id":"components-avatar--size-sm","name":"Size Sm","snippet":"const SizeSm = () => <Avatar fallback=\"SM\" size=\"sm\" variant=\"circle\" type=\"photo\" />;","description":"Small avatar (32px) for compact layouts and table rows.","summary":"Small 32px avatar"},{"id":"components-avatar--size-lg","name":"Size Lg","snippet":"const SizeLg = () => <Avatar fallback=\"LG\" size=\"lg\" variant=\"circle\" type=\"photo\" />;","description":"Large avatar (48px) for profile sections and detail views.","summary":"Large 48px avatar"},{"id":"components-avatar--size-xl","name":"Size Xl","snippet":"const SizeXl = () => <Avatar fallback=\"XL\" size=\"xl\" variant=\"circle\" type=\"photo\" />;","description":"Extra-large avatar (64px) for hero sections and prominent display.","summary":"Extra-large 64px avatar"},{"id":"components-avatar--colorized","name":"Colorized","snippet":"const Colorized = () => <Avatar fallback=\"JD\" size=\"md\" variant=\"circle\" type=\"photo\" colorize=\"jane doe\" />;","description":"The `colorize` prop deterministically maps a string (typically a user name) to a color from the palette, applying a tinted background and matching text color. Useful for distinguishing users in lists without profile photos.","summary":"Colorized avatar based on user name"},{"id":"components-avatar--all-colorized","name":"All Colorized","snippet":"const AllColorized = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {['alice', 'bob', 'carol', 'dave', 'eve', 'frank', 'grace', 'henry', 'iris'].map(name => (\n <Avatar key={name} size=\"lg\" colorize={name} fallback={name.slice(0, 2).toUpperCase()} />\n ))}\n </div>\n);","description":"Multiple colorized avatars showing how different names map to different colors from the palette for visual distinction.","summary":"Multiple colorized avatars for visual distinction"},{"id":"components-avatar--all-sizes","name":"All Sizes","snippet":"const AllSizes = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {(['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'] as const).map(size => (\n <Avatar key={size} size={size} fallback={size.toUpperCase()} />\n ))}\n </div>\n);","description":"All available sizes displayed together for visual comparison. Sizes range from `xs` (24px) to `4xl` (128px).","summary":"Visual comparison of all avatar sizes"},{"id":"components-avatar--all-sizes-with-image","name":"All Sizes With Image","snippet":"const AllSizesWithImage = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {(['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'] as const).map(size => (\n <Avatar\n key={size}\n size={size}\n src=\"https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&w=256&h=256&q=70&crop=focalpoint&fp-x=0.5&fp-y=0.3&fp-z=1&fit=crop\"\n alt=\"Alex Morgan\"\n fallback=\"AM\"\n />\n ))}\n </div>\n);","description":"All sizes with a profile image to verify image scaling and quality across the full size range from `xs` (24px) to `4xl` (128px).","summary":"All avatar sizes with a profile image"},{"id":"components-avatar--all-variants","name":"All Variants","snippet":"const AllVariants = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {(['circle', 'square', 'pillow', 'pentagon'] as const).map(variant => (\n <Avatar\n key={variant}\n size=\"lg\"\n variant={variant}\n fallback={variant.slice(0, 2).toUpperCase()}\n />\n ))}\n </div>\n);","description":"All available shape variants displayed together for visual comparison. Each variant serves a different use case: user photos, workspaces, friendly branding, and unique identity.","summary":"Visual comparison of all avatar shapes"},{"id":"components-avatar--all-variants-with-image","name":"All Variants With Image","snippet":"const AllVariantsWithImage = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>\n {(['circle', 'square', 'pillow', 'pentagon'] as const).map(variant => (\n <Avatar\n key={variant}\n size=\"lg\"\n variant={variant}\n src=\"https://images.unsplash.com/photo-1502823403499-6ccfcf4fb453?&w=256&h=256&q=70&crop=focalpoint&fp-x=0.5&fp-y=0.3&fp-z=1&fit=crop\"\n alt=\"Alex Morgan\"\n fallback=\"AM\"\n />\n ))}\n </div>\n);","description":"All shape variants with a profile image to show how each mask clips the photo. Particularly useful for verifying the pentagon mask and pillow shape render correctly with real imagery.","summary":"All avatar shapes with a profile image"}],"import":"import { Avatar } from \"@agentero/design-system\";","jsDocTags":{},"description":"Avatar displays a user's profile image, initials, or a fallback icon. Use for user identification in lists, headers, cards, and comment threads. Supports multiple shapes (`circle`, `square`, `pillow`, `pentagon`), content types (`photo`, `initials`, `isotype`), and sizes from `xs` (24px) to `4xl` (128px).","reactDocgenTypescript":{"tags":{"summary":"Displays a user's profile image, initials, or fallback icon","example":"<Avatar src=\"/photos/jane.jpg\" alt=\"Jane Doe\" size=\"md\" variant=\"circle\" />\n<Avatar fallback=\"JD\" size=\"lg\" variant=\"square\" />"},"filePath":"/home/runner/work/design-system/design-system/src/avatar/avatar.tsx","description":"Avatar displays a user's profile image, initials, or a fallback icon.\nUse Avatar for user identification in lists, headers, cards, and comment threads.\n\nDo **not** use Avatar for decorative images or thumbnails unrelated to a person\nor entity — use a standard `<img>` or a Thumbnail component instead.\n\nRenders an image when `src` is provided; otherwise displays `fallback` content\n(typically initials or an icon). Built on Radix UI Avatar primitives.\n\nAvailable shapes: `circle` (default), `square`, `pillow`, and `pentagon`.\nSizes range from `xs` (24px) to `4xl` (128px), defaulting to `md` (40px).","displayName":"Avatar","methods":[],"props":{"asChild":{"defaultValue":null,"description":"","name":"asChild","declarations":[{"fileName":"design-system/node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive/dist/index.d.mts","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"alt":{"defaultValue":null,"description":"Accessible alt text describing the avatar image. Required when `src` is provided.","name":"alt","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}},"src":{"defaultValue":null,"description":"Image URL to display. When unavailable or loading fails, `fallback` content is shown instead.","name":"src","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}},"fallback":{"defaultValue":null,"description":"Content rendered when `src` is missing or fails to load. Typically user initials (e.g., \"JD\") or an icon.","name":"fallback","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"ReactNode"}},"colorize":{"defaultValue":null,"description":"When provided, deterministically maps the string (typically a user name) to a\ncolor from the palette, applying a light background, matching text color, and\nborder color. Useful for distinguishing users in lists without profile photos.","name":"colorize","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}},"size":{"defaultValue":null,"description":"Controls the avatar dimensions. Defaults to `'md'` (40px).\n- `xs` (24px) — inline indicators, dense lists\n- `sm` (32px) — compact layouts, table rows\n- `md` (40px) — standard usage, cards, headers\n- `lg` (48px) — profile sections, detail views\n- `xl` (64px) — hero sections, prominent display\n- `2xl` (80px), `3xl` (96px), `4xl` (128px) — large feature areas, profile pages","name":"size","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"sm\" | \"md\" | \"xs\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" | \"4xl\"","value":[{"value":"\"sm\""},{"value":"\"md\""},{"value":"\"xs\""},{"value":"\"lg\""},{"value":"\"xl\""},{"value":"\"2xl\""},{"value":"\"3xl\""},{"value":"\"4xl\""}]}},"variant":{"defaultValue":null,"description":"Shape of the avatar container. Defaults to `'circle'`.\n- `circle` — standard round avatar for user photos\n- `square` — rounded rectangle, suitable for workspace or team icons\n- `pillow` — soft, organic squircle shape\n- `pentagon` — distinctive five-sided shape for unique visual identity","name":"variant","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"circle\" | \"square\" | \"pillow\" | \"pentagon\"","value":[{"value":"\"circle\""},{"value":"\"square\""},{"value":"\"pillow\""},{"value":"\"pentagon\""}]}},"type":{"defaultValue":null,"description":"Content type the avatar represents. Defaults to `'photo'`.\n- `photo` — a user's profile photograph filling the avatar shape\n- `initials` — text initials standing in for a missing photo\n- `isotype` — a brand or organization icon rendered smaller than the avatar\n so it sits centered inside the shape instead of filling it","name":"type","declarations":[{"fileName":"design-system/src/avatar/avatar.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"isotype\" | \"photo\" | \"initials\"","value":[{"value":"\"isotype\""},{"value":"\"photo\""},{"value":"\"initials\""}]}}},"exportName":"Avatar"}},"components-button":{"id":"components-button","name":"Button","path":"./src/button/button.stories.tsx","stories":[{"id":"components-button--default","name":"Default","snippet":"const Default = () => <Button variant=\"primary\" size=\"sm\">{TEXT}</Button>;","description":"Args-controlled playground. Toggle `variant`, `size`, `status`, `loading`, `disabled`, and `rounded` from the Controls panel to explore every visual combination of the Button.","summary":"Default args playground for Button"},{"id":"components-button--variants","name":"Variants","snippet":"const Variants = () => (\n <Row>\n {VARIANTS.map(variant => (\n <Button key={variant} variant={variant}>\n {TEXT}\n </Button>\n ))}\n </Row>\n);","description":"All five variants at the default `sm` size. Variants express visual hierarchy: `primary` for the main CTA, `secondary` / `tertiary` for supporting actions, `ghost` for low-emphasis inline actions, and `link` for text-only actions.","summary":"All Button variants at default size"},{"id":"components-button--sizes","name":"Sizes","snippet":"const Sizes = () => (\n <Row>\n {SIZES.map(size => (\n <Button key={size} size={size}>\n {TEXT}\n </Button>\n ))}\n </Row>\n);","description":"All four sizes at the default `primary` variant. Sizes scale from `xs` (24px) for dense toolbars up to `lg` (48px) for hero CTAs.","summary":"All Button sizes at default variant"},{"id":"components-button--disabled","name":"Disabled","snippet":"const Disabled = () => (\n <Row>\n {VARIANTS.map(variant => (\n <Button asChild key={variant} variant={variant} disabled>\n <a>{TEXT}</a>\n </Button>\n ))}\n </Row>\n);","description":"Disabled state across all variants. Rendered via `asChild` with `<a>` children to show the disabled treatment applied via className — native anchors ignore the `disabled` attribute, so Button emits `aria-disabled` and `data-disabled` on the child instead.","summary":"Disabled treatment for every variant"},{"id":"components-button--with-icons","name":"With Icons","snippet":"const WithIcons = () => (\n <Stack>\n {VARIANTS.map(variant => (\n <Row key={variant}>\n {SIZES.map(size => (\n <Button key={size} variant={variant} size={size}>\n <IconAdd />\n {TEXT}\n <IconAdd />\n </Button>\n ))}\n </Row>\n ))}\n </Stack>\n);","description":"Variant × size grid with leading and trailing icons.","summary":"Variant × size grid with leading + trailing icons"},{"id":"components-button--only-icon","name":"Only Icon","snippet":"const OnlyIcon = () => (\n <Stack>\n {NON_LINK_VARIANTS.map(variant => (\n <Row key={variant}>\n {SIZES.map(size => (\n <Button key={size} variant={variant} size={size} aria-label=\"Close\">\n <IconClose />\n </Button>\n ))}\n </Row>\n ))}\n </Stack>\n);","description":"Icon-only buttons across the variant × size grid. Excludes `variant=\"link\"` — combining `link` with icon-only children logs a dev-only warning because the link treatment has no padding to accommodate an icon alone.","summary":"Icon-only Button across variant × size (excluding `link`)"},{"id":"components-button--loading","name":"Loading","snippet":"const Loading = () => (\n <Stack>\n {NON_LINK_VARIANTS.map(variant => (\n <Row key={variant}>\n {SIZES.map(size => (\n <div key={size} style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>\n <Button variant={variant} size={size} loading aria-label=\"Loading\">\n <IconAdd />\n </Button>\n <Button variant={variant} size={size} loading>\n {TEXT}\n </Button>\n </div>\n ))}\n </Row>\n ))}\n </Stack>\n);","description":"Loading state across the variant × size grid. Each row shows two buttons per size: one icon-only, one with text. Loading forces `disabled` and overlays a spinner that inherits the variant's text color. Excludes `variant=\"link\"` — combining `link` with `loading` logs a dev-only warning.","summary":"Loading state across variant × size (excluding `link`)"},{"id":"components-button--status","name":"Status","snippet":"const Status = () => (\n <Stack>\n <Row>\n {VARIANTS.map(variant => (\n <Button key={variant} variant={variant} status=\"danger\">\n <IconAdd />\n {TEXT}\n <IconAdd />\n </Button>\n ))}\n </Row>\n <Row>\n {VARIANTS.map(variant => (\n <Button asChild key={variant} variant={variant} status=\"danger\" disabled>\n <a>\n <IconAdd />\n {TEXT}\n <IconAdd />\n </a>\n </Button>\n ))}\n </Row>\n </Stack>\n);","description":"Destructive treatment via `status=\"danger\"`. The top row shows every variant enabled; the bottom row shows every variant disabled. Use `status=\"danger\"` for delete, remove, or disconnect actions regardless of variant.","summary":"`status=\"danger\"` across every variant, enabled + disabled"},{"id":"components-button--rounded","name":"Rounded","snippet":"const Rounded = () => (\n <Stack>\n {NON_LINK_VARIANTS.map(variant => (\n <Row key={variant}>\n {SIZES.map(size => (\n <Button key={size} variant={variant} size={size} rounded>\n <IconAdd />\n {TEXT}\n <IconAdd />\n </Button>\n ))}\n </Row>\n ))}\n </Stack>\n);","description":"Fully pill-shaped buttons across the variant × size grid. Excludes `variant=\"link\"` since the link treatment has no background to round.","summary":"`rounded` pill shape across variant × size (excluding `link`)"},{"id":"components-button--as-child","name":"As Child","snippet":"const AsChild = () => (\n <Row>\n <Button asChild variant=\"primary\">\n <a href=\"/dashboard\">Go to dashboard</a>\n </Button>\n <Button asChild variant=\"secondary\">\n <a href=\"https://agentero.com\" target=\"_blank\" rel=\"noreferrer\">\n Visit Agentero\n </a>\n </Button>\n </Row>\n);","description":"`asChild` renders Button's styles on the nested child element rather than on a `<button>` — the child receives Button's `className`, `ref`, and merged props via Radix's `Slot` primitive. Use it to turn any anchor or framework `Link` into a Button without coupling the design system to a router. In app code, swap the plain `<a>` below for your framework's Link (`next/link`, `react-router`, `@tanstack/react-router`, etc.).","summary":"`asChild` composes Button's styles onto any element"}],"import":"import { Button } from \"@agentero/design-system\";","jsDocTags":{},"description":"Button is the design system's primary actionable control. Pick `variant` to express hierarchy, `size` for prominence, and `status=\"danger\"` for destructive actions. Pass `asChild` to render Button's styles on any nested element — a plain `<a>`, a framework `<Link>`, or a custom component — without Button binding to any particular framework.","reactDocgenTypescript":{"tags":{"summary":"Primary actionable control; renders a `<button>` or, with `asChild`, any nested element","example":"<Button variant=\"primary\" size=\"sm\" onClick={handleSave}>\n Save changes\n</Button>\n<Button asChild variant=\"secondary\">\n <a href=\"https://agentero.com\" target=\"_blank\" rel=\"noreferrer\">Visit Agentero</a>\n</Button>\n// Framework-agnostic: wrap any Link implementation\n<Button asChild variant=\"primary\">\n <Link href=\"/dashboard\">Go to dashboard</Link>\n</Button>\n<Button variant=\"primary\" status=\"danger\" loading={isDeleting} onClick={handleDelete}>\n Delete account\n</Button>"},"filePath":"/home/runner/work/design-system/design-system/src/button/button.tsx","description":"Button is the design system's primary actionable control. Use it for any\ninteraction that triggers behavior, submits a form, or navigates the user.\nBy default Button renders a `<button>`; pass `asChild` to render its single\nchild element as the underlying tag instead — Button merges its styles,\n`className`, `ref`, and props onto whatever the consumer nests. This keeps\nthe design system framework-agnostic: route a plain `<a>`, a Next.js\n`<Link>`, a React Router `<Link>`, or any custom element through the same\nvisual treatment.\n\nPick `variant` to express hierarchy (`primary` for the main CTA,\n`secondary` / `tertiary` for supporting actions, `ghost` for low-emphasis\ninline actions, `link` for text-only actions). Use `status=\"danger\"` for\ndestructive actions and `loading` to block interaction while async work\nresolves.\n\nDo **not** use Button for toggle states (prefer a Switch or ToggleButton),\nfor passive decorative anchors without action intent (use a plain `<a>`),\nor with `variant=\"link\"` when loading or when the button has no text\nchildren — both combinations log a dev-only warning (silent in production).","displayName":"Button","methods":[],"props":{"children":{"defaultValue":null,"description":"Content rendered inside the Button. Accepts a text label, icon elements,\nor any mix of both. Icon-only children switch the Button to a square\naspect ratio and trigger the icon-only layout.\n\nWhen `asChild` is set, the single child element is merged with Button's\nprops and styles; auto-detection of icon-only children is skipped — use\nthe `iconOnly` prop to opt into the square icon-only layout.\n\nNot supported with `variant=\"link\"` when children resolve to icons only\n— passing both logs a dev-only warning (silent in production).","name":"children","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"},{"fileName":"design-system/node_modules/@types/react/index.d.ts","name":"DOMAttributes"}],"required":false,"type":{"name":"ReactNode"}},"variant":{"defaultValue":null,"description":"Visual hierarchy. Defaults to `'primary'`.\n- `primary` — main call-to-action; use once per view.\n- `secondary` — alternative action alongside a primary button.\n- `tertiary` — low-emphasis action, subtle background.\n- `ghost` — minimal background; low-emphasis action in dense layouts.\n- `link` — inline text-style action; no padding or background.","name":"variant","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"ButtonVariantType","value":[{"value":"\"ghost\""},{"value":"\"link\""},{"value":"\"primary\""},{"value":"\"secondary\""},{"value":"\"tertiary\""}]}},"size":{"defaultValue":null,"description":"Control size. Defaults to `'sm'`.\n- `xs` (24px) — dense toolbars, compact inline actions.\n- `sm` (32px) — standard usage in forms and cards.\n- `md` (40px) — prominent actions in modals or feature rows.\n- `lg` (48px) — hero CTAs and full-width mobile actions.","name":"size","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"ButtonSizeType","value":[{"value":"\"sm\""},{"value":"\"md\""},{"value":"\"xs\""},{"value":"\"lg\""}]}},"status":{"defaultValue":null,"description":"Semantic status override. Set to `'danger'` for destructive actions\n(delete, remove, disconnect) — applies the destructive color treatment\nacross all variants.","name":"status","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"danger\"","value":[{"value":"\"danger\""}]}},"loading":{"defaultValue":null,"description":"When `true`, shows a spinner overlay and forces the button into a disabled\nstate to block further interaction. Not supported with `variant=\"link\"` —\npassing both logs a dev-only warning (silent in production).","name":"loading","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"disabled":{"defaultValue":null,"description":"Disables interaction and applies the disabled color treatment. Applied\nvia className so it still affects anchors rendered via `asChild`, which\nignore the native `disabled` attribute — in that case `aria-disabled`\nand `data-disabled` are forwarded to the child element instead.","name":"disabled","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"},{"fileName":"design-system/node_modules/@types/react/index.d.ts","name":"ButtonHTMLAttributes"}],"required":false,"type":{"name":"boolean"}},"iconOnly":{"defaultValue":null,"description":"Forces the icon-only layout (square aspect ratio, no min-width). Useful\nwith `asChild` where the single wrapper child prevents auto-detection.\nFor non-`asChild` usage, prefer passing icon elements as children — the\nicon-only layout is applied automatically.","name":"iconOnly","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"rounded":{"defaultValue":null,"description":"When `true`, renders a fully pill-shaped button (rounded-full). Otherwise\nuses the variant's default corner radius.","name":"rounded","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"align":{"defaultValue":null,"description":"Justifies children along the main axis. Defaults to `'center'`.\nUse `'justify'` to push leading and trailing icons to the edges.","name":"align","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"center\" | \"start\" | \"end\" | \"justify\"","value":[{"value":"\"center\""},{"value":"\"start\""},{"value":"\"end\""},{"value":"\"justify\""}]}},"fitContent":{"defaultValue":null,"description":"When `true`, removes the per-size `min-width` floor so the button hugs\nits content. Useful for inline actions inside tight containers.","name":"fitContent","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"ref":{"defaultValue":null,"description":"Ref forwarded to the underlying element. Typed as a union covering both\n`<button>` and `<a>` because `asChild` lets consumers render either tag\n(or any forwardRef component) through Radix's `Slot`.","name":"ref","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"Ref<HTMLButtonElement | HTMLAnchorElement>"}},"asChild":{"defaultValue":null,"description":"When `true`, Button clones its single child element and merges\nButton's `className`, `ref`, and event handlers onto it rather than\nrendering a `<button>`. Use this to style any element (a plain `<a>`,\na framework `Link`, a `React.forwardRef` component) as a Button.\n\nWhen combined with `disabled`, Button emits `aria-disabled` and\n`data-disabled` on the child instead of the native `disabled`\nattribute (which is ignored by non-form-control elements).","name":"asChild","declarations":[{"fileName":"design-system/src/button/button.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}}},"exportName":"Button"}},"components-divider":{"id":"components-divider","name":"Divider","path":"./src/divider/divider.stories.tsx","stories":[{"id":"components-divider--default","name":"Default","snippet":"const Default = () => <div\n className={cn(\n 'flex gap-4 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary p-6',\n args.orientation === 'vertical' ? 'h-40 w-lg items-stretch' : 'w-80 flex-col'\n )}>\n <div className=\"flex flex-1 flex-col justify-center gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">First section</h3>\n <p className=\"text-sm text-text-default-base-secondary\">Content on one side of the divider, visually separated from the other.\n </p>\n </div>\n <Divider orientation=\"horizontal\" decorative />\n <div className=\"flex flex-1 flex-col justify-center gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Second section</h3>\n <p className=\"text-sm text-text-default-base-secondary\">Content on the other side of the divider, clearly separated from the first.\n </p>\n </div>\n</div>;","description":"The default horizontal, decorative divider — a 1px line that spans the parent width. Use this form between stacked content blocks.","summary":"Default horizontal decorative divider"},{"id":"components-divider--horizontal","name":"Horizontal","snippet":"const Horizontal = () => (\n <div className=\"w-80\">\n <Divider />\n </div>\n);","description":"Horizontal divider — a 1px line spanning the parent's full width. The default orientation; use to separate stacked content.","summary":"Horizontal 1px line spanning the parent width"},{"id":"components-divider--vertical","name":"Vertical","snippet":"const Vertical = () => (\n <div className=\"flex h-24 items-stretch\">\n <Divider orientation=\"vertical\" />\n </div>\n);","description":"Vertical divider — a 1px line spanning the parent's full height. Parent must establish a height (via `h-*` or an intrinsic flex item height) for the line to be visible.","summary":"Vertical 1px line spanning the parent height"},{"id":"components-divider--with-label","name":"With Label","snippet":"const WithLabel = () => <div className=\"flex w-80 flex-col gap-2\">\n <Button variant=\"primary\">Continue with email</Button>\n <Divider orientation=\"horizontal\" decorative label=\"or\" />\n <Button variant=\"secondary\">Continue with SSO</Button>\n</div>;","description":"Labelled divider. The label sits centered between two flanking 1px lines — a common pattern for \"or\" breaks between authentication options.","summary":"Horizontal divider with a centered \"or\" label"},{"id":"components-divider--vertical-with-label","name":"Vertical With Label","snippet":"const VerticalWithLabel = () => <div\n className=\"flex h-40 items-stretch gap-4 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary p-6\">\n <div className=\"flex flex-col justify-center gap-1\">\n <h3 className=\"text-sm font-semibold text-text-default-base-primary\">Left panel</h3>\n <p className=\"text-xs text-text-default-base-secondary\">Content on the left side</p>\n </div>\n <Divider orientation=\"vertical\" decorative label=\"OR\" />\n <div className=\"flex flex-col justify-center gap-1\">\n <h3 className=\"text-sm font-semibold text-text-default-base-primary\">Right panel</h3>\n <p className=\"text-xs text-text-default-base-secondary\">Content on the right side</p>\n </div>\n</div>;","description":"Vertical divider with a label. The label sits between two stacked 1px line segments; use sparingly — horizontal labelled dividers are more common.","summary":"Vertical divider with a centered label"},{"id":"components-divider--semantic","name":"Semantic","snippet":"const Semantic = () => <div\n className=\"flex w-80 flex-col gap-4 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary p-6\">\n <section className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Section one</h3>\n <p className=\"text-sm text-text-default-base-secondary\">Semantically separated from the next section for screen readers.\n </p>\n </section>\n <Divider orientation=\"horizontal\" decorative={false} />\n <section className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Section two</h3>\n <p className=\"text-sm text-text-default-base-secondary\">Screen readers will announce this as a separate section.\n </p>\n </section>\n</div>;","description":"Semantic divider (`decorative={false}`). Exposes `role=\"separator\"` and `aria-orientation` to assistive technologies, marking a meaningful section break rather than a purely visual one.","summary":"Semantic separator announced to assistive technologies"},{"id":"components-divider--in-list","name":"In List","snippet":"const InList = () => (\n <div className=\"w-80 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary\">\n <div className=\"flex flex-col gap-1 px-4 py-3\">\n <h4 className=\"text-sm text-text-default-base-primary\">Notification 1</h4>\n <p className=\"text-xs text-text-default-base-secondary\">\n You have a new message from Jane.\n </p>\n </div>\n <Divider />\n <div className=\"flex flex-col gap-1 px-4 py-3\">\n <h4 className=\"text-sm text-text-default-base-primary\">Notification 2</h4>\n <p className=\"text-xs text-text-default-base-secondary\">\n Your report is ready to download.\n </p>\n </div>\n <Divider />\n <div className=\"flex flex-col gap-1 px-4 py-3\">\n <h4 className=\"text-sm text-text-default-base-primary\">Notification 3</h4>\n <p className=\"text-xs text-text-default-base-secondary\">\n System maintenance is scheduled for tonight.\n </p>\n </div>\n </div>\n);","description":"Divider between list rows. Dividers delineate each item without the visual weight of a full border on every row.","summary":"Horizontal dividers between stacked list rows"},{"id":"components-divider--in-toolbar","name":"In Toolbar","snippet":"const InToolbar = () => (\n <div className=\"inline-flex h-10 items-center gap-1 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary px-2 shadow-1\">\n <Button variant=\"ghost\" size=\"xs\">\n Cut\n </Button>\n <Button variant=\"ghost\" size=\"xs\">\n Copy\n </Button>\n <Button variant=\"ghost\" size=\"xs\">\n Paste\n </Button>\n <Divider orientation=\"vertical\" className=\"mx-1 h-6\" />\n <Button variant=\"ghost\" size=\"xs\">\n Undo\n </Button>\n <Button variant=\"ghost\" size=\"xs\">\n Redo\n </Button>\n <Divider orientation=\"vertical\" className=\"mx-1 h-6\" />\n <Button variant=\"ghost\" size=\"xs\">\n Settings\n </Button>\n </div>\n);","description":"Vertical dividers grouping related toolbar actions. Use to separate logical clusters of buttons (editing vs. history vs. settings) without visual weight.","summary":"Vertical dividers grouping toolbar actions"},{"id":"components-divider--horizontal-in-content","name":"Horizontal In Content","snippet":"const HorizontalInContent = () => (\n <div className=\"flex w-96 flex-col gap-4 p-6\">\n <div className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Section title</h3>\n <p className=\"text-sm text-text-default-base-secondary\">\n Descriptive content for the first section. The divider below separates it from the next.\n </p>\n </div>\n <Divider />\n <div className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Another section</h3>\n <p className=\"text-sm text-text-default-base-secondary\">\n The second section is clearly separated from the previous one.\n </p>\n </div>\n <Divider />\n <div className=\"flex flex-col gap-1\">\n <h3 className=\"text-base font-semibold text-text-default-base-primary\">Final section</h3>\n <p className=\"text-sm text-text-default-base-secondary\">\n Dividers help establish visual hierarchy in content-heavy layouts.\n </p>\n </div>\n </div>\n);","description":"Horizontal dividers between content sections in a long-form layout. Helps create visual hierarchy in content-heavy pages.","summary":"Horizontal dividers between content sections"},{"id":"components-divider--vertical-between-elements","name":"Vertical Between Elements","snippet":"const VerticalBetweenElements = () => (\n <div className=\"flex items-stretch gap-3\">\n <Button variant=\"primary\" size=\"sm\">\n Button 1\n </Button>\n <Divider orientation=\"vertical\" />\n <Button variant=\"primary\" size=\"sm\">\n Button 2\n </Button>\n <Divider orientation=\"vertical\" />\n <Button variant=\"primary\" size=\"sm\">\n Button 3\n </Button>\n </div>\n);","description":"Vertical dividers between inline elements. Common for separating a row of related controls or inline links without visual weight.","summary":"Vertical dividers separating inline elements"}],"import":"import { Button, Divider } from \"@agentero/design-system\";","jsDocTags":{},"description":"Divider separates content visually along either a horizontal or vertical axis. Use between page or card sections, between inline items in a toolbar or list, or — with the `label` prop — to render an \"or\"-style break between options. Set `decorative={false}` when the separator carries semantic meaning so it's announced to assistive technologies.","reactDocgenTypescript":{"tags":{"summary":"Visual or semantic separator that optionally renders a centered label","param":"orientation - Axis along which the separator renders. Defaults to `'horizontal'`.\n- `horizontal` — 1px line spanning the parent width.\n- `vertical` — 1px line spanning the parent height; parent must establish a height.\ndecorative - When `true` (default), the separator is purely visual and hidden\nfrom assistive technologies. Set to `false` to expose `role=\"separator\"` plus\n`aria-orientation` for meaningful section breaks.\nlabel - Optional inline content rendered between two flanking 1px lines.\nWhen omitted, Divider renders a single line.","example":"<Divider />\n<Divider orientation=\"vertical\" />\n<Divider label=\"or\" />\n<Divider decorative={false} />"},"filePath":"/home/runner/work/design-system/design-system/src/divider/divider.tsx","description":"Divider separates content visually (or semantically, via `decorative={false}`)\nalong either a horizontal or vertical axis. Use Divider between page or card\nsections, between inline items in a toolbar or list, or to break up long\ncontent regions. Pass a `label` to render the \"or\"-style divider with text\ncentered between two line segments — useful for auth flows and step breaks.\n\nBuilt on Radix UI's Separator primitive for the unlabelled case; the\nlabelled case renders a `<div>` that still forwards the correct\n`role`/`aria-orientation` when `decorative={false}`.\n\nDo **not** use Divider as a bare horizontal rule to add vertical rhythm —\nreach for margin utilities or a layout wrapper instead. Divider should carry\nmeaning (visual or semantic section break), not whitespace.","displayName":"Divider","methods":[],"props":{"asChild":{"defaultValue":null,"description":"","name":"asChild","declarations":[{"fileName":"design-system/node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive/dist/index.d.mts","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"label":{"defaultValue":null,"description":"Optional label rendered inline between two flanking 1px lines. When set,\nDivider renders a styled `<div>` (rather than the underlying separator\nprimitive) so the label can sit centered between the two line segments.","name":"label","declarations":[{"fileName":"design-system/src/divider/divider.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"ReactNode"}}},"exportName":"Divider"}},"components-dropdownmenu":{"id":"components-dropdownmenu","name":"DropdownMenu.Root","path":"./src/dropdown-menu/dropdown-menu.stories.tsx","stories":[{"id":"components-dropdownmenu--default","name":"Default","snippet":"const Default = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Click me\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('Edit clicked')}>Edit</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Duplicate clicked')}>\n Duplicate\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Archive clicked')}>\n Archive\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item onSelect={() => console.log('Delete clicked')}>\n <span className=\"text-red-500\">Delete</span>\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"A minimal DropdownMenu with four `Item`s — edit/duplicate/archive plus a separator before a destructive delete. Use this as the starting point for most overflow menus.","summary":"Basic menu with item rows and a separated destructive action"},{"id":"components-dropdownmenu--with-groups-and-dividers","name":"With Groups And Dividers","snippet":"const WithGroupsAndDividers = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n More Options\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('Undo')}>Undo</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Redo')}>Redo</DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item onSelect={() => console.log('Copy')}>Copy</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Cut')}>Cut</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Paste')}>Paste</DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item disabled>Print (disabled)</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Export')}>Export</DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"Multiple clusters of `Item`s split by `Separator` rules — mirrors an \"edit history / clipboard / export\" overflow menu. Demonstrates the `disabled` state on a menu row.","summary":"Menu with multiple `Separator`-split groups and a disabled item"},{"id":"components-dropdownmenu--with-icons","name":"With Icons","snippet":"const WithIcons = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Actions\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('Copy')}>\n <IconContentCopy />\n Copy\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n onSelect={() => console.log('Delete')}\n className=\"data-[highlighted]:bg-red-100\">\n <IconDelete className=\"[&>path]:fill-red-500\" />\n <span className=\"text-red-500\">Delete</span>\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"Menu items with leading icons and a destructive row using the `data-[highlighted]:bg-red-100` + `text-red-500` escape hatch. Use this pattern when a row should read as destructive.","summary":"Icon-leading items with a destructive delete row"},{"id":"components-dropdownmenu--with-group-titles","name":"With Group Titles","snippet":"const WithGroupTitles = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Account Menu\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Label>Profile</DropdownMenu.Label>\n <DropdownMenu.Item onSelect={() => console.log('View Profile')}>\n View Profile\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Edit Profile')}>\n Edit Profile\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Label>Settings</DropdownMenu.Label>\n <DropdownMenu.Item onSelect={() => console.log('Preferences')}>\n Preferences\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Privacy')}>Privacy</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Notifications')}>\n Notifications\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Label>Account</DropdownMenu.Label>\n <DropdownMenu.Item onSelect={() => console.log('Billing')}>Billing</DropdownMenu.Item>\n <DropdownMenu.Item\n onSelect={() => console.log('Logout')}\n className=\"data-[highlighted]:bg-red-100\">\n <span className=\"text-red-500\">Logout</span>\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"`Label`-segmented Profile / Settings / Account sections with a destructive Logout row. Use `Label` to name groups that would otherwise be ambiguous from the item text alone.","summary":"Menu with `Label`-titled sections and a destructive logout row"},{"id":"components-dropdownmenu--with-submenu","name":"With Submenu","snippet":"const WithSubmenu = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n File Options\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('New File')}>New File</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Open')}>Open</DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n <IconIosShare />\n Share\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('Email')}>Email</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Slack')}>Slack</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Copy Link')}>\n Copy Link\n </DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n <IconDriveFileMove />\n Move to\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('Archive')}>\n Archive\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Projects')}>\n Projects\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Drafts')}>Drafts</DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n onSelect={() => console.log('Delete')}\n className=\"data-[highlighted]:bg-red-100\">\n <IconDelete className=\"[&>path]:fill-red-500\" />\n <span className=\"text-red-500\">Delete</span>\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"One level of nesting: Share and Move-to submenus wired via `Sub` / `SubTrigger` / `SubContent`. Each submenu is portaled independently so it escapes the parent's stacking context.","summary":"Single-level submenus for Share and Move-to flows"},{"id":"components-dropdownmenu--nested-submenus","name":"Nested Submenus","snippet":"const NestedSubmenus = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Organization Menu\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Label>Organization</DropdownMenu.Label>\n <DropdownMenu.Item onSelect={() => console.log('Dashboard')}>Dashboard</DropdownMenu.Item>\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n <IconPeople />\n Teams\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('View All Teams')}>\n View All Teams\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>Engineering</DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('Frontend')}>\n Frontend\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Backend')}>\n Backend\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('DevOps')}>\n DevOps\n </DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>Design</DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('Product Design')}>\n Product Design\n </DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Brand')}>\n Brand\n </DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Item onSelect={() => console.log('Marketing')}>\n Marketing\n </DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Separator />\n <DropdownMenu.Item onSelect={() => console.log('Settings')}>Settings</DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"Two levels of nesting: Organization → Teams → (Engineering, Design). Deeper nesting is rarely a good UX — prefer splitting into separate screens once the tree grows past two levels.","summary":"Two-level nested submenus inside a parent menu"},{"id":"components-dropdownmenu--submenu-with-disabled-items","name":"Submenu With Disabled Items","snippet":"const SubmenuWithDisabledItems = () => (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button size=\"md\" variant=\"secondary\">\n Document Actions\n <IconKeyboardArrowDown />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content>\n <DropdownMenu.Item onSelect={() => console.log('View')}>View</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Edit')}>Edit</DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>\n <IconContentCopy />\n Export as\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item onSelect={() => console.log('PDF')}>PDF</DropdownMenu.Item>\n <DropdownMenu.Item onSelect={() => console.log('Word')}>\n Word Document\n </DropdownMenu.Item>\n <DropdownMenu.Item disabled>Excel (Premium only)</DropdownMenu.Item>\n <DropdownMenu.Item disabled>PowerPoint (Premium only)</DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger disabled>\n <IconIosShare />\n Share (Sign in required)\n </DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item>Email</DropdownMenu.Item>\n <DropdownMenu.Item>Link</DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n);","description":"Submenu that contains `disabled` `Item`s alongside a fully-disabled `SubTrigger`. Use `disabled` sparingly — prefer hiding unavailable actions outright unless the user needs to see them and understand why.","summary":"Submenu with `disabled` items and a disabled `SubTrigger`"}],"import":"import { Button, DropdownMenu } from \"@agentero/design-system\";","jsDocTags":{},"description":"DropdownMenu is a compound overlay for secondary actions, bulk operations, or navigation shortcuts triggered off a button or icon. Compose it from `Root` / `Trigger` / `Portal` / `Content` and fill the menu with `Item`, `Separator`, `Label`, and — for nested flows — `Sub` / `SubTrigger` / `SubContent`. Built on Radix UI's DropdownMenu primitive, so keyboard navigation, focus trapping, typeahead, and collision detection come for free.","reactDocgenTypescript":{"tags":{"summary":"Compound overlay menu for secondary actions, grouped items, and submenus","see":"{@link https://www.radix-ui.com/primitives/docs/components/dropdown-menu Radix UI DropdownMenu}","example":"```tsx\nimport { DropdownMenu } from '@agentero/design-system/dropdown-menu';\n\n<DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconMoreVert />\n </DropdownMenu.Trigger>\n\n <DropdownMenu.Portal>\n <DropdownMenu.Content side=\"bottom\" align=\"end\">\n <DropdownMenu.Label>Actions</DropdownMenu.Label>\n\n <DropdownMenu.Item onSelect={() => handleEdit()}>\n <IconEdit />\n Edit\n </DropdownMenu.Item>\n\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger>Share</DropdownMenu.SubTrigger>\n <DropdownMenu.Portal>\n <DropdownMenu.SubContent>\n <DropdownMenu.Item>Email</DropdownMenu.Item>\n <DropdownMenu.Item>Slack</DropdownMenu.Item>\n </DropdownMenu.SubContent>\n </DropdownMenu.Portal>\n </DropdownMenu.Sub>\n\n <DropdownMenu.Separator />\n\n <DropdownMenu.Item\n onSelect={() => handleDelete()}\n disabled={!canDelete}\n >\n <IconDelete />\n Delete\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n</DropdownMenu.Root>\n```","component":"","namespace":"DropdownMenu"},"filePath":"/home/runner/work/design-system/design-system/src/dropdown-menu/dropdown-menu.tsx","description":"DropdownMenu is the compound component for attaching a menu of secondary\nactions to a button or icon trigger — edit/duplicate/delete rows, account\nmenus, overflow affordances, and nested submenus. Built on Radix UI's\nDropdownMenu primitive, so keyboard navigation, focus trapping, typeahead,\nand viewport-collision detection come for free.\n\nCompose it from `Root` / `Trigger` / `Portal` / `Content` and fill the\nmenu with `Item`, `Separator`, `Label`, and — for nested flows — `Sub` /\n`SubTrigger` / `SubContent`. Wrap content in `Portal` so the menu escapes\nancestor `overflow:hidden` and z-index stacking contexts.\n\nDo **not** use DropdownMenu for primary navigation (use a real nav menu),\nfor single-choice form input (use a `Select`), or for command palettes\n(use a dedicated command component). For radio/checkbox-style toggles,\nuse Radix's `CheckboxItem` / `RadioItem` primitives directly — those\nparts are not exposed here yet.","displayName":"DropdownMenu","methods":[],"props":{},"exportName":"DropdownMenu"}},"components-loading":{"id":"components-loading","name":"Loading","path":"./src/loading/loading.stories.tsx","stories":[{"id":"components-loading--default","name":"Default","snippet":"const Default = () => <Loading size=\"sm\" />;","description":"The default spinner at `size=\"sm\"` (1em diameter), inheriting the current text color. Matches the out-of-the-box behavior when Loading is dropped into any layout.","summary":"Default spinner at the `sm` size"},{"id":"components-loading--size-sm","name":"Size Sm","snippet":"const SizeSm = () => <Loading size=\"sm\" />;","description":"Small spinner (1em diameter) — the default. Ideal for inline indicators, buttons, and compact layouts where the spinner needs to sit next to text.","summary":"Small 1em spinner for inline indicators"},{"id":"components-loading--size-md","name":"Size Md","snippet":"const SizeMd = () => <Loading size=\"md\" />;","description":"Medium spinner (1.5em diameter). Use for cards, panels, and standalone loading states where the spinner is the primary visual signal.","summary":"Medium 1.5em spinner for cards and panels"},{"id":"components-loading--size-lg","name":"Size Lg","snippet":"const SizeLg = () => <Loading size=\"lg\" />;","description":"Large spinner (2em diameter). Use for page-level or section-level loading where the spinner needs more visual weight.","summary":"Large 2em spinner for page or section loading"},{"id":"components-loading--sizes","name":"Sizes","snippet":"const Sizes = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '2rem' }}>\n {(['sm', 'md', 'lg'] as const).map(size => (\n <Loading key={size} size={size} />\n ))}\n </div>\n);","description":"All three sizes rendered side by side for visual comparison of the `em`-based scaling. Each spinner inherits the same parent text color.","summary":"Visual comparison of all three spinner sizes"},{"id":"components-loading--inherits-color","name":"Inherits Color","snippet":"const InheritsColor = () => (\n <div style={{ display: 'flex', alignItems: 'center', gap: '2rem' }}>\n <div className=\"text-text-default-base-primary\">\n <Loading size=\"md\" />\n </div>\n <div className=\"text-text-default-brand-primary\">\n <Loading size=\"md\" />\n </div>\n <div className=\"text-text-default-danger-primary\">\n <Loading size=\"md\" />\n </div>\n </div>\n);","description":"The spinner color tracks the parent `color` (text color) via `border-current`. Wrap Loading in any element with a text color utility — or set `color` on Loading itself — and the spinner adopts that color without extra props.","summary":"Spinner color inherits from the parent text color"},{"id":"components-loading--on-dark-surface","name":"On Dark Surface","snippet":"const OnDarkSurface = () => (\n <div className=\"flex items-center gap-8 rounded-lg bg-bg-button-primary-enable p-8 text-text-default-base-inverse-primary\">\n <Loading size=\"sm\" />\n <Loading size=\"md\" />\n <Loading size=\"lg\" />\n </div>\n);","description":"Spinner on a dark surface to verify `border-current` contrast. The parent sets a light text color, which the spinner inherits so it remains visible against the dark background.","summary":"Spinner on a dark-background surface"}],"import":"import { Loading } from \"@agentero/design-system\";","jsDocTags":{},"description":"Loading displays a circular spinner that indicates an in-progress operation. Use for inline fetch, form submission, or asynchronous task indicators. The spinner inherits its color from the parent `color` and scales with the parent font size via `em`-based size variants (`sm`, `md`, `lg`).","reactDocgenTypescript":{"tags":{"summary":"Circular spinner for in-progress and loading states","example":"<Loading />\n<Loading size=\"lg\" className=\"text-text-default-brand-primary\" />"},"filePath":"/home/runner/work/design-system/design-system/src/loading/loading.tsx","description":"Loading displays a circular spinner that indicates an in-progress operation.\nUse Loading to signal that content is being fetched, a form is submitting,\nor any asynchronous task is running inline with surrounding content.\n\nThe spinner inherits its color from the parent `color` (text color) via\n`border-current`, so it adapts to the surrounding context without extra\nprops. It fades in on mount and spins continuously until unmounted.\n\nAvailable sizes: `sm` (1em, default), `md` (1.5em), and `lg` (2em). Each\nsize is expressed in `em` units so the spinner scales with the parent\nfont size — wrap the Loading (or its ancestor) with the appropriate\n`text-[size]` utility to override the absolute diameter.\n\nExposes `role=\"status\"` and `aria-label=\"Loading\"` for screen readers, and\n`data-slot=\"loading\"` for styling hooks.\n\nDo **not** use Loading as the busy indicator for a button — the Button\ncomponent has its own built-in loading overlay ([Button](?path=/docs/button--docs)).\nFor full-page or skeleton loading states prefer a dedicated skeleton\nplaceholder instead of a spinner.","displayName":"Loading","methods":[],"props":{"size":{"defaultValue":null,"description":"Controls the spinner diameter in `em` units relative to the parent font size.\nDefaults to `'sm'`.\n- `sm` (1em) — inline indicators, buttons, and compact layouts\n- `md` (1.5em) — cards, panels, and standalone loading states\n- `lg` (2em) — page-level or section-level loading","name":"size","declarations":[{"fileName":"design-system/src/loading/loading.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"sm\" | \"md\" | \"lg\"","value":[{"value":"\"sm\""},{"value":"\"md\""},{"value":"\"lg\""}]}}},"exportName":"Loading"}},"components-pagination":{"id":"components-pagination","name":"Pagination","path":"./src/pagination/pagination.stories.tsx","stories":[{"id":"components-pagination--default","name":"Default","snippet":"const Default = () => <Pagination currentPage={1} totalCount={1000} pageSize={10} onPageChange={fn()} />;","description":"Default args playground. The first page of a 1,000-item list paged 10 at a time — renders pages 1–5, an ellipsis, and the last page (100), with the previous-page button disabled because we're on page 1.","summary":"Default args playground for Pagination"},{"id":"components-pagination--few-pages","name":"Few Pages","snippet":"const FewPages = () => <Pagination\n currentPage={2}\n totalCount={30}\n pageSize={10}\n onPageChange={(page: number) => console.log('onPageChange', page)} />;","description":"Short list whose total pages fit in the visible window — no ellipsis is rendered. Exercises the `totalPageNumbers >= totalPageCount` branch in `getPages`.","summary":"Short page list with no ellipsis collapse"},{"id":"components-pagination--dots-right","name":"Dots Right","snippet":"const DotsRight = () => <Pagination\n currentPage={2}\n totalCount={1000}\n pageSize={10}\n onPageChange={(page: number) => console.log('onPageChange', page)} />;","description":"Current page sits near the start of the range — left ellipsis is hidden, right ellipsis is shown, and the last page button anchors the right edge.","summary":"Right-side ellipsis only (current page near start)"},{"id":"components-pagination--dots-left","name":"Dots Left","snippet":"const DotsLeft = () => <Pagination\n currentPage={99}\n totalCount={1000}\n pageSize={10}\n onPageChange={(page: number) => console.log('onPageChange', page)} />;","description":"Current page sits near the end of the range — left ellipsis is shown, right ellipsis is hidden, and the first page button anchors the left edge.","summary":"Left-side ellipsis only (current page near end)"},{"id":"components-pagination--dots-both","name":"Dots Both","snippet":"const DotsBoth = () => <Pagination\n currentPage={50}\n totalCount={1000}\n pageSize={10}\n onPageChange={(page: number) => console.log('onPageChange', page)} />;","description":"Current page sits in the middle of the range — both ellipses are visible, with the first and last page buttons anchoring each edge.","summary":"Both ellipses visible (current page in middle)"},{"id":"components-pagination--last-page","name":"Last Page","snippet":"const LastPage = () => <Pagination currentPage={100} totalCount={1000} pageSize={10} onPageChange={fn()} />;","description":"Last page selected — the next-page button is disabled and the active page indicator sits on the trailing number.","summary":"Last page selected with disabled next button"},{"id":"components-pagination--controlled","name":"Controlled","snippet":"const Controlled = ({ totalCount, pageSize }) => {\n const [page, setPage] = useState(1);\n\n return (\n <Pagination\n currentPage={page}\n totalCount={totalCount}\n pageSize={pageSize}\n onPageChange={setPage}\n />\n );\n};","description":"Interactive controlled example. Local `useState` owns the page; clicking a page, previous, or next button updates it so the active page indicator and entries summary follow along.","summary":"Interactive controlled example backed by `useState`"}],"import":"import { Pagination } from \"@agentero/design-system\";","jsDocTags":{},"description":"Pagination is a 1-indexed paged navigation control with previous/next icon buttons, numeric page buttons, and a leading \"X - Y of Z\" entries summary. The page list collapses long ranges with `…` ellipses so the control stays compact regardless of total page count. Use it for lists, tables, or grids that are split across pages.","reactDocgenTypescript":{"tags":{"summary":"1-indexed paged navigation control with prev/next, numeric pages, and entries summary","example":"```tsx\nimport { useState } from 'react';\nimport { Pagination } from '@agentero/design-system/pagination';\n\nconst [page, setPage] = useState(1);\n\n<Pagination\n currentPage={page}\n pageSize={10}\n totalCount={1000}\n onPageChange={setPage}\n/>\n```"},"filePath":"/home/runner/work/design-system/design-system/src/pagination/pagination.tsx","description":"Pagination is a 1-indexed paged navigation control with previous/next icon\nbuttons, numeric page buttons, and a leading \"X - Y of Z\" entries summary.\nThe page list collapses long ranges with `…` ellipses, keeping at most a\nhandful of buttons in view regardless of total page count. Use it whenever\na list, table, or grid is split across pages and the user needs direct\naccess to specific pages (not just prev/next).\n\nThe control short-circuits to `null` when `currentPage === 0` (legacy \"off\"\nsentinel) or when there are no pages to show, so it's safe to mount\nunconditionally above a list that may be empty.\n\nDo **not** use Pagination for infinite-scroll feeds, sub-page-1 indexing\n(the `0` value is reserved as the off-switch), or as a tab/segmented\ncontrol — it's strictly a page-of-pages affordance.","displayName":"Pagination","methods":[],"props":{"onPageChange":{"defaultValue":null,"description":"","name":"onPageChange","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":true,"type":{"name":"(page: number) => void"}},"totalCount":{"defaultValue":null,"description":"","name":"totalCount","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":true,"type":{"name":"number"}},"currentPage":{"defaultValue":null,"description":"","name":"currentPage","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":true,"type":{"name":"number"}},"pageSize":{"defaultValue":null,"description":"","name":"pageSize","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":true,"type":{"name":"number"}},"className":{"defaultValue":null,"description":"","name":"className","declarations":[{"fileName":"design-system/src/pagination/pagination.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}}},"exportName":"Pagination"}},"components-statusball":{"id":"components-statusball","name":"StatusBall","path":"./src/status-ball/status-ball.stories.tsx","stories":[{"id":"components-statusball--default","name":"Default","snippet":"const Default = () => <div className=\"flex items-center gap-2\">\n <StatusBall color=\"neutral\" />\n</div>;","description":"The default dot — `color=\"neutral\"` for an unknown or inactive status. Drop next to a text label to surface state at a glance.","summary":"Default neutral dot representing an inactive status"},{"id":"components-statusball--intents","name":"Intents","snippet":"const Intents = () => {\n const samples: { color: (typeof INTENTS)[number]; label: string }[] = [\n { color: 'success', label: 'Active' },\n { color: 'info', label: 'Scheduled' },\n { color: 'warning', label: 'Pending' },\n { color: 'danger', label: 'Expired' },\n { color: 'creative', label: 'In review' },\n { color: 'playful', label: 'Flagged' },\n { color: 'dynamic', label: 'Needs attention' },\n { color: 'neutral', label: 'Inactive' }\n ];\n\n return (\n <div className=\"grid grid-cols-2 gap-x-8 gap-y-3\">\n {samples.map(({ color, label }) => (\n <div key={color} className=\"flex items-center gap-2\">\n <StatusBall color={color} />\n <span className=\"text-sm text-text-default-base-primary\">{label}</span>\n </div>\n ))}\n </div>\n );\n};","description":"All 8 semantic intents rendered in a single grid, each paired with a sample label. Consumers typically drive the `color` prop from a domain-specific status → intent lookup table.","summary":"Every intent paired with a representative status label"},{"id":"components-statusball--success","name":"Success","snippet":"const Success = () => <StatusBall color=\"success\" data-testid=\"status-ball-success\" />;","description":"Success dot for positive / active states — the most common pairing for \"live\" records such as active licenses or confirmed appointments.","summary":"Success dot for positive or active statuses"},{"id":"components-statusball--info","name":"Info","snippet":"const Info = () => <StatusBall color=\"info\" />;","description":"Info dot for informational or neutral-positive states — e.g., scheduled or queued records that are progressing normally.","summary":"Info dot for informational statuses"},{"id":"components-statusball--warning","name":"Warning","snippet":"const Warning = () => <StatusBall color=\"warning\" />;","description":"Warning dot for pending states or records approaching a deadline — e.g., a license nearing expiration or an appointment awaiting confirmation.","summary":"Warning dot for pending or approaching-deadline statuses"},{"id":"components-statusball--danger","name":"Danger","snippet":"const Danger = () => <StatusBall color=\"danger\" />;","description":"Danger dot for error / expired / blocking states — e.g., an expired license or a failed payment that blocks progress.","summary":"Danger dot for error or expired statuses"},{"id":"components-statusball--creative","name":"Creative","snippet":"const Creative = () => <StatusBall color=\"creative\" />;","description":"Creative dot for category-specific statuses without a direct success/info/ warning/danger mapping — often used for \"in review\" or \"under assessment\" domain states.","summary":"Creative dot for category-specific statuses"},{"id":"components-statusball--dynamic","name":"Dynamic","snippet":"const Dynamic = () => <StatusBall color=\"dynamic\" />;","description":"Dynamic dot for attention-worthy states that sit between warning and danger — e.g., records that need action soon but are not yet failed.","summary":"Dynamic dot for attention-needed statuses"},{"id":"components-statusball--playful","name":"Playful","snippet":"const Playful = () => <StatusBall color=\"playful\" />;","description":"Playful dot for flagged or priority domain states that need to stand out from warnings with a distinct hue.","summary":"Playful dot for flagged or priority statuses"},{"id":"components-statusball--neutral","name":"Neutral","snippet":"const Neutral = () => <StatusBall color=\"neutral\" />;","description":"Neutral dot for inactive, unknown, or default states — the fallback when no other intent applies.","summary":"Neutral dot for inactive or unknown statuses"},{"id":"components-statusball--in-list","name":"In List","snippet":"const InList = () => {\n const rows = [\n { color: 'success', name: 'Ada Lovelace', status: 'Active' },\n { color: 'warning', name: 'Grace Hopper', status: 'Pending renewal' },\n { color: 'danger', name: 'Alan Turing', status: 'Expired' },\n { color: 'neutral', name: 'Katherine Johnson', status: 'Inactive' }\n ] as const;\n\n return (\n <ul className=\"w-80 divide-y divide-border-default-base-primary rounded-lg border border-border-default-base-primary bg-bg-default-base-primary\">\n {rows.map(row => (\n <li key={row.name} className=\"flex items-center gap-3 px-4 py-3\">\n <StatusBall color={row.color} />\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-medium text-text-default-base-primary\">{row.name}</span>\n <span className=\"text-xs text-text-default-base-secondary\">{row.status}</span>\n </div>\n </li>\n ))}\n </ul>\n );\n};","description":"StatusBall inside a list row — the canonical production usage, mirroring the appointment and license list patterns in `producerflow/mono`. Each row pairs a dot with a label and supporting text.","summary":"StatusBall paired with labels inside a list"},{"id":"components-statusball--in-pill","name":"In Pill","snippet":"const InPill = () => (\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default-base-primary bg-bg-default-base-primary px-2.5 py-1 text-xs text-text-default-base-primary\">\n <StatusBall color=\"success\" />\n Active\n </span>\n <span className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default-base-primary bg-bg-default-base-primary px-2.5 py-1 text-xs text-text-default-base-primary\">\n <StatusBall color=\"warning\" />\n Pending\n </span>\n <span className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default-base-primary bg-bg-default-base-primary px-2.5 py-1 text-xs text-text-default-base-primary\">\n <StatusBall color=\"danger\" />\n Expired\n </span>\n </div>\n);","description":"StatusBall inside a status pill — a tinted badge that pairs the dot with a label in a single rounded container. Use when the status needs more visual weight than a bare list row provides.","summary":"StatusBall inside a rounded status pill"}],"import":"import { StatusBall } from \"@agentero/design-system\";","jsDocTags":{},"description":"StatusBall renders a small colored dot that marks the state of an adjacent label — appointment confirmation, license validity, availability, or any list row where a single glyph of color communicates status. Pair it with text; the dot alone is not announced to assistive technologies, so the surrounding label must carry the meaning.","reactDocgenTypescript":{"tags":{"summary":"Small colored dot that signals the status of an adjacent label","example":"<div className=\"flex items-center gap-2\">\n <StatusBall color=\"success\" />\n <span>Active</span>\n</div>\n<StatusBall color={statusToIntent[appointment.status]} />"},"filePath":"/home/runner/work/design-system/design-system/src/status-ball/status-ball.tsx","description":"StatusBall renders a small colored dot used to mark the state of an adjacent\nlabel — things like an appointment's confirmation state, a license's validity,\nor any list-row entry where a single glyph of color conveys the status at a\nglance. Pair it with text; the dot alone is not announced to assistive\ntechnologies, so the surrounding label must carry the meaning.\n\nThe 8 intents (`success`, `info`, `warning`, `danger`, `creative`,\n`dynamic`, `playful`, `neutral`) map to semantic tokens\n(`--color-bg-status-ball-*`) and mirror the convention used by\n[Alert](?path=/docs/components-alert--docs). Consumers typically resolve a\ndomain-specific status to an intent via their own lookup table\n(e.g., `active → success`, `expired → danger`).\n\nDo **not** use StatusBall as a progress or loading indicator — reach for\n[Loading](?path=/docs/components-loading--docs) for async state. For\nsection-level alerts with copy, use [Alert](?path=/docs/components-alert--docs)\ninstead.","displayName":"StatusBall","methods":[],"props":{},"exportName":"StatusBall"}},"components-toast":{"id":"components-toast","name":"Toast","path":"./src/toast/toast.stories.tsx","stories":[{"id":"components-toast--default","name":"Default","snippet":"const Default = () => (\n <div style={{ minHeight: '240px' }}>\n <Button variant=\"secondary\" onClick={() => toast('Hello from Toast')}>\n Show toast\n </Button>\n </div>\n);","description":"Args-controlled playground. Click the button to fire a neutral toast; tweak `position` and `duration` from the Controls panel to preview the provider defaults.","summary":"Default playground for the Toast provider"},{"id":"components-toast--inline","name":"Inline","snippet":"const Inline = () => (\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>\n <Button\n variant=\"secondary\"\n onClick={() => toast('Something happened', { description: 'Additional context.' })}>\n Neutral\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() => toast.success('Policy saved', { description: 'Your edits are live.' })}>\n Success\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.error('Failed to save', { description: 'The file could not be processed.' })\n }>\n Error\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.warning('License expiring soon', { description: 'Renew before end of month.' })\n }>\n Warning\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.info('Sync in progress', { description: 'Please wait while we sync your data.' })\n }>\n Info\n </Button>\n </div>\n);","description":"Inline layout (default). Compact treatment — title with an optional description stacked directly below it. The `type` drives the icon color. Use for short acknowledgments that don't need a colored rail.","summary":"Inline layout across all five semantic types"},{"id":"components-toast--expanded","name":"Expanded","snippet":"const Expanded = () => (\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast('Something happened', {\n variant: 'expanded',\n description: 'Additional context for the user.'\n })\n }>\n Neutral\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.success('Policy saved', {\n variant: 'expanded',\n description: 'Your changes have been saved successfully.'\n })\n }>\n Success\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.error('Failed to save', {\n variant: 'expanded',\n description: 'The file could not be processed.'\n })\n }>\n Error\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.warning('License expiring soon', {\n variant: 'expanded',\n description: 'Renew before the end of the month to avoid interruption.'\n })\n }>\n Warning\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.info('Sync in progress', {\n variant: 'expanded',\n description: 'Please wait while we sync your data.'\n })\n }>\n Info\n </Button>\n </div>\n);","description":"Expanded layout. Multi-line treatment with a 0.375rem colored left rail that tracks the toast's `type`. Use for feedback that benefits from a description on its own line or a trailing action button.","summary":"Expanded layout across all five semantic types"},{"id":"components-toast--with-action-object","name":"With Action Object","snippet":"const WithActionObject = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.error('Upload failed', {\n variant: 'expanded',\n description: 'The file could not be processed.',\n action: { label: 'Retry', onClick: () => {} }\n })\n }>\n Show toast with action\n </Button>\n);","description":"Toast with a structured `action` object. Passing `{ label, onClick }` renders the built-in secondary Button; the handler runs and the toast auto-dismisses afterward.","summary":"Toast with a structured action button"},{"id":"components-toast--with-action-node","name":"With Action Node","snippet":"const WithActionNode = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast('File uploaded', {\n description: 'document.pdf is ready.',\n action: (\n <Button variant=\"link\" onClick={() => {}}>\n View file\n </Button>\n )\n })\n }>\n Show toast with link action\n </Button>\n);","description":"Toast with a raw-ReactNode `action`. Pass any JSX to render a custom trailing control — a link, a pair of buttons, etc. — when the default secondary Button doesn't fit.","summary":"Toast with a custom ReactNode action"},{"id":"components-toast--with-action-and-cancel","name":"With Action And Cancel","snippet":"const WithActionAndCancel = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.success('Record archived', {\n variant: 'expanded',\n description: 'The record is hidden from the default view.',\n action: { label: 'Undo', onClick: () => {} },\n cancel: { label: 'Dismiss', onClick: () => {} }\n })\n }>\n Show toast with action + cancel\n </Button>\n);","description":"Toast with both `action` and `cancel`. Cancel renders as a ghost Button next to the action; its handler runs and the toast auto-dismisses.","summary":"Toast with an action and a cancel control"},{"id":"components-toast--non-dismissible","name":"Non Dismissible","snippet":"const NonDismissible = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.info('Sync in progress', {\n dismissible: false,\n description: 'Please wait while we sync your data.'\n })\n }>\n Show non-dismissible toast\n </Button>\n);","description":"Non-dismissible toast. Setting `dismissible: false` hides the close button; the toast still auto-dismisses when its `duration` elapses, or programmatically via `toast.dismiss(id)`.","summary":"Non-dismissible toast (no close button)"},{"id":"components-toast--long-duration","name":"Long Duration","snippet":"const LongDuration = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.info('Uploading documents', {\n description: 'This may take a moment.',\n duration: 10_000\n })\n }>\n Show 10s toast\n </Button>\n);","description":"Long-duration toast. `duration` (in ms) overrides the provider default so long-running operations stay visible until they're relevant.","summary":"Toast with a custom `duration`"},{"id":"components-toast--programmatic-dismiss","name":"Programmatic Dismiss","snippet":"const ProgrammaticDismiss = () => {\n let toastId: string | number | undefined;\n return (\n <div style={{ display: 'flex', gap: '0.5rem' }}>\n <Button\n variant=\"secondary\"\n onClick={() => {\n toastId = toast.info('Uploading...', { duration: 60_000 });\n }}>\n Start\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => {\n if (toastId !== undefined) toast.dismiss(toastId);\n }}>\n Dismiss\n </Button>\n </div>\n );\n};","description":"Programmatic dismissal. `toast()` returns the toast id, which you can pass to `toast.dismiss(id)` to clear it before its duration elapses.","summary":"Dismiss a toast programmatically via its id"},{"id":"components-toast--with-promise","name":"With Promise","snippet":"const WithPromise = () => {\n const fakeFetch = () =>\n new Promise<string>((resolve, reject) => {\n window.setTimeout(\n () => (Math.random() > 0.5 ? resolve('ok') : reject(new globalThis.Error('nope'))),\n 1500\n );\n });\n return (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.promise(fakeFetch(), {\n loading: 'Saving document…',\n success: 'Document saved',\n error: 'Save failed'\n })\n }>\n Run promise\n </Button>\n );\n};","description":"`toast.promise` wires a toast to an async operation — loading while the promise is pending, success or error when it settles. Useful for save/submit flows where the outcome feeds back into the same toast.","summary":"Wire a toast to an async operation via `toast.promise`"},{"id":"components-toast--custom-icon","name":"Custom Icon","snippet":"const CustomIcon = () => (\n <Button\n variant=\"secondary\"\n onClick={() =>\n toast.success('Sync started', {\n description: 'Data sync is in progress.',\n icon: (\n <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"currentColor\" aria-hidden>\n <path d=\"M12 4V1L8 5l4 4V6c3.3 0 6 2.7 6 6 0 1-.3 2-.7 2.8l1.5 1.5C19.5 15 20 13.6 20 12c0-4.4-3.6-8-8-8zm0 14c-3.3 0-6-2.7-6-6 0-1 .3-2 .7-2.8L5.2 7.7C4.5 9 4 10.4 4 12c0 4.4 3.6 8 8 8v3l4-4-4-4v3z\" />\n </svg>\n )\n })\n }>\n Show toast with custom icon\n </Button>\n);","description":"Custom `icon` override. Pass any ReactNode as `icon` to replace the type-based default — helpful when the toast reflects a domain-specific action (e.g., a sync icon for a sync-in-progress toast).","summary":"Override the default type-based icon"}],"import":"import { Button, Toast } from \"@agentero/design-system\";","jsDocTags":{},"description":"Toast renders transient feedback about an outcome — saved, failed, warning, info — without interrupting the user's flow. Mount `<Toast />` once near the app root to register the provider, then call the imperative `toast()` API from anywhere in the tree. Five semantic types (`neutral`, `success`, `error`, `warning`, `info`) × two layouts (`inline`, `expanded`) cover the common feedback patterns.","reactDocgenTypescript":{"tags":{"summary":"Toast provider; mount once near the app root","example":"<Toast />\n<Toast position=\"top-center\" duration={4000} />"},"filePath":"/home/runner/work/design-system/design-system/src/toast/toast.tsx","description":"Toast provider. Renders the sonner `<Toaster />` configured for the\n{@link toast} imperative API. Mount it once near the root of your React\ntree (below any context providers that the toasts need, and above the\nrest of the app) so every call to `toast()` from anywhere in the tree\nrenders into the same surface.\n\nDefaults: `position='bottom-right'`, `duration=5000`. The Toaster is sized\nto `23.75rem` (`[--width:23.75rem]`) and each list item stretches to that\nwidth (`[&>li]:w-full`) so the DS Toast fills the Toaster row rather than\nsonner's 356px default. The provider disables sonner's built-in close\nbutton (`closeButton={false}`) — dismissal is rendered inside each Toast\nby the DS component itself.\n\nDo **not** use Toast for persistent feedback — mount an `Alert` with\n`color=\"success|danger\"` instead. Do **not** use Toast for form\nvalidation errors — render those inline with the form field.","displayName":"Toast","methods":[],"props":{"position":{"defaultValue":{"value":"bottom-right"},"description":"Placement of the toaster on the screen. Defaults to `'bottom-right'`.","name":"position","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"ToastPosition","value":[{"value":"\"top-left\""},{"value":"\"top-center\""},{"value":"\"top-right\""},{"value":"\"bottom-left\""},{"value":"\"bottom-center\""},{"value":"\"bottom-right\""}]}},"duration":{"defaultValue":{"value":"5000"},"description":"Default auto-dismiss duration in ms for toasts fired against this provider. Defaults to `5000`.","name":"duration","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"number"}},"dir":{"defaultValue":null,"description":"Text direction. Sonner forwards this to the rendered toaster root.","name":"dir","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"enum","raw":"\"auto\" | \"ltr\" | \"rtl\"","value":[{"value":"\"auto\""},{"value":"\"ltr\""},{"value":"\"rtl\""}]}},"gap":{"defaultValue":null,"description":"Gap between stacked toasts, in pixels.","name":"gap","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"number"}},"offset":{"defaultValue":null,"description":"Offset from the screen edge, in pixels or as a CSS length.","name":"offset","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string | number"}},"expand":{"defaultValue":null,"description":"When `true`, stack expands on hover instead of auto-collapsing.","name":"expand","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"visibleToasts":{"defaultValue":null,"description":"Maximum number of toasts rendered at once before earlier ones dismiss.","name":"visibleToasts","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"number"}},"hotkey":{"defaultValue":null,"description":"Keyboard shortcut used to focus the toaster.","name":"hotkey","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string[]"}},"richColors":{"defaultValue":null,"description":"When `true`, sonner paints colored backgrounds per type (DS uses its own icon tokens by default).","name":"richColors","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"invert":{"defaultValue":null,"description":"When `true`, flips light/dark theme on the toaster root.","name":"invert","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"boolean"}},"className":{"defaultValue":null,"description":"Additional className merged onto the sonner `<Toaster>` root.","name":"className","declarations":[{"fileName":"design-system/src/toast/toast.tsx","name":"TypeLiteral"}],"required":false,"type":{"name":"string"}}},"exportName":"Toast"}}},"meta":{"docgen":"react-docgen-typescript","durationMs":2395}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentero/design-system",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "A React component library built with Tailwind CSS v4 and Radix UI primitives",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -55,6 +55,11 @@ export declare const avatarRecipe: import('tailwind-variants').TVReturnType<{
55
55
  root: string[];
56
56
  };
57
57
  };
58
+ type: {
59
+ photo: {};
60
+ initials: {};
61
+ isotype: {};
62
+ };
58
63
  }, {
59
64
  root: string[];
60
65
  image: string[];
@@ -108,6 +113,11 @@ export declare const avatarRecipe: import('tailwind-variants').TVReturnType<{
108
113
  root: string[];
109
114
  };
110
115
  };
116
+ type: {
117
+ photo: {};
118
+ initials: {};
119
+ isotype: {};
120
+ };
111
121
  }, {
112
122
  root: string[];
113
123
  image: string[];
@@ -161,6 +171,11 @@ export declare const avatarRecipe: import('tailwind-variants').TVReturnType<{
161
171
  root: string[];
162
172
  };
163
173
  };
174
+ type: {
175
+ photo: {};
176
+ initials: {};
177
+ isotype: {};
178
+ };
164
179
  }, {
165
180
  root: string[];
166
181
  image: string[];
@@ -209,6 +224,14 @@ type AvatarProps = ComponentPropsWithRef<typeof AvatarPrimitive.Root> & {
209
224
  * - `pentagon` — distinctive five-sided shape for unique visual identity
210
225
  */
211
226
  variant?: AvatarVariants['variant'];
227
+ /**
228
+ * Content type the avatar represents. Defaults to `'photo'`.
229
+ * - `photo` — a user's profile photograph filling the avatar shape
230
+ * - `initials` — text initials standing in for a missing photo
231
+ * - `isotype` — a brand or organization icon rendered smaller than the avatar
232
+ * so it sits centered inside the shape instead of filling it
233
+ */
234
+ type?: AvatarVariants['type'];
212
235
  };
213
236
  /**
214
237
  * Avatar displays a user's profile image, initials, or a fallback icon.
@@ -231,5 +254,5 @@ type AvatarProps = ComponentPropsWithRef<typeof AvatarPrimitive.Root> & {
231
254
  * @example
232
255
  * <Avatar fallback="JD" size="lg" variant="square" />
233
256
  */
234
- export declare const Avatar: ({ alt, src, fallback, colorize, size, variant, ref, ...props }: AvatarProps) => import("react/jsx-runtime").JSX.Element;
257
+ export declare const Avatar: ({ alt, src, fallback, colorize, size, variant, type, ref, ...props }: AvatarProps) => import("react/jsx-runtime").JSX.Element;
235
258
  export {};
@@ -72,30 +72,80 @@ var s = r({
72
72
  "after:[mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB2aWV3Qm94PSItMC41IC0wLjUgMzQgMzQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE0LjU2NTcgMC4yNTA5NzdDMTUuODM0OCAtMC4wODM2NTk0IDE3LjE2NTggLTAuMDgzNjU4NCAxOC40MzQ4IDAuMjUwOTc3QzE5Ljg5NDIgMC42MzU4OCAyMS4yMTMzIDEuNjMwODkgMjMuNjM0IDMuNDM3NUwyNy4yNDQ0IDYuMTMxODRDMjkuNjY3IDcuOTM5OCAzMC45OTMyIDguOTE5NzcgMzEuNzk4MSAxMC4yMjI3QzMyLjQ5NzcgMTEuMzU1IDMyLjkwNzYgMTIuNjQ5OCAzMi45ODk1IDEzLjk4NjNDMzMuMDgzNSAxNS41MjI3IDMyLjU3MjQgMTcuMTExOSAzMS42NDY3IDIwLjAzODFMMzAuMjY3OCAyNC4zOTc1QzI5LjM0MjUgMjcuMzIyNyAyOC44NDU4IDI4LjkxODIgMjcuODg4OSAzMC4xMDY0QzI3LjA1NjEgMzEuMTQwNiAyNS45ODA4IDMxLjk0MzIgMjQuNzYzIDMyLjQzODVDMjMuMzYxNSAzMy4wMDg0IDIxLjcyMzggMzMgMTguNzMxNyAzM0gxNC4yNjg4QzExLjI3NjcgMzMgOS42MzkwNCAzMy4wMDg0IDguMjM3NiAzMi40Mzg1QzcuMDE5NzUgMzEuOTQzMiA1Ljk0NDQ4IDMxLjE0MDYgNS4xMTE2MiAzMC4xMDY0QzQuMTU0NzIgMjguOTE4MiAzLjY1ODAyIDI3LjMyMjcgMi43MzI3MiAyNC4zOTc1TDEuMzUzODEgMjAuMDM4MUMwLjQyODE4NyAxNy4xMTE5IC0wLjA4Mjk0NiAxNS41MjI3IDAuMDExMDM5IDEzLjk4NjNDMC4wOTI5MDMgMTIuNjQ5OCAwLjUwMjg4MSAxMS4zNTUgMS4yMDI0NCAxMC4yMjI3QzIuMDA3NCA4LjkxOTc3IDMuMzMzNTggNy45Mzk4IDUuNzU2MTYgNi4xMzE4NEw5LjM2NjUxIDMuNDM3NUMxMS43ODcyIDEuNjMwODkgMTMuMTA2MyAwLjYzNTg4IDE0LjU2NTcgMC4yNTA5NzdaIiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjEiIHZlY3Rvci1lZmZlY3Q9Im5vbi1zY2FsaW5nLXN0cm9rZSIvPjwvc3ZnPg==)]",
73
73
  "after:[mask-size:100%_100%] after:[mask-repeat:no-repeat] after:[mask-position:center]"
74
74
  ] }
75
+ },
76
+ type: {
77
+ photo: {},
78
+ initials: {},
79
+ isotype: {}
75
80
  }
76
81
  },
82
+ compoundVariants: [
83
+ {
84
+ type: "isotype",
85
+ size: "xs",
86
+ className: { image: "w-4 h-4" }
87
+ },
88
+ {
89
+ type: "isotype",
90
+ size: "sm",
91
+ className: { image: "w-5 h-5" }
92
+ },
93
+ {
94
+ type: "isotype",
95
+ size: "md",
96
+ className: { image: "w-6 h-6" }
97
+ },
98
+ {
99
+ type: "isotype",
100
+ size: "lg",
101
+ className: { image: "w-7 h-7" }
102
+ },
103
+ {
104
+ type: "isotype",
105
+ size: "xl",
106
+ className: { image: "w-8 h-8" }
107
+ },
108
+ {
109
+ type: "isotype",
110
+ size: "2xl",
111
+ className: { image: "w-10 h-10" }
112
+ },
113
+ {
114
+ type: "isotype",
115
+ size: "3xl",
116
+ className: { image: "w-12 h-12" }
117
+ },
118
+ {
119
+ type: "isotype",
120
+ size: "4xl",
121
+ className: { image: "w-16 h-16" }
122
+ }
123
+ ],
77
124
  defaultVariants: {
78
125
  size: "md",
79
- variant: "circle"
126
+ variant: "circle",
127
+ type: "photo"
80
128
  }
81
129
  }), c = t(null), l = () => {
82
130
  let e = n(c);
83
131
  if (!e) throw Error("useAvatar must be used within an AvatarProvider");
84
132
  return e;
85
- }, u = ({ size: t, variant: n, ...r }) => {
86
- let a = s({
133
+ }, u = ({ size: t, variant: n, type: r, ...a }) => {
134
+ let l = s({
87
135
  size: t,
88
- variant: n
136
+ variant: n,
137
+ type: r
89
138
  });
90
139
  return /* @__PURE__ */ i(c, {
91
140
  value: {
92
141
  size: t,
93
142
  variant: n,
94
- slotsStyles: a
143
+ type: r,
144
+ slotsStyles: l
95
145
  },
96
146
  children: /* @__PURE__ */ i(o.Root, {
97
- ...r,
98
- className: e(a.root(), r.className)
147
+ ...a,
148
+ className: e(l.root(), a.className)
99
149
  })
100
150
  });
101
151
  }, d = (t) => {
@@ -110,16 +160,17 @@ var s = r({
110
160
  ...t,
111
161
  className: e(n.fallback(), t.className)
112
162
  });
113
- }, p = ({ alt: e, src: t, fallback: n, colorize: r, size: o, variant: s, ref: c, ...l }) => {
114
- let p = r ? g(r) : void 0;
163
+ }, p = ({ alt: e, src: t, fallback: n, colorize: r, size: o, variant: s, type: c, ref: l, ...p }) => {
164
+ let m = r ? g(r) : void 0;
115
165
  return /* @__PURE__ */ a(u, {
116
- ...l,
117
- ref: c,
166
+ ...p,
167
+ ref: l,
118
168
  size: o,
119
169
  variant: s,
170
+ type: c,
120
171
  style: {
121
- ...p,
122
- ...l.style
172
+ ...m,
173
+ ...p.style
123
174
  },
124
175
  children: [/* @__PURE__ */ i(d, {
125
176
  alt: e,