@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.
- package/mcp/manifests/components.html +661 -11
- package/mcp/manifests/components.json +1 -1
- package/package.json +1 -1
- package/src/modal/modal.d.ts +13 -4
- package/src/modal/modal.js +19 -12
- package/src/tabs/index.d.ts +23 -1
- package/src/tabs/index.js +11 -2
- package/src/tabs/tabs.d.ts +59 -24
- package/src/tabs/tabs.js +1 -8
|
@@ -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><
|
|
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>
|
|
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?: "sm" | "md" | "lg"</code></pre>
|
|
|
3810
3810
|
<div class="badges">
|
|
3811
3811
|
|
|
3812
3812
|
|
|
3813
|
-
<label for="c-13-components-modal-stories" class="badge ok as-toggle">
|
|
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?: "sm" | "md" | "lg"</code></pre>
|
|
|
3869
3869
|
</Modal.Footer>
|
|
3870
3870
|
</Modal.Content>
|
|
3871
3871
|
</Modal.Root>
|
|
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 = () => (
|
|
3882
|
+
<Modal.Root>
|
|
3883
|
+
<Modal.Trigger asChild>
|
|
3884
|
+
<Button variant="secondary">Delete carrier</Button>
|
|
3885
|
+
</Modal.Trigger>
|
|
3886
|
+
<Modal.Content>
|
|
3887
|
+
<Modal.Title>Delete carrier</Modal.Title>
|
|
3888
|
+
<Modal.Description>This action cannot be undone.</Modal.Description>
|
|
3889
|
+
<Modal.Footer>
|
|
3890
|
+
<Modal.Close asChild>
|
|
3891
|
+
<Button variant="ghost">Cancel</Button>
|
|
3892
|
+
</Modal.Close>
|
|
3893
|
+
<Button variant="primary">Delete</Button>
|
|
3894
|
+
</Modal.Footer>
|
|
3895
|
+
</Modal.Content>
|
|
3896
|
+
</Modal.Root>
|
|
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
|
-
|
|
4898
|
-
|
|
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-
|
|
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
|
-
|
|
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 "Tabs.Root" component.
|
|
4958
|
+
4 | import { Tabs } from '.';
|
|
4959
|
+
5 |
|
|
4960
|
+
> 6 | const meta = {
|
|
4961
|
+
| ^
|
|
4962
|
+
7 | title: 'Components/Tabs',
|
|
4963
|
+
8 | component: Tabs.Root,
|
|
4964
|
+
9 | tags: ['autodocs']
|
|
4965
|
+
|
|
4966
|
+
./src/tabs/tabs.stories.tsx:
|
|
4967
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
4968
|
+
import { expect, userEvent, within } from 'storybook/test';
|
|
4969
|
+
|
|
4970
|
+
import { Tabs } from '.';
|
|
4971
|
+
|
|
4972
|
+
const meta = {
|
|
4973
|
+
title: 'Components/Tabs',
|
|
4974
|
+
component: Tabs.Root,
|
|
4975
|
+
tags: ['autodocs']
|
|
4976
|
+
} satisfies Meta<typeof Tabs.Root>;
|
|
4977
|
+
|
|
4978
|
+
export default meta;
|
|
4979
|
+
|
|
4980
|
+
type Story = StoryObj<typeof meta>;
|
|
4981
|
+
|
|
4982
|
+
const TABS = [
|
|
4983
|
+
{ value: 'overview', label: 'Overview', body: 'A summary of the policy and its coverage.' },
|
|
4984
|
+
{ value: 'documents', label: 'Documents', body: 'Declarations, endorsements and forms.' },
|
|
4985
|
+
{ value: 'activity', label: 'Activity', body: 'A timeline of recent changes and events.' }
|
|
4986
|
+
] as const;
|
|
4987
|
+
|
|
4988
|
+
const TabItems = () =>
|
|
4989
|
+
TABS.map(({ value, label }) => (
|
|
4990
|
+
<Tabs.Trigger key={value} value={value}>
|
|
4991
|
+
{label}
|
|
4992
|
+
</Tabs.Trigger>
|
|
4993
|
+
));
|
|
4994
|
+
|
|
4995
|
+
const TabPanels = () =>
|
|
4996
|
+
TABS.map(({ value, body }) => (
|
|
4997
|
+
<Tabs.Content key={value} value={value} className="p-4 text-sm text-text-default-base-primary">
|
|
4998
|
+
{body}
|
|
4999
|
+
</Tabs.Content>
|
|
5000
|
+
));
|
|
5001
|
+
|
|
5002
|
+
/** `line` (default): the active tab is marked with an animated underline. */
|
|
5003
|
+
export const Default: Story = {
|
|
5004
|
+
args: {
|
|
5005
|
+
variant: 'line',
|
|
5006
|
+
defaultValue: 'overview'
|
|
5007
|
+
},
|
|
5008
|
+
argTypes: {
|
|
5009
|
+
variant: {
|
|
5010
|
+
control: 'radio',
|
|
5011
|
+
options: ['line', 'enclosed', 'button'],
|
|
5012
|
+
description: 'line = underline; enclosed = segmented pills; button = button-like tabs'
|
|
5013
|
+
}
|
|
5014
|
+
},
|
|
5015
|
+
render: args => (
|
|
5016
|
+
<Tabs.Root {...args}>
|
|
5017
|
+
<Tabs.List>
|
|
5018
|
+
<TabItems />
|
|
5019
|
+
</Tabs.List>
|
|
5020
|
+
<TabPanels />
|
|
5021
|
+
</Tabs.Root>
|
|
5022
|
+
)
|
|
5023
|
+
};
|
|
5024
|
+
|
|
5025
|
+
/** `enclosed` renders segmented pills; the active tab sits on a raised surface. */
|
|
5026
|
+
export const Enclosed: Story = {
|
|
5027
|
+
render: () => (
|
|
5028
|
+
<Tabs.Root variant="enclosed" defaultValue="overview">
|
|
5029
|
+
<Tabs.List>
|
|
5030
|
+
<TabItems />
|
|
5031
|
+
</Tabs.List>
|
|
5032
|
+
<TabPanels />
|
|
5033
|
+
</Tabs.Root>
|
|
5034
|
+
)
|
|
5035
|
+
};
|
|
5036
|
+
|
|
5037
|
+
/** `button` renders button-like tabs, with room for a leading icon per trigger. */
|
|
5038
|
+
export const Buttons: Story = {
|
|
5039
|
+
render: () => (
|
|
5040
|
+
<Tabs.Root variant="button" defaultValue="overview">
|
|
5041
|
+
<Tabs.List>
|
|
5042
|
+
<TabItems />
|
|
5043
|
+
</Tabs.List>
|
|
5044
|
+
<TabPanels />
|
|
5045
|
+
</Tabs.Root>
|
|
5046
|
+
)
|
|
5047
|
+
};
|
|
5048
|
+
|
|
5049
|
+
/** `position` aligns the tab list within the row (`start` is the default). */
|
|
5050
|
+
export const Positions: Story = {
|
|
5051
|
+
render: () => (
|
|
5052
|
+
<div className="flex flex-col gap-8">
|
|
5053
|
+
{(['start', 'center', 'end'] as const).map(position => (
|
|
5054
|
+
<Tabs.Root key={position} variant="enclosed" position={position} defaultValue="overview">
|
|
5055
|
+
<Tabs.List>
|
|
5056
|
+
<TabItems />
|
|
5057
|
+
</Tabs.List>
|
|
5058
|
+
<TabPanels />
|
|
5059
|
+
</Tabs.Root>
|
|
5060
|
+
))}
|
|
5061
|
+
</div>
|
|
5062
|
+
)
|
|
5063
|
+
};
|
|
5064
|
+
|
|
5065
|
+
/** `position="full"` stretches the tab list to fill the available width. */
|
|
5066
|
+
export const FullWidth: Story = {
|
|
5067
|
+
render: () => (
|
|
5068
|
+
<Tabs.Root variant="enclosed" position="full" defaultValue="overview">
|
|
5069
|
+
<Tabs.List>
|
|
5070
|
+
<TabItems />
|
|
5071
|
+
</Tabs.List>
|
|
5072
|
+
<TabPanels />
|
|
5073
|
+
</Tabs.Root>
|
|
5074
|
+
)
|
|
5075
|
+
};
|
|
5076
|
+
|
|
5077
|
+
/**
|
|
5078
|
+
* Triggers accept `asChild` to render as another element — e.g. a router link.
|
|
5079
|
+
* The trigger resets the anchor's default underline, so link-based tabs match
|
|
5080
|
+
* the button-based ones.
|
|
5081
|
+
*/
|
|
5082
|
+
export const AsChildLinks: Story = {
|
|
5083
|
+
render: () => (
|
|
5084
|
+
<Tabs.Root variant="line" defaultValue="overview">
|
|
5085
|
+
<Tabs.List>
|
|
5086
|
+
{TABS.map(({ value, label }) => (
|
|
5087
|
+
<Tabs.Trigger key={value} value={value} asChild>
|
|
5088
|
+
<a href={`#${value}`}>{label}</a>
|
|
5089
|
+
</Tabs.Trigger>
|
|
5090
|
+
))}
|
|
5091
|
+
</Tabs.List>
|
|
5092
|
+
<TabPanels />
|
|
5093
|
+
</Tabs.Root>
|
|
5094
|
+
),
|
|
5095
|
+
play: async ({ canvasElement }) => {
|
|
5096
|
+
const canvas = within(canvasElement);
|
|
5097
|
+
const overview = canvas.getByRole('tab', { name: /overview/i });
|
|
5098
|
+
|
|
5099
|
+
await expect(overview.tagName).toBe('A');
|
|
5100
|
+
await expect(getComputedStyle(overview).textDecorationLine).toBe('none');
|
|
5101
|
+
}
|
|
5102
|
+
};
|
|
5103
|
+
|
|
5104
|
+
/** Selecting a tab reveals its panel and hides the others. */
|
|
5105
|
+
export const SwitchTabs: Story = {
|
|
5106
|
+
args: {
|
|
5107
|
+
variant: 'line',
|
|
5108
|
+
defaultValue: 'overview'
|
|
5109
|
+
},
|
|
5110
|
+
render: args => (
|
|
5111
|
+
<Tabs.Root {...args}>
|
|
5112
|
+
<Tabs.List>
|
|
5113
|
+
<TabItems />
|
|
5114
|
+
</Tabs.List>
|
|
5115
|
+
<TabPanels />
|
|
5116
|
+
</Tabs.Root>
|
|
5117
|
+
),
|
|
5118
|
+
play: async ({ canvasElement }) => {
|
|
5119
|
+
const canvas = within(canvasElement);
|
|
5120
|
+
const overview = canvas.getByRole('tab', { name: /overview/i });
|
|
5121
|
+
const documents = canvas.getByRole('tab', { name: /documents/i });
|
|
5122
|
+
|
|
5123
|
+
await expect(overview).toHaveAttribute('data-state', 'active');
|
|
5124
|
+
await expect(await canvas.findByText(/summary of the policy/i)).toBeVisible();
|
|
5125
|
+
|
|
5126
|
+
await userEvent.click(documents);
|
|
5127
|
+
await expect(documents).toHaveAttribute('data-state', 'active');
|
|
5128
|
+
await expect(overview).toHaveAttribute('data-state', 'inactive');
|
|
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'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: () => (
|
|
5142
|
+
<div className="flex flex-col items-start gap-6">
|
|
5143
|
+
{(['line', 'enclosed', 'button'] as const).map(variant => (
|
|
5144
|
+
<h2 key={variant}>
|
|
5145
|
+
<Tabs.Label variant={variant}>Shared coverages ({variant})</Tabs.Label>
|
|
5146
|
+
</h2>
|
|
5147
|
+
))}
|
|
5148
|
+
</div>
|
|
5149
|
+
),
|
|
5150
|
+
play: async ({ canvasElement }) => {
|
|
5151
|
+
const canvas = within(canvasElement);
|
|
5152
|
+
|
|
5153
|
+
await expect(canvas.getAllByRole('heading')).toHaveLength(3);
|
|
5154
|
+
await expect(canvas.queryByRole('tablist')).not.toBeInTheDocument();
|
|
5155
|
+
await expect(canvas.queryByRole('tab')).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 "Tabs.Root" component.
|
|
6465
|
+
4 | import { Tabs } from '.';
|
|
6466
|
+
5 |
|
|
6467
|
+
> 6 | const meta = {
|
|
6468
|
+
| ^
|
|
6469
|
+
7 | title: 'Components/Tabs',
|
|
6470
|
+
8 | component: Tabs.Root,
|
|
6471
|
+
9 | tags: ['autodocs']
|
|
6472
|
+
|
|
6473
|
+
./src/tabs/tabs.stories.tsx:
|
|
6474
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
6475
|
+
import { expect, userEvent, within } from 'storybook/test';
|
|
6476
|
+
|
|
6477
|
+
import { Tabs } from '.';
|
|
6478
|
+
|
|
6479
|
+
const meta = {
|
|
6480
|
+
title: 'Components/Tabs',
|
|
6481
|
+
component: Tabs.Root,
|
|
6482
|
+
tags: ['autodocs']
|
|
6483
|
+
} satisfies Meta<typeof Tabs.Root>;
|
|
6484
|
+
|
|
6485
|
+
export default meta;
|
|
6486
|
+
|
|
6487
|
+
type Story = StoryObj<typeof meta>;
|
|
6488
|
+
|
|
6489
|
+
const TABS = [
|
|
6490
|
+
{ value: 'overview', label: 'Overview', body: 'A summary of the policy and its coverage.' },
|
|
6491
|
+
{ value: 'documents', label: 'Documents', body: 'Declarations, endorsements and forms.' },
|
|
6492
|
+
{ value: 'activity', label: 'Activity', body: 'A timeline of recent changes and events.' }
|
|
6493
|
+
] as const;
|
|
6494
|
+
|
|
6495
|
+
const TabItems = () =>
|
|
6496
|
+
TABS.map(({ value, label }) => (
|
|
6497
|
+
<Tabs.Trigger key={value} value={value}>
|
|
6498
|
+
{label}
|
|
6499
|
+
</Tabs.Trigger>
|
|
6500
|
+
));
|
|
6501
|
+
|
|
6502
|
+
const TabPanels = () =>
|
|
6503
|
+
TABS.map(({ value, body }) => (
|
|
6504
|
+
<Tabs.Content key={value} value={value} className="p-4 text-sm text-text-default-base-primary">
|
|
6505
|
+
{body}
|
|
6506
|
+
</Tabs.Content>
|
|
6507
|
+
));
|
|
6508
|
+
|
|
6509
|
+
/** `line` (default): the active tab is marked with an animated underline. */
|
|
6510
|
+
export const Default: Story = {
|
|
6511
|
+
args: {
|
|
6512
|
+
variant: 'line',
|
|
6513
|
+
defaultValue: 'overview'
|
|
6514
|
+
},
|
|
6515
|
+
argTypes: {
|
|
6516
|
+
variant: {
|
|
6517
|
+
control: 'radio',
|
|
6518
|
+
options: ['line', 'enclosed', 'button'],
|
|
6519
|
+
description: 'line = underline; enclosed = segmented pills; button = button-like tabs'
|
|
6520
|
+
}
|
|
6521
|
+
},
|
|
6522
|
+
render: args => (
|
|
6523
|
+
<Tabs.Root {...args}>
|
|
6524
|
+
<Tabs.List>
|
|
6525
|
+
<TabItems />
|
|
6526
|
+
</Tabs.List>
|
|
6527
|
+
<TabPanels />
|
|
6528
|
+
</Tabs.Root>
|
|
6529
|
+
)
|
|
6530
|
+
};
|
|
6531
|
+
|
|
6532
|
+
/** `enclosed` renders segmented pills; the active tab sits on a raised surface. */
|
|
6533
|
+
export const Enclosed: Story = {
|
|
6534
|
+
render: () => (
|
|
6535
|
+
<Tabs.Root variant="enclosed" defaultValue="overview">
|
|
6536
|
+
<Tabs.List>
|
|
6537
|
+
<TabItems />
|
|
6538
|
+
</Tabs.List>
|
|
6539
|
+
<TabPanels />
|
|
6540
|
+
</Tabs.Root>
|
|
6541
|
+
)
|
|
6542
|
+
};
|
|
6543
|
+
|
|
6544
|
+
/** `button` renders button-like tabs, with room for a leading icon per trigger. */
|
|
6545
|
+
export const Buttons: Story = {
|
|
6546
|
+
render: () => (
|
|
6547
|
+
<Tabs.Root variant="button" defaultValue="overview">
|
|
6548
|
+
<Tabs.List>
|
|
6549
|
+
<TabItems />
|
|
6550
|
+
</Tabs.List>
|
|
6551
|
+
<TabPanels />
|
|
6552
|
+
</Tabs.Root>
|
|
6553
|
+
)
|
|
6554
|
+
};
|
|
6555
|
+
|
|
6556
|
+
/** `position` aligns the tab list within the row (`start` is the default). */
|
|
6557
|
+
export const Positions: Story = {
|
|
6558
|
+
render: () => (
|
|
6559
|
+
<div className="flex flex-col gap-8">
|
|
6560
|
+
{(['start', 'center', 'end'] as const).map(position => (
|
|
6561
|
+
<Tabs.Root key={position} variant="enclosed" position={position} defaultValue="overview">
|
|
6562
|
+
<Tabs.List>
|
|
6563
|
+
<TabItems />
|
|
6564
|
+
</Tabs.List>
|
|
6565
|
+
<TabPanels />
|
|
6566
|
+
</Tabs.Root>
|
|
6567
|
+
))}
|
|
6568
|
+
</div>
|
|
6569
|
+
)
|
|
6570
|
+
};
|
|
6571
|
+
|
|
6572
|
+
/** `position="full"` stretches the tab list to fill the available width. */
|
|
6573
|
+
export const FullWidth: Story = {
|
|
6574
|
+
render: () => (
|
|
6575
|
+
<Tabs.Root variant="enclosed" position="full" defaultValue="overview">
|
|
6576
|
+
<Tabs.List>
|
|
6577
|
+
<TabItems />
|
|
6578
|
+
</Tabs.List>
|
|
6579
|
+
<TabPanels />
|
|
6580
|
+
</Tabs.Root>
|
|
6581
|
+
)
|
|
6582
|
+
};
|
|
6583
|
+
|
|
6584
|
+
/**
|
|
6585
|
+
* Triggers accept `asChild` to render as another element — e.g. a router link.
|
|
6586
|
+
* The trigger resets the anchor's default underline, so link-based tabs match
|
|
6587
|
+
* the button-based ones.
|
|
6588
|
+
*/
|
|
6589
|
+
export const AsChildLinks: Story = {
|
|
6590
|
+
render: () => (
|
|
6591
|
+
<Tabs.Root variant="line" defaultValue="overview">
|
|
6592
|
+
<Tabs.List>
|
|
6593
|
+
{TABS.map(({ value, label }) => (
|
|
6594
|
+
<Tabs.Trigger key={value} value={value} asChild>
|
|
6595
|
+
<a href={`#${value}`}>{label}</a>
|
|
6596
|
+
</Tabs.Trigger>
|
|
6597
|
+
))}
|
|
6598
|
+
</Tabs.List>
|
|
6599
|
+
<TabPanels />
|
|
6600
|
+
</Tabs.Root>
|
|
6601
|
+
),
|
|
6602
|
+
play: async ({ canvasElement }) => {
|
|
6603
|
+
const canvas = within(canvasElement);
|
|
6604
|
+
const overview = canvas.getByRole('tab', { name: /overview/i });
|
|
6605
|
+
|
|
6606
|
+
await expect(overview.tagName).toBe('A');
|
|
6607
|
+
await expect(getComputedStyle(overview).textDecorationLine).toBe('none');
|
|
6608
|
+
}
|
|
6609
|
+
};
|
|
6610
|
+
|
|
6611
|
+
/** Selecting a tab reveals its panel and hides the others. */
|
|
6612
|
+
export const SwitchTabs: Story = {
|
|
6613
|
+
args: {
|
|
6614
|
+
variant: 'line',
|
|
6615
|
+
defaultValue: 'overview'
|
|
6616
|
+
},
|
|
6617
|
+
render: args => (
|
|
6618
|
+
<Tabs.Root {...args}>
|
|
6619
|
+
<Tabs.List>
|
|
6620
|
+
<TabItems />
|
|
6621
|
+
</Tabs.List>
|
|
6622
|
+
<TabPanels />
|
|
6623
|
+
</Tabs.Root>
|
|
6624
|
+
),
|
|
6625
|
+
play: async ({ canvasElement }) => {
|
|
6626
|
+
const canvas = within(canvasElement);
|
|
6627
|
+
const overview = canvas.getByRole('tab', { name: /overview/i });
|
|
6628
|
+
const documents = canvas.getByRole('tab', { name: /documents/i });
|
|
6629
|
+
|
|
6630
|
+
await expect(overview).toHaveAttribute('data-state', 'active');
|
|
6631
|
+
await expect(await canvas.findByText(/summary of the policy/i)).toBeVisible();
|
|
6632
|
+
|
|
6633
|
+
await userEvent.click(documents);
|
|
6634
|
+
await expect(documents).toHaveAttribute('data-state', 'active');
|
|
6635
|
+
await expect(overview).toHaveAttribute('data-state', 'inactive');
|
|
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'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: () => (
|
|
6649
|
+
<div className="flex flex-col items-start gap-6">
|
|
6650
|
+
{(['line', 'enclosed', 'button'] as const).map(variant => (
|
|
6651
|
+
<h2 key={variant}>
|
|
6652
|
+
<Tabs.Label variant={variant}>Shared coverages ({variant})</Tabs.Label>
|
|
6653
|
+
</h2>
|
|
6654
|
+
))}
|
|
6655
|
+
</div>
|
|
6656
|
+
),
|
|
6657
|
+
play: async ({ canvasElement }) => {
|
|
6658
|
+
const canvas = within(canvasElement);
|
|
6659
|
+
|
|
6660
|
+
await expect(canvas.getAllByRole('heading')).toHaveLength(3);
|
|
6661
|
+
await expect(canvas.queryByRole('tablist')).not.toBeInTheDocument();
|
|
6662
|
+
await expect(canvas.queryByRole('tab')).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 = () => <Tabs.Root variant="line" defaultValue="overview">
|
|
6698
|
+
<Tabs.List>
|
|
6699
|
+
<TabItems />
|
|
6700
|
+
</Tabs.List>
|
|
6701
|
+
<TabPanels />
|
|
6702
|
+
</Tabs.Root>;</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 = () => (
|
|
6712
|
+
<Tabs.Root variant="enclosed" defaultValue="overview">
|
|
6713
|
+
<Tabs.List>
|
|
6714
|
+
<TabItems />
|
|
6715
|
+
</Tabs.List>
|
|
6716
|
+
<TabPanels />
|
|
6717
|
+
</Tabs.Root>
|
|
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 = () => (
|
|
6728
|
+
<Tabs.Root variant="button" defaultValue="overview">
|
|
6729
|
+
<Tabs.List>
|
|
6730
|
+
<TabItems />
|
|
6731
|
+
</Tabs.List>
|
|
6732
|
+
<TabPanels />
|
|
6733
|
+
</Tabs.Root>
|
|
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 = () => (
|
|
6744
|
+
<div className="flex flex-col gap-8">
|
|
6745
|
+
{(['start', 'center', 'end'] as const).map(position => (
|
|
6746
|
+
<Tabs.Root key={position} variant="enclosed" position={position} defaultValue="overview">
|
|
6747
|
+
<Tabs.List>
|
|
6748
|
+
<TabItems />
|
|
6749
|
+
</Tabs.List>
|
|
6750
|
+
<TabPanels />
|
|
6751
|
+
</Tabs.Root>
|
|
6752
|
+
))}
|
|
6753
|
+
</div>
|
|
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="full"` stretches the tab list to fill the available width.</div>
|
|
6763
|
+
<pre><code>const FullWidth = () => (
|
|
6764
|
+
<Tabs.Root variant="enclosed" position="full" defaultValue="overview">
|
|
6765
|
+
<Tabs.List>
|
|
6766
|
+
<TabItems />
|
|
6767
|
+
</Tabs.List>
|
|
6768
|
+
<TabPanels />
|
|
6769
|
+
</Tabs.Root>
|
|
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's default underline, so link-based tabs match the button-based ones.</div>
|
|
6779
|
+
<pre><code>const AsChildLinks = () => (
|
|
6780
|
+
<Tabs.Root variant="line" defaultValue="overview">
|
|
6781
|
+
<Tabs.List>
|
|
6782
|
+
{TABS.map(({ value, label }) => (
|
|
6783
|
+
<Tabs.Trigger key={value} value={value} asChild>
|
|
6784
|
+
<a href={`#${value}`}>{label}</a>
|
|
6785
|
+
</Tabs.Trigger>
|
|
6786
|
+
))}
|
|
6787
|
+
</Tabs.List>
|
|
6788
|
+
<TabPanels />
|
|
6789
|
+
</Tabs.Root>
|
|
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 = () => <Tabs.Root variant="line" defaultValue="overview">
|
|
6800
|
+
<Tabs.List>
|
|
6801
|
+
<TabItems />
|
|
6802
|
+
</Tabs.List>
|
|
6803
|
+
<TabPanels />
|
|
6804
|
+
</Tabs.Root>;</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'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 = () => (
|
|
6814
|
+
<div className="flex flex-col items-start gap-6">
|
|
6815
|
+
{(['line', 'enclosed', 'button'] as const).map(variant => (
|
|
6816
|
+
<h2 key={variant}>
|
|
6817
|
+
<Tabs.Label variant={variant}>Shared coverages ({variant})</Tabs.Label>
|
|
6818
|
+
</h2>
|
|
6819
|
+
))}
|
|
6820
|
+
</div>
|
|
6821
|
+
);</code></pre>
|
|
6822
|
+
</div>
|
|
6823
|
+
</div>
|
|
6824
|
+
|
|
6825
|
+
</div>
|
|
6826
|
+
</article></div>
|
|
6827
|
+
</section>
|
|
6828
|
+
</div>
|
|
6179
6829
|
|
|
6180
6830
|
|
|
6181
6831
|
</div>
|