@agentero/design-system 0.24.1 → 0.24.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">25 components ok</span><span class="filter-pill ok" aria-disabled="true">191 stories ok</span></div>
579
+ <div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><a class="filter-pill err" data-k="errors" href="#filter-errors">1/25 prop type error</a><a class="filter-pill info" data-k="infos" href="#filter-infos">1/25 info</a><span class="filter-pill ok" aria-disabled="true">192 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.7s</strong>.
585
+ Using <code>react-docgen-typescript</code>. Generation took <strong>3.7s</strong>.
586
586
  </div>
587
587
  <h2 class="section-title">Components</h2>
588
588
  <div class="grid" role="list">
@@ -3810,7 +3810,7 @@ size?: &quot;sm&quot; | &quot;md&quot; | &quot;lg&quot;</code></pre>
3810
3810
  <div class="badges">
3811
3811
 
3812
3812
 
3813
- <label for="c-13-components-modal-stories" class="badge ok as-toggle">5 stories</label>
3813
+ <label for="c-13-components-modal-stories" class="badge ok as-toggle">6 stories</label>
3814
3814
 
3815
3815
  </div>
3816
3816
  </div>
@@ -3869,6 +3869,31 @@ size?: &quot;sm&quot; | &quot;md&quot; | &quot;lg&quot;</code></pre>
3869
3869
  &lt;/Modal.Footer&gt;
3870
3870
  &lt;/Modal.Content&gt;
3871
3871
  &lt;/Modal.Root&gt;
3872
+ );</code></pre>
3873
+ </div>
3874
+ <div class="note ok">
3875
+ <div class="row">
3876
+ <span class="ex-name">With Description</span>
3877
+ <span class="badge ok">story ok</span>
3878
+ </div>
3879
+
3880
+ <div class="hint">`Modal.Description` sits 0.5rem below `Modal.Title` and doubles as the accessible description.</div>
3881
+ <pre><code>const WithDescription = () =&gt; (
3882
+ &lt;Modal.Root&gt;
3883
+ &lt;Modal.Trigger asChild&gt;
3884
+ &lt;Button variant=&quot;secondary&quot;&gt;Delete carrier&lt;/Button&gt;
3885
+ &lt;/Modal.Trigger&gt;
3886
+ &lt;Modal.Content&gt;
3887
+ &lt;Modal.Title&gt;Delete carrier&lt;/Modal.Title&gt;
3888
+ &lt;Modal.Description&gt;This action cannot be undone.&lt;/Modal.Description&gt;
3889
+ &lt;Modal.Footer&gt;
3890
+ &lt;Modal.Close asChild&gt;
3891
+ &lt;Button variant=&quot;ghost&quot;&gt;Cancel&lt;/Button&gt;
3892
+ &lt;/Modal.Close&gt;
3893
+ &lt;Button variant=&quot;primary&quot;&gt;Delete&lt;/Button&gt;
3894
+ &lt;/Modal.Footer&gt;
3895
+ &lt;/Modal.Content&gt;
3896
+ &lt;/Modal.Root&gt;
3872
3897
  );</code></pre>
3873
3898
  </div>
3874
3899
  <div class="note ok">
@@ -4894,38 +4919,253 @@ import { Fragment } from "react";</code></pre>
4894
4919
  </article>
4895
4920
  <article
4896
4921
  class="card
4897
- no-error
4898
- no-info
4922
+ has-error
4923
+ has-info
4899
4924
  no-story-error
4900
4925
  no-doc-error"
4901
4926
  role="listitem"
4902
4927
  aria-label="Tabs.Root">
4903
4928
  <div class="head">
4904
4929
  <div class="title">
4905
- <h2><span class="status-dot dot-ok"></span> Tabs.Root</h2>
4930
+ <h2><span class="status-dot dot-err"></span> Tabs.Root</h2>
4906
4931
  <div class="badges">
4907
-
4908
-
4932
+ <label for="c-20-components-tabs-err" class="badge err as-toggle">prop type error</label>
4933
+ <label for="c-20-components-tabs-info" class="badge info as-toggle">1 info</label>
4909
4934
  <label for="c-20-components-tabs-stories" class="badge ok as-toggle">8 stories</label>
4910
4935
 
4911
4936
  </div>
4912
4937
  </div>
4913
4938
  <div class="meta" title="./src/tabs/tabs.stories.tsx">components-tabs · ./src/tabs/tabs.stories.tsx</div>
4914
4939
 
4915
- <div class="hint">Tabs built on Radix UI&#39;s Tabs (keyboard nav, roving focus and ARIA come for free). Compose `Root` with a `List` of `Trigger`s and matching `Content`s, pairing each `Trigger`/`Content` by `value`.</div>
4940
+
4916
4941
 
