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