4917
4942
  </div>
4918
4943
 
4919
4944
  <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
4920
-
4921
-
4945
+ <input id="c-20-components-tabs-err" class="tg tg-err" type="checkbox" hidden />
4946
+ <input id="c-20-components-tabs-info" class="tg tg-info" type="checkbox" hidden />
4922
4947
  <input id="c-20-components-tabs-stories" class="tg tg-stories" type="checkbox" hidden />
4923
4948
 
4924
4949
 
4925
4950
 
4926
4951
  <div class="panels">
4927
4952
 
4953
+ <div class="panel panel-err">
4954
+
4955
+ <div class="note err">
4956
+ <div class="note-title">Prop type error</div>
4957
+ <div class="note-body"><pre><code>No component file found for the &quot;Tabs.Root&quot; component.
4958
+ 4 | import { Tabs } from &#39;.&#39;;
4959
+ 5 |
4960
+ &gt; 6 | const meta = {
4961
+ | ^
4962
+ 7 | title: &#39;Components/Tabs&#39;,
4963
+ 8 | component: Tabs.Root,
4964
+ 9 | tags: [&#39;autodocs&#39;]
4965
+
4966
+ ./src/tabs/tabs.stories.tsx:
4967
+ import type { Meta, StoryObj } from &#39;@storybook/react-vite&#39;;
4968
+ import { expect, userEvent, within } from &#39;storybook/test&#39;;
4969
+
4970
+ import { Tabs } from &#39;.&#39;;
4971
+
4972
+ const meta = {
4973
+ title: &#39;Components/Tabs&#39;,
4974
+ component: Tabs.Root,
4975
+ tags: [&#39;autodocs&#39;]
4976
+ } satisfies Meta&lt;typeof Tabs.Root&gt;;
4977
+
4978
+ export default meta;
4979
+
4980
+ type Story = StoryObj&lt;typeof meta&gt;;
4981
+
4982
+ const TABS = [
4983
+ { value: &#39;overview&#39;, label: &#39;Overview&#39;, body: &#39;A summary of the policy and its coverage.&#39; },
4984
+ { value: &#39;documents&#39;, label: &#39;Documents&#39;, body: &#39;Declarations, endorsements and forms.&#39; },
4985
+ { value: &#39;activity&#39;, label: &#39;Activity&#39;, body: &#39;A timeline of recent changes and events.&#39; }
4986
+ ] as const;
4987
+
4988
+ const TabItems = () =&gt;
4989
+ TABS.map(({ value, label }) =&gt; (
4990
+ &lt;Tabs.Trigger key={value} value={value}&gt;
4991
+ {label}
4992
+ &lt;/Tabs.Trigger&gt;
4993
+ ));
4994
+
4995
+ const TabPanels = () =&gt;
4996
+ TABS.map(({ value, body }) =&gt; (
4997
+ &lt;Tabs.Content key={value} value={value} className=&quot;p-4 text-sm text-text-default-base-primary&quot;&gt;
4998
+ {body}
4999
+ &lt;/Tabs.Content&gt;
5000
+ ));
5001
+
5002
+ /** `line` (default): the active tab is marked with an animated underline. */
5003
+ export const Default: Story = {
5004
+ args: {
5005
+ variant: &#39;line&#39;,
5006
+ defaultValue: &#39;overview&#39;
5007
+ },
5008
+ argTypes: {
5009
+ variant: {
5010
+ control: &#39;radio&#39;,
5011
+ options: [&#39;line&#39;, &#39;enclosed&#39;, &#39;button&#39;],
5012
+ description: &#39;line = underline; enclosed = segmented pills; button = button-like tabs&#39;
5013
+ }
5014
+ },
5015
+ render: args =&gt; (
5016
+ &lt;Tabs.Root {...args}&gt;
5017
+ &lt;Tabs.List&gt;
5018
+ &lt;TabItems /&gt;
5019
+ &lt;/Tabs.List&gt;
5020
+ &lt;TabPanels /&gt;
5021
+ &lt;/Tabs.Root&gt;
5022
+ )
5023
+ };
5024
+
5025
+ /** `enclosed` renders segmented pills; the active tab sits on a raised surface. */
5026
+ export const Enclosed: Story = {
5027
+ render: () =&gt; (
5028
+ &lt;Tabs.Root variant=&quot;enclosed&quot; defaultValue=&quot;overview&quot;&gt;
5029
+ &lt;Tabs.List&gt;
5030
+ &lt;TabItems /&gt;
5031
+ &lt;/Tabs.List&gt;
5032
+ &lt;TabPanels /&gt;
5033
+ &lt;/Tabs.Root&gt;
5034
+ )
5035
+ };
5036
+
5037
+ /** `button` renders button-like tabs, with room for a leading icon per trigger. */
5038
+ export const Buttons: Story = {
5039
+ render: () =&gt; (
5040
+ &lt;Tabs.Root variant=&quot;button&quot; defaultValue=&quot;overview&quot;&gt;
5041
+ &lt;Tabs.List&gt;
5042
+ &lt;TabItems /&gt;
5043
+ &lt;/Tabs.List&gt;
5044
+ &lt;TabPanels /&gt;
5045
+ &lt;/Tabs.Root&gt;
5046
+ )
5047
+ };
5048
+
5049
+ /** `position` aligns the tab list within the row (`start` is the default). */
5050
+ export const Positions: Story = {
5051
+ render: () =&gt; (
5052
+ &lt;div className=&quot;flex flex-col gap-8&quot;&gt;
5053
+ {([&#39;start&#39;, &#39;center&#39;, &#39;end&#39;] as const).map(position =&gt; (
5054
+ &lt;Tabs.Root key={position} variant=&quot;enclosed&quot; position={position} defaultValue=&quot;overview&quot;&gt;
5055
+ &lt;Tabs.List&gt;
5056
+ &lt;TabItems /&gt;
5057
+ &lt;/Tabs.List&gt;
5058
+ &lt;TabPanels /&gt;
5059
+ &lt;/Tabs.Root&gt;
5060
+ ))}
5061
+ &lt;/div&gt;
5062
+ )
5063
+ };
5064
+
5065
+ /** `position=&quot;full&quot;` stretches the tab list to fill the available width. */
5066
+ export const FullWidth: Story = {
5067
+ render: () =&gt; (
5068
+ &lt;Tabs.Root variant=&quot;enclosed&quot; position=&quot;full&quot; defaultValue=&quot;overview&quot;&gt;
5069
+ &lt;Tabs.List&gt;
5070
+ &lt;TabItems /&gt;
5071
+ &lt;/Tabs.List&gt;
5072
+ &lt;TabPanels /&gt;
5073
+ &lt;/Tabs.Root&gt;
5074
+ )
5075
+ };
5076
+
5077
+ /**
5078
+ * Triggers accept `asChild` to render as another element — e.g. a router link.
5079
+ * The trigger resets the anchor&#39;s default underline, so link-based tabs match
5080
+ * the button-based ones.
5081
+ */
5082
+ export const AsChildLinks: Story = {
5083
+ render: () =&gt; (
5084
+ &lt;Tabs.Root variant=&quot;line&quot; defaultValue=&quot;overview&quot;&gt;
5085
+ &lt;Tabs.List&gt;
5086
+ {TABS.map(({ value, label }) =&gt; (
5087
+ &lt;Tabs.Trigger key={value} value={value} asChild&gt;
5088
+ &lt;a href={`#${value}`}&gt;{label}&lt;/a&gt;
5089
+ &lt;/Tabs.Trigger&gt;
5090
+ ))}
5091
+ &lt;/Tabs.List&gt;
5092
+ &lt;TabPanels /&gt;
5093
+ &lt;/Tabs.Root&gt;
5094
+ ),
5095
+ play: async ({ canvasElement }) =&gt; {
5096
+ const canvas = within(canvasElement);
5097
+ const overview = canvas.getByRole(&#39;tab&#39;, { name: /overview/i });
5098
+
5099
+ await expect(overview.tagName).toBe(&#39;A&#39;);
5100
+ await expect(getComputedStyle(overview).textDecorationLine).toBe(&#39;none&#39;);
5101
+ }
5102
+ };
5103
+
5104
+ /** Selecting a tab reveals its panel and hides the others. */
5105
+ export const SwitchTabs: Story = {
5106
+ args: {
5107
+ variant: &#39;line&#39;,
5108
+ defaultValue: &#39;overview&#39;
5109
+ },
5110
+ render: args =&gt; (
5111
+ &lt;Tabs.Root {...args}&gt;
5112
+ &lt;Tabs.List&gt;
5113
+ &lt;TabItems /&gt;
5114
+ &lt;/Tabs.List&gt;
5115
+ &lt;TabPanels /&gt;
5116
+ &lt;/Tabs.Root&gt;
5117
+ ),
5118
+ play: async ({ canvasElement }) =&gt; {
5119
+ const canvas = within(canvasElement);
5120
+ const overview = canvas.getByRole(&#39;tab&#39;, { name: /overview/i });
5121
+ const documents = canvas.getByRole(&#39;tab&#39;, { name: /documents/i });
5122
+
5123
+ await expect(overview).toHaveAttribute(&#39;data-state&#39;, &#39;active&#39;);
5124
+ await expect(await canvas.findByText(/summary of the policy/i)).toBeVisible();
5125
+
5126
+ await userEvent.click(documents);
5127
+ await expect(documents).toHaveAttribute(&#39;data-state&#39;, &#39;active&#39;);
5128
+ await expect(overview).toHaveAttribute(&#39;data-state&#39;, &#39;inactive&#39;);
5129
+ await expect(await canvas.findByText(/declarations, endorsements/i)).toBeVisible();
5130
+ }
5131
+ };
5132
+
5133
+ /**
5134
+ * A standalone `Label` gives a panel with a single, non-interactive title the
5135
+ * inactive trigger&#39;s exact look: outside a `Root` it never gets the active
5136
+ * data-state, and `pointer-events-none` keeps hover styles off. It is a plain
5137
+ * `span`, so wrap it in a heading element for heading semantics. No tab or
5138
+ * tablist role is announced.
5139
+ */
5140
+ export const SingleTitle: Story = {
5141
+ render: () =&gt; (
5142
+ &lt;div className=&quot;flex flex-col items-start gap-6&quot;&gt;
5143
+ {([&#39;line&#39;, &#39;enclosed&#39;, &#39;button&#39;] as const).map(variant =&gt; (
5144
+ &lt;h2 key={variant}&gt;
5145
+ &lt;Tabs.Label variant={variant}&gt;Shared coverages ({variant})&lt;/Tabs.Label&gt;
5146
+ &lt;/h2&gt;
5147
+ ))}
5148
+ &lt;/div&gt;
5149
+ ),
5150
+ play: async ({ canvasElement }) =&gt; {
5151
+ const canvas = within(canvasElement);
5152
+
5153
+ await expect(canvas.getAllByRole(&#39;heading&#39;)).toHaveLength(3);
5154
+ await expect(canvas.queryByRole(&#39;tablist&#39;)).not.toBeInTheDocument();
5155
+ await expect(canvas.queryByRole(&#39;tab&#39;)).not.toBeInTheDocument();
5156
+ }
5157
+ };
5158
+ </code></pre></div>
5159
+ </div>
5160
+ </div>
4928
5161
 
5162
+ <div class="panel panel-info">
5163
+
5164
+ <div class="note info">
5165
+ <div class="note-title">Info</div>
5166
+ <div class="note-body">No description found. Write a jsdoc comment such as /** Component description */.</div>
5167
+ </div>
5168
+ </div>
4929
5169
 
4930
5170
 
4931
5171
  <div class="panel panel-stories">
@@ -6175,7 +6415,417 @@ value: string</code></pre>
6175
6415
  </div>
6176
6416
  </article>
6177
6417
  </div>
6418
+ <div class="error-groups" role="region" aria-label="Prop type error groups">
6419
+ <section class="group">
6420
+ <input id="no-component-import-found-toggle" class="group-tg" type="checkbox" hidden />
6421
+ <label for="no-component-import-found-toggle" class="group-header">
6422
+ <span class="caret">▸</span>
6423
+ <span class="group-title">No component import found</span>
6424
+ <span class="group-count">1</span>
6425
+ </label>
6426
+ <div class="group-cards">
6427
+ <article
6428
+ class="card
6429
+ has-error
6430
+ has-info
6431
+ no-story-error
6432
+ no-doc-error"
6433
+ role="listitem"
6434
+ aria-label="Tabs.Root">
6435
+ <div class="head">
6436
+ <div class="title">
6437
+ <h2><span class="status-dot dot-err"></span> Tabs.Root</h2>
6438
+ <div class="badges">
6439
+ <label for="c-error-0-components-tabs-err" class="badge err as-toggle">prop type error</label>
6440
+ <label for="c-error-0-components-tabs-info" class="badge info as-toggle">1 info</label>
6441
+ <label for="c-error-0-components-tabs-stories" class="badge ok as-toggle">8 stories</label>
6442
+
6443
+ </div>
6444
+ </div>
6445
+ <div class="meta" title="./src/tabs/tabs.stories.tsx">components-tabs · ./src/tabs/tabs.stories.tsx</div>
6446
+
6447
+
6448
+
6449
+ </div>
6450
+
6451
+ <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
6452
+ <input id="c-error-0-components-tabs-err" class="tg tg-err" type="checkbox" hidden />
6453
+ <input id="c-error-0-components-tabs-info" class="tg tg-info" type="checkbox" hidden />
6454
+ <input id="c-error-0-components-tabs-stories" class="tg tg-stories" type="checkbox" hidden />
6455
+
6456
+
6457
+
6458
+ <div class="panels">
6459
+
6460
+ <div class="panel panel-err">
6461
+
6462
+ <div class="note err">
6463
+ <div class="note-title">Prop type error</div>
6464
+ <div class="note-body"><pre><code>No component file found for the &quot;Tabs.Root&quot; component.
6465
+ 4 | import { Tabs } from &#39;.&#39;;
6466
+ 5 |
6467
+ &gt; 6 | const meta = {
6468
+ | ^
6469
+ 7 | title: &#39;Components/Tabs&#39;,
6470
+ 8 | component: Tabs.Root,
6471
+ 9 | tags: [&#39;autodocs&#39;]
6472
+
6473
+ ./src/tabs/tabs.stories.tsx:
6474
+ import type { Meta, StoryObj } from &#39;@storybook/react-vite&#39;;
6475
+ import { expect, userEvent, within } from &#39;storybook/test&#39;;
6476
+
6477
+ import { Tabs } from &#39;.&#39;;
6478
+
6479
+ const meta = {
6480
+ title: &#39;Components/Tabs&#39;,
6481
+ component: Tabs.Root,
6482
+ tags: [&#39;autodocs&#39;]
6483
+ } satisfies Meta&lt;typeof Tabs.Root&gt;;
6484
+
6485
+ export default meta;
6486
+
6487
+ type Story = StoryObj&lt;typeof meta&gt;;
6488
+
6489
+ const TABS = [
6490
+ { value: &#39;overview&#39;, label: &#39;Overview&#39;, body: &#39;A summary of the policy and its coverage.&#39; },
6491
+ { value: &#39;documents&#39;, label: &#39;Documents&#39;, body: &#39;Declarations, endorsements and forms.&#39; },
6492
+ { value: &#39;activity&#39;, label: &#39;Activity&#39;, body: &#39;A timeline of recent changes and events.&#39; }
6493
+ ] as const;
6494
+
6495
+ const TabItems = () =&gt;
6496
+ TABS.map(({ value, label }) =&gt; (
6497
+ &lt;Tabs.Trigger key={value} value={value}&gt;
6498
+ {label}
6499
+ &lt;/Tabs.Trigger&gt;
6500
+ ));
6501
+
6502
+ const TabPanels = () =&gt;
6503
+ TABS.map(({ value, body }) =&gt; (
6504
+ &lt;Tabs.Content key={value} value={value} className=&quot;p-4 text-sm text-text-default-base-primary&quot;&gt;
6505
+ {body}
6506
+ &lt;/Tabs.Content&gt;
6507
+ ));
6508
+
6509
+ /** `line` (default): the active tab is marked with an animated underline. */
6510
+ export const Default: Story = {
6511
+ args: {
6512
+ variant: &#39;line&#39;,
6513
+ defaultValue: &#39;overview&#39;
6514
+ },
6515
+ argTypes: {
6516
+ variant: {
6517
+ control: &#39;radio&#39;,
6518
+ options: [&#39;line&#39;, &#39;enclosed&#39;, &#39;button&#39;],
6519
+ description: &#39;line = underline; enclosed = segmented pills; button = button-like tabs&#39;
6520
+ }
6521
+ },
6522
+ render: args =&gt; (
6523
+ &lt;Tabs.Root {...args}&gt;
6524
+ &lt;Tabs.List&gt;
6525
+ &lt;TabItems /&gt;
6526
+ &lt;/Tabs.List&gt;
6527
+ &lt;TabPanels /&gt;
6528
+ &lt;/Tabs.Root&gt;
6529
+ )
6530
+ };
6531
+
6532
+ /** `enclosed` renders segmented pills; the active tab sits on a raised surface. */
6533
+ export const Enclosed: Story = {
6534
+ render: () =&gt; (
6535
+ &lt;Tabs.Root variant=&quot;enclosed&quot; defaultValue=&quot;overview&quot;&gt;
6536
+ &lt;Tabs.List&gt;
6537
+ &lt;TabItems /&gt;
6538
+ &lt;/Tabs.List&gt;
6539
+ &lt;TabPanels /&gt;
6540
+ &lt;/Tabs.Root&gt;
6541
+ )
6542
+ };
6543
+
6544
+ /** `button` renders button-like tabs, with room for a leading icon per trigger. */
6545
+ export const Buttons: Story = {
6546
+ render: () =&gt; (
6547
+ &lt;Tabs.Root variant=&quot;button&quot; defaultValue=&quot;overview&quot;&gt;
6548
+ &lt;Tabs.List&gt;
6549
+ &lt;TabItems /&gt;
6550
+ &lt;/Tabs.List&gt;
6551
+ &lt;TabPanels /&gt;
6552
+ &lt;/Tabs.Root&gt;
6553
+ )
6554
+ };
6555
+
6556
+ /** `position` aligns the tab list within the row (`start` is the default). */
6557
+ export const Positions: Story = {
6558
+ render: () =&gt; (
6559
+ &lt;div className=&quot;flex flex-col gap-8&quot;&gt;
6560
+ {([&#39;start&#39;, &#39;center&#39;, &#39;end&#39;] as const).map(position =&gt; (
6561
+ &lt;Tabs.Root key={position} variant=&quot;enclosed&quot; position={position} defaultValue=&quot;overview&quot;&gt;
6562
+ &lt;Tabs.List&gt;
6563
+ &lt;TabItems /&gt;
6564
+ &lt;/Tabs.List&gt;
6565
+ &lt;TabPanels /&gt;
6566
+ &lt;/Tabs.Root&gt;
6567
+ ))}
6568
+ &lt;/div&gt;
6569
+ )
6570
+ };
6571
+
6572
+ /** `position=&quot;full&quot;` stretches the tab list to fill the available width. */
6573
+ export const FullWidth: Story = {
6574
+ render: () =&gt; (
6575
+ &lt;Tabs.Root variant=&quot;enclosed&quot; position=&quot;full&quot; defaultValue=&quot;overview&quot;&gt;
6576
+ &lt;Tabs.List&gt;
6577
+ &lt;TabItems /&gt;
6578
+ &lt;/Tabs.List&gt;
6579
+ &lt;TabPanels /&gt;
6580
+ &lt;/Tabs.Root&gt;
6581
+ )
6582
+ };
6583
+
6584
+ /**
6585
+ * Triggers accept `asChild` to render as another element — e.g. a router link.
6586
+ * The trigger resets the anchor&#39;s default underline, so link-based tabs match
6587
+ * the button-based ones.
6588
+ */
6589
+ export const AsChildLinks: Story = {
6590
+ render: () =&gt; (
6591
+ &lt;Tabs.Root variant=&quot;line&quot; defaultValue=&quot;overview&quot;&gt;
6592
+ &lt;Tabs.List&gt;
6593
+ {TABS.map(({ value, label }) =&gt; (
6594
+ &lt;Tabs.Trigger key={value} value={value} asChild&gt;
6595
+ &lt;a href={`#${value}`}&gt;{label}&lt;/a&gt;
6596
+ &lt;/Tabs.Trigger&gt;
6597
+ ))}
6598
+ &lt;/Tabs.List&gt;
6599
+ &lt;TabPanels /&gt;
6600
+ &lt;/Tabs.Root&gt;
6601
+ ),
6602
+ play: async ({ canvasElement }) =&gt; {
6603
+ const canvas = within(canvasElement);
6604
+ const overview = canvas.getByRole(&#39;tab&#39;, { name: /overview/i });
6605
+
6606
+ await expect(overview.tagName).toBe(&#39;A&#39;);
6607
+ await expect(getComputedStyle(overview).textDecorationLine).toBe(&#39;none&#39;);
6608
+ }
6609
+ };
6610
+
6611
+ /** Selecting a tab reveals its panel and hides the others. */
6612
+ export const SwitchTabs: Story = {
6613
+ args: {
6614
+ variant: &#39;line&#39;,
6615
+ defaultValue: &#39;overview&#39;
6616
+ },
6617
+ render: args =&gt; (
6618
+ &lt;Tabs.Root {...args}&gt;
6619
+ &lt;Tabs.List&gt;
6620
+ &lt;TabItems /&gt;
6621
+ &lt;/Tabs.List&gt;
6622
+ &lt;TabPanels /&gt;
6623
+ &lt;/Tabs.Root&gt;
6624
+ ),
6625
+ play: async ({ canvasElement }) =&gt; {
6626
+ const canvas = within(canvasElement);
6627
+ const overview = canvas.getByRole(&#39;tab&#39;, { name: /overview/i });
6628
+ const documents = canvas.getByRole(&#39;tab&#39;, { name: /documents/i });
6629
+
6630
+ await expect(overview).toHaveAttribute(&#39;data-state&#39;, &#39;active&#39;);
6631
+ await expect(await canvas.findByText(/summary of the policy/i)).toBeVisible();
6632
+
6633
+ await userEvent.click(documents);
6634
+ await expect(documents).toHaveAttribute(&#39;data-state&#39;, &#39;active&#39;);
6635
+ await expect(overview).toHaveAttribute(&#39;data-state&#39;, &#39;inactive&#39;);
6636
+ await expect(await canvas.findByText(/declarations, endorsements/i)).toBeVisible();
6637
+ }
6638
+ };
6639
+
6640
+ /**
6641
+ * A standalone `Label` gives a panel with a single, non-interactive title the
6642
+ * inactive trigger&#39;s exact look: outside a `Root` it never gets the active
6643
+ * data-state, and `pointer-events-none` keeps hover styles off. It is a plain
6644
+ * `span`, so wrap it in a heading element for heading semantics. No tab or
6645
+ * tablist role is announced.
6646
+ */
6647
+ export const SingleTitle: Story = {
6648
+ render: () =&gt; (
6649
+ &lt;div className=&quot;flex flex-col items-start gap-6&quot;&gt;
6650
+ {([&#39;line&#39;, &#39;enclosed&#39;, &#39;button&#39;] as const).map(variant =&gt; (
6651
+ &lt;h2 key={variant}&gt;
6652
+ &lt;Tabs.Label variant={variant}&gt;Shared coverages ({variant})&lt;/Tabs.Label&gt;
6653
+ &lt;/h2&gt;
6654
+ ))}
6655
+ &lt;/div&gt;
6656
+ ),
6657
+ play: async ({ canvasElement }) =&gt; {
6658
+ const canvas = within(canvasElement);
6659
+
6660
+ await expect(canvas.getAllByRole(&#39;heading&#39;)).toHaveLength(3);
6661
+ await expect(canvas.queryByRole(&#39;tablist&#39;)).not.toBeInTheDocument();
6662
+ await expect(canvas.queryByRole(&#39;tab&#39;)).not.toBeInTheDocument();
6663
+ }
6664
+ };
6665
+ </code></pre></div>
6666
+ </div>
6667
+ </div>
6178
6668
 
6669
+ <div class="panel panel-info">
6670
+
6671
+ <div class="note info">
6672
+ <div class="note-title">Info</div>
6673
+ <div class="note-body">No description found. Write a jsdoc comment such as /** Component description */.</div>
6674
+ </div>
6675
+ </div>
6676
+
6677
+
6678
+ <div class="panel panel-stories">
6679
+
6680
+
6681
+
6682
+ <div class="note ok">
6683
+ <div class="row">
6684
+ <span class="ex-name">Imports</span>
6685
+ </div>
6686
+ <pre><code>import { Tabs } from "@agentero/design-system";</code></pre>
6687
+ </div>
6688
+
6689
+
6690
+ <div class="note ok">
6691
+ <div class="row">
6692
+ <span class="ex-name">Default</span>
6693
+ <span class="badge ok">story ok</span>
6694
+ </div>
6695
+
6696
+ <div class="hint">`line` (default): the active tab is marked with an animated underline.</div>
6697
+ <pre><code>const Default = () =&gt; &lt;Tabs.Root variant=&quot;line&quot; defaultValue=&quot;overview&quot;&gt;
6698
+ &lt;Tabs.List&gt;
6699
+ &lt;TabItems /&gt;
6700
+ &lt;/Tabs.List&gt;
6701
+ &lt;TabPanels /&gt;
6702
+ &lt;/Tabs.Root&gt;;</code></pre>
6703
+ </div>
6704
+ <div class="note ok">
6705
+ <div class="row">
6706
+ <span class="ex-name">Enclosed</span>
6707
+ <span class="badge ok">story ok</span>
6708
+ </div>
6709
+
6710
+ <div class="hint">`enclosed` renders segmented pills; the active tab sits on a raised surface.</div>
6711
+ <pre><code>const Enclosed = () =&gt; (
6712
+ &lt;Tabs.Root variant=&quot;enclosed&quot; defaultValue=&quot;overview&quot;&gt;
6713
+ &lt;Tabs.List&gt;
6714
+ &lt;TabItems /&gt;
6715
+ &lt;/Tabs.List&gt;
6716
+ &lt;TabPanels /&gt;
6717
+ &lt;/Tabs.Root&gt;
6718
+ );</code></pre>
6719
+ </div>
6720
+ <div class="note ok">
6721
+ <div class="row">
6722
+ <span class="ex-name">Buttons</span>
6723
+ <span class="badge ok">story ok</span>
6724
+ </div>
6725
+
6726
+ <div class="hint">`button` renders button-like tabs, with room for a leading icon per trigger.</div>
6727
+ <pre><code>const Buttons = () =&gt; (
6728
+ &lt;Tabs.Root variant=&quot;button&quot; defaultValue=&quot;overview&quot;&gt;
6729
+ &lt;Tabs.List&gt;
6730
+ &lt;TabItems /&gt;
6731
+ &lt;/Tabs.List&gt;
6732
+ &lt;TabPanels /&gt;
6733
+ &lt;/Tabs.Root&gt;
6734
+ );</code></pre>
6735
+ </div>
6736
+ <div class="note ok">
6737
+ <div class="row">
6738
+ <span class="ex-name">Positions</span>
6739
+ <span class="badge ok">story ok</span>
6740
+ </div>
6741
+
6742
+ <div class="hint">`position` aligns the tab list within the row (`start` is the default).</div>
6743
+ <pre><code>const Positions = () =&gt; (
6744
+ &lt;div className=&quot;flex flex-col gap-8&quot;&gt;
6745
+ {([&#39;start&#39;, &#39;center&#39;, &#39;end&#39;] as const).map(position =&gt; (
6746
+ &lt;Tabs.Root key={position} variant=&quot;enclosed&quot; position={position} defaultValue=&quot;overview&quot;&gt;
6747
+ &lt;Tabs.List&gt;
6748
+ &lt;TabItems /&gt;
6749
+ &lt;/Tabs.List&gt;
6750
+ &lt;TabPanels /&gt;
6751
+ &lt;/Tabs.Root&gt;
6752
+ ))}
6753
+ &lt;/div&gt;
6754
+ );</code></pre>
6755
+ </div>
6756
+ <div class="note ok">
6757
+ <div class="row">
6758
+ <span class="ex-name">Full Width</span>
6759
+ <span class="badge ok">story ok</span>
6760
+ </div>
6761
+
6762
+ <div class="hint">`position=&quot;full&quot;` stretches the tab list to fill the available width.</div>
6763
+ <pre><code>const FullWidth = () =&gt; (
6764
+ &lt;Tabs.Root variant=&quot;enclosed&quot; position=&quot;full&quot; defaultValue=&quot;overview&quot;&gt;
6765
+ &lt;Tabs.List&gt;
6766
+ &lt;TabItems /&gt;
6767
+ &lt;/Tabs.List&gt;
6768
+ &lt;TabPanels /&gt;
6769
+ &lt;/Tabs.Root&gt;
6770
+ );</code></pre>
6771
+ </div>
6772
+ <div class="note ok">
6773
+ <div class="row">
6774
+ <span class="ex-name">As Child Links</span>
6775
+ <span class="badge ok">story ok</span>
6776
+ </div>
6777
+
6778
+ <div class="hint">Triggers accept `asChild` to render as another element — e.g. a router link. The trigger resets the anchor&#39;s default underline, so link-based tabs match the button-based ones.</div>
6779
+ <pre><code>const AsChildLinks = () =&gt; (
6780
+ &lt;Tabs.Root variant=&quot;line&quot; defaultValue=&quot;overview&quot;&gt;
6781
+ &lt;Tabs.List&gt;
6782
+ {TABS.map(({ value, label }) =&gt; (
6783
+ &lt;Tabs.Trigger key={value} value={value} asChild&gt;
6784
+ &lt;a href={`#${value}`}&gt;{label}&lt;/a&gt;
6785
+ &lt;/Tabs.Trigger&gt;
6786
+ ))}
6787
+ &lt;/Tabs.List&gt;
6788
+ &lt;TabPanels /&gt;
6789
+ &lt;/Tabs.Root&gt;
6790
+ );</code></pre>
6791
+ </div>
6792
+ <div class="note ok">
6793
+ <div class="row">
6794
+ <span class="ex-name">Switch Tabs</span>
6795
+ <span class="badge ok">story ok</span>
6796
+ </div>
6797
+
6798
+ <div class="hint">Selecting a tab reveals its panel and hides the others.</div>
6799
+ <pre><code>const SwitchTabs = () =&gt; &lt;Tabs.Root variant=&quot;line&quot; defaultValue=&quot;overview&quot;&gt;
6800
+ &lt;Tabs.List&gt;
6801
+ &lt;TabItems /&gt;
6802
+ &lt;/Tabs.List&gt;
6803
+ &lt;TabPanels /&gt;
6804
+ &lt;/Tabs.Root&gt;;</code></pre>
6805
+ </div>
6806
+ <div class="note ok">
6807
+ <div class="row">
6808
+ <span class="ex-name">Single Title</span>
6809
+ <span class="badge ok">story ok</span>
6810
+ </div>
6811
+
6812
+ <div class="hint">A standalone `Label` gives a panel with a single, non-interactive title the inactive trigger&#39;s exact look: outside a `Root` it never gets the active data-state, and `pointer-events-none` keeps hover styles off. It is a plain `span`, so wrap it in a heading element for heading semantics. No tab or tablist role is announced.</div>
6813
+ <pre><code>const SingleTitle = () =&gt; (
6814
+ &lt;div className=&quot;flex flex-col items-start gap-6&quot;&gt;
6815
+ {([&#39;line&#39;, &#39;enclosed&#39;, &#39;button&#39;] as const).map(variant =&gt; (
6816
+ &lt;h2 key={variant}&gt;
6817
+ &lt;Tabs.Label variant={variant}&gt;Shared coverages ({variant})&lt;/Tabs.Label&gt;
6818
+ &lt;/h2&gt;
6819
+ ))}
6820
+ &lt;/div&gt;
6821
+ );</code></pre>
6822
+ </div>
6823
+ </div>
6824
+
6825
+ </div>
6826
+ </article></div>
6827
+ </section>
6828
+ </div>
6179
6829
 
6180
6830
 
6181
6831
  </div>