@agentero/design-system 0.24.3 → 0.24.5
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 +1714 -1001
- package/mcp/manifests/components.json +6985 -1
- package/mcp/server.mjs +3921 -2320
- package/package.json +1 -1
- package/src/accordion/accordion.d.ts +35 -23
- package/src/accordion/accordion.js +1 -8
- package/src/accordion/index.d.ts +18 -1
- package/src/accordion/index.js +10 -2
- package/src/avatar-group/avatar-group.d.ts +2 -0
- package/src/avatar-group/avatar-group.js +0 -1
- package/src/button/button.js +0 -1
- package/src/check-list/check-list.d.ts +15 -14
- package/src/check-list/check-list.js +1 -6
- package/src/check-list/index.d.ts +11 -1
- package/src/check-list/index.js +8 -2
- package/src/command/command.d.ts +117 -43
- package/src/command/command.js +1 -9
- package/src/command/index.d.ts +86 -1
- package/src/command/index.js +12 -2
- package/src/data-table/data-table.d.ts +81 -46
- package/src/data-table/data-table.js +71 -78
- package/src/data-table/index.d.ts +175 -2
- package/src/data-table/index.js +22 -3
- package/src/data-table/table.d.ts +107 -44
- package/src/data-table/table.js +1 -12
- package/src/divider/divider.js +0 -1
- package/src/dropdown-menu/dropdown-menu.d.ts +254 -136
- package/src/dropdown-menu/dropdown-menu.js +1 -14
- package/src/dropdown-menu/index.d.ts +51 -1
- package/src/dropdown-menu/index.js +16 -2
- package/src/hover-card/hover-card.d.ts +40 -26
- package/src/hover-card/hover-card.js +1 -9
- package/src/hover-card/index.d.ts +20 -1
- package/src/hover-card/index.js +11 -2
- package/src/label/label.js +0 -1
- package/src/modal/index.d.ts +38 -1
- package/src/modal/index.js +14 -2
- package/src/modal/modal.d.ts +125 -81
- package/src/modal/modal.js +1 -11
- package/src/popover/index.d.ts +24 -1
- package/src/popover/index.js +12 -2
- package/src/popover/popover.d.ts +30 -30
- package/src/popover/popover.js +1 -10
- package/src/skeleton/skeleton.js +0 -1
- package/src/tag/tag.js +0 -1
- package/src/validation-list/validation-list.d.ts +2 -0
- package/src/validation-list/validation-list.js +0 -1
|
@@ -250,6 +250,7 @@
|
|
|
250
250
|
.tg-info:checked + label.as-toggle,
|
|
251
251
|
.tg-stories:checked + label.as-toggle,
|
|
252
252
|
.tg-docs:checked + label.as-toggle,
|
|
253
|
+
.tg-subcomponents:checked + label.as-toggle,
|
|
253
254
|
.tg-content:checked + label.as-toggle,
|
|
254
255
|
.tg-props:checked + label.as-toggle {
|
|
255
256
|
box-shadow: 0 0 0 var(--active-ring) currentColor;
|
|
@@ -285,6 +286,11 @@
|
|
|
285
286
|
gap: 8px;
|
|
286
287
|
}
|
|
287
288
|
|
|
289
|
+
.tg-subcomponents:checked ~ .panels .panel-subcomponents {
|
|
290
|
+
display: grid;
|
|
291
|
+
gap: 8px;
|
|
292
|
+
}
|
|
293
|
+
|
|
288
294
|
.tg-content:checked ~ .panels .panel-content {
|
|
289
295
|
display: grid;
|
|
290
296
|
gap: 8px;
|
|
@@ -507,6 +513,10 @@
|
|
|
507
513
|
display: grid;
|
|
508
514
|
}
|
|
509
515
|
|
|
516
|
+
.card > .tg-subcomponents:checked ~ .panels .panel-subcomponents {
|
|
517
|
+
display: grid;
|
|
518
|
+
}
|
|
519
|
+
|
|
510
520
|
.card > .tg-content:checked ~ .panels .panel-content {
|
|
511
521
|
display: grid;
|
|
512
522
|
}
|
|
@@ -516,6 +526,7 @@
|
|
|
516
526
|
.card > .tg-info:checked ~ .panels,
|
|
517
527
|
.card > .tg-stories:checked ~ .panels,
|
|
518
528
|
.card > .tg-docs:checked ~ .panels,
|
|
529
|
+
.card > .tg-subcomponents:checked ~ .panels,
|
|
519
530
|
.card > .tg-content:checked ~ .panels,
|
|
520
531
|
.card > .tg-props:checked ~ .panels {
|
|
521
532
|
margin: 10px 0;
|
|
@@ -527,6 +538,7 @@
|
|
|
527
538
|
.card:has(.tg-info:checked) label[for$='-info'],
|
|
528
539
|
.card:has(.tg-stories:checked) label[for$='-stories'],
|
|
529
540
|
.card:has(.tg-docs:checked) label[for$='-docs'],
|
|
541
|
+
.card:has(.tg-subcomponents:checked) label[for$='-subcomponents'],
|
|
530
542
|
.card:has(.tg-content:checked) label[for$='-content'],
|
|
531
543
|
.card:has(.tg-props:checked) label[for$='-props'] {
|
|
532
544
|
box-shadow: 0 0 0 1px currentColor;
|
|
@@ -576,13 +588,13 @@
|
|
|
576
588
|
<header>
|
|
577
589
|
<div class="wrap">
|
|
578
590
|
<h1>Manifest Debugger</h1>
|
|
579
|
-
<div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><
|
|
591
|
+
<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">192 stories ok</span></div>
|
|
580
592
|
</div>
|
|
581
593
|
</header>
|
|
582
594
|
<main>
|
|
583
595
|
<div class="wrap">
|
|
584
596
|
<div class="note ok" style="margin-bottom: 16px;">
|
|
585
|
-
Using <code>react-
|
|
597
|
+
Using <code>react-component-meta</code>. Generation took <strong>3.7s</strong>.
|
|
586
598
|
</div>
|
|
587
599
|
<h2 class="section-title">Components</h2>
|
|
588
600
|
<div class="grid" role="list">
|
|
@@ -599,16 +611,29 @@
|
|
|
599
611
|
<div class="title">
|
|
600
612
|
<h2><span class="status-dot dot-ok"></span> Accordion.Root</h2>
|
|
601
613
|
<div class="badges">
|
|
602
|
-
|
|
614
|
+
<label for="c-0-components-accordion-props" class="badge ok as-toggle">10 prop types</label>
|
|
603
615
|
|
|
604
616
|
<label for="c-0-components-accordion-stories" class="badge ok as-toggle">7 stories</label>
|
|
605
617
|
|
|
618
|
+
|
|
606
619
|
</div>
|
|
607
620
|
</div>
|
|
608
621
|
<div class="meta" title="./src/accordion/accordion.stories.tsx">components-accordion · ./src/accordion/accordion.stories.tsx</div>
|
|
609
|
-
|
|
610
|
-
<div class="hint">
|
|
611
|
-
|
|
622
|
+
<div>Root of a group of collapsible sections</div>
|
|
623
|
+
<div class="hint">Accordion is a compound built on Radix UI: `Root` holds the `Item`s, each
|
|
624
|
+
with a `Trigger` and a `Content`. `type="single"` (with optional
|
|
625
|
+
`collapsible`) opens one section at a time; `type="multiple"` opens them
|
|
626
|
+
independently. `enclosed` renders the group as a bordered card.</div>
|
|
627
|
+
<div class="kv"><span class="chip">summary: Root of a group of collapsible sections</span><span class="chip">example: ```tsx
|
|
628
|
+
import { Accordion } from '@agentero/design-system/accordion';
|
|
629
|
+
|
|
630
|
+
<Accordion.Root type="single" collapsible>
|
|
631
|
+
<Accordion.Item value="coverages">
|
|
632
|
+
<Accordion.Trigger>Coverages</Accordion.Trigger>
|
|
633
|
+
<Accordion.Content>…</Accordion.Content>
|
|
634
|
+
</Accordion.Item>
|
|
635
|
+
</Accordion.Root>
|
|
636
|
+
```</span></div>
|
|
612
637
|
</div>
|
|
613
638
|
|
|
614
639
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -617,11 +642,63 @@
|
|
|
617
642
|
<input id="c-0-components-accordion-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
618
643
|
|
|
619
644
|
|
|
645
|
+
<input id="c-0-components-accordion-props" class="tg tg-props" type="checkbox" hidden />
|
|
620
646
|
|
|
621
647
|
<div class="panels">
|
|
622
648
|
|
|
623
649
|
|
|
624
650
|
|
|
651
|
+
<div class="panel panel-props">
|
|
652
|
+
<div class="note ok">
|
|
653
|
+
<div class="row">
|
|
654
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
655
|
+
<span class="badge ok">10 prop types</span>
|
|
656
|
+
</div>
|
|
657
|
+
<pre><code>Component: src/accordion/index.ts::Accordion</code></pre>
|
|
658
|
+
<pre><code>Props:</code></pre>
|
|
659
|
+
<pre><code>asChild?: boolean
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Whether an accordion item can be collapsed after it has been opened.
|
|
663
|
+
*/
|
|
664
|
+
collapsible?: boolean = false
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* The value of the item whose content is expanded when the accordion is initially rendered. Use
|
|
668
|
+
* `defaultValue` if you do not need to control the state of an accordion.
|
|
669
|
+
*/
|
|
670
|
+
defaultValue?: string | string[] | undefined
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* The language read direction.
|
|
674
|
+
*/
|
|
675
|
+
dir?: "ltr" | "rtl"
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Whether or not an accordion is disabled from user interaction.
|
|
679
|
+
*/
|
|
680
|
+
disabled?: boolean = false
|
|
681
|
+
|
|
682
|
+
enclosed?: boolean
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* The callback that fires when the state of the accordion changes.
|
|
686
|
+
*/
|
|
687
|
+
onValueChange?: ((value: string) => void) | ((value: string[]) => void) | undefined
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* The layout in which the Accordion operates.
|
|
691
|
+
*/
|
|
692
|
+
orientation?: "horizontal" | "vertical" = vertical
|
|
693
|
+
|
|
694
|
+
type: "single" | "multiple"
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* The controlled stateful value of the accordion item whose content is expanded.
|
|
698
|
+
*/
|
|
699
|
+
value?: string | string[] | undefined</code></pre>
|
|
700
|
+
</div>
|
|
701
|
+
</div>
|
|
625
702
|
|
|
626
703
|
<div class="panel panel-stories">
|
|
627
704
|
|
|
@@ -740,6 +817,7 @@
|
|
|
740
817
|
</div>
|
|
741
818
|
</div>
|
|
742
819
|
|
|
820
|
+
|
|
743
821
|
</div>
|
|
744
822
|
</article>
|
|
745
823
|
<article
|
|
@@ -758,12 +836,32 @@
|
|
|
758
836
|
|
|
759
837
|
<label for="c-1-components-alert-stories" class="badge ok as-toggle">23 stories</label>
|
|
760
838
|
|
|
839
|
+
|
|
761
840
|
</div>
|
|
762
841
|
</div>
|
|
763
842
|
<div class="meta" title="./src/alert/alert.stories.tsx">components-alert · ./src/alert/alert.stories.tsx</div>
|
|
764
|
-
|
|
765
|
-
<div class="hint">Alert surfaces feedback about outcomes or state changes — success, danger,
|
|
766
|
-
|
|
843
|
+
<div>Feedback banner with color variants, optional icon, and dismiss</div>
|
|
844
|
+
<div class="hint">Alert surfaces feedback about outcomes or state changes — success, danger,
|
|
845
|
+
warning, or info. Compose it from `Alert.Content`, `Alert.Title`,
|
|
846
|
+
`Alert.Paragraph`, `Alert.Actions`, and `Alert.Button` to build the layout
|
|
847
|
+
your flow needs. Eight colors, two sizes, and a ghost mode cover most
|
|
848
|
+
feedback scenarios.</div>
|
|
849
|
+
<div class="kv"><span class="chip">summary: Feedback banner with color variants, optional icon, and dismiss</span><span class="chip">example: <Alert color="success" size="sm">
|
|
850
|
+
<Alert.Content>
|
|
851
|
+
<Alert.Title>Policy saved</Alert.Title>
|
|
852
|
+
<Alert.Paragraph>Your changes are live.</Alert.Paragraph>
|
|
853
|
+
</Alert.Content>
|
|
854
|
+
</Alert></span><span class="chip">example: <Alert color="warning" onDismiss={() => setOpen(false)}>
|
|
855
|
+
<Alert.Content>
|
|
856
|
+
<Alert.Title>Session expiring</Alert.Title>
|
|
857
|
+
<Alert.Paragraph>Renew to continue editing.</Alert.Paragraph>
|
|
858
|
+
</Alert.Content>
|
|
859
|
+
<Alert.Actions>
|
|
860
|
+
<Alert.Button onClick={renew}>Renew session</Alert.Button>
|
|
861
|
+
</Alert.Actions>
|
|
862
|
+
</Alert></span><span class="chip">example: <Alert color="danger" ghost>
|
|
863
|
+
<Alert.Paragraph>This field is required.</Alert.Paragraph>
|
|
864
|
+
</Alert></span></div>
|
|
767
865
|
</div>
|
|
768
866
|
|
|
769
867
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -771,6 +869,7 @@
|
|
|
771
869
|
|
|
772
870
|
<input id="c-1-components-alert-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
773
871
|
|
|
872
|
+
|
|
774
873
|
<input id="c-1-components-alert-props" class="tg tg-props" type="checkbox" hidden />
|
|
775
874
|
|
|
776
875
|
<div class="panels">
|
|
@@ -780,7 +879,7 @@
|
|
|
780
879
|
<div class="panel panel-props">
|
|
781
880
|
<div class="note ok">
|
|
782
881
|
<div class="row">
|
|
783
|
-
<span class="ex-name">Prop types <small>(react-
|
|
882
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
784
883
|
<span class="badge ok">6 prop types</span>
|
|
785
884
|
</div>
|
|
786
885
|
<pre><code>Component: src/alert/alert.tsx::Alert</code></pre>
|
|
@@ -794,7 +893,7 @@
|
|
|
794
893
|
* - `info` — informational highlight.
|
|
795
894
|
* - `creative`, `dynamic`, `playful` — brand-aligned accents.
|
|
796
895
|
*/
|
|
797
|
-
color?: "neutral" | "success" | "danger" | "warning" | "info" | "creative" | "dynamic" | "playful" = neutral
|
|
896
|
+
color?: "neutral" | "success" | "danger" | "warning" | "info" | "creative" | "dynamic" | "playful" = 'neutral'
|
|
798
897
|
|
|
799
898
|
/**
|
|
800
899
|
* When `true`, removes background and padding so the alert blends inline
|
|
@@ -811,19 +910,19 @@ hasIcon?: boolean = true
|
|
|
811
910
|
/**
|
|
812
911
|
* Overrides the default icon for the current `color`. Receives the slot-computed className so color tokens still apply.
|
|
813
912
|
*/
|
|
814
|
-
icon?: ComponentType<SVGProps<SVGSVGElement>>
|
|
913
|
+
icon?: ComponentType<SVGProps<SVGSVGElement>> | undefined
|
|
815
914
|
|
|
816
915
|
/**
|
|
817
916
|
* Fires when the dismiss button is clicked. When provided, renders an `iconOnly` close button with `aria-label="Dismiss"`.
|
|
818
917
|
*/
|
|
819
|
-
onDismiss?: (
|
|
918
|
+
onDismiss?: () => void
|
|
820
919
|
|
|
821
920
|
/**
|
|
822
921
|
* Size treatment. Defaults to `'sm'`.
|
|
823
922
|
* - `sm` — compact inline alerts (1rem padding, 14/12px typography).
|
|
824
923
|
* - `md` — prominent standalone alerts (2rem padding, 18/14px typography).
|
|
825
924
|
*/
|
|
826
|
-
size?:
|
|
925
|
+
size?: "sm" | "md" = 'sm'</code></pre>
|
|
827
926
|
</div>
|
|
828
927
|
</div>
|
|
829
928
|
|
|
@@ -845,7 +944,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
845
944
|
<span class="badge ok">story ok</span>
|
|
846
945
|
</div>
|
|
847
946
|
<div>Default args playground for Alert</div>
|
|
848
|
-
<div class="hint">Args-controlled playground. Toggle `color`, `size`, `ghost`, `hasIcon`, and
|
|
947
|
+
<div class="hint">Args-controlled playground. Toggle `color`, `size`, `ghost`, `hasIcon`, and
|
|
948
|
+
`onDismiss` from the Controls panel to explore every visual combination.</div>
|
|
849
949
|
<pre><code>const Default = () => <Alert
|
|
850
950
|
color="neutral"
|
|
851
951
|
size="sm"
|
|
@@ -864,7 +964,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
864
964
|
<span class="badge ok">story ok</span>
|
|
865
965
|
</div>
|
|
866
966
|
<div>Neutral color (default)</div>
|
|
867
|
-
<div class="hint">Neutral color is the default and carries no strong semantic signal — use it
|
|
967
|
+
<div class="hint">Neutral color is the default and carries no strong semantic signal — use it
|
|
968
|
+
for generic inline information.</div>
|
|
868
969
|
<pre><code>const Neutral = () => <Alert
|
|
869
970
|
color="neutral"
|
|
870
971
|
size="sm"
|
|
@@ -883,7 +984,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
883
984
|
<span class="badge ok">story ok</span>
|
|
884
985
|
</div>
|
|
885
986
|
<div>Success color for positive outcomes</div>
|
|
886
|
-
<div class="hint">Success color confirms a positive outcome — saved record, completed task,
|
|
987
|
+
<div class="hint">Success color confirms a positive outcome — saved record, completed task,
|
|
988
|
+
healthy state.</div>
|
|
887
989
|
<pre><code>const Success = () => <Alert
|
|
888
990
|
color="success"
|
|
889
991
|
size="sm"
|
|
@@ -902,7 +1004,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
902
1004
|
<span class="badge ok">story ok</span>
|
|
903
1005
|
</div>
|
|
904
1006
|
<div>Danger color for errors and destructive outcomes</div>
|
|
905
|
-
<div class="hint">Danger color flags errors and destructive outcomes that require the user's
|
|
1007
|
+
<div class="hint">Danger color flags errors and destructive outcomes that require the user's
|
|
1008
|
+
attention.</div>
|
|
906
1009
|
<pre><code>const Danger = () => <Alert
|
|
907
1010
|
color="danger"
|
|
908
1011
|
size="sm"
|
|
@@ -959,7 +1062,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
959
1062
|
<span class="badge ok">story ok</span>
|
|
960
1063
|
</div>
|
|
961
1064
|
<div>Creative brand accent color</div>
|
|
962
|
-
<div class="hint">Creative color uses a brand-aligned purple accent for marketing or
|
|
1065
|
+
<div class="hint">Creative color uses a brand-aligned purple accent for marketing or
|
|
1066
|
+
onboarding moments.</div>
|
|
963
1067
|
<pre><code>const Creative = () => <Alert
|
|
964
1068
|
color="creative"
|
|
965
1069
|
size="sm"
|
|
@@ -978,7 +1082,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
978
1082
|
<span class="badge ok">story ok</span>
|
|
979
1083
|
</div>
|
|
980
1084
|
<div>Dynamic brand accent color</div>
|
|
981
|
-
<div class="hint">Dynamic color uses a brand-aligned orange accent for activity or
|
|
1085
|
+
<div class="hint">Dynamic color uses a brand-aligned orange accent for activity or
|
|
1086
|
+
momentum-focused content.</div>
|
|
982
1087
|
<pre><code>const Dynamic = () => <Alert
|
|
983
1088
|
color="dynamic"
|
|
984
1089
|
size="sm"
|
|
@@ -997,7 +1102,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
997
1102
|
<span class="badge ok">story ok</span>
|
|
998
1103
|
</div>
|
|
999
1104
|
<div>Playful brand accent color</div>
|
|
1000
|
-
<div class="hint">Playful color uses a brand-aligned pink accent for lighter or celebratory
|
|
1105
|
+
<div class="hint">Playful color uses a brand-aligned pink accent for lighter or celebratory
|
|
1106
|
+
content.</div>
|
|
1001
1107
|
<pre><code>const Playful = () => <Alert
|
|
1002
1108
|
color="playful"
|
|
1003
1109
|
size="sm"
|
|
@@ -1016,7 +1122,9 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1016
1122
|
<span class="badge ok">story ok</span>
|
|
1017
1123
|
</div>
|
|
1018
1124
|
<div>Ghost mode for inline, low-emphasis alerts</div>
|
|
1019
|
-
<div class="hint">Ghost mode removes the background and padding so the alert blends inline
|
|
1125
|
+
<div class="hint">Ghost mode removes the background and padding so the alert blends inline
|
|
1126
|
+
with surrounding text (e.g., form field errors). Colors switch to the ghost
|
|
1127
|
+
token ramp for lower visual weight.</div>
|
|
1020
1128
|
<pre><code>const Ghost = () => <Alert
|
|
1021
1129
|
color="danger"
|
|
1022
1130
|
size="sm"
|
|
@@ -1035,7 +1143,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1035
1143
|
<span class="badge ok">story ok</span>
|
|
1036
1144
|
</div>
|
|
1037
1145
|
<div>Small size (default, compact)</div>
|
|
1038
|
-
<div class="hint">Small size (default) uses compact padding and 14/12px typography — suitable
|
|
1146
|
+
<div class="hint">Small size (default) uses compact padding and 14/12px typography — suitable
|
|
1147
|
+
for inline alerts inside forms, tables, or cards.</div>
|
|
1039
1148
|
<pre><code>const SmallSize = () => <Alert
|
|
1040
1149
|
color="neutral"
|
|
1041
1150
|
size="sm"
|
|
@@ -1054,7 +1163,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1054
1163
|
<span class="badge ok">story ok</span>
|
|
1055
1164
|
</div>
|
|
1056
1165
|
<div>Medium size (prominent, standalone)</div>
|
|
1057
|
-
<div class="hint">Medium size uses larger padding and 18/14px typography — suitable for
|
|
1166
|
+
<div class="hint">Medium size uses larger padding and 18/14px typography — suitable for
|
|
1167
|
+
standalone alerts in empty states, modals, or dedicated feedback regions.</div>
|
|
1058
1168
|
<pre><code>const MediumSize = () => <Alert
|
|
1059
1169
|
color="neutral"
|
|
1060
1170
|
size="md"
|
|
@@ -1073,7 +1183,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1073
1183
|
<span class="badge ok">story ok</span>
|
|
1074
1184
|
</div>
|
|
1075
1185
|
<div>Alert with a dismiss button</div>
|
|
1076
|
-
<div class="hint">Dismissible alert. Providing `onDismiss` shows an icon-only close button
|
|
1186
|
+
<div class="hint">Dismissible alert. Providing `onDismiss` shows an icon-only close button
|
|
1187
|
+
with `aria-label="Dismiss"` that inherits the alert's color.</div>
|
|
1077
1188
|
<pre><code>const WithDismiss = () => <Alert color="warning" size="sm" ghost={false} hasIcon onDismiss={fn()}>
|
|
1078
1189
|
<Alert.Content>
|
|
1079
1190
|
<Alert.Title>Title</Alert.Title>
|
|
@@ -1087,7 +1198,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1087
1198
|
<span class="badge ok">story ok</span>
|
|
1088
1199
|
</div>
|
|
1089
1200
|
<div>Alert with a trailing action button</div>
|
|
1090
|
-
<div class="hint">Alert with a trailing action pinned to the right edge. Use `Alert.Actions`
|
|
1201
|
+
<div class="hint">Alert with a trailing action pinned to the right edge. Use `Alert.Actions`
|
|
1202
|
+
+ `Alert.Button` for the common "message + action" pattern.</div>
|
|
1091
1203
|
<pre><code>const WithActions = () => <Alert
|
|
1092
1204
|
color="info"
|
|
1093
1205
|
size="sm"
|
|
@@ -1109,7 +1221,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1109
1221
|
<span class="badge ok">story ok</span>
|
|
1110
1222
|
</div>
|
|
1111
1223
|
<div>Alert with both dismiss and action</div>
|
|
1112
|
-
<div class="hint">Alert combining a dismiss button with a trailing action. Dismiss is pinned
|
|
1224
|
+
<div class="hint">Alert combining a dismiss button with a trailing action. Dismiss is pinned
|
|
1225
|
+
to the right edge after the actions.</div>
|
|
1113
1226
|
<pre><code>const WithDismissAndAction = () => <Alert
|
|
1114
1227
|
color="warning"
|
|
1115
1228
|
size="md"
|
|
@@ -1131,7 +1244,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1131
1244
|
<span class="badge ok">story ok</span>
|
|
1132
1245
|
</div>
|
|
1133
1246
|
<div>Alert without the default icon</div>
|
|
1134
|
-
<div class="hint">Alert rendered without the built-in color icon. Use `hasIcon={false}` when
|
|
1247
|
+
<div class="hint">Alert rendered without the built-in color icon. Use `hasIcon={false}` when
|
|
1248
|
+
the surrounding context already conveys the semantic intent.</div>
|
|
1135
1249
|
<pre><code>const WithoutIcon = () => <Alert
|
|
1136
1250
|
color="info"
|
|
1137
1251
|
size="sm"
|
|
@@ -1150,7 +1264,9 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1150
1264
|
<span class="badge ok">story ok</span>
|
|
1151
1265
|
</div>
|
|
1152
1266
|
<div>Alert with a custom icon override</div>
|
|
1153
|
-
<div class="hint">Alert with a caller-supplied icon that replaces the default color icon. The
|
|
1267
|
+
<div class="hint">Alert with a caller-supplied icon that replaces the default color icon. The
|
|
1268
|
+
custom icon receives the slot-computed className so color tokens still
|
|
1269
|
+
apply.</div>
|
|
1154
1270
|
<pre><code>const WithCustomIcon = () => <Alert
|
|
1155
1271
|
color="creative"
|
|
1156
1272
|
size="sm"
|
|
@@ -1170,7 +1286,9 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1170
1286
|
<span class="badge ok">story ok</span>
|
|
1171
1287
|
</div>
|
|
1172
1288
|
<div>Alert paragraph rendered from HTML</div>
|
|
1173
|
-
<div class="hint">Alert rendering a paragraph from pre-sanitized HTML via
|
|
1289
|
+
<div class="hint">Alert rendering a paragraph from pre-sanitized HTML via
|
|
1290
|
+
`Alert.ParagraphHtml`. The caller is responsible for sanitizing the HTML
|
|
1291
|
+
string before passing it in.</div>
|
|
1174
1292
|
<pre><code>const WithParagraphHtml = () => <Alert
|
|
1175
1293
|
color="success"
|
|
1176
1294
|
size="sm"
|
|
@@ -1190,7 +1308,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1190
1308
|
<span class="badge ok">story ok</span>
|
|
1191
1309
|
</div>
|
|
1192
1310
|
<div>Alert with a pictogram illustration</div>
|
|
1193
|
-
<div class="hint">Alert with a 64×64 pictogram in place of the inline icon. Use
|
|
1311
|
+
<div class="hint">Alert with a 64×64 pictogram in place of the inline icon. Use
|
|
1312
|
+
`Alert.Pictograms` when the message benefits from a richer illustration.</div>
|
|
1194
1313
|
<pre><code>const WithPictograms = () => <Alert
|
|
1195
1314
|
color="info"
|
|
1196
1315
|
size="md"
|
|
@@ -1216,7 +1335,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1216
1335
|
<span class="badge ok">story ok</span>
|
|
1217
1336
|
</div>
|
|
1218
1337
|
<div>Alert with only a paragraph body</div>
|
|
1219
|
-
<div class="hint">Alert rendered with only a paragraph — no title. The root omits
|
|
1338
|
+
<div class="hint">Alert rendered with only a paragraph — no title. The root omits
|
|
1339
|
+
`aria-labelledby` since there is no title to reference.</div>
|
|
1220
1340
|
<pre><code>const OnlyParagraph = () => <Alert
|
|
1221
1341
|
color="neutral"
|
|
1222
1342
|
size="sm"
|
|
@@ -1232,7 +1352,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1232
1352
|
<span class="badge ok">story ok</span>
|
|
1233
1353
|
</div>
|
|
1234
1354
|
<div>Alert with actions placed below the content</div>
|
|
1235
|
-
<div class="hint">Action button rendered inline below the paragraphs, inside
|
|
1355
|
+
<div class="hint">Action button rendered inline below the paragraphs, inside
|
|
1356
|
+
`Alert.Content`, rather than pinned to the right via `Alert.Actions`.</div>
|
|
1236
1357
|
<pre><code>const WithActionsBelow = () => <Alert
|
|
1237
1358
|
color="success"
|
|
1238
1359
|
size="sm"
|
|
@@ -1254,7 +1375,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1254
1375
|
<span class="badge ok">story ok</span>
|
|
1255
1376
|
</div>
|
|
1256
1377
|
<div>Visual comparison of all Alert colors</div>
|
|
1257
|
-
<div class="hint">All eight colors in their primary (non-ghost) treatment, stacked for
|
|
1378
|
+
<div class="hint">All eight colors in their primary (non-ghost) treatment, stacked for
|
|
1379
|
+
comparison. Each alert uses the built-in icon mapping for its color.</div>
|
|
1258
1380
|
<pre><code>const AllColors = () => (
|
|
1259
1381
|
<Stack>
|
|
1260
1382
|
{COLORS.map(color => (
|
|
@@ -1276,7 +1398,8 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1276
1398
|
<span class="badge ok">story ok</span>
|
|
1277
1399
|
</div>
|
|
1278
1400
|
<div>Visual comparison of all Alert colors in ghost mode</div>
|
|
1279
|
-
<div class="hint">All eight colors in ghost mode, stacked for comparison. Ghost alerts use a
|
|
1401
|
+
<div class="hint">All eight colors in ghost mode, stacked for comparison. Ghost alerts use a
|
|
1402
|
+
lower-weight token ramp and omit background + padding.</div>
|
|
1280
1403
|
<pre><code>const AllGhostColors = () => (
|
|
1281
1404
|
<Stack>
|
|
1282
1405
|
{COLORS.map(color => (
|
|
@@ -1294,6 +1417,7 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1294
1417
|
</div>
|
|
1295
1418
|
</div>
|
|
1296
1419
|
|
|
1420
|
+
|
|
1297
1421
|
</div>
|
|
1298
1422
|
</article>
|
|
1299
1423
|
<article
|
|
@@ -1312,12 +1436,17 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1312
1436
|
|
|
1313
1437
|
<label for="c-2-components-avatar-stories" class="badge ok as-toggle">22 stories</label>
|
|
1314
1438
|
|
|
1439
|
+
|
|
1315
1440
|
</div>
|
|
1316
1441
|
</div>
|
|
1317
1442
|
<div class="meta" title="./src/avatar/avatar.stories.tsx">components-avatar · ./src/avatar/avatar.stories.tsx</div>
|
|
1318
|
-
|
|
1319
|
-
<div class="hint">Avatar displays a user's profile image, initials, or a fallback icon.
|
|
1320
|
-
|
|
1443
|
+
<div>Displays a user's profile image, initials, or fallback icon</div>
|
|
1444
|
+
<div class="hint">Avatar displays a user's profile image, initials, or a fallback icon.
|
|
1445
|
+
Use for user identification in lists, headers, cards, and comment threads.
|
|
1446
|
+
Supports multiple shapes (`circle`, `square`, `pillow`, `pentagon`),
|
|
1447
|
+
content types (`photo`, `initials`, `isotype`), and sizes from `xs` (24px)
|
|
1448
|
+
to `4xl` (128px).</div>
|
|
1449
|
+
<div class="kv"><span class="chip">summary: Displays a user's profile image, initials, or fallback icon</span><span class="chip">example: <Avatar src="/photos/jane.jpg" alt="Jane Doe" size="md" variant="circle" /></span><span class="chip">example: <Avatar fallback="JD" size="lg" variant="square" /></span></div>
|
|
1321
1450
|
</div>
|
|
1322
1451
|
|
|
1323
1452
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -1325,6 +1454,7 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1325
1454
|
|
|
1326
1455
|
<input id="c-2-components-avatar-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
1327
1456
|
|
|
1457
|
+
|
|
1328
1458
|
<input id="c-2-components-avatar-props" class="tg tg-props" type="checkbox" hidden />
|
|
1329
1459
|
|
|
1330
1460
|
<div class="panels">
|
|
@@ -1334,7 +1464,7 @@ size?: AlertSizeType = sm</code></pre>
|
|
|
1334
1464
|
<div class="panel panel-props">
|
|
1335
1465
|
<div class="note ok">
|
|
1336
1466
|
<div class="row">
|
|
1337
|
-
<span class="ex-name">Prop types <small>(react-
|
|
1467
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
1338
1468
|
<span class="badge ok">8 prop types</span>
|
|
1339
1469
|
</div>
|
|
1340
1470
|
<pre><code>Component: src/avatar/avatar.tsx::Avatar</code></pre>
|
|
@@ -1412,7 +1542,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1412
1542
|
<span class="badge ok">story ok</span>
|
|
1413
1543
|
</div>
|
|
1414
1544
|
<div>Default avatar with fallback initials</div>
|
|
1415
|
-
<div class="hint">The default avatar with fallback initials. Renders as a medium circle
|
|
1545
|
+
<div class="hint">The default avatar with fallback initials. Renders as a medium circle
|
|
1546
|
+
when no image source is provided.</div>
|
|
1416
1547
|
<pre><code>const Default = () => <Avatar fallback="JD" size="md" variant="circle" type="photo" />;</code></pre>
|
|
1417
1548
|
</div>
|
|
1418
1549
|
<div class="note ok">
|
|
@@ -1421,7 +1552,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1421
1552
|
<span class="badge ok">story ok</span>
|
|
1422
1553
|
</div>
|
|
1423
1554
|
<div>Avatar with a profile image</div>
|
|
1424
|
-
<div class="hint">Avatar displaying a user profile photo. The image fills the avatar shape
|
|
1555
|
+
<div class="hint">Avatar displaying a user profile photo. The image fills the avatar shape
|
|
1556
|
+
and the fallback is hidden while the image loads successfully.</div>
|
|
1425
1557
|
<pre><code>const WithImage = () => <Avatar
|
|
1426
1558
|
fallback="JD"
|
|
1427
1559
|
size="md"
|
|
@@ -1436,7 +1568,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1436
1568
|
<span class="badge ok">story ok</span>
|
|
1437
1569
|
</div>
|
|
1438
1570
|
<div>Fallback content shown when image is unavailable</div>
|
|
1439
|
-
<div class="hint">When the image fails to load, the fallback content is displayed.
|
|
1571
|
+
<div class="hint">When the image fails to load, the fallback content is displayed.
|
|
1572
|
+
Pass initials, an icon, or any ReactNode as the `fallback` prop.</div>
|
|
1440
1573
|
<pre><code>const WithFallbackInitials = () => <Avatar
|
|
1441
1574
|
fallback="AM"
|
|
1442
1575
|
size="md"
|
|
@@ -1459,7 +1592,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1459
1592
|
<span class="badge ok">story ok</span>
|
|
1460
1593
|
</div>
|
|
1461
1594
|
<div>Square-shaped avatar for workspaces</div>
|
|
1462
|
-
<div class="hint">The square variant uses a rounded rectangle, suitable for workspace,
|
|
1595
|
+
<div class="hint">The square variant uses a rounded rectangle, suitable for workspace,
|
|
1596
|
+
team, or organization icons.</div>
|
|
1463
1597
|
<pre><code>const Square = () => <Avatar fallback="WS" size="md" variant="square" type="photo" />;</code></pre>
|
|
1464
1598
|
</div>
|
|
1465
1599
|
<div class="note ok">
|
|
@@ -1468,7 +1602,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1468
1602
|
<span class="badge ok">story ok</span>
|
|
1469
1603
|
</div>
|
|
1470
1604
|
<div>Pillow-shaped avatar with organic squircle</div>
|
|
1471
|
-
<div class="hint">The pillow variant uses a soft, organic squircle shape for a
|
|
1605
|
+
<div class="hint">The pillow variant uses a soft, organic squircle shape for a
|
|
1606
|
+
friendly and distinctive appearance.</div>
|
|
1472
1607
|
<pre><code>const Pillow = () => <Avatar fallback="PL" size="md" variant="pillow" type="photo" />;</code></pre>
|
|
1473
1608
|
</div>
|
|
1474
1609
|
<div class="note ok">
|
|
@@ -1477,7 +1612,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1477
1612
|
<span class="badge ok">story ok</span>
|
|
1478
1613
|
</div>
|
|
1479
1614
|
<div>Pentagon-shaped avatar for unique identity</div>
|
|
1480
|
-
<div class="hint">The pentagon variant uses a five-sided mask for a unique visual identity.
|
|
1615
|
+
<div class="hint">The pentagon variant uses a five-sided mask for a unique visual identity.
|
|
1616
|
+
Note: the border is hidden in this variant due to the mask shape.</div>
|
|
1481
1617
|
<pre><code>const Pentagon = () => <Avatar fallback="PT" size="md" variant="pentagon" type="photo" />;</code></pre>
|
|
1482
1618
|
</div>
|
|
1483
1619
|
<div class="note ok">
|
|
@@ -1486,7 +1622,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1486
1622
|
<span class="badge ok">story ok</span>
|
|
1487
1623
|
</div>
|
|
1488
1624
|
<div>Photo type fills the avatar shape edge-to-edge</div>
|
|
1489
|
-
<div class="hint">The `photo` type is the default. The image fills the avatar shape edge-to-edge,
|
|
1625
|
+
<div class="hint">The `photo` type is the default. The image fills the avatar shape edge-to-edge,
|
|
1626
|
+
which is ideal for user profile photographs.</div>
|
|
1490
1627
|
<pre><code>const TypePhoto = () => <Avatar
|
|
1491
1628
|
fallback="AM"
|
|
1492
1629
|
size="md"
|
|
@@ -1501,7 +1638,9 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1501
1638
|
<span class="badge ok">story ok</span>
|
|
1502
1639
|
</div>
|
|
1503
1640
|
<div>Initials type for users without a profile photo</div>
|
|
1504
|
-
<div class="hint">The `initials` type is intended when no image is available and the avatar
|
|
1641
|
+
<div class="hint">The `initials` type is intended when no image is available and the avatar
|
|
1642
|
+
stands in for a user with their initials. The fallback text is centered
|
|
1643
|
+
within the avatar shape.</div>
|
|
1505
1644
|
<pre><code>const TypeInitials = () => <Avatar fallback="JD" size="md" variant="circle" type="initials" />;</code></pre>
|
|
1506
1645
|
</div>
|
|
1507
1646
|
<div class="note ok">
|
|
@@ -1510,7 +1649,10 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1510
1649
|
<span class="badge ok">story ok</span>
|
|
1511
1650
|
</div>
|
|
1512
1651
|
<div>Isotype type centers a brand icon inside the shape</div>
|
|
1513
|
-
<div class="hint">The `isotype` type renders the image smaller than the avatar shape so a
|
|
1652
|
+
<div class="hint">The `isotype` type renders the image smaller than the avatar shape so a
|
|
1653
|
+
brand or organization icon sits centered inside the container rather than
|
|
1654
|
+
filling it. Use for workspace, team, or company avatars where a logo
|
|
1655
|
+
should remain legible inside the bounding shape.</div>
|
|
1514
1656
|
<pre><code>const TypeIsotype = () => <Avatar
|
|
1515
1657
|
fallback="FG"
|
|
1516
1658
|
size="md"
|
|
@@ -1525,7 +1667,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1525
1667
|
<span class="badge ok">story ok</span>
|
|
1526
1668
|
</div>
|
|
1527
1669
|
<div>Visual comparison of all avatar content types</div>
|
|
1528
|
-
<div class="hint">All content types shown side by side: `photo` fills the shape, `initials`
|
|
1670
|
+
<div class="hint">All content types shown side by side: `photo` fills the shape, `initials`
|
|
1671
|
+
centers text, and `isotype` shrinks a brand icon inside the bounding shape.</div>
|
|
1529
1672
|
<pre><code>const AllTypes = () => (
|
|
1530
1673
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
1531
1674
|
<Avatar
|
|
@@ -1553,7 +1696,9 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1553
1696
|
<span class="badge ok">story ok</span>
|
|
1554
1697
|
</div>
|
|
1555
1698
|
<div>Isotype scaling across all avatar sizes</div>
|
|
1556
|
-
<div class="hint">The isotype icon scales proportionally smaller than the avatar shape at
|
|
1699
|
+
<div class="hint">The isotype icon scales proportionally smaller than the avatar shape at
|
|
1700
|
+
every size, keeping a consistent inset around the logo from `xs` (24px)
|
|
1701
|
+
to `4xl` (128px).</div>
|
|
1557
1702
|
<pre><code>const AllSizesIsotype = () => (
|
|
1558
1703
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
1559
1704
|
{(['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'] as const).map(size => (
|
|
@@ -1612,7 +1757,9 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1612
1757
|
<span class="badge ok">story ok</span>
|
|
1613
1758
|
</div>
|
|
1614
1759
|
<div>Colorized avatar based on user name</div>
|
|
1615
|
-
<div class="hint">The `colorize` prop deterministically maps a string (typically a user name)
|
|
1760
|
+
<div class="hint">The `colorize` prop deterministically maps a string (typically a user name)
|
|
1761
|
+
to a color from the palette, applying a tinted background and matching
|
|
1762
|
+
text color. Useful for distinguishing users in lists without profile photos.</div>
|
|
1616
1763
|
<pre><code>const Colorized = () => <Avatar fallback="JD" size="md" variant="circle" type="photo" colorize="jane doe" />;</code></pre>
|
|
1617
1764
|
</div>
|
|
1618
1765
|
<div class="note ok">
|
|
@@ -1621,7 +1768,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1621
1768
|
<span class="badge ok">story ok</span>
|
|
1622
1769
|
</div>
|
|
1623
1770
|
<div>Multiple colorized avatars for visual distinction</div>
|
|
1624
|
-
<div class="hint">Multiple colorized avatars showing how different names map to different
|
|
1771
|
+
<div class="hint">Multiple colorized avatars showing how different names map to different
|
|
1772
|
+
colors from the palette for visual distinction.</div>
|
|
1625
1773
|
<pre><code>const AllColorized = () => (
|
|
1626
1774
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
1627
1775
|
{['alice', 'bob', 'carol', 'dave', 'eve', 'frank', 'grace', 'henry', 'iris'].map(name => (
|
|
@@ -1636,7 +1784,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1636
1784
|
<span class="badge ok">story ok</span>
|
|
1637
1785
|
</div>
|
|
1638
1786
|
<div>Visual comparison of all avatar sizes</div>
|
|
1639
|
-
<div class="hint">All available sizes displayed together for visual comparison.
|
|
1787
|
+
<div class="hint">All available sizes displayed together for visual comparison.
|
|
1788
|
+
Sizes range from `xs` (24px) to `4xl` (128px).</div>
|
|
1640
1789
|
<pre><code>const AllSizes = () => (
|
|
1641
1790
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
1642
1791
|
{(['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'] as const).map(size => (
|
|
@@ -1651,7 +1800,8 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1651
1800
|
<span class="badge ok">story ok</span>
|
|
1652
1801
|
</div>
|
|
1653
1802
|
<div>All avatar sizes with a profile image</div>
|
|
1654
|
-
<div class="hint">All sizes with a profile image to verify image scaling and quality
|
|
1803
|
+
<div class="hint">All sizes with a profile image to verify image scaling and quality
|
|
1804
|
+
across the full size range from `xs` (24px) to `4xl` (128px).</div>
|
|
1655
1805
|
<pre><code>const AllSizesWithImage = () => (
|
|
1656
1806
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
1657
1807
|
{(['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'] as const).map(size => (
|
|
@@ -1672,7 +1822,9 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1672
1822
|
<span class="badge ok">story ok</span>
|
|
1673
1823
|
</div>
|
|
1674
1824
|
<div>Visual comparison of all avatar shapes</div>
|
|
1675
|
-
<div class="hint">All available shape variants displayed together for visual comparison.
|
|
1825
|
+
<div class="hint">All available shape variants displayed together for visual comparison.
|
|
1826
|
+
Each variant serves a different use case: user photos, workspaces,
|
|
1827
|
+
friendly branding, and unique identity.</div>
|
|
1676
1828
|
<pre><code>const AllVariants = () => (
|
|
1677
1829
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
1678
1830
|
{(['circle', 'square', 'pillow', 'pentagon'] as const).map(variant => (
|
|
@@ -1692,7 +1844,9 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1692
1844
|
<span class="badge ok">story ok</span>
|
|
1693
1845
|
</div>
|
|
1694
1846
|
<div>All avatar shapes with a profile image</div>
|
|
1695
|
-
<div class="hint">All shape variants with a profile image to show how each mask clips
|
|
1847
|
+
<div class="hint">All shape variants with a profile image to show how each mask clips
|
|
1848
|
+
the photo. Particularly useful for verifying the pentagon mask and
|
|
1849
|
+
pillow shape render correctly with real imagery.</div>
|
|
1696
1850
|
<pre><code>const AllVariantsWithImage = () => (
|
|
1697
1851
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
1698
1852
|
{(['circle', 'square', 'pillow', 'pentagon'] as const).map(variant => (
|
|
@@ -1710,6 +1864,7 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1710
1864
|
</div>
|
|
1711
1865
|
</div>
|
|
1712
1866
|
|
|
1867
|
+
|
|
1713
1868
|
</div>
|
|
1714
1869
|
</article>
|
|
1715
1870
|
<article
|
|
@@ -1724,16 +1879,24 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1724
1879
|
<div class="title">
|
|
1725
1880
|
<h2><span class="status-dot dot-ok"></span> AvatarGroup</h2>
|
|
1726
1881
|
<div class="badges">
|
|
1727
|
-
<label for="c-3-components-avatargroup-props" class="badge ok as-toggle">
|
|
1882
|
+
<label for="c-3-components-avatargroup-props" class="badge ok as-toggle">4 prop types</label>
|
|
1728
1883
|
|
|
1729
1884
|
<label for="c-3-components-avatargroup-stories" class="badge ok as-toggle">4 stories</label>
|
|
1730
1885
|
|
|
1886
|
+
|
|
1731
1887
|
</div>
|
|
1732
1888
|
</div>
|
|
1733
1889
|
<div class="meta" title="./src/avatar-group/avatar-group.stories.tsx">components-avatargroup · ./src/avatar-group/avatar-group.stories.tsx</div>
|
|
1734
|
-
|
|
1735
|
-
<div class="hint">AvatarGroup stacks `<Avatar>` children into an overlapping row and collapses
|
|
1736
|
-
|
|
1890
|
+
<div>Overlapping row of avatars, collapsing the rest into `+N`</div>
|
|
1891
|
+
<div class="hint">AvatarGroup stacks `<Avatar>` children into an overlapping row and collapses
|
|
1892
|
+
everything past `max` into a trailing `+N` bubble. The group owns the layout:
|
|
1893
|
+
it forces a uniform `size` (and `variant`, when set) and rings each avatar in
|
|
1894
|
+
the surface color so they read as separate.</div>
|
|
1895
|
+
<div class="kv"><span class="chip">summary: Overlapping row of avatars, collapsing the rest into `+N`</span><span class="chip">example: <AvatarGroup size="sm" max={3}>
|
|
1896
|
+
<Avatar fallback="AL" colorize="Ada Lovelace" />
|
|
1897
|
+
<Avatar fallback="GH" colorize="Grace Hopper" />
|
|
1898
|
+
<Avatar fallback="MK" colorize="Mary Kom" />
|
|
1899
|
+
</AvatarGroup></span></div>
|
|
1737
1900
|
</div>
|
|
1738
1901
|
|
|
1739
1902
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -1741,6 +1904,7 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1741
1904
|
|
|
1742
1905
|
<input id="c-3-components-avatargroup-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
1743
1906
|
|
|
1907
|
+
|
|
1744
1908
|
<input id="c-3-components-avatargroup-props" class="tg tg-props" type="checkbox" hidden />
|
|
1745
1909
|
|
|
1746
1910
|
<div class="panels">
|
|
@@ -1750,14 +1914,16 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1750
1914
|
<div class="panel panel-props">
|
|
1751
1915
|
<div class="note ok">
|
|
1752
1916
|
<div class="row">
|
|
1753
|
-
<span class="ex-name">Prop types <small>(react-
|
|
1754
|
-
<span class="badge ok">
|
|
1917
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
1918
|
+
<span class="badge ok">4 prop types</span>
|
|
1755
1919
|
</div>
|
|
1756
1920
|
<pre><code>Component: src/avatar-group/avatar-group.tsx::AvatarGroup</code></pre>
|
|
1757
1921
|
<pre><code>Props:</code></pre>
|
|
1758
|
-
<pre><code>
|
|
1922
|
+
<pre><code>children?: ReactNode
|
|
1923
|
+
|
|
1924
|
+
max?: number = 3
|
|
1759
1925
|
|
|
1760
|
-
size?: "sm" | "md" | "xs" | "lg" | "xl" | "2xl" | "3xl" | "4xl" = md
|
|
1926
|
+
size?: "sm" | "md" | "xs" | "lg" | "xl" | "2xl" | "3xl" | "4xl" = 'md'
|
|
1761
1927
|
|
|
1762
1928
|
/**
|
|
1763
1929
|
* Shape applied uniformly to every avatar and the `+N` bubble. Defaults to `circle`.
|
|
@@ -1838,6 +2004,7 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1838
2004
|
</div>
|
|
1839
2005
|
</div>
|
|
1840
2006
|
|
|
2007
|
+
|
|
1841
2008
|
</div>
|
|
1842
2009
|
</article>
|
|
1843
2010
|
<article
|
|
@@ -1856,12 +2023,26 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1856
2023
|
|
|
1857
2024
|
<label for="c-4-components-button-stories" class="badge ok as-toggle">11 stories</label>
|
|
1858
2025
|
|
|
2026
|
+
|
|
1859
2027
|
</div>
|
|
1860
2028
|
</div>
|
|
1861
2029
|
<div class="meta" title="./src/button/button.stories.tsx">components-button · ./src/button/button.stories.tsx</div>
|
|
1862
|
-
|
|
1863
|
-
<div class="hint">Button is the design system's primary actionable control. Pick `variant` to
|
|
1864
|
-
|
|
2030
|
+
<div>Primary actionable control; renders a `<button>` or, with `asChild`, any nested element</div>
|
|
2031
|
+
<div class="hint">Button is the design system's primary actionable control. Pick `variant` to
|
|
2032
|
+
express hierarchy, `size` for prominence, and `status="danger"` for
|
|
2033
|
+
destructive actions. Pass `asChild` to render Button's styles on any nested
|
|
2034
|
+
element — a plain `<a>`, a framework `<Link>`, or a custom component —
|
|
2035
|
+
without Button binding to any particular framework.</div>
|
|
2036
|
+
<div class="kv"><span class="chip">summary: Primary actionable control; renders a `<button>` or, with `asChild`, any nested element</span><span class="chip">example: <Button variant="primary" size="sm" onClick={handleSave}>
|
|
2037
|
+
Save changes
|
|
2038
|
+
</Button></span><span class="chip">example: <Button asChild variant="secondary">
|
|
2039
|
+
<a href="https://agentero.com" target="_blank" rel="noreferrer">Visit Agentero</a>
|
|
2040
|
+
</Button></span><span class="chip">example: // Framework-agnostic: wrap any Link implementation
|
|
2041
|
+
<Button asChild variant="primary">
|
|
2042
|
+
<Link href="/dashboard">Go to dashboard</Link>
|
|
2043
|
+
</Button></span><span class="chip">example: <Button variant="primary" status="danger" loading={isDeleting} onClick={handleDelete}>
|
|
2044
|
+
Delete account
|
|
2045
|
+
</Button></span></div>
|
|
1865
2046
|
</div>
|
|
1866
2047
|
|
|
1867
2048
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -1869,6 +2050,7 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1869
2050
|
|
|
1870
2051
|
<input id="c-4-components-button-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
1871
2052
|
|
|
2053
|
+
|
|
1872
2054
|
<input id="c-4-components-button-props" class="tg tg-props" type="checkbox" hidden />
|
|
1873
2055
|
|
|
1874
2056
|
<div class="panels">
|
|
@@ -1878,7 +2060,7 @@ variant?: "circle" | "square" | "pillow" | "p
|
|
|
1878
2060
|
<div class="panel panel-props">
|
|
1879
2061
|
<div class="note ok">
|
|
1880
2062
|
<div class="row">
|
|
1881
|
-
<span class="ex-name">Prop types <small>(react-
|
|
2063
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
1882
2064
|
<span class="badge ok">12 prop types</span>
|
|
1883
2065
|
</div>
|
|
1884
2066
|
<pre><code>Component: src/button/button.tsx::Button</code></pre>
|
|
@@ -1949,7 +2131,7 @@ loading?: boolean
|
|
|
1949
2131
|
* `<button>` and `<a>` because `asChild` lets consumers render either tag
|
|
1950
2132
|
* (or any forwardRef component) through Radix's `Slot`.
|
|
1951
2133
|
*/
|
|
1952
|
-
ref?: Ref<HTMLButtonElement | HTMLAnchorElement>
|
|
2134
|
+
ref?: Ref<HTMLButtonElement | HTMLAnchorElement> | undefined
|
|
1953
2135
|
|
|
1954
2136
|
/**
|
|
1955
2137
|
* When `true`, renders a fully pill-shaped button (rounded-full). Otherwise
|
|
@@ -1964,7 +2146,7 @@ rounded?: boolean
|
|
|
1964
2146
|
* - `md` (40px) — prominent actions in modals or feature rows.
|
|
1965
2147
|
* - `lg` (48px) — hero CTAs and full-width mobile actions.
|
|
1966
2148
|
*/
|
|
1967
|
-
size?:
|
|
2149
|
+
size?: "sm" | "md" | "xs" | "lg"
|
|
1968
2150
|
|
|
1969
2151
|
/**
|
|
1970
2152
|
* Semantic status override. Set to `'danger'` for destructive actions
|
|
@@ -1981,7 +2163,7 @@ status?: "danger"
|
|
|
1981
2163
|
* - `ghost` — minimal background; low-emphasis action in dense layouts.
|
|
1982
2164
|
* - `link` — inline text-style action; no padding or background.
|
|
1983
2165
|
*/
|
|
1984
|
-
variant?:
|
|
2166
|
+
variant?: "link" | "ghost" | "primary" | "secondary" | "tertiary"</code></pre>
|
|
1985
2167
|
</div>
|
|
1986
2168
|
</div>
|
|
1987
2169
|
|
|
@@ -2003,7 +2185,9 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2003
2185
|
<span class="badge ok">story ok</span>
|
|
2004
2186
|
</div>
|
|
2005
2187
|
<div>Default args playground for Button</div>
|
|
2006
|
-
<div class="hint">Args-controlled playground. Toggle `variant`, `size`, `status`, `loading`,
|
|
2188
|
+
<div class="hint">Args-controlled playground. Toggle `variant`, `size`, `status`, `loading`,
|
|
2189
|
+
`disabled`, and `rounded` from the Controls panel to explore every visual
|
|
2190
|
+
combination of the Button.</div>
|
|
2007
2191
|
<pre><code>const Default = () => <Button variant="primary" size="sm">{TEXT}</Button>;</code></pre>
|
|
2008
2192
|
</div>
|
|
2009
2193
|
<div class="note ok">
|
|
@@ -2012,7 +2196,10 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2012
2196
|
<span class="badge ok">story ok</span>
|
|
2013
2197
|
</div>
|
|
2014
2198
|
<div>All Button variants at default size</div>
|
|
2015
|
-
<div class="hint">All five variants at the default `sm` size. Variants express visual
|
|
2199
|
+
<div class="hint">All five variants at the default `sm` size. Variants express visual
|
|
2200
|
+
hierarchy: `primary` for the main CTA, `secondary` / `tertiary` for
|
|
2201
|
+
supporting actions, `ghost` for low-emphasis inline actions, and `link`
|
|
2202
|
+
for text-only actions.</div>
|
|
2016
2203
|
<pre><code>const Variants = () => (
|
|
2017
2204
|
<Row>
|
|
2018
2205
|
{VARIANTS.map(variant => (
|
|
@@ -2029,7 +2216,8 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2029
2216
|
<span class="badge ok">story ok</span>
|
|
2030
2217
|
</div>
|
|
2031
2218
|
<div>All Button sizes at default variant</div>
|
|
2032
|
-
<div class="hint">All four sizes at the default `primary` variant. Sizes scale from `xs`
|
|
2219
|
+
<div class="hint">All four sizes at the default `primary` variant. Sizes scale from `xs`
|
|
2220
|
+
(24px) for dense toolbars up to `lg` (48px) for hero CTAs.</div>
|
|
2033
2221
|
<pre><code>const Sizes = () => (
|
|
2034
2222
|
<Row>
|
|
2035
2223
|
{SIZES.map(size => (
|
|
@@ -2046,7 +2234,10 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2046
2234
|
<span class="badge ok">story ok</span>
|
|
2047
2235
|
</div>
|
|
2048
2236
|
<div>Disabled treatment for every variant</div>
|
|
2049
|
-
<div class="hint">Disabled state across all variants. Rendered via `asChild` with `<a>`
|
|
2237
|
+
<div class="hint">Disabled state across all variants. Rendered via `asChild` with `<a>`
|
|
2238
|
+
children to show the disabled treatment applied via className — native
|
|
2239
|
+
anchors ignore the `disabled` attribute, so Button emits `aria-disabled`
|
|
2240
|
+
and `data-disabled` on the child instead.</div>
|
|
2050
2241
|
<pre><code>const Disabled = () => (
|
|
2051
2242
|
<Row>
|
|
2052
2243
|
{VARIANTS.map(variant => (
|
|
@@ -2086,7 +2277,9 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2086
2277
|
<span class="badge ok">story ok</span>
|
|
2087
2278
|
</div>
|
|
2088
2279
|
<div>Icon-only Button across variant × size (excluding `link`)</div>
|
|
2089
|
-
<div class="hint">Icon-only buttons across the variant × size grid. Excludes `variant="link"`
|
|
2280
|
+
<div class="hint">Icon-only buttons across the variant × size grid. Excludes `variant="link"`
|
|
2281
|
+
— combining `link` with icon-only children logs a dev-only warning because
|
|
2282
|
+
the link treatment has no padding to accommodate an icon alone.</div>
|
|
2090
2283
|
<pre><code>const OnlyIcon = () => (
|
|
2091
2284
|
<Stack>
|
|
2092
2285
|
{NON_LINK_VARIANTS.map(variant => (
|
|
@@ -2107,7 +2300,10 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2107
2300
|
<span class="badge ok">story ok</span>
|
|
2108
2301
|
</div>
|
|
2109
2302
|
<div>Loading state across variant × size (excluding `link`)</div>
|
|
2110
|
-
<div class="hint">Loading state across the variant × size grid. Each row shows two buttons
|
|
2303
|
+
<div class="hint">Loading state across the variant × size grid. Each row shows two buttons
|
|
2304
|
+
per size: one icon-only, one with text. Loading forces `disabled` and
|
|
2305
|
+
overlays a spinner that inherits the variant's text color. Excludes
|
|
2306
|
+
`variant="link"` — combining `link` with `loading` logs a dev-only warning.</div>
|
|
2111
2307
|
<pre><code>const Loading = () => (
|
|
2112
2308
|
<Stack>
|
|
2113
2309
|
{NON_LINK_VARIANTS.map(variant => (
|
|
@@ -2133,7 +2329,10 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2133
2329
|
<span class="badge ok">story ok</span>
|
|
2134
2330
|
</div>
|
|
2135
2331
|
<div>`status="danger"` across every variant, enabled + disabled</div>
|
|
2136
|
-
<div class="hint">Destructive treatment via `status="danger"`. The top row shows every
|
|
2332
|
+
<div class="hint">Destructive treatment via `status="danger"`. The top row shows every
|
|
2333
|
+
variant enabled; the bottom row shows every variant disabled. Use
|
|
2334
|
+
`status="danger"` for delete, remove, or disconnect actions regardless of
|
|
2335
|
+
variant.</div>
|
|
2137
2336
|
<pre><code>const Status = () => (
|
|
2138
2337
|
<Stack>
|
|
2139
2338
|
<Row>
|
|
@@ -2165,7 +2364,8 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2165
2364
|
<span class="badge ok">story ok</span>
|
|
2166
2365
|
</div>
|
|
2167
2366
|
<div>`rounded` pill shape across variant × size (excluding `link`)</div>
|
|
2168
|
-
<div class="hint">Fully pill-shaped buttons across the variant × size grid. Excludes
|
|
2367
|
+
<div class="hint">Fully pill-shaped buttons across the variant × size grid. Excludes
|
|
2368
|
+
`variant="link"` since the link treatment has no background to round.</div>
|
|
2169
2369
|
<pre><code>const Rounded = () => (
|
|
2170
2370
|
<Stack>
|
|
2171
2371
|
{NON_LINK_VARIANTS.map(variant => (
|
|
@@ -2188,7 +2388,12 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2188
2388
|
<span class="badge ok">story ok</span>
|
|
2189
2389
|
</div>
|
|
2190
2390
|
<div>`asChild` composes Button's styles onto any element</div>
|
|
2191
|
-
<div class="hint">`asChild` renders Button's styles on the nested child element rather than
|
|
2391
|
+
<div class="hint">`asChild` renders Button's styles on the nested child element rather than
|
|
2392
|
+
on a `<button>` — the child receives Button's `className`, `ref`, and
|
|
2393
|
+
merged props via Radix's `Slot` primitive. Use it to turn any anchor or
|
|
2394
|
+
framework `Link` into a Button without coupling the design system to a
|
|
2395
|
+
router. In app code, swap the plain `<a>` below for your framework's Link
|
|
2396
|
+
(`next/link`, `react-router`, `@tanstack/react-router`, etc.).</div>
|
|
2192
2397
|
<pre><code>const AsChild = () => (
|
|
2193
2398
|
<Row>
|
|
2194
2399
|
<Button asChild variant="primary">
|
|
@@ -2208,7 +2413,15 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2208
2413
|
<span class="badge ok">story ok</span>
|
|
2209
2414
|
</div>
|
|
2210
2415
|
<div>Press feedback dips the button, excluding `link` and disabled</div>
|
|
2211
|
-
<div class="hint">Buttons dip to 97% while held so the control answers the pointer rather than
|
|
2416
|
+
<div class="hint">Buttons dip to 97% while held so the control answers the pointer rather than
|
|
2417
|
+
only changing color. Press and hold one below to feel it — the effect is
|
|
2418
|
+
deliberately small, and if a quick click draws the eye it is too strong.
|
|
2419
|
+
|
|
2420
|
+
`variant="link"` is excluded: it has no padding or background, so scaling
|
|
2421
|
+
bare text reads as a wobble rather than a button being pushed. Disabled
|
|
2422
|
+
buttons are excluded too, including the `asChild` anchor form, which stays
|
|
2423
|
+
keyboard-focusable and would otherwise dip on Enter. The whole effect is
|
|
2424
|
+
gated behind `motion-safe`, so it disappears under `prefers-reduced-motion`.</div>
|
|
2212
2425
|
<pre><code>const Pressed = () => (
|
|
2213
2426
|
<Stack>
|
|
2214
2427
|
<Row>
|
|
@@ -2232,6 +2445,7 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2232
2445
|
</div>
|
|
2233
2446
|
</div>
|
|
2234
2447
|
|
|
2448
|
+
|
|
2235
2449
|
</div>
|
|
2236
2450
|
</article>
|
|
2237
2451
|
<article
|
|
@@ -2250,12 +2464,20 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2250
2464
|
|
|
2251
2465
|
<label for="c-5-components-checklist-stories" class="badge ok as-toggle">2 stories</label>
|
|
2252
2466
|
|
|
2467
|
+
|
|
2253
2468
|
</div>
|
|
2254
2469
|
</div>
|
|
2255
2470
|
<div class="meta" title="./src/check-list/check-list.stories.tsx">components-checklist · ./src/check-list/check-list.stories.tsx</div>
|
|
2256
|
-
|
|
2257
|
-
<div class="hint">CheckList renders a vertical list where every row is marked with a check
|
|
2258
|
-
|
|
2471
|
+
<div>List container for check-marked items</div>
|
|
2472
|
+
<div class="hint">CheckList renders a vertical list where every row is marked with a check
|
|
2473
|
+
icon. Purely presentational — for interactive selection use a checkbox group.</div>
|
|
2474
|
+
<div class="kv"><span class="chip">summary: List container for check-marked items</span><span class="chip">example: ```tsx
|
|
2475
|
+
import { CheckList } from '@agentero/design-system/check-list';
|
|
2476
|
+
|
|
2477
|
+
<CheckList.Root>
|
|
2478
|
+
<CheckList.Item>Instant appointment</CheckList.Item>
|
|
2479
|
+
</CheckList.Root>
|
|
2480
|
+
```</span></div>
|
|
2259
2481
|
</div>
|
|
2260
2482
|
|
|
2261
2483
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -2264,6 +2486,7 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2264
2486
|
<input id="c-5-components-checklist-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
2265
2487
|
|
|
2266
2488
|
|
|
2489
|
+
|
|
2267
2490
|
|
|
2268
2491
|
<div class="panels">
|
|
2269
2492
|
|
|
@@ -2322,6 +2545,7 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2322
2545
|
</div>
|
|
2323
2546
|
</div>
|
|
2324
2547
|
|
|
2548
|
+
|
|
2325
2549
|
</div>
|
|
2326
2550
|
</article>
|
|
2327
2551
|
<article
|
|
@@ -2336,16 +2560,36 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2336
2560
|
<div class="title">
|
|
2337
2561
|
<h2><span class="status-dot dot-ok"></span> Command.Root</h2>
|
|
2338
2562
|
<div class="badges">
|
|
2339
|
-
|
|
2563
|
+
<label for="c-6-components-command-props" class="badge ok as-toggle">10 prop types</label>
|
|
2340
2564
|
|
|
2341
2565
|
<label for="c-6-components-command-stories" class="badge ok as-toggle">5 stories</label>
|
|
2342
2566
|
|
|
2567
|
+
|
|
2343
2568
|
</div>
|
|
2344
2569
|
</div>
|
|
2345
2570
|
<div class="meta" title="./src/command/command.stories.tsx">components-command · ./src/command/command.stories.tsx</div>
|
|
2346
|
-
|
|
2347
|
-
<div class="hint">Command is a filterable list built on `cmdk`. Type to narrow the options,
|
|
2348
|
-
|
|
2571
|
+
<div>Filterable command palette container</div>
|
|
2572
|
+
<div class="hint">Command is a filterable list built on `cmdk`. Type to narrow the options,
|
|
2573
|
+
navigate with the arrow keys, select with Enter. It carries its own panel
|
|
2574
|
+
chrome, so dropping it inside a `Popover.Content` yields a combobox.</div>
|
|
2575
|
+
<div class="kv"><span class="chip">summary: Filterable command palette container</span><span class="chip">see: {@link https://github.com/pacocoursey/cmdk cmdk}</span><span class="chip">example: ```tsx
|
|
2576
|
+
import { Command } from '@agentero/design-system/command';
|
|
2577
|
+
|
|
2578
|
+
<Command.Root label="Search lines of business">
|
|
2579
|
+
<Command.Input placeholder="Search lines of business..." />
|
|
2580
|
+
<Command.List>
|
|
2581
|
+
<Command.Item onSelect={() => select('home')}>Homeowners</Command.Item>
|
|
2582
|
+
<Command.Item onSelect={() => select('auto')}>Auto</Command.Item>
|
|
2583
|
+
</Command.List>
|
|
2584
|
+
<Command.Empty>No options found</Command.Empty>
|
|
2585
|
+
</Command.Root>
|
|
2586
|
+
```</span><span class="chip">example: ```tsx
|
|
2587
|
+
// Filtering handled upstream (async search): let every item through.
|
|
2588
|
+
<Command.Root label="Search options" shouldFilter={false}>
|
|
2589
|
+
<Command.Input placeholder="Search..." />
|
|
2590
|
+
<Command.List>...</Command.List>
|
|
2591
|
+
</Command.Root>
|
|
2592
|
+
```</span></div>
|
|
2349
2593
|
</div>
|
|
2350
2594
|
|
|
2351
2595
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -2354,11 +2598,68 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2354
2598
|
<input id="c-6-components-command-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
2355
2599
|
|
|
2356
2600
|
|
|
2601
|
+
<input id="c-6-components-command-props" class="tg tg-props" type="checkbox" hidden />
|
|
2357
2602
|
|
|
2358
2603
|
<div class="panels">
|
|
2359
2604
|
|
|
2360
2605
|
|
|
2361
2606
|
|
|
2607
|
+
<div class="panel panel-props">
|
|
2608
|
+
<div class="note ok">
|
|
2609
|
+
<div class="row">
|
|
2610
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
2611
|
+
<span class="badge ok">10 prop types</span>
|
|
2612
|
+
</div>
|
|
2613
|
+
<pre><code>Component: src/command/index.ts::Command</code></pre>
|
|
2614
|
+
<pre><code>Props:</code></pre>
|
|
2615
|
+
<pre><code>asChild?: boolean
|
|
2616
|
+
|
|
2617
|
+
children?: ReactNode
|
|
2618
|
+
|
|
2619
|
+
/**
|
|
2620
|
+
* Optionally set to `true` to disable selection via pointer events.
|
|
2621
|
+
*/
|
|
2622
|
+
disablePointerSelection?: boolean
|
|
2623
|
+
|
|
2624
|
+
/**
|
|
2625
|
+
* Custom filter function for whether each command menu item should matches the given search query.
|
|
2626
|
+
* It should return a number between 0 and 1, with 1 being the best match and 0 being hidden entirely.
|
|
2627
|
+
* By default, uses the `command-score` library.
|
|
2628
|
+
*/
|
|
2629
|
+
filter?: CommandFilter
|
|
2630
|
+
|
|
2631
|
+
/**
|
|
2632
|
+
* Accessible label for this command menu. Not shown visibly.
|
|
2633
|
+
*/
|
|
2634
|
+
label?: string
|
|
2635
|
+
|
|
2636
|
+
/**
|
|
2637
|
+
* Optionally set to `true` to turn on looping around when using the arrow keys.
|
|
2638
|
+
*/
|
|
2639
|
+
loop?: boolean
|
|
2640
|
+
|
|
2641
|
+
/**
|
|
2642
|
+
* Event handler called when the selected item of the menu changes.
|
|
2643
|
+
*/
|
|
2644
|
+
onValueChange?: (value: string) => void
|
|
2645
|
+
|
|
2646
|
+
/**
|
|
2647
|
+
* Optionally set to `false` to turn off the automatic filtering and sorting.
|
|
2648
|
+
* If `false`, you must conditionally render valid items based on the search query yourself.
|
|
2649
|
+
*/
|
|
2650
|
+
shouldFilter?: boolean
|
|
2651
|
+
|
|
2652
|
+
/**
|
|
2653
|
+
* Optional controlled state of the selected command menu item.
|
|
2654
|
+
*/
|
|
2655
|
+
value?: string
|
|
2656
|
+
|
|
2657
|
+
/**
|
|
2658
|
+
* Set to `false` to disable ctrl+n/j/p/k shortcuts. Defaults to `true`.
|
|
2659
|
+
*/
|
|
2660
|
+
vimBindings?: boolean</code></pre>
|
|
2661
|
+
</div>
|
|
2662
|
+
</div>
|
|
2362
2663
|
|
|
2363
2664
|
<div class="panel panel-stories">
|
|
2364
2665
|
|
|
@@ -2416,7 +2717,8 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2416
2717
|
<span class="badge ok">story ok</span>
|
|
2417
2718
|
</div>
|
|
2418
2719
|
|
|
2419
|
-
<div class="hint">`Group` sections related options. It ships unstyled, so the heading is styled
|
|
2720
|
+
<div class="hint">`Group` sections related options. It ships unstyled, so the heading is styled
|
|
2721
|
+
per usage through the `[cmdk-group-heading]` hook.</div>
|
|
2420
2722
|
<pre><code>const Grouped = () => (
|
|
2421
2723
|
<Command.Root label="Search commands">
|
|
2422
2724
|
<Command.Input placeholder="Search..." />
|
|
@@ -2440,7 +2742,9 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2440
2742
|
<span class="badge ok">story ok</span>
|
|
2441
2743
|
</div>
|
|
2442
2744
|
|
|
2443
|
-
<div class="hint">With more rows than the list cap fits, the list scrolls — by wheel, or by
|
|
2745
|
+
<div class="hint">With more rows than the list cap fits, the list scrolls — by wheel, or by
|
|
2746
|
+
keyboard: cmdk scrolls the active row into view as the arrow keys move it,
|
|
2747
|
+
and `scroll-py-2` keeps that row off the container edges.</div>
|
|
2444
2748
|
<pre><code>const ScrollingList = () => (
|
|
2445
2749
|
<Command.Root label="Search states">
|
|
2446
2750
|
<Command.Input placeholder="Search states..." />
|
|
@@ -2473,6 +2777,7 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2473
2777
|
</div>
|
|
2474
2778
|
</div>
|
|
2475
2779
|
|
|
2780
|
+
|
|
2476
2781
|
</div>
|
|
2477
2782
|
</article>
|
|
2478
2783
|
<article
|
|
@@ -2487,16 +2792,46 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2487
2792
|
<div class="title">
|
|
2488
2793
|
<h2><span class="status-dot dot-ok"></span> DataTable.Root</h2>
|
|
2489
2794
|
<div class="badges">
|
|
2490
|
-
|
|
2795
|
+
<label for="c-7-components-datatable-props" class="badge ok as-toggle">88 prop types</label>
|
|
2491
2796
|
|
|
2492
2797
|
<label for="c-7-components-datatable-stories" class="badge ok as-toggle">4 stories</label>
|
|
2493
2798
|
|
|
2799
|
+
|
|
2494
2800
|
</div>
|
|
2495
2801
|
</div>
|
|
2496
2802
|
<div class="meta" title="./src/data-table/data-table.stories.tsx">components-datatable · ./src/data-table/data-table.stories.tsx</div>
|
|
2497
|
-
|
|
2498
|
-
<div class="hint">DataTable is the data-driven table compound built on TanStack Table. This
|
|
2499
|
-
|
|
2803
|
+
<div>DataTable root that builds the table instance and shares context</div>
|
|
2804
|
+
<div class="hint">DataTable is the data-driven table compound built on TanStack Table. This
|
|
2805
|
+
story shows a representative leads table: an `Applicant` column with a name +
|
|
2806
|
+
address, contact info, insurance type with an icon, a sortable `Created`
|
|
2807
|
+
column, a status badge, and hover-revealed row actions (open + a kebab menu).
|
|
2808
|
+
The toolbar (search + filters) and the footer pagination are **separate
|
|
2809
|
+
components** composed inside `ToolBar` / `Footer`.</div>
|
|
2810
|
+
<div class="kv"><span class="chip">summary: DataTable root that builds the table instance and shares context</span><span class="chip">see: {@link https://tanstack.com/table/latest TanStack Table}</span><span class="chip">example: ```tsx
|
|
2811
|
+
import { DataTable } from '@agentero/design-system/data-table';
|
|
2812
|
+
import { createColumnHelper } from '@tanstack/react-table';
|
|
2813
|
+
|
|
2814
|
+
const columnHelper = createColumnHelper<User>();
|
|
2815
|
+
const columns = [
|
|
2816
|
+
columnHelper.accessor('name', { header: 'Name', enableSorting: true }),
|
|
2817
|
+
columnHelper.accessor('email', { header: 'Email' })
|
|
2818
|
+
];
|
|
2819
|
+
|
|
2820
|
+
<DataTable.Root data={users} columns={columns}>
|
|
2821
|
+
<DataTable.ToolBar>
|
|
2822
|
+
<SearchInput />
|
|
2823
|
+
</DataTable.ToolBar>
|
|
2824
|
+
<DataTable.Table />
|
|
2825
|
+
<DataTable.Footer>
|
|
2826
|
+
<DataTable.Pagination
|
|
2827
|
+
currentPage={page}
|
|
2828
|
+
pageSize={10}
|
|
2829
|
+
totalCount={total}
|
|
2830
|
+
onPageChange={setPage}
|
|
2831
|
+
/>
|
|
2832
|
+
</DataTable.Footer>
|
|
2833
|
+
</DataTable.Root>
|
|
2834
|
+
```</span></div>
|
|
2500
2835
|
</div>
|
|
2501
2836
|
|
|
2502
2837
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -2505,172 +2840,645 @@ variant?: ButtonVariantType</code></pre>
|
|
|
2505
2840
|
<input id="c-7-components-datatable-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
2506
2841
|
|
|
2507
2842
|
|
|
2843
|
+
<input id="c-7-components-datatable-props" class="tg tg-props" type="checkbox" hidden />
|
|
2508
2844
|
|
|
2509
2845
|
<div class="panels">
|
|
2510
2846
|
|
|
2511
2847
|
|
|
2512
2848
|
|
|
2513
|
-
|
|
2514
|
-
<div class="panel panel-stories">
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2849
|
+
<div class="panel panel-props">
|
|
2518
2850
|
<div class="note ok">
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
<pre><code>import { Button, DataTable, DropdownMenu, Pagination, Table } from "@agentero/design-system";</code></pre>
|
|
2523
|
-
</div>
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
<div class="note ok">
|
|
2527
|
-
<div class="row">
|
|
2528
|
-
<span class="ex-name">Playground</span>
|
|
2529
|
-
<span class="badge ok">story ok</span>
|
|
2530
|
-
</div>
|
|
2531
|
-
<div>Display props playground (size / embed / enclosed / sticky)</div>
|
|
2532
|
-
<div class="hint">Playground for `DataTable.Table` display props — toggle `size`, `embed`, `enclosed`, and `sticky` from the controls panel.</div>
|
|
2533
|
-
<pre><code>const Playground = () => <div
|
|
2534
|
-
className={args.enclosed ? 'flex min-h-0 flex-1 flex-col p-4' : 'contents'}>
|
|
2535
|
-
<DataTable.Root data={LEADS} columns={columns}>
|
|
2536
|
-
<DataTable.Table size="md" embed enclosed={false} sticky="header" />
|
|
2537
|
-
</DataTable.Root>
|
|
2538
|
-
</div>;</code></pre>
|
|
2851
|
+
<div class="row">
|
|
2852
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
2853
|
+
<span class="badge ok">88 prop types</span>
|
|
2539
2854
|
</div>
|
|
2540
|
-
<
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
<div class="hint">A leads-table composition: sortable `Created` column, a status badge, row navigation via `rowHref`, hover-revealed actions, a search input + filters in the toolbar, and pagination in the footer.</div>
|
|
2547
|
-
<pre><code>const Leads = () => {
|
|
2548
|
-
const [sorting, setSorting] = useState<SortingState>([]);
|
|
2549
|
-
const [page, setPage] = useState(1);
|
|
2550
|
-
const [search, setSearch] = useState('');
|
|
2855
|
+
<pre><code>Component: src/data-table/index.ts::DataTable</code></pre>
|
|
2856
|
+
<pre><code>Props:</code></pre>
|
|
2857
|
+
<pre><code>/**
|
|
2858
|
+
* An array of extra features that you can add to the table instance.
|
|
2859
|
+
*/
|
|
2860
|
+
_features?: TableFeature<any>[]
|
|
2551
2861
|
|
|
2552
|
-
|
|
2553
|
-
() => LEADS.filter(l => l.contact.toLowerCase().includes(search.toLowerCase())),
|
|
2554
|
-
[search]
|
|
2555
|
-
);
|
|
2862
|
+
aggregationFns?: Record<string, AggregationFn<any>>
|
|
2556
2863
|
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
state={{ sorting }}
|
|
2562
|
-
onSortingChange={setSorting}
|
|
2563
|
-
getSortedRowModel={getSortedRowModel()}
|
|
2564
|
-
enableSortingRemoval={false}
|
|
2565
|
-
rowHref={lead => `/leads/${lead.leadId}`}>
|
|
2566
|
-
<DataTable.ToolBar>
|
|
2567
|
-
<input
|
|
2568
|
-
value={search}
|
|
2569
|
-
onChange={e => setSearch(e.target.value)}
|
|
2570
|
-
placeholder="Search..."
|
|
2571
|
-
aria-label="Search leads"
|
|
2572
|
-
className="h-8 w-60 rounded-md border border-border-default-base-primary px-3 text-sm outline-none"
|
|
2573
|
-
/>
|
|
2574
|
-
<Button variant="secondary" size="sm">
|
|
2575
|
-
Filters
|
|
2576
|
-
</Button>
|
|
2577
|
-
</DataTable.ToolBar>
|
|
2864
|
+
/**
|
|
2865
|
+
* Set this option to override any of the `autoReset...` feature options.
|
|
2866
|
+
*/
|
|
2867
|
+
autoResetAll?: boolean
|
|
2578
2868
|
|
|
2579
|
-
|
|
2869
|
+
/**
|
|
2870
|
+
* Enable this setting to automatically reset the expanded state of the table when expanding state changes.
|
|
2871
|
+
*/
|
|
2872
|
+
autoResetExpanded?: boolean
|
|
2580
2873
|
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
pageSize={10}
|
|
2586
|
-
onPageChange={setPage}
|
|
2587
|
-
/>
|
|
2588
|
-
</DataTable.Footer>
|
|
2589
|
-
</DataTable.Root>
|
|
2590
|
-
);
|
|
2591
|
-
};</code></pre>
|
|
2592
|
-
</div>
|
|
2593
|
-
<div class="note ok">
|
|
2594
|
-
<div class="row">
|
|
2595
|
-
<span class="ex-name">Empty</span>
|
|
2596
|
-
<span class="badge ok">story ok</span>
|
|
2597
|
-
</div>
|
|
2598
|
-
<div>Empty state when there are no rows</div>
|
|
2599
|
-
<div class="hint">No rows: the table renders its default empty state instead of body rows.</div>
|
|
2600
|
-
<pre><code>const Empty = () => (
|
|
2601
|
-
<DataTable.Root data={[] as Lead[]} columns={columns}>
|
|
2602
|
-
<DataTable.Table />
|
|
2603
|
-
</DataTable.Root>
|
|
2604
|
-
);</code></pre>
|
|
2605
|
-
</div>
|
|
2606
|
-
<div class="note ok">
|
|
2607
|
-
<div class="row">
|
|
2608
|
-
<span class="ex-name">Loading</span>
|
|
2609
|
-
<span class="badge ok">story ok</span>
|
|
2610
|
-
</div>
|
|
2611
|
-
<div>Loading state dims the table and hides the empty state</div>
|
|
2612
|
-
<div class="hint">Loading: the body is dimmed and the empty state is suppressed while data is in flight.</div>
|
|
2613
|
-
<pre><code>const Loading = () => (
|
|
2614
|
-
<DataTable.Root data={[] as Lead[]} columns={columns} isLoading>
|
|
2615
|
-
<DataTable.Table />
|
|
2616
|
-
</DataTable.Root>
|
|
2617
|
-
);</code></pre>
|
|
2618
|
-
</div>
|
|
2619
|
-
</div>
|
|
2620
|
-
|
|
2621
|
-
</div>
|
|
2622
|
-
</article>
|
|
2623
|
-
<article
|
|
2624
|
-
class="card
|
|
2625
|
-
no-error
|
|
2626
|
-
no-info
|
|
2627
|
-
no-story-error
|
|
2628
|
-
no-doc-error"
|
|
2629
|
-
role="listitem"
|
|
2630
|
-
aria-label="Divider">
|
|
2631
|
-
<div class="head">
|
|
2632
|
-
<div class="title">
|
|
2633
|
-
<h2><span class="status-dot dot-ok"></span> Divider</h2>
|
|
2634
|
-
<div class="badges">
|
|
2635
|
-
<label for="c-8-components-divider-props" class="badge ok as-toggle">2 prop types</label>
|
|
2636
|
-
|
|
2637
|
-
<label for="c-8-components-divider-stories" class="badge ok as-toggle">10 stories</label>
|
|
2638
|
-
|
|
2639
|
-
</div>
|
|
2640
|
-
</div>
|
|
2641
|
-
<div class="meta" title="./src/divider/divider.stories.tsx">components-divider · ./src/divider/divider.stories.tsx</div>
|
|
2642
|
-
|
|
2643
|
-
<div class="hint">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.</div>
|
|
2644
|
-
|
|
2645
|
-
</div>
|
|
2874
|
+
/**
|
|
2875
|
+
* If set to `true`, pagination will be reset to the first page when page-altering state changes eg. `data` is updated, filters change, grouping changes, etc.
|
|
2876
|
+
*/
|
|
2877
|
+
autoResetPageIndex?: boolean
|
|
2646
2878
|
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
<input id="c-8-components-divider-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
2651
|
-
|
|
2652
|
-
<input id="c-8-components-divider-props" class="tg tg-props" type="checkbox" hidden />
|
|
2879
|
+
children?: ReactNode
|
|
2653
2880
|
|
|
2654
|
-
|
|
2881
|
+
/**
|
|
2882
|
+
* Enables or disables right-to-left support for resizing the column. defaults to 'ltr'.
|
|
2883
|
+
*/
|
|
2884
|
+
columnResizeDirection?: "ltr" | "rtl"
|
|
2885
|
+
|
|
2886
|
+
/**
|
|
2887
|
+
* Determines when the columnSizing state is updated. `onChange` updates the state when the user is dragging the resize handle. `onEnd` updates the state when the user releases the resize handle.
|
|
2888
|
+
*/
|
|
2889
|
+
columnResizeMode?: "onChange" | "onEnd"
|
|
2890
|
+
|
|
2891
|
+
/**
|
|
2892
|
+
* The array of column defs to use for the table.
|
|
2893
|
+
*/
|
|
2894
|
+
columns: ColumnDef<Lead, any>[]
|
|
2895
|
+
|
|
2896
|
+
/**
|
|
2897
|
+
* The data for the table to display. This array should match the type you provided to `table.setRowType<...>`. Columns can access this data via string/index or a functional accessor. When the `data` option changes reference, the table will reprocess the data.
|
|
2898
|
+
*/
|
|
2899
|
+
data: Lead[]
|
|
2900
|
+
|
|
2901
|
+
/**
|
|
2902
|
+
* Set this option to `true` to output all debugging information to the console.
|
|
2903
|
+
*/
|
|
2904
|
+
debugAll?: boolean
|
|
2905
|
+
|
|
2906
|
+
/**
|
|
2907
|
+
* Set this option to `true` to output cell debugging information to the console.
|
|
2908
|
+
*/
|
|
2909
|
+
debugCells?: boolean
|
|
2910
|
+
|
|
2911
|
+
/**
|
|
2912
|
+
* Set this option to `true` to output column debugging information to the console.
|
|
2913
|
+
*/
|
|
2914
|
+
debugColumns?: boolean
|
|
2915
|
+
|
|
2916
|
+
/**
|
|
2917
|
+
* Set this option to `true` to output header debugging information to the console.
|
|
2918
|
+
*/
|
|
2919
|
+
debugHeaders?: boolean
|
|
2920
|
+
|
|
2921
|
+
/**
|
|
2922
|
+
* Set this option to `true` to output row debugging information to the console.
|
|
2923
|
+
*/
|
|
2924
|
+
debugRows?: boolean
|
|
2925
|
+
|
|
2926
|
+
/**
|
|
2927
|
+
* Set this option to `true` to output table debugging information to the console.
|
|
2928
|
+
*/
|
|
2929
|
+
debugTable?: boolean
|
|
2930
|
+
|
|
2931
|
+
/**
|
|
2932
|
+
* Default column options to use for all column defs supplied to the table.
|
|
2933
|
+
*/
|
|
2934
|
+
defaultColumn?: Partial<ColumnDef<Lead, unknown>> | undefined
|
|
2935
|
+
|
|
2936
|
+
/**
|
|
2937
|
+
* Enables/disables **column** filtering for all columns.
|
|
2938
|
+
*/
|
|
2939
|
+
enableColumnFilters?: boolean
|
|
2940
|
+
|
|
2941
|
+
/**
|
|
2942
|
+
* Enables/disables column pinning for the table. Defaults to `true`.
|
|
2943
|
+
*/
|
|
2944
|
+
enableColumnPinning?: boolean
|
|
2945
|
+
|
|
2946
|
+
/**
|
|
2947
|
+
* Enables or disables column resizing for the column.
|
|
2948
|
+
*/
|
|
2949
|
+
enableColumnResizing?: boolean
|
|
2950
|
+
|
|
2951
|
+
/**
|
|
2952
|
+
* Enable/disable expanding for all rows.
|
|
2953
|
+
*/
|
|
2954
|
+
enableExpanding?: boolean
|
|
2955
|
+
|
|
2956
|
+
/**
|
|
2957
|
+
* Enables/disables all filtering for the table.
|
|
2958
|
+
*/
|
|
2959
|
+
enableFilters?: boolean
|
|
2960
|
+
|
|
2961
|
+
/**
|
|
2962
|
+
* Enables/disables **global** filtering for all columns.
|
|
2963
|
+
*/
|
|
2964
|
+
enableGlobalFilter?: boolean
|
|
2965
|
+
|
|
2966
|
+
/**
|
|
2967
|
+
* Enables/disables grouping for the table.
|
|
2968
|
+
*/
|
|
2969
|
+
enableGrouping?: boolean
|
|
2970
|
+
|
|
2971
|
+
/**
|
|
2972
|
+
* Whether to enable column hiding. Defaults to `true`.
|
|
2973
|
+
*/
|
|
2974
|
+
enableHiding?: boolean
|
|
2975
|
+
|
|
2976
|
+
/**
|
|
2977
|
+
* Enables/disables the ability to remove multi-sorts
|
|
2978
|
+
*/
|
|
2979
|
+
enableMultiRemove?: boolean
|
|
2980
|
+
|
|
2981
|
+
/**
|
|
2982
|
+
* - Enables/disables multiple row selection for all rows in the table OR
|
|
2983
|
+
* - A function that given a row, returns whether to enable/disable multiple row selection for that row's children/grandchildren
|
|
2984
|
+
*/
|
|
2985
|
+
enableMultiRowSelection?: boolean | ((row: Row<Lead>) => boolean) | undefined
|
|
2986
|
+
|
|
2987
|
+
/**
|
|
2988
|
+
* Enables/Disables multi-sorting for the table.
|
|
2989
|
+
*/
|
|
2990
|
+
enableMultiSort?: boolean
|
|
2991
|
+
|
|
2992
|
+
enablePinning?: boolean
|
|
2993
|
+
|
|
2994
|
+
/**
|
|
2995
|
+
* Enables/disables row pinning for the table. Defaults to `true`.
|
|
2996
|
+
*/
|
|
2997
|
+
enableRowPinning?: boolean | ((row: Row<Lead>) => boolean) | undefined
|
|
2998
|
+
|
|
2999
|
+
/**
|
|
3000
|
+
* - Enables/disables row selection for all rows in the table OR
|
|
3001
|
+
* - A function that given a row, returns whether to enable/disable row selection for that row
|
|
3002
|
+
*/
|
|
3003
|
+
enableRowSelection?: boolean | ((row: Row<Lead>) => boolean) | undefined
|
|
3004
|
+
|
|
3005
|
+
/**
|
|
3006
|
+
* Enables/Disables sorting for the table.
|
|
3007
|
+
*/
|
|
3008
|
+
enableSorting?: boolean
|
|
3009
|
+
|
|
3010
|
+
/**
|
|
3011
|
+
* Enables/Disables the ability to remove sorting for the table.
|
|
3012
|
+
* - If `true` then changing sort order will circle like: 'none' -> 'desc' -> 'asc' -> 'none' -> ...
|
|
3013
|
+
* - If `false` then changing sort order will circle like: 'none' -> 'desc' -> 'asc' -> 'desc' -> 'asc' -> ...
|
|
3014
|
+
*/
|
|
3015
|
+
enableSortingRemoval?: boolean
|
|
3016
|
+
|
|
3017
|
+
/**
|
|
3018
|
+
* Enables/disables automatic sub-row selection when a parent row is selected, or a function that enables/disables automatic sub-row selection for each row.
|
|
3019
|
+
* (Use in combination with expanding or grouping features)
|
|
3020
|
+
*/
|
|
3021
|
+
enableSubRowSelection?: boolean | ((row: Row<Lead>) => boolean) | undefined
|
|
3022
|
+
|
|
3023
|
+
filterFns?: Record<string, FilterFn<any>>
|
|
3024
|
+
|
|
3025
|
+
/**
|
|
3026
|
+
* By default, filtering is done from parent rows down (so if a parent row is filtered out, all of its children will be filtered out as well). Setting this option to `true` will cause filtering to be done from leaf rows up (which means parent rows will be included so long as one of their child or grand-child rows is also included).
|
|
3027
|
+
*/
|
|
3028
|
+
filterFromLeafRows?: boolean
|
|
3029
|
+
|
|
3030
|
+
/**
|
|
3031
|
+
* If provided, this function will be called with the column and should return `true` or `false` to indicate whether this column should be used for global filtering.
|
|
3032
|
+
*
|
|
3033
|
+
* This is useful if the column can contain data that is not `string` or `number` (i.e. `undefined`).
|
|
3034
|
+
*/
|
|
3035
|
+
getColumnCanGlobalFilter?: (column: Column<Lead, unknown>) => boolean
|
|
3036
|
+
|
|
3037
|
+
/**
|
|
3038
|
+
* This function is responsible for returning the expanded row model. If this function is not provided, the table will not expand rows. You can use the default exported `getExpandedRowModel` function to get the expanded row model or implement your own.
|
|
3039
|
+
*/
|
|
3040
|
+
getExpandedRowModel?: (table: Table<any>) => () => RowModel<any>
|
|
3041
|
+
|
|
3042
|
+
getFacetedMinMaxValues?: (table: Table<Lead>, columnId: string) => () => [number, number] | undefined
|
|
3043
|
+
|
|
3044
|
+
getFacetedRowModel?: (table: Table<Lead>, columnId: string) => () => RowModel<Lead>
|
|
3045
|
+
|
|
3046
|
+
getFacetedUniqueValues?: (table: Table<Lead>, columnId: string) => () => Map<any, number>
|
|
3047
|
+
|
|
3048
|
+
/**
|
|
3049
|
+
* If provided, this function is called **once** per table and should return a **new function** which will calculate and return the row model for the table when it's filtered.
|
|
3050
|
+
* - For server-side filtering, this function is unnecessary and can be ignored since the server should already return the filtered row model.
|
|
3051
|
+
* - For client-side filtering, this function is required. A default implementation is provided via any table adapter's `{ getFilteredRowModel }` export.
|
|
3052
|
+
*/
|
|
3053
|
+
getFilteredRowModel?: (table: Table<any>) => () => RowModel<any>
|
|
3054
|
+
|
|
3055
|
+
/**
|
|
3056
|
+
* Returns the row model after grouping has taken place, but no further.
|
|
3057
|
+
*/
|
|
3058
|
+
getGroupedRowModel?: (table: Table<any>) => () => RowModel<any>
|
|
3059
|
+
|
|
3060
|
+
/**
|
|
3061
|
+
* If provided, allows you to override the default behavior of determining whether a row is currently expanded.
|
|
3062
|
+
*/
|
|
3063
|
+
getIsRowExpanded?: (row: Row<Lead>) => boolean
|
|
3064
|
+
|
|
3065
|
+
/**
|
|
3066
|
+
* Returns the row model after pagination has taken place, but no further.
|
|
3067
|
+
*
|
|
3068
|
+
* Pagination columns are automatically reordered by default to the start of the columns list. If you would rather remove them or leave them as-is, set the appropriate mode here.
|
|
3069
|
+
*/
|
|
3070
|
+
getPaginationRowModel?: (table: Table<any>) => () => RowModel<any>
|
|
3071
|
+
|
|
3072
|
+
/**
|
|
3073
|
+
* If provided, allows you to override the default behavior of determining whether a row can be expanded.
|
|
3074
|
+
*/
|
|
3075
|
+
getRowCanExpand?: (row: Row<Lead>) => boolean
|
|
3076
|
+
|
|
3077
|
+
/**
|
|
3078
|
+
* This optional function is used to derive a unique ID for any given row. If not provided the rows index is used (nested rows join together with `.` using their grandparents' index eg. `index.index.index`). If you need to identify individual rows that are originating from any server-side operations, it's suggested you use this function to return an ID that makes sense regardless of network IO/ambiguity eg. a userId, taskId, database ID field, etc.
|
|
3079
|
+
*/
|
|
3080
|
+
getRowId?: (originalRow: Lead, index: number, parent?: Row<Lead> | undefined) => string
|
|
3081
|
+
|
|
3082
|
+
/**
|
|
3083
|
+
* This function is used to retrieve the sorted row model. If using server-side sorting, this function is not required. To use client-side sorting, pass the exported `getSortedRowModel()` from your adapter to your table or implement your own.
|
|
3084
|
+
*/
|
|
3085
|
+
getSortedRowModel?: (table: Table<any>) => () => RowModel<any>
|
|
3086
|
+
|
|
3087
|
+
/**
|
|
3088
|
+
* This optional function is used to access the sub rows for any given row. If you are using nested rows, you will need to use this function to return the sub rows object (or undefined) from the row.
|
|
3089
|
+
*/
|
|
3090
|
+
getSubRows?: (originalRow: Lead, index: number) => Lead[] | undefined
|
|
3091
|
+
|
|
3092
|
+
/**
|
|
3093
|
+
* The filter function to use for global filtering.
|
|
3094
|
+
* - A `string` referencing a built-in filter function
|
|
3095
|
+
* - A `string` that references a custom filter functions provided via the `tableOptions.filterFns` option
|
|
3096
|
+
* - A custom filter function
|
|
3097
|
+
*/
|
|
3098
|
+
globalFilterFn?: FilterFnOption<Lead> | undefined
|
|
3099
|
+
|
|
3100
|
+
/**
|
|
3101
|
+
* Grouping columns are automatically reordered by default to the start of the columns list. If you would rather remove them or leave them as-is, set the appropriate mode here.
|
|
3102
|
+
*/
|
|
3103
|
+
groupedColumnMode?: false | "reorder" | "remove" | undefined
|
|
3104
|
+
|
|
3105
|
+
/**
|
|
3106
|
+
* Use this option to optionally pass initial state to the table. This state will be used when resetting various table states either automatically by the table (eg. `options.autoResetPageIndex`) or via functions like `table.resetRowSelection()`. Most reset function allow you optionally pass a flag to reset to a blank/default state instead of the initial state.
|
|
3107
|
+
*
|
|
3108
|
+
* Table state will not be reset when this object changes, which also means that the initial state object does not need to be stable.
|
|
3109
|
+
*/
|
|
3110
|
+
initialState?: InitialTableState
|
|
3111
|
+
|
|
3112
|
+
/**
|
|
3113
|
+
* Dims the table while data is loading and suppresses the empty state.
|
|
3114
|
+
*/
|
|
3115
|
+
isLoading?: boolean = false
|
|
3116
|
+
|
|
3117
|
+
/**
|
|
3118
|
+
* Pass a custom function that will be used to determine if a multi-sort event should be triggered. It is passed the event from the sort toggle handler and should return `true` if the event should trigger a multi-sort.
|
|
3119
|
+
*/
|
|
3120
|
+
isMultiSortEvent?: (e: unknown) => boolean
|
|
3121
|
+
|
|
3122
|
+
/**
|
|
3123
|
+
* When `false`, pinned rows will not be visible if they are filtered or paginated out of the table. When `true`, pinned rows will always be visible regardless of filtering or pagination. Defaults to `true`.
|
|
3124
|
+
*/
|
|
3125
|
+
keepPinnedRows?: boolean
|
|
3126
|
+
|
|
3127
|
+
/**
|
|
3128
|
+
* Renders the per-row link when `rowHref` is set. Defaults to `'a'`; pass a
|
|
3129
|
+
* framework link (e.g. Next.js `Link`) for client-side navigation.
|
|
3130
|
+
*/
|
|
3131
|
+
linkComponent?: ElementType | undefined = 'a'
|
|
3132
|
+
|
|
3133
|
+
/**
|
|
3134
|
+
* Enables manual row expansion. If this is set to `true`, `getExpandedRowModel` will not be used to expand rows and you would be expected to perform the expansion in your own data model. This is useful if you are doing server-side expansion.
|
|
3135
|
+
*/
|
|
3136
|
+
manualExpanding?: boolean
|
|
3137
|
+
|
|
3138
|
+
/**
|
|
3139
|
+
* Disables the `getFilteredRowModel` from being used to filter data. This may be useful if your table needs to dynamically support both client-side and server-side filtering.
|
|
3140
|
+
*/
|
|
3141
|
+
manualFiltering?: boolean
|
|
3142
|
+
|
|
3143
|
+
/**
|
|
3144
|
+
* Enables manual grouping. If this option is set to `true`, the table will not automatically group rows using `getGroupedRowModel()` and instead will expect you to manually group the rows before passing them to the table. This is useful if you are doing server-side grouping and aggregation.
|
|
3145
|
+
*/
|
|
3146
|
+
manualGrouping?: boolean
|
|
3147
|
+
|
|
3148
|
+
/**
|
|
3149
|
+
* Enables manual pagination. If this option is set to `true`, the table will not automatically paginate rows using `getPaginationRowModel()` and instead will expect you to manually paginate the rows before passing them to the table. This is useful if you are doing server-side pagination and aggregation.
|
|
3150
|
+
*/
|
|
3151
|
+
manualPagination?: boolean
|
|
3152
|
+
|
|
3153
|
+
/**
|
|
3154
|
+
* Enables manual sorting for the table. If this is `true`, you will be expected to sort your data before it is passed to the table. This is useful if you are doing server-side sorting.
|
|
3155
|
+
*/
|
|
3156
|
+
manualSorting?: boolean
|
|
3157
|
+
|
|
3158
|
+
/**
|
|
3159
|
+
* By default, filtering is done for all rows (max depth of 100), no matter if they are root level parent rows or the child leaf rows of a parent row. Setting this option to `0` will cause filtering to only be applied to the root level parent rows, with all sub-rows remaining unfiltered. Similarly, setting this option to `1` will cause filtering to only be applied to child leaf rows 1 level deep, and so on.
|
|
3160
|
+
*
|
|
3161
|
+
* This is useful for situations where you want a row's entire child hierarchy to be visible regardless of the applied filter.
|
|
3162
|
+
*/
|
|
3163
|
+
maxLeafRowFilterDepth?: number
|
|
3164
|
+
|
|
3165
|
+
/**
|
|
3166
|
+
* Set a maximum number of columns that can be multi-sorted.
|
|
3167
|
+
*/
|
|
3168
|
+
maxMultiSortColCount?: number
|
|
3169
|
+
|
|
3170
|
+
/**
|
|
3171
|
+
* This option is used to optionally implement the merging of table options.
|
|
3172
|
+
*/
|
|
3173
|
+
mergeOptions?: (defaultOptions: TableOptions<Lead>, options: Partial<TableOptions<Lead>>) => TableOptions<Lead>
|
|
3174
|
+
|
|
3175
|
+
/**
|
|
3176
|
+
* You can pass any object to `options.meta` and access it anywhere the `table` is available via `table.options.meta`.
|
|
3177
|
+
*/
|
|
3178
|
+
meta?: TableMeta<Lead>
|
|
3179
|
+
|
|
3180
|
+
/**
|
|
3181
|
+
* If provided, this function will be called with an `updaterFn` when `state.columnFilters` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
|
|
3182
|
+
*/
|
|
3183
|
+
onColumnFiltersChange?: OnChangeFn<ColumnFiltersState>
|
|
3184
|
+
|
|
3185
|
+
/**
|
|
3186
|
+
* If provided, this function will be called with an `updaterFn` when `state.columnOrder` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
|
|
3187
|
+
*/
|
|
3188
|
+
onColumnOrderChange?: OnChangeFn<ColumnOrderState>
|
|
3189
|
+
|
|
3190
|
+
/**
|
|
3191
|
+
* If provided, this function will be called with an `updaterFn` when `state.columnPinning` changes. This overrides the default internal state management, so you will also need to supply `state.columnPinning` from your own managed state.
|
|
3192
|
+
*/
|
|
3193
|
+
onColumnPinningChange?: OnChangeFn<ColumnPinningState>
|
|
3194
|
+
|
|
3195
|
+
/**
|
|
3196
|
+
* If provided, this function will be called with an `updaterFn` when `state.columnSizing` changes. This overrides the default internal state management, so you will also need to supply `state.columnSizing` from your own managed state.
|
|
3197
|
+
*/
|
|
3198
|
+
onColumnSizingChange?: OnChangeFn<ColumnSizingState>
|
|
3199
|
+
|
|
3200
|
+
/**
|
|
3201
|
+
* If provided, this function will be called with an `updaterFn` when `state.columnSizingInfo` changes. This overrides the default internal state management, so you will also need to supply `state.columnSizingInfo` from your own managed state.
|
|
3202
|
+
*/
|
|
3203
|
+
onColumnSizingInfoChange?: OnChangeFn<ColumnSizingInfoState>
|
|
3204
|
+
|
|
3205
|
+
/**
|
|
3206
|
+
* If provided, this function will be called with an `updaterFn` when `state.columnVisibility` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
|
|
3207
|
+
*/
|
|
3208
|
+
onColumnVisibilityChange?: OnChangeFn<VisibilityState>
|
|
3209
|
+
|
|
3210
|
+
/**
|
|
3211
|
+
* This function is called when the `expanded` table state changes. If a function is provided, you will be responsible for managing this state on your own. To pass the managed state back to the table, use the `tableOptions.state.expanded` option.
|
|
3212
|
+
*/
|
|
3213
|
+
onExpandedChange?: OnChangeFn<ExpandedState>
|
|
3214
|
+
|
|
3215
|
+
/**
|
|
3216
|
+
* If provided, this function will be called with an `updaterFn` when `state.globalFilter` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
|
|
3217
|
+
*/
|
|
3218
|
+
onGlobalFilterChange?: OnChangeFn<any>
|
|
3219
|
+
|
|
3220
|
+
/**
|
|
3221
|
+
* If this function is provided, it will be called when the grouping state changes and you will be expected to manage the state yourself. You can pass the managed state back to the table via the `tableOptions.state.grouping` option.
|
|
3222
|
+
*/
|
|
3223
|
+
onGroupingChange?: OnChangeFn<GroupingState>
|
|
3224
|
+
|
|
3225
|
+
/**
|
|
3226
|
+
* If this function is provided, it will be called when the pagination state changes and you will be expected to manage the state yourself. You can pass the managed state back to the table via the `tableOptions.state.pagination` option.
|
|
3227
|
+
*/
|
|
3228
|
+
onPaginationChange?: OnChangeFn<PaginationState>
|
|
3229
|
+
|
|
3230
|
+
/**
|
|
3231
|
+
* Called with the row's data when a non-interactive part of the row is clicked.
|
|
3232
|
+
*/
|
|
3233
|
+
onRowClick?: (row: Lead) => void
|
|
3234
|
+
|
|
3235
|
+
/**
|
|
3236
|
+
* If provided, this function will be called with an `updaterFn` when `state.rowPinning` changes. This overrides the default internal state management, so you will also need to supply `state.rowPinning` from your own managed state.
|
|
3237
|
+
*/
|
|
3238
|
+
onRowPinningChange?: OnChangeFn<RowPinningState>
|
|
3239
|
+
|
|
3240
|
+
/**
|
|
3241
|
+
* If provided, this function will be called with an `updaterFn` when `state.rowSelection` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
|
|
3242
|
+
*/
|
|
3243
|
+
onRowSelectionChange?: OnChangeFn<RowSelectionState>
|
|
3244
|
+
|
|
3245
|
+
/**
|
|
3246
|
+
* If provided, this function will be called with an `updaterFn` when `state.sorting` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.
|
|
3247
|
+
*/
|
|
3248
|
+
onSortingChange?: OnChangeFn<SortingState>
|
|
3249
|
+
|
|
3250
|
+
/**
|
|
3251
|
+
* The `onStateChange` option can be used to optionally listen to state changes within the table.
|
|
3252
|
+
*/
|
|
3253
|
+
onStateChange?: (updater: Updater<TableState>) => void
|
|
3254
|
+
|
|
3255
|
+
/**
|
|
3256
|
+
* When manually controlling pagination, you can supply a total `pageCount` value to the table if you know it (Or supply a `rowCount` and `pageCount` will be calculated). If you do not know how many pages there are, you can set this to `-1`.
|
|
3257
|
+
*/
|
|
3258
|
+
pageCount?: number
|
|
3259
|
+
|
|
3260
|
+
/**
|
|
3261
|
+
* If `true` expanded rows will be paginated along with the rest of the table (which means expanded rows may span multiple pages). If `false` expanded rows will not be considered for pagination (which means expanded rows will always render on their parents page. This also means more rows will be rendered than the set page size)
|
|
3262
|
+
*/
|
|
3263
|
+
paginateExpandedRows?: boolean
|
|
3264
|
+
|
|
3265
|
+
/**
|
|
3266
|
+
* Value used when the desired value is not found in the data.
|
|
3267
|
+
*/
|
|
3268
|
+
renderFallbackValue?: any
|
|
3269
|
+
|
|
3270
|
+
/**
|
|
3271
|
+
* When manually controlling pagination, you can supply a total `rowCount` value to the table if you know it. The `pageCount` can be calculated from this value and the `pageSize`.
|
|
3272
|
+
*/
|
|
3273
|
+
rowCount?: number
|
|
3274
|
+
|
|
3275
|
+
/**
|
|
3276
|
+
* Returns an href for a row; the row becomes a link (see `linkComponent`).
|
|
3277
|
+
*/
|
|
3278
|
+
rowHref?: (row: Lead) => string
|
|
3279
|
+
|
|
3280
|
+
/**
|
|
3281
|
+
* If `true`, all sorts will default to descending as their first toggle state.
|
|
3282
|
+
*/
|
|
3283
|
+
sortDescFirst?: boolean
|
|
3284
|
+
|
|
3285
|
+
sortingFns?: Record<string, SortingFn<any>>
|
|
3286
|
+
|
|
3287
|
+
/**
|
|
3288
|
+
* The `state` option can be used to optionally _control_ part or all of the table state. The state you pass here will merge with and overwrite the internal automatically-managed state to produce the final state for the table. You can also listen to state changes via the `onStateChange` option.
|
|
3289
|
+
* > Note: Any state passed in here will override both the internal state and any other `initialState` you provide.
|
|
3290
|
+
*/
|
|
3291
|
+
state?: Partial<TableState></code></pre>
|
|
3292
|
+
</div>
|
|
3293
|
+
</div>
|
|
3294
|
+
|
|
3295
|
+
<div class="panel panel-stories">
|
|
3296
|
+
|
|
3297
|
+
|
|
3298
|
+
|
|
3299
|
+
<div class="note ok">
|
|
3300
|
+
<div class="row">
|
|
3301
|
+
<span class="ex-name">Imports</span>
|
|
3302
|
+
</div>
|
|
3303
|
+
<pre><code>import { Button, DataTable, DropdownMenu, Pagination, Table } from "@agentero/design-system";</code></pre>
|
|
3304
|
+
</div>
|
|
3305
|
+
|
|
3306
|
+
|
|
3307
|
+
<div class="note ok">
|
|
3308
|
+
<div class="row">
|
|
3309
|
+
<span class="ex-name">Playground</span>
|
|
3310
|
+
<span class="badge ok">story ok</span>
|
|
3311
|
+
</div>
|
|
3312
|
+
<div>Display props playground (size / embed / enclosed / sticky)</div>
|
|
3313
|
+
<div class="hint">Playground for `DataTable.Table` display props — toggle `size`, `embed`,
|
|
3314
|
+
`enclosed`, and `sticky` from the controls panel.</div>
|
|
3315
|
+
<pre><code>const Playground = () => <div
|
|
3316
|
+
className={args.enclosed ? 'flex min-h-0 flex-1 flex-col p-4' : 'contents'}>
|
|
3317
|
+
<DataTable.Root data={LEADS} columns={columns}>
|
|
3318
|
+
<DataTable.Table size="md" embed enclosed={false} sticky="header" />
|
|
3319
|
+
</DataTable.Root>
|
|
3320
|
+
</div>;</code></pre>
|
|
3321
|
+
</div>
|
|
3322
|
+
<div class="note ok">
|
|
3323
|
+
<div class="row">
|
|
3324
|
+
<span class="ex-name">Leads</span>
|
|
3325
|
+
<span class="badge ok">story ok</span>
|
|
3326
|
+
</div>
|
|
3327
|
+
<div>Representative leads table composition</div>
|
|
3328
|
+
<div class="hint">A leads-table composition: sortable `Created` column, a status badge, row
|
|
3329
|
+
navigation via `rowHref`, hover-revealed actions, a search input + filters in
|
|
3330
|
+
the toolbar, and pagination in the footer.</div>
|
|
3331
|
+
<pre><code>const Leads = () => {
|
|
3332
|
+
const [sorting, setSorting] = useState<SortingState>([]);
|
|
3333
|
+
const [page, setPage] = useState(1);
|
|
3334
|
+
const [search, setSearch] = useState('');
|
|
3335
|
+
|
|
3336
|
+
const data = useMemo(
|
|
3337
|
+
() => LEADS.filter(l => l.contact.toLowerCase().includes(search.toLowerCase())),
|
|
3338
|
+
[search]
|
|
3339
|
+
);
|
|
3340
|
+
|
|
3341
|
+
return (
|
|
3342
|
+
<DataTable.Root
|
|
3343
|
+
data={data}
|
|
3344
|
+
columns={columns}
|
|
3345
|
+
state={{ sorting }}
|
|
3346
|
+
onSortingChange={setSorting}
|
|
3347
|
+
getSortedRowModel={getSortedRowModel()}
|
|
3348
|
+
enableSortingRemoval={false}
|
|
3349
|
+
rowHref={lead => `/leads/${lead.leadId}`}>
|
|
3350
|
+
<DataTable.ToolBar>
|
|
3351
|
+
<input
|
|
3352
|
+
value={search}
|
|
3353
|
+
onChange={e => setSearch(e.target.value)}
|
|
3354
|
+
placeholder="Search..."
|
|
3355
|
+
aria-label="Search leads"
|
|
3356
|
+
className="h-8 w-60 rounded-md border border-border-default-base-primary px-3 text-sm outline-none"
|
|
3357
|
+
/>
|
|
3358
|
+
<Button variant="secondary" size="sm">
|
|
3359
|
+
Filters
|
|
3360
|
+
</Button>
|
|
3361
|
+
</DataTable.ToolBar>
|
|
3362
|
+
|
|
3363
|
+
<DataTable.Table />
|
|
3364
|
+
|
|
3365
|
+
<DataTable.Footer>
|
|
3366
|
+
<Pagination
|
|
3367
|
+
totalCount={LEADS.length}
|
|
3368
|
+
currentPage={page}
|
|
3369
|
+
pageSize={10}
|
|
3370
|
+
onPageChange={setPage}
|
|
3371
|
+
/>
|
|
3372
|
+
</DataTable.Footer>
|
|
3373
|
+
</DataTable.Root>
|
|
3374
|
+
);
|
|
3375
|
+
};</code></pre>
|
|
3376
|
+
</div>
|
|
3377
|
+
<div class="note ok">
|
|
3378
|
+
<div class="row">
|
|
3379
|
+
<span class="ex-name">Empty</span>
|
|
3380
|
+
<span class="badge ok">story ok</span>
|
|
3381
|
+
</div>
|
|
3382
|
+
<div>Empty state when there are no rows</div>
|
|
3383
|
+
<div class="hint">No rows: the table renders its default empty state instead of body rows.</div>
|
|
3384
|
+
<pre><code>const Empty = () => (
|
|
3385
|
+
<DataTable.Root data={[] as Lead[]} columns={columns}>
|
|
3386
|
+
<DataTable.Table />
|
|
3387
|
+
</DataTable.Root>
|
|
3388
|
+
);</code></pre>
|
|
3389
|
+
</div>
|
|
3390
|
+
<div class="note ok">
|
|
3391
|
+
<div class="row">
|
|
3392
|
+
<span class="ex-name">Loading</span>
|
|
3393
|
+
<span class="badge ok">story ok</span>
|
|
3394
|
+
</div>
|
|
3395
|
+
<div>Loading state dims the table and hides the empty state</div>
|
|
3396
|
+
<div class="hint">Loading: the body is dimmed and the empty state is suppressed while data is
|
|
3397
|
+
in flight.</div>
|
|
3398
|
+
<pre><code>const Loading = () => (
|
|
3399
|
+
<DataTable.Root data={[] as Lead[]} columns={columns} isLoading>
|
|
3400
|
+
<DataTable.Table />
|
|
3401
|
+
</DataTable.Root>
|
|
3402
|
+
);</code></pre>
|
|
3403
|
+
</div>
|
|
3404
|
+
</div>
|
|
3405
|
+
|
|
3406
|
+
|
|
3407
|
+
</div>
|
|
3408
|
+
</article>
|
|
3409
|
+
<article
|
|
3410
|
+
class="card
|
|
3411
|
+
no-error
|
|
3412
|
+
no-info
|
|
3413
|
+
no-story-error
|
|
3414
|
+
no-doc-error"
|
|
3415
|
+
role="listitem"
|
|
3416
|
+
aria-label="Divider">
|
|
3417
|
+
<div class="head">
|
|
3418
|
+
<div class="title">
|
|
3419
|
+
<h2><span class="status-dot dot-ok"></span> Divider</h2>
|
|
3420
|
+
<div class="badges">
|
|
3421
|
+
<label for="c-8-components-divider-props" class="badge ok as-toggle">4 prop types</label>
|
|
3422
|
+
|
|
3423
|
+
<label for="c-8-components-divider-stories" class="badge ok as-toggle">10 stories</label>
|
|
3424
|
+
|
|
3425
|
+
|
|
3426
|
+
</div>
|
|
3427
|
+
</div>
|
|
3428
|
+
<div class="meta" title="./src/divider/divider.stories.tsx">components-divider · ./src/divider/divider.stories.tsx</div>
|
|
3429
|
+
<div>Visual or semantic separator that optionally renders a centered label</div>
|
|
3430
|
+
<div class="hint">Divider separates content visually along either a horizontal or vertical
|
|
3431
|
+
axis. Use between page or card sections, between inline items in a toolbar
|
|
3432
|
+
or list, or — with the `label` prop — to render an "or"-style break between
|
|
3433
|
+
options. Set `decorative={false}` when the separator carries semantic
|
|
3434
|
+
meaning so it's announced to assistive technologies.</div>
|
|
3435
|
+
<div class="kv"><span class="chip">summary: Visual or semantic separator that optionally renders a centered label</span><span class="chip">param: orientation - Axis along which the separator renders. Defaults to `'horizontal'`.
|
|
3436
|
+
- `horizontal` — 1px line spanning the parent width.
|
|
3437
|
+
- `vertical` — 1px line spanning the parent height; parent must establish a height.</span><span class="chip">param: decorative - When `true` (default), the separator is purely visual and hidden
|
|
3438
|
+
from assistive technologies. Set to `false` to expose `role="separator"` plus
|
|
3439
|
+
`aria-orientation` for meaningful section breaks.</span><span class="chip">param: label - Optional inline content rendered between two flanking 1px lines.
|
|
3440
|
+
When omitted, Divider renders a single line.</span><span class="chip">example: <Divider /></span><span class="chip">example: <Divider orientation="vertical" /></span><span class="chip">example: <Divider label="or" /></span><span class="chip">example: <Divider decorative={false} /></span></div>
|
|
3441
|
+
</div>
|
|
3442
|
+
|
|
3443
|
+
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
3444
|
+
|
|
3445
|
+
|
|
3446
|
+
<input id="c-8-components-divider-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
3447
|
+
|
|
3448
|
+
|
|
3449
|
+
<input id="c-8-components-divider-props" class="tg tg-props" type="checkbox" hidden />
|
|
3450
|
+
|
|
3451
|
+
<div class="panels">
|
|
2655
3452
|
|
|
2656
3453
|
|
|
2657
3454
|
|
|
2658
3455
|
<div class="panel panel-props">
|
|
2659
3456
|
<div class="note ok">
|
|
2660
3457
|
<div class="row">
|
|
2661
|
-
<span class="ex-name">Prop types <small>(react-
|
|
2662
|
-
<span class="badge ok">
|
|
3458
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
3459
|
+
<span class="badge ok">4 prop types</span>
|
|
2663
3460
|
</div>
|
|
2664
3461
|
<pre><code>Component: src/divider/divider.tsx::Divider</code></pre>
|
|
2665
3462
|
<pre><code>Props:</code></pre>
|
|
2666
3463
|
<pre><code>asChild?: boolean
|
|
2667
3464
|
|
|
3465
|
+
/**
|
|
3466
|
+
* Whether or not the component is purely decorative. When true, accessibility-related attributes
|
|
3467
|
+
* are updated so that that the rendered element is removed from the accessibility tree.
|
|
3468
|
+
*/
|
|
3469
|
+
decorative?: boolean = true
|
|
3470
|
+
|
|
2668
3471
|
/**
|
|
2669
3472
|
* Optional label rendered inline between two flanking 1px lines. When set,
|
|
2670
3473
|
* Divider renders a styled `<div>` (rather than the underlying separator
|
|
2671
3474
|
* primitive) so the label can sit centered between the two line segments.
|
|
2672
3475
|
*/
|
|
2673
|
-
label?: ReactNode
|
|
3476
|
+
label?: ReactNode
|
|
3477
|
+
|
|
3478
|
+
/**
|
|
3479
|
+
* Either `vertical` or `horizontal`. Defaults to `horizontal`.
|
|
3480
|
+
*/
|
|
3481
|
+
orientation?: "horizontal" | "vertical" = 'horizontal'</code></pre>
|
|
2674
3482
|
</div>
|
|
2675
3483
|
</div>
|
|
2676
3484
|
|
|
@@ -2692,7 +3500,8 @@ label?: ReactNode</code></pre>
|
|
|
2692
3500
|
<span class="badge ok">story ok</span>
|
|
2693
3501
|
</div>
|
|
2694
3502
|
<div>Default horizontal decorative divider</div>
|
|
2695
|
-
<div class="hint">The default horizontal, decorative divider — a 1px line that spans the
|
|
3503
|
+
<div class="hint">The default horizontal, decorative divider — a 1px line that spans the
|
|
3504
|
+
parent width. Use this form between stacked content blocks.</div>
|
|
2696
3505
|
<pre><code>const Default = () => <div
|
|
2697
3506
|
className={cn(
|
|
2698
3507
|
'flex gap-4 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary p-6',
|
|
@@ -2717,7 +3526,8 @@ label?: ReactNode</code></pre>
|
|
|
2717
3526
|
<span class="badge ok">story ok</span>
|
|
2718
3527
|
</div>
|
|
2719
3528
|
<div>Horizontal 1px line spanning the parent width</div>
|
|
2720
|
-
<div class="hint">Horizontal divider — a 1px line spanning the parent's full width. The
|
|
3529
|
+
<div class="hint">Horizontal divider — a 1px line spanning the parent's full width. The
|
|
3530
|
+
default orientation; use to separate stacked content.</div>
|
|
2721
3531
|
<pre><code>const Horizontal = () => (
|
|
2722
3532
|
<div className="w-80">
|
|
2723
3533
|
<Divider />
|
|
@@ -2730,7 +3540,9 @@ label?: ReactNode</code></pre>
|
|
|
2730
3540
|
<span class="badge ok">story ok</span>
|
|
2731
3541
|
</div>
|
|
2732
3542
|
<div>Vertical 1px line spanning the parent height</div>
|
|
2733
|
-
<div class="hint">Vertical divider — a 1px line spanning the parent's full height. Parent must
|
|
3543
|
+
<div class="hint">Vertical divider — a 1px line spanning the parent's full height. Parent must
|
|
3544
|
+
establish a height (via `h-*` or an intrinsic flex item height) for the line
|
|
3545
|
+
to be visible.</div>
|
|
2734
3546
|
<pre><code>const Vertical = () => (
|
|
2735
3547
|
<div className="flex h-24 items-stretch">
|
|
2736
3548
|
<Divider orientation="vertical" />
|
|
@@ -2743,7 +3555,8 @@ label?: ReactNode</code></pre>
|
|
|
2743
3555
|
<span class="badge ok">story ok</span>
|
|
2744
3556
|
</div>
|
|
2745
3557
|
<div>Horizontal divider with a centered "or" label</div>
|
|
2746
|
-
<div class="hint">Labelled divider. The label sits centered between two flanking 1px lines —
|
|
3558
|
+
<div class="hint">Labelled divider. The label sits centered between two flanking 1px lines —
|
|
3559
|
+
a common pattern for "or" breaks between authentication options.</div>
|
|
2747
3560
|
<pre><code>const WithLabel = () => <div className="flex w-80 flex-col gap-2">
|
|
2748
3561
|
<Button variant="primary">Continue with email</Button>
|
|
2749
3562
|
<Divider orientation="horizontal" decorative label="or" />
|
|
@@ -2756,7 +3569,8 @@ label?: ReactNode</code></pre>
|
|
|
2756
3569
|
<span class="badge ok">story ok</span>
|
|
2757
3570
|
</div>
|
|
2758
3571
|
<div>Vertical divider with a centered label</div>
|
|
2759
|
-
<div class="hint">Vertical divider with a label. The label sits between two stacked 1px line
|
|
3572
|
+
<div class="hint">Vertical divider with a label. The label sits between two stacked 1px line
|
|
3573
|
+
segments; use sparingly — horizontal labelled dividers are more common.</div>
|
|
2760
3574
|
<pre><code>const VerticalWithLabel = () => <div
|
|
2761
3575
|
className="flex h-40 items-stretch gap-4 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary p-6">
|
|
2762
3576
|
<div className="flex flex-col justify-center gap-1">
|
|
@@ -2776,7 +3590,9 @@ label?: ReactNode</code></pre>
|
|
|
2776
3590
|
<span class="badge ok">story ok</span>
|
|
2777
3591
|
</div>
|
|
2778
3592
|
<div>Semantic separator announced to assistive technologies</div>
|
|
2779
|
-
<div class="hint">Semantic divider (`decorative={false}`). Exposes `role="separator"` and
|
|
3593
|
+
<div class="hint">Semantic divider (`decorative={false}`). Exposes `role="separator"` and
|
|
3594
|
+
`aria-orientation` to assistive technologies, marking a meaningful section
|
|
3595
|
+
break rather than a purely visual one.</div>
|
|
2780
3596
|
<pre><code>const Semantic = () => <div
|
|
2781
3597
|
className="flex w-80 flex-col gap-4 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary p-6">
|
|
2782
3598
|
<section className="flex flex-col gap-1">
|
|
@@ -2798,7 +3614,8 @@ label?: ReactNode</code></pre>
|
|
|
2798
3614
|
<span class="badge ok">story ok</span>
|
|
2799
3615
|
</div>
|
|
2800
3616
|
<div>Horizontal dividers between stacked list rows</div>
|
|
2801
|
-
<div class="hint">Divider between list rows. Dividers delineate each item without the visual
|
|
3617
|
+
<div class="hint">Divider between list rows. Dividers delineate each item without the visual
|
|
3618
|
+
weight of a full border on every row.</div>
|
|
2802
3619
|
<pre><code>const InList = () => (
|
|
2803
3620
|
<div className="w-80 rounded-lg border border-border-default-base-primary bg-bg-default-base-primary">
|
|
2804
3621
|
<div className="flex flex-col gap-1 px-4 py-3">
|
|
@@ -2830,7 +3647,9 @@ label?: ReactNode</code></pre>
|
|
|
2830
3647
|
<span class="badge ok">story ok</span>
|
|
2831
3648
|
</div>
|
|
2832
3649
|
<div>Vertical dividers grouping toolbar actions</div>
|
|
2833
|
-
<div class="hint">Vertical dividers grouping related toolbar actions. Use to separate logical
|
|
3650
|
+
<div class="hint">Vertical dividers grouping related toolbar actions. Use to separate logical
|
|
3651
|
+
clusters of buttons (editing vs. history vs. settings) without visual
|
|
3652
|
+
weight.</div>
|
|
2834
3653
|
<pre><code>const InToolbar = () => (
|
|
2835
3654
|
<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">
|
|
2836
3655
|
<Button variant="ghost" size="xs">
|
|
@@ -2862,7 +3681,8 @@ label?: ReactNode</code></pre>
|
|
|
2862
3681
|
<span class="badge ok">story ok</span>
|
|
2863
3682
|
</div>
|
|
2864
3683
|
<div>Horizontal dividers between content sections</div>
|
|
2865
|
-
<div class="hint">Horizontal dividers between content sections in a long-form layout. Helps
|
|
3684
|
+
<div class="hint">Horizontal dividers between content sections in a long-form layout. Helps
|
|
3685
|
+
create visual hierarchy in content-heavy pages.</div>
|
|
2866
3686
|
<pre><code>const HorizontalInContent = () => (
|
|
2867
3687
|
<div className="flex w-96 flex-col gap-4 p-6">
|
|
2868
3688
|
<div className="flex flex-col gap-1">
|
|
@@ -2894,7 +3714,8 @@ label?: ReactNode</code></pre>
|
|
|
2894
3714
|
<span class="badge ok">story ok</span>
|
|
2895
3715
|
</div>
|
|
2896
3716
|
<div>Vertical dividers separating inline elements</div>
|
|
2897
|
-
<div class="hint">Vertical dividers between inline elements. Common for separating a row of
|
|
3717
|
+
<div class="hint">Vertical dividers between inline elements. Common for separating a row of
|
|
3718
|
+
related controls or inline links without visual weight.</div>
|
|
2898
3719
|
<pre><code>const VerticalBetweenElements = () => (
|
|
2899
3720
|
<div className="flex items-stretch gap-3">
|
|
2900
3721
|
<Button variant="primary" size="sm">
|
|
@@ -2913,6 +3734,7 @@ label?: ReactNode</code></pre>
|
|
|
2913
3734
|
</div>
|
|
2914
3735
|
</div>
|
|
2915
3736
|
|
|
3737
|
+
|
|
2916
3738
|
</div>
|
|
2917
3739
|
</article>
|
|
2918
3740
|
<article
|
|
@@ -2927,16 +3749,62 @@ label?: ReactNode</code></pre>
|
|
|
2927
3749
|
<div class="title">
|
|
2928
3750
|
<h2><span class="status-dot dot-ok"></span> DropdownMenu.Root</h2>
|
|
2929
3751
|
<div class="badges">
|
|
2930
|
-
|
|
3752
|
+
<label for="c-9-components-dropdownmenu-props" class="badge ok as-toggle">6 prop types</label>
|
|
2931
3753
|
|
|
2932
3754
|
<label for="c-9-components-dropdownmenu-stories" class="badge ok as-toggle">7 stories</label>
|
|
2933
3755
|
|
|
3756
|
+
|
|
2934
3757
|
</div>
|
|
2935
3758
|
</div>
|
|
2936
3759
|
<div class="meta" title="./src/dropdown-menu/dropdown-menu.stories.tsx">components-dropdownmenu · ./src/dropdown-menu/dropdown-menu.stories.tsx</div>
|
|
2937
|
-
|
|
2938
|
-
<div class="hint">DropdownMenu is a compound overlay for secondary actions, bulk operations,
|
|
2939
|
-
|
|
3760
|
+
<div>Root provider for a DropdownMenu's open state</div>
|
|
3761
|
+
<div class="hint">DropdownMenu is a compound overlay for secondary actions, bulk operations,
|
|
3762
|
+
or navigation shortcuts triggered off a button or icon. Compose it from
|
|
3763
|
+
`Root` / `Trigger` / `Portal` / `Content` and fill the menu with `Item`,
|
|
3764
|
+
`Separator`, `Label`, and — for nested flows — `Sub` / `SubTrigger` /
|
|
3765
|
+
`SubContent`. Built on Radix UI's DropdownMenu primitive, so keyboard
|
|
3766
|
+
navigation, focus trapping, typeahead, and collision detection come for
|
|
3767
|
+
free.</div>
|
|
3768
|
+
<div class="kv"><span class="chip">summary: Root provider for a DropdownMenu's open state</span><span class="chip">see: {@link https://www.radix-ui.com/primitives/docs/components/dropdown-menu Radix UI DropdownMenu}</span><span class="chip">example: ```tsx
|
|
3769
|
+
import { DropdownMenu } from '@agentero/design-system/dropdown-menu';
|
|
3770
|
+
|
|
3771
|
+
<DropdownMenu.Root>
|
|
3772
|
+
<DropdownMenu.Trigger>
|
|
3773
|
+
<IconMoreVert />
|
|
3774
|
+
</DropdownMenu.Trigger>
|
|
3775
|
+
|
|
3776
|
+
<DropdownMenu.Portal>
|
|
3777
|
+
<DropdownMenu.Content side="bottom" align="end">
|
|
3778
|
+
<DropdownMenu.Label>Actions</DropdownMenu.Label>
|
|
3779
|
+
|
|
3780
|
+
<DropdownMenu.Item onSelect={() => handleEdit()}>
|
|
3781
|
+
<IconEdit />
|
|
3782
|
+
Edit
|
|
3783
|
+
</DropdownMenu.Item>
|
|
3784
|
+
|
|
3785
|
+
<DropdownMenu.Sub>
|
|
3786
|
+
<DropdownMenu.SubTrigger>Share</DropdownMenu.SubTrigger>
|
|
3787
|
+
<DropdownMenu.Portal>
|
|
3788
|
+
<DropdownMenu.SubContent>
|
|
3789
|
+
<DropdownMenu.Item>Email</DropdownMenu.Item>
|
|
3790
|
+
<DropdownMenu.Item>Slack</DropdownMenu.Item>
|
|
3791
|
+
</DropdownMenu.SubContent>
|
|
3792
|
+
</DropdownMenu.Portal>
|
|
3793
|
+
</DropdownMenu.Sub>
|
|
3794
|
+
|
|
3795
|
+
<DropdownMenu.Separator />
|
|
3796
|
+
|
|
3797
|
+
<DropdownMenu.Item
|
|
3798
|
+
onSelect={() => handleDelete()}
|
|
3799
|
+
disabled={!canDelete}
|
|
3800
|
+
>
|
|
3801
|
+
<IconDelete />
|
|
3802
|
+
Delete
|
|
3803
|
+
</DropdownMenu.Item>
|
|
3804
|
+
</DropdownMenu.Content>
|
|
3805
|
+
</DropdownMenu.Portal>
|
|
3806
|
+
</DropdownMenu.Root>
|
|
3807
|
+
```</span></div>
|
|
2940
3808
|
</div>
|
|
2941
3809
|
|
|
2942
3810
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -2945,11 +3813,33 @@ label?: ReactNode</code></pre>
|
|
|
2945
3813
|
<input id="c-9-components-dropdownmenu-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
2946
3814
|
|
|
2947
3815
|
|
|
3816
|
+
<input id="c-9-components-dropdownmenu-props" class="tg tg-props" type="checkbox" hidden />
|
|
2948
3817
|
|
|
2949
3818
|
<div class="panels">
|
|
2950
3819
|
|
|
2951
3820
|
|
|
2952
3821
|
|
|
3822
|
+
<div class="panel panel-props">
|
|
3823
|
+
<div class="note ok">
|
|
3824
|
+
<div class="row">
|
|
3825
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
3826
|
+
<span class="badge ok">6 prop types</span>
|
|
3827
|
+
</div>
|
|
3828
|
+
<pre><code>Component: src/dropdown-menu/index.ts::DropdownMenu</code></pre>
|
|
3829
|
+
<pre><code>Props:</code></pre>
|
|
3830
|
+
<pre><code>children?: ReactNode
|
|
3831
|
+
|
|
3832
|
+
defaultOpen?: boolean
|
|
3833
|
+
|
|
3834
|
+
dir?: "ltr" | "rtl"
|
|
3835
|
+
|
|
3836
|
+
modal?: boolean
|
|
3837
|
+
|
|
3838
|
+
onOpenChange?: (open: boolean) => void
|
|
3839
|
+
|
|
3840
|
+
open?: boolean</code></pre>
|
|
3841
|
+
</div>
|
|
3842
|
+
</div>
|
|
2953
3843
|
|
|
2954
3844
|
<div class="panel panel-stories">
|
|
2955
3845
|
|
|
@@ -2969,7 +3859,9 @@ label?: ReactNode</code></pre>
|
|
|
2969
3859
|
<span class="badge ok">story ok</span>
|
|
2970
3860
|
</div>
|
|
2971
3861
|
<div>Basic menu with item rows and a separated destructive action</div>
|
|
2972
|
-
<div class="hint">A minimal DropdownMenu with four `Item`s — edit/duplicate/archive plus a
|
|
3862
|
+
<div class="hint">A minimal DropdownMenu with four `Item`s — edit/duplicate/archive plus a
|
|
3863
|
+
separator before a destructive delete. Use this as the starting point for
|
|
3864
|
+
most overflow menus.</div>
|
|
2973
3865
|
<pre><code>const Default = () => (
|
|
2974
3866
|
<DropdownMenu.Root>
|
|
2975
3867
|
<DropdownMenu.Trigger asChild>
|
|
@@ -3002,7 +3894,9 @@ label?: ReactNode</code></pre>
|
|
|
3002
3894
|
<span class="badge ok">story ok</span>
|
|
3003
3895
|
</div>
|
|
3004
3896
|
<div>Menu with multiple `Separator`-split groups and a disabled item</div>
|
|
3005
|
-
<div class="hint">Multiple clusters of `Item`s split by `Separator` rules — mirrors an
|
|
3897
|
+
<div class="hint">Multiple clusters of `Item`s split by `Separator` rules — mirrors an
|
|
3898
|
+
"edit history / clipboard / export" overflow menu. Demonstrates the
|
|
3899
|
+
`disabled` state on a menu row.</div>
|
|
3006
3900
|
<pre><code>const WithGroupsAndDividers = () => (
|
|
3007
3901
|
<DropdownMenu.Root>
|
|
3008
3902
|
<DropdownMenu.Trigger asChild>
|
|
@@ -3033,7 +3927,9 @@ label?: ReactNode</code></pre>
|
|
|
3033
3927
|
<span class="badge ok">story ok</span>
|
|
3034
3928
|
</div>
|
|
3035
3929
|
<div>Icon-leading items with a destructive delete row</div>
|
|
3036
|
-
<div class="hint">Menu items with leading icons and a destructive row using the
|
|
3930
|
+
<div class="hint">Menu items with leading icons and a destructive row using the
|
|
3931
|
+
`data-[highlighted]:bg-red-100` + `text-red-500` escape hatch. Use this
|
|
3932
|
+
pattern when a row should read as destructive.</div>
|
|
3037
3933
|
<pre><code>const WithIcons = () => (
|
|
3038
3934
|
<DropdownMenu.Root>
|
|
3039
3935
|
<DropdownMenu.Trigger asChild>
|
|
@@ -3066,7 +3962,9 @@ label?: ReactNode</code></pre>
|
|
|
3066
3962
|
<span class="badge ok">story ok</span>
|
|
3067
3963
|
</div>
|
|
3068
3964
|
<div>Menu with `Label`-titled sections and a destructive logout row</div>
|
|
3069
|
-
<div class="hint">`Label`-segmented Profile / Settings / Account sections with a
|
|
3965
|
+
<div class="hint">`Label`-segmented Profile / Settings / Account sections with a
|
|
3966
|
+
destructive Logout row. Use `Label` to name groups that would otherwise
|
|
3967
|
+
be ambiguous from the item text alone.</div>
|
|
3070
3968
|
<pre><code>const WithGroupTitles = () => (
|
|
3071
3969
|
<DropdownMenu.Root>
|
|
3072
3970
|
<DropdownMenu.Trigger asChild>
|
|
@@ -3112,7 +4010,9 @@ label?: ReactNode</code></pre>
|
|
|
3112
4010
|
<span class="badge ok">story ok</span>
|
|
3113
4011
|
</div>
|
|
3114
4012
|
<div>Single-level submenus for Share and Move-to flows</div>
|
|
3115
|
-
<div class="hint">One level of nesting: Share and Move-to submenus wired via `Sub` /
|
|
4013
|
+
<div class="hint">One level of nesting: Share and Move-to submenus wired via `Sub` /
|
|
4014
|
+
`SubTrigger` / `SubContent`. Each submenu is portaled independently so
|
|
4015
|
+
it escapes the parent's stacking context.</div>
|
|
3116
4016
|
<pre><code>const WithSubmenu = () => (
|
|
3117
4017
|
<DropdownMenu.Root>
|
|
3118
4018
|
<DropdownMenu.Trigger asChild>
|
|
@@ -3176,7 +4076,9 @@ label?: ReactNode</code></pre>
|
|
|
3176
4076
|
<span class="badge ok">story ok</span>
|
|
3177
4077
|
</div>
|
|
3178
4078
|
<div>Two-level nested submenus inside a parent menu</div>
|
|
3179
|
-
<div class="hint">Two levels of nesting: Organization → Teams → (Engineering, Design).
|
|
4079
|
+
<div class="hint">Two levels of nesting: Organization → Teams → (Engineering, Design).
|
|
4080
|
+
Deeper nesting is rarely a good UX — prefer splitting into separate
|
|
4081
|
+
screens once the tree grows past two levels.</div>
|
|
3180
4082
|
<pre><code>const NestedSubmenus = () => (
|
|
3181
4083
|
<DropdownMenu.Root>
|
|
3182
4084
|
<DropdownMenu.Trigger asChild>
|
|
@@ -3248,7 +4150,9 @@ label?: ReactNode</code></pre>
|
|
|
3248
4150
|
<span class="badge ok">story ok</span>
|
|
3249
4151
|
</div>
|
|
3250
4152
|
<div>Submenu with `disabled` items and a disabled `SubTrigger`</div>
|
|
3251
|
-
<div class="hint">Submenu that contains `disabled` `Item`s alongside a fully-disabled
|
|
4153
|
+
<div class="hint">Submenu that contains `disabled` `Item`s alongside a fully-disabled
|
|
4154
|
+
`SubTrigger`. Use `disabled` sparingly — prefer hiding unavailable
|
|
4155
|
+
actions outright unless the user needs to see them and understand why.</div>
|
|
3252
4156
|
<pre><code>const SubmenuWithDisabledItems = () => (
|
|
3253
4157
|
<DropdownMenu.Root>
|
|
3254
4158
|
<DropdownMenu.Trigger asChild>
|
|
@@ -3297,6 +4201,7 @@ label?: ReactNode</code></pre>
|
|
|
3297
4201
|
</div>
|
|
3298
4202
|
</div>
|
|
3299
4203
|
|
|
4204
|
+
|
|
3300
4205
|
</div>
|
|
3301
4206
|
</article>
|
|
3302
4207
|
<article
|
|
@@ -3311,16 +4216,35 @@ label?: ReactNode</code></pre>
|
|
|
3311
4216
|
<div class="title">
|
|
3312
4217
|
<h2><span class="status-dot dot-ok"></span> HoverCard.Root</h2>
|
|
3313
4218
|
<div class="badges">
|
|
3314
|
-
|
|
4219
|
+
<label for="c-10-components-hovercard-props" class="badge ok as-toggle">6 prop types</label>
|
|
3315
4220
|
|
|
3316
4221
|
<label for="c-10-components-hovercard-stories" class="badge ok as-toggle">7 stories</label>
|
|
3317
4222
|
|
|
4223
|
+
|
|
3318
4224
|
</div>
|
|
3319
4225
|
</div>
|
|
3320
4226
|
<div class="meta" title="./src/hover-card/hover-card.stories.tsx">components-hovercard · ./src/hover-card/hover-card.stories.tsx</div>
|
|
3321
|
-
|
|
3322
|
-
<div class="hint">HoverCard reveals rich, sighted-user preview content anchored to a trigger
|
|
3323
|
-
|
|
4227
|
+
<div>Root provider for a rich hover preview of an entity</div>
|
|
4228
|
+
<div class="hint">HoverCard reveals rich, sighted-user preview content anchored to a trigger
|
|
4229
|
+
on pointer hover or keyboard focus. Compose it from `Root` / `Trigger` /
|
|
4230
|
+
`Portal` / `Content`.
|
|
4231
|
+
|
|
4232
|
+
`Trigger` takes any focusable control through `asChild`; these stories use a
|
|
4233
|
+
`secondary` Button throughout. Radix mirrors open state onto whatever you
|
|
4234
|
+
pass, so the trigger can style itself off `data-state`.</div>
|
|
4235
|
+
<div class="kv"><span class="chip">summary: Root provider for a rich hover preview of an entity</span><span class="chip">see: {@link https://www.radix-ui.com/primitives/docs/components/hover-card Radix UI HoverCard}</span><span class="chip">example: ```tsx
|
|
4236
|
+
import { HoverCard } from '@agentero/design-system/hover-card';
|
|
4237
|
+
|
|
4238
|
+
<HoverCard.Root>
|
|
4239
|
+
<HoverCard.Trigger>@rafa</HoverCard.Trigger>
|
|
4240
|
+
<HoverCard.Portal>
|
|
4241
|
+
<HoverCard.Content>
|
|
4242
|
+
<ProfileCard />
|
|
4243
|
+
<HoverCard.Arrow />
|
|
4244
|
+
</HoverCard.Content>
|
|
4245
|
+
</HoverCard.Portal>
|
|
4246
|
+
</HoverCard.Root>
|
|
4247
|
+
```</span></div>
|
|
3324
4248
|
</div>
|
|
3325
4249
|
|
|
3326
4250
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -3329,11 +4253,33 @@ label?: ReactNode</code></pre>
|
|
|
3329
4253
|
<input id="c-10-components-hovercard-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
3330
4254
|
|
|
3331
4255
|
|
|
4256
|
+
<input id="c-10-components-hovercard-props" class="tg tg-props" type="checkbox" hidden />
|
|
3332
4257
|
|
|
3333
4258
|
<div class="panels">
|
|
3334
4259
|
|
|
3335
4260
|
|
|
3336
4261
|
|
|
4262
|
+
<div class="panel panel-props">
|
|
4263
|
+
<div class="note ok">
|
|
4264
|
+
<div class="row">
|
|
4265
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
4266
|
+
<span class="badge ok">6 prop types</span>
|
|
4267
|
+
</div>
|
|
4268
|
+
<pre><code>Component: src/hover-card/index.ts::HoverCard</code></pre>
|
|
4269
|
+
<pre><code>Props:</code></pre>
|
|
4270
|
+
<pre><code>children?: ReactNode
|
|
4271
|
+
|
|
4272
|
+
closeDelay?: number
|
|
4273
|
+
|
|
4274
|
+
defaultOpen?: boolean
|
|
4275
|
+
|
|
4276
|
+
onOpenChange?: (open: boolean) => void
|
|
4277
|
+
|
|
4278
|
+
open?: boolean
|
|
4279
|
+
|
|
4280
|
+
openDelay?: number</code></pre>
|
|
4281
|
+
</div>
|
|
4282
|
+
</div>
|
|
3337
4283
|
|
|
3338
4284
|
<div class="panel panel-stories">
|
|
3339
4285
|
|
|
@@ -3371,7 +4317,11 @@ label?: ReactNode</code></pre>
|
|
|
3371
4317
|
<span class="badge ok">story ok</span>
|
|
3372
4318
|
</div>
|
|
3373
4319
|
|
|
3374
|
-
<div class="hint">Brushing the trigger and leaving without ever reaching the card is the most
|
|
4320
|
+
<div class="hint">Brushing the trigger and leaving without ever reaching the card is the most
|
|
4321
|
+
common way a hover card gets dismissed, so the exit reverses the entrance
|
|
4322
|
+
from wherever it got to. Driving it with keyframes instead would restart the
|
|
4323
|
+
exit at full opacity and scale, popping the half-faded card to fully visible
|
|
4324
|
+
on its way out.</div>
|
|
3375
4325
|
<pre><code>const AbandonedHover = () => <HoverCard.Root openDelay={0} closeDelay={0}>
|
|
3376
4326
|
<HoverCard.Trigger asChild>
|
|
3377
4327
|
<Button variant="secondary">Hover me</Button>
|
|
@@ -3389,7 +4339,10 @@ label?: ReactNode</code></pre>
|
|
|
3389
4339
|
<span class="badge ok">story ok</span>
|
|
3390
4340
|
</div>
|
|
3391
4341
|
|
|
3392
|
-
<div class="hint">Opens on focus as a supplementary affordance. Note this is not the same as
|
|
4342
|
+
<div class="hint">Opens on focus as a supplementary affordance. Note this is not the same as
|
|
4343
|
+
being keyboard-accessible: focus does not move into the card and it closes
|
|
4344
|
+
on blur, so any interactive content inside stays unreachable by keyboard —
|
|
4345
|
+
never put essential actions there.</div>
|
|
3393
4346
|
<pre><code>const OpensOnFocus = () => <HoverCard.Root openDelay={0} closeDelay={0}>
|
|
3394
4347
|
<HoverCard.Trigger asChild>
|
|
3395
4348
|
<Button variant="secondary">Focus me</Button>
|
|
@@ -3435,7 +4388,10 @@ label?: ReactNode</code></pre>
|
|
|
3435
4388
|
<span class="badge ok">story ok</span>
|
|
3436
4389
|
</div>
|
|
3437
4390
|
|
|
3438
|
-
<div class="hint">The whole point of a HoverCard over a Tooltip: freely laid-out content that
|
|
4391
|
+
<div class="hint">The whole point of a HoverCard over a Tooltip: freely laid-out content that
|
|
4392
|
+
may include its own links and actions. Keep those actions at `secondary` or
|
|
4393
|
+
below — a primary CTA inside a card the keyboard can't reach reads as the
|
|
4394
|
+
main path to something it isn't. The trigger still has to stand on its own.</div>
|
|
3439
4395
|
<pre><code>const RichContent = () => <HoverCard.Root openDelay={0} closeDelay={0}>
|
|
3440
4396
|
<HoverCard.Trigger asChild>
|
|
3441
4397
|
<Button variant="secondary">Hover me</Button>
|
|
@@ -3476,7 +4432,9 @@ label?: ReactNode</code></pre>
|
|
|
3476
4432
|
<span class="badge ok">story ok</span>
|
|
3477
4433
|
</div>
|
|
3478
4434
|
|
|
3479
|
-
<div class="hint">An optional `Arrow` points back at the trigger; render it inside `Content`.
|
|
4435
|
+
<div class="hint">An optional `Arrow` points back at the trigger; render it inside `Content`.
|
|
4436
|
+
It carries the card's border down both slopes and leaves its base open, so
|
|
4437
|
+
the card and the point read as one shape on any background.</div>
|
|
3480
4438
|
<pre><code>const WithArrow = () => <HoverCard.Root openDelay={0} closeDelay={0}>
|
|
3481
4439
|
<HoverCard.Trigger asChild>
|
|
3482
4440
|
<Button variant="secondary">Hover me</Button>
|
|
@@ -3495,7 +4453,9 @@ label?: ReactNode</code></pre>
|
|
|
3495
4453
|
<span class="badge ok">story ok</span>
|
|
3496
4454
|
</div>
|
|
3497
4455
|
|
|
3498
|
-
<div class="hint">`openDelay` / `closeDelay` tune the hover latency. Default is a deliberate
|
|
4456
|
+
<div class="hint">`openDelay` / `closeDelay` tune the hover latency. Default is a deliberate
|
|
4457
|
+
`700ms` open so cards don't flash on incidental passes; drop it to `0` for
|
|
4458
|
+
trigger-dense UIs where an instant preview reads as more responsive.</div>
|
|
3499
4459
|
<pre><code>const Delays = () => (
|
|
3500
4460
|
// Grid rather than flex so both triggers take the wider label's width —
|
|
3501
4461
|
// a size difference would read as part of what the delay changes.
|
|
@@ -3525,6 +4485,7 @@ label?: ReactNode</code></pre>
|
|
|
3525
4485
|
</div>
|
|
3526
4486
|
</div>
|
|
3527
4487
|
|
|
4488
|
+
|
|
3528
4489
|
</div>
|
|
3529
4490
|
</article>
|
|
3530
4491
|
<article
|
|
@@ -3543,12 +4504,19 @@ label?: ReactNode</code></pre>
|
|
|
3543
4504
|
|
|
3544
4505
|
<label for="c-11-components-label-stories" class="badge ok as-toggle">4 stories</label>
|
|
3545
4506
|
|
|
4507
|
+
|
|
3546
4508
|
</div>
|
|
3547
4509
|
</div>
|
|
3548
4510
|
<div class="meta" title="./src/label/label.stories.tsx">components-label · ./src/label/label.stories.tsx</div>
|
|
3549
|
-
|
|
3550
|
-
<div class="hint">Label is the accessible caption for a form control, built on Radix's Label
|
|
3551
|
-
|
|
4511
|
+
<div>Accessible caption for a form control</div>
|
|
4512
|
+
<div class="hint">Label is the accessible caption for a form control, built on Radix's Label
|
|
4513
|
+
primitive: it associates with the control through `htmlFor` and does not select
|
|
4514
|
+
text on double-click.
|
|
4515
|
+
|
|
4516
|
+
`optional` and `required` are display-only affordances — the control itself
|
|
4517
|
+
still has to carry `required` / `aria-required`.</div>
|
|
4518
|
+
<div class="kv"><span class="chip">summary: Accessible caption for a form control</span><span class="chip">example: <Label htmlFor="phone" optional>Phone number</Label>
|
|
4519
|
+
<Input id="phone" type="tel" /></span></div>
|
|
3552
4520
|
</div>
|
|
3553
4521
|
|
|
3554
4522
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -3556,6 +4524,7 @@ label?: ReactNode</code></pre>
|
|
|
3556
4524
|
|
|
3557
4525
|
<input id="c-11-components-label-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
3558
4526
|
|
|
4527
|
+
|
|
3559
4528
|
<input id="c-11-components-label-props" class="tg tg-props" type="checkbox" hidden />
|
|
3560
4529
|
|
|
3561
4530
|
<div class="panels">
|
|
@@ -3565,7 +4534,7 @@ label?: ReactNode</code></pre>
|
|
|
3565
4534
|
<div class="panel panel-props">
|
|
3566
4535
|
<div class="note ok">
|
|
3567
4536
|
<div class="row">
|
|
3568
|
-
<span class="ex-name">Prop types <small>(react-
|
|
4537
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
3569
4538
|
<span class="badge ok">3 prop types</span>
|
|
3570
4539
|
</div>
|
|
3571
4540
|
<pre><code>Component: src/label/label.tsx::Label</code></pre>
|
|
@@ -3623,7 +4592,8 @@ required?: boolean = false</code></pre>
|
|
|
3623
4592
|
<span class="badge ok">story ok</span>
|
|
3624
4593
|
</div>
|
|
3625
4594
|
<div>Required field with a decorative asterisk</div>
|
|
3626
|
-
<div class="hint">Appends an asterisk. It is `aria-hidden`, so the control still needs its own
|
|
4595
|
+
<div class="hint">Appends an asterisk. It is `aria-hidden`, so the control still needs its own
|
|
4596
|
+
`required` attribute for assistive technology.</div>
|
|
3627
4597
|
<pre><code>const Required = () => <Label required>Full name</Label>;</code></pre>
|
|
3628
4598
|
</div>
|
|
3629
4599
|
<div class="note ok">
|
|
@@ -3632,11 +4602,13 @@ required?: boolean = false</code></pre>
|
|
|
3632
4602
|
<span class="badge ok">story ok</span>
|
|
3633
4603
|
</div>
|
|
3634
4604
|
<div>required takes precedence over optional</div>
|
|
3635
|
-
<div class="hint">Contradictory props do not throw — `required` wins and the optional suffix is
|
|
4605
|
+
<div class="hint">Contradictory props do not throw — `required` wins and the optional suffix is
|
|
4606
|
+
dropped, so a mistake never takes the page down.</div>
|
|
3636
4607
|
<pre><code>const RequiredWinsOverOptional = () => <Label optional required>Agency name</Label>;</code></pre>
|
|
3637
4608
|
</div>
|
|
3638
4609
|
</div>
|
|
3639
4610
|
|
|
4611
|
+
|
|
3640
4612
|
</div>
|
|
3641
4613
|
</article>
|
|
3642
4614
|
<article
|
|
@@ -3655,12 +4627,16 @@ required?: boolean = false</code></pre>
|
|
|
3655
4627
|
|
|
3656
4628
|
<label for="c-12-components-loading-stories" class="badge ok as-toggle">7 stories</label>
|
|
3657
4629
|
|
|
4630
|
+
|
|
3658
4631
|
</div>
|
|
3659
4632
|
</div>
|
|
3660
4633
|
<div class="meta" title="./src/loading/loading.stories.tsx">components-loading · ./src/loading/loading.stories.tsx</div>
|
|
3661
|
-
|
|
3662
|
-
<div class="hint">Loading displays a circular spinner that indicates an in-progress operation.
|
|
3663
|
-
|
|
4634
|
+
<div>Circular spinner for in-progress and loading states</div>
|
|
4635
|
+
<div class="hint">Loading displays a circular spinner that indicates an in-progress operation.
|
|
4636
|
+
Use for inline fetch, form submission, or asynchronous task indicators.
|
|
4637
|
+
The spinner inherits its color from the parent `color` and scales with the
|
|
4638
|
+
parent font size via `em`-based size variants (`sm`, `md`, `lg`).</div>
|
|
4639
|
+
<div class="kv"><span class="chip">summary: Circular spinner for in-progress and loading states</span><span class="chip">example: <Loading /></span><span class="chip">example: <Loading size="lg" className="text-text-default-brand-primary" /></span></div>
|
|
3664
4640
|
</div>
|
|
3665
4641
|
|
|
3666
4642
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -3668,6 +4644,7 @@ required?: boolean = false</code></pre>
|
|
|
3668
4644
|
|
|
3669
4645
|
<input id="c-12-components-loading-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
3670
4646
|
|
|
4647
|
+
|
|
3671
4648
|
<input id="c-12-components-loading-props" class="tg tg-props" type="checkbox" hidden />
|
|
3672
4649
|
|
|
3673
4650
|
<div class="panels">
|
|
@@ -3677,7 +4654,7 @@ required?: boolean = false</code></pre>
|
|
|
3677
4654
|
<div class="panel panel-props">
|
|
3678
4655
|
<div class="note ok">
|
|
3679
4656
|
<div class="row">
|
|
3680
|
-
<span class="ex-name">Prop types <small>(react-
|
|
4657
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
3681
4658
|
<span class="badge ok">1 prop type</span>
|
|
3682
4659
|
</div>
|
|
3683
4660
|
<pre><code>Component: src/loading/loading.tsx::Loading</code></pre>
|
|
@@ -3711,7 +4688,9 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3711
4688
|
<span class="badge ok">story ok</span>
|
|
3712
4689
|
</div>
|
|
3713
4690
|
<div>Default spinner at the `sm` size</div>
|
|
3714
|
-
<div class="hint">The default spinner at `size="sm"` (1em diameter), inheriting the current
|
|
4691
|
+
<div class="hint">The default spinner at `size="sm"` (1em diameter), inheriting the current
|
|
4692
|
+
text color. Matches the out-of-the-box behavior when Loading is dropped
|
|
4693
|
+
into any layout.</div>
|
|
3715
4694
|
<pre><code>const Default = () => <Loading size="sm" />;</code></pre>
|
|
3716
4695
|
</div>
|
|
3717
4696
|
<div class="note ok">
|
|
@@ -3720,7 +4699,8 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3720
4699
|
<span class="badge ok">story ok</span>
|
|
3721
4700
|
</div>
|
|
3722
4701
|
<div>Small 1em spinner for inline indicators</div>
|
|
3723
|
-
<div class="hint">Small spinner (1em diameter) — the default. Ideal for inline indicators,
|
|
4702
|
+
<div class="hint">Small spinner (1em diameter) — the default. Ideal for inline indicators,
|
|
4703
|
+
buttons, and compact layouts where the spinner needs to sit next to text.</div>
|
|
3724
4704
|
<pre><code>const SizeSm = () => <Loading size="sm" />;</code></pre>
|
|
3725
4705
|
</div>
|
|
3726
4706
|
<div class="note ok">
|
|
@@ -3729,7 +4709,8 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3729
4709
|
<span class="badge ok">story ok</span>
|
|
3730
4710
|
</div>
|
|
3731
4711
|
<div>Medium 1.5em spinner for cards and panels</div>
|
|
3732
|
-
<div class="hint">Medium spinner (1.5em diameter). Use for cards, panels, and standalone
|
|
4712
|
+
<div class="hint">Medium spinner (1.5em diameter). Use for cards, panels, and standalone
|
|
4713
|
+
loading states where the spinner is the primary visual signal.</div>
|
|
3733
4714
|
<pre><code>const SizeMd = () => <Loading size="md" />;</code></pre>
|
|
3734
4715
|
</div>
|
|
3735
4716
|
<div class="note ok">
|
|
@@ -3738,7 +4719,8 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3738
4719
|
<span class="badge ok">story ok</span>
|
|
3739
4720
|
</div>
|
|
3740
4721
|
<div>Large 2em spinner for page or section loading</div>
|
|
3741
|
-
<div class="hint">Large spinner (2em diameter). Use for page-level or section-level loading
|
|
4722
|
+
<div class="hint">Large spinner (2em diameter). Use for page-level or section-level loading
|
|
4723
|
+
where the spinner needs more visual weight.</div>
|
|
3742
4724
|
<pre><code>const SizeLg = () => <Loading size="lg" />;</code></pre>
|
|
3743
4725
|
</div>
|
|
3744
4726
|
<div class="note ok">
|
|
@@ -3747,7 +4729,8 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3747
4729
|
<span class="badge ok">story ok</span>
|
|
3748
4730
|
</div>
|
|
3749
4731
|
<div>Visual comparison of all three spinner sizes</div>
|
|
3750
|
-
<div class="hint">All three sizes rendered side by side for visual comparison of the
|
|
4732
|
+
<div class="hint">All three sizes rendered side by side for visual comparison of the
|
|
4733
|
+
`em`-based scaling. Each spinner inherits the same parent text color.</div>
|
|
3751
4734
|
<pre><code>const Sizes = () => (
|
|
3752
4735
|
<div style={{ display: 'flex', alignItems: 'center', gap: '2rem' }}>
|
|
3753
4736
|
{(['sm', 'md', 'lg'] as const).map(size => (
|
|
@@ -3762,7 +4745,9 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3762
4745
|
<span class="badge ok">story ok</span>
|
|
3763
4746
|
</div>
|
|
3764
4747
|
<div>Spinner color inherits from the parent text color</div>
|
|
3765
|
-
<div class="hint">The spinner color tracks the parent `color` (text color) via `border-current`.
|
|
4748
|
+
<div class="hint">The spinner color tracks the parent `color` (text color) via `border-current`.
|
|
4749
|
+
Wrap Loading in any element with a text color utility — or set `color` on
|
|
4750
|
+
Loading itself — and the spinner adopts that color without extra props.</div>
|
|
3766
4751
|
<pre><code>const InheritsColor = () => (
|
|
3767
4752
|
<div style={{ display: 'flex', alignItems: 'center', gap: '2rem' }}>
|
|
3768
4753
|
<div className="text-text-default-base-primary">
|
|
@@ -3783,7 +4768,9 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3783
4768
|
<span class="badge ok">story ok</span>
|
|
3784
4769
|
</div>
|
|
3785
4770
|
<div>Spinner on a dark-background surface</div>
|
|
3786
|
-
<div class="hint">Spinner on a dark surface to verify `border-current` contrast. The parent
|
|
4771
|
+
<div class="hint">Spinner on a dark surface to verify `border-current` contrast. The parent
|
|
4772
|
+
sets a light text color, which the spinner inherits so it remains visible
|
|
4773
|
+
against the dark background.</div>
|
|
3787
4774
|
<pre><code>const OnDarkSurface = () => (
|
|
3788
4775
|
<div className="flex items-center gap-8 rounded-lg bg-bg-button-primary-enable p-8 text-text-default-base-inverse-primary">
|
|
3789
4776
|
<Loading size="sm" />
|
|
@@ -3794,6 +4781,7 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3794
4781
|
</div>
|
|
3795
4782
|
</div>
|
|
3796
4783
|
|
|
4784
|
+
|
|
3797
4785
|
</div>
|
|
3798
4786
|
</article>
|
|
3799
4787
|
<article
|
|
@@ -3808,16 +4796,49 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3808
4796
|
<div class="title">
|
|
3809
4797
|
<h2><span class="status-dot dot-ok"></span> Modal.Root</h2>
|
|
3810
4798
|
<div class="badges">
|
|
3811
|
-
|
|
4799
|
+
<label for="c-13-components-modal-props" class="badge ok as-toggle">5 prop types</label>
|
|
3812
4800
|
|
|
3813
4801
|
<label for="c-13-components-modal-stories" class="badge ok as-toggle">6 stories</label>
|
|
3814
4802
|
|
|
4803
|
+
|
|
3815
4804
|
</div>
|
|
3816
4805
|
</div>
|
|
3817
4806
|
<div class="meta" title="./src/modal/modal.stories.tsx">components-modal · ./src/modal/modal.stories.tsx</div>
|
|
3818
|
-
|
|
3819
|
-
<div class="hint">Modal is a compound dialog built on Radix UI: `Root` owns the open state,
|
|
3820
|
-
|
|
4807
|
+
<div>Root provider for a Modal's open state</div>
|
|
4808
|
+
<div class="hint">Modal is a compound dialog built on Radix UI: `Root` owns the open state,
|
|
4809
|
+
`Content` is the centered surface (`size` md/lg), and `Title`/`Body`/`Footer`
|
|
4810
|
+
structure it. Close it with `Escape`, the overlay, the X button, or a
|
|
4811
|
+
`Modal.Close asChild` around your own button.
|
|
4812
|
+
|
|
4813
|
+
`Content` also takes `variant="alert"` for the modal the user has to answer:
|
|
4814
|
+
it drops all three implicit ways out and is announced as an `alertdialog`.</div>
|
|
4815
|
+
<div class="kv"><span class="chip">summary: Root provider for a Modal's open state</span><span class="chip">example: ```tsx
|
|
4816
|
+
import { Modal } from '@agentero/design-system/modal';
|
|
4817
|
+
|
|
4818
|
+
<Modal.Root open={isOpen} onOpenChange={setIsOpen}>
|
|
4819
|
+
<Modal.Content size="md">
|
|
4820
|
+
<Modal.Title>Delete carrier</Modal.Title>
|
|
4821
|
+
<Modal.Description>This action cannot be undone.</Modal.Description>
|
|
4822
|
+
<Modal.Footer>
|
|
4823
|
+
<Modal.Close asChild>
|
|
4824
|
+
<Button variant="ghost">Cancel</Button>
|
|
4825
|
+
</Modal.Close>
|
|
4826
|
+
<Button onClick={handleDelete}>Delete</Button>
|
|
4827
|
+
</Modal.Footer>
|
|
4828
|
+
</Modal.Content>
|
|
4829
|
+
</Modal.Root>
|
|
4830
|
+
```</span><span class="chip">example: ```tsx
|
|
4831
|
+
// Alert: no Escape, no overlay click, no X — the user must answer.
|
|
4832
|
+
<Modal.Root open={isOpen}>
|
|
4833
|
+
<Modal.Content variant="alert">
|
|
4834
|
+
<Modal.Title>Complete your Docusign integration</Modal.Title>
|
|
4835
|
+
<Modal.Body>Authorize access to finish connecting your account.</Modal.Body>
|
|
4836
|
+
<Modal.Footer>
|
|
4837
|
+
<Button onClick={handleAuthorize}>Authorize</Button>
|
|
4838
|
+
</Modal.Footer>
|
|
4839
|
+
</Modal.Content>
|
|
4840
|
+
</Modal.Root>
|
|
4841
|
+
```</span></div>
|
|
3821
4842
|
</div>
|
|
3822
4843
|
|
|
3823
4844
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -3826,11 +4847,31 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3826
4847
|
<input id="c-13-components-modal-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
3827
4848
|
|
|
3828
4849
|
|
|
4850
|
+
<input id="c-13-components-modal-props" class="tg tg-props" type="checkbox" hidden />
|
|
3829
4851
|
|
|
3830
4852
|
<div class="panels">
|
|
3831
4853
|
|
|
3832
4854
|
|
|
3833
4855
|
|
|
4856
|
+
<div class="panel panel-props">
|
|
4857
|
+
<div class="note ok">
|
|
4858
|
+
<div class="row">
|
|
4859
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
4860
|
+
<span class="badge ok">5 prop types</span>
|
|
4861
|
+
</div>
|
|
4862
|
+
<pre><code>Component: src/modal/index.ts::Modal</code></pre>
|
|
4863
|
+
<pre><code>Props:</code></pre>
|
|
4864
|
+
<pre><code>children?: ReactNode
|
|
4865
|
+
|
|
4866
|
+
defaultOpen?: boolean
|
|
4867
|
+
|
|
4868
|
+
modal?: boolean
|
|
4869
|
+
|
|
4870
|
+
onOpenChange?: (open: boolean) => void
|
|
4871
|
+
|
|
4872
|
+
open?: boolean</code></pre>
|
|
4873
|
+
</div>
|
|
4874
|
+
</div>
|
|
3834
4875
|
|
|
3835
4876
|
<div class="panel panel-stories">
|
|
3836
4877
|
|
|
@@ -3963,7 +5004,9 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3963
5004
|
<span class="badge ok">story ok</span>
|
|
3964
5005
|
</div>
|
|
3965
5006
|
|
|
3966
|
-
<div class="hint">`variant="alert"` for a decision the user cannot skip: `Escape` and overlay
|
|
5007
|
+
<div class="hint">`variant="alert"` for a decision the user cannot skip: `Escape` and overlay
|
|
5008
|
+
clicks are ignored, `Modal.Title` renders no X button, and the surface is
|
|
5009
|
+
announced as an `alertdialog`. Only the footer actions close it.</div>
|
|
3967
5010
|
<pre><code>const Alert = () => (
|
|
3968
5011
|
<Modal.Root>
|
|
3969
5012
|
<Modal.Trigger asChild>
|
|
@@ -3986,6 +5029,7 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
3986
5029
|
</div>
|
|
3987
5030
|
</div>
|
|
3988
5031
|
|
|
5032
|
+
|
|
3989
5033
|
</div>
|
|
3990
5034
|
</article>
|
|
3991
5035
|
<article
|
|
@@ -4004,12 +5048,29 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
4004
5048
|
|
|
4005
5049
|
<label for="c-14-components-pagination-stories" class="badge ok as-toggle">7 stories</label>
|
|
4006
5050
|
|
|
5051
|
+
|
|
4007
5052
|
</div>
|
|
4008
5053
|
</div>
|
|
4009
5054
|
<div class="meta" title="./src/pagination/pagination.stories.tsx">components-pagination · ./src/pagination/pagination.stories.tsx</div>
|
|
4010
|
-
|
|
4011
|
-
<div class="hint">Pagination is a 1-indexed paged navigation control with previous/next icon
|
|
4012
|
-
|
|
5055
|
+
<div>1-indexed paged navigation control with prev/next, numeric pages, and entries summary</div>
|
|
5056
|
+
<div class="hint">Pagination is a 1-indexed paged navigation control with previous/next icon
|
|
5057
|
+
buttons, numeric page buttons, and a leading "X - Y of Z" entries summary.
|
|
5058
|
+
The page list collapses long ranges with `…` ellipses so the control stays
|
|
5059
|
+
compact regardless of total page count. Use it for lists, tables, or grids
|
|
5060
|
+
that are split across pages.</div>
|
|
5061
|
+
<div class="kv"><span class="chip">summary: 1-indexed paged navigation control with prev/next, numeric pages, and entries summary</span><span class="chip">example: ```tsx
|
|
5062
|
+
import { useState } from 'react';
|
|
5063
|
+
import { Pagination } from '@agentero/design-system/pagination';
|
|
5064
|
+
|
|
5065
|
+
const [page, setPage] = useState(1);
|
|
5066
|
+
|
|
5067
|
+
<Pagination
|
|
5068
|
+
currentPage={page}
|
|
5069
|
+
pageSize={10}
|
|
5070
|
+
totalCount={1000}
|
|
5071
|
+
onPageChange={setPage}
|
|
5072
|
+
/>
|
|
5073
|
+
```</span></div>
|
|
4013
5074
|
</div>
|
|
4014
5075
|
|
|
4015
5076
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -4017,6 +5078,7 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
4017
5078
|
|
|
4018
5079
|
<input id="c-14-components-pagination-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4019
5080
|
|
|
5081
|
+
|
|
4020
5082
|
<input id="c-14-components-pagination-props" class="tg tg-props" type="checkbox" hidden />
|
|
4021
5083
|
|
|
4022
5084
|
<div class="panels">
|
|
@@ -4026,7 +5088,7 @@ size?: "sm" | "md" | "lg"</code></pre>
|
|
|
4026
5088
|
<div class="panel panel-props">
|
|
4027
5089
|
<div class="note ok">
|
|
4028
5090
|
<div class="row">
|
|
4029
|
-
<span class="ex-name">Prop types <small>(react-
|
|
5091
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
4030
5092
|
<span class="badge ok">5 prop types</span>
|
|
4031
5093
|
</div>
|
|
4032
5094
|
<pre><code>Component: src/pagination/pagination.tsx::Pagination</code></pre>
|
|
@@ -4061,7 +5123,9 @@ totalCount: number</code></pre>
|
|
|
4061
5123
|
<span class="badge ok">story ok</span>
|
|
4062
5124
|
</div>
|
|
4063
5125
|
<div>Default args playground for Pagination</div>
|
|
4064
|
-
<div class="hint">Default args playground. The first page of a 1,000-item list paged 10 at a
|
|
5126
|
+
<div class="hint">Default args playground. The first page of a 1,000-item list paged 10 at a
|
|
5127
|
+
time — renders pages 1–5, an ellipsis, and the last page (100), with the
|
|
5128
|
+
previous-page button disabled because we're on page 1.</div>
|
|
4065
5129
|
<pre><code>const Default = () => <Pagination currentPage={1} totalCount={1000} pageSize={10} onPageChange={fn()} />;</code></pre>
|
|
4066
5130
|
</div>
|
|
4067
5131
|
<div class="note ok">
|
|
@@ -4070,7 +5134,9 @@ totalCount: number</code></pre>
|
|
|
4070
5134
|
<span class="badge ok">story ok</span>
|
|
4071
5135
|
</div>
|
|
4072
5136
|
<div>Short page list with no ellipsis collapse</div>
|
|
4073
|
-
<div class="hint">Short list whose total pages fit in the visible window — no ellipsis is
|
|
5137
|
+
<div class="hint">Short list whose total pages fit in the visible window — no ellipsis is
|
|
5138
|
+
rendered. Exercises the `totalPageNumbers >= totalPageCount` branch in
|
|
5139
|
+
`getPages`.</div>
|
|
4074
5140
|
<pre><code>const FewPages = () => <Pagination
|
|
4075
5141
|
currentPage={2}
|
|
4076
5142
|
totalCount={30}
|
|
@@ -4083,7 +5149,8 @@ totalCount: number</code></pre>
|
|
|
4083
5149
|
<span class="badge ok">story ok</span>
|
|
4084
5150
|
</div>
|
|
4085
5151
|
<div>Right-side ellipsis only (current page near start)</div>
|
|
4086
|
-
<div class="hint">Current page sits near the start of the range — left ellipsis is hidden,
|
|
5152
|
+
<div class="hint">Current page sits near the start of the range — left ellipsis is hidden,
|
|
5153
|
+
right ellipsis is shown, and the last page button anchors the right edge.</div>
|
|
4087
5154
|
<pre><code>const DotsRight = () => <Pagination
|
|
4088
5155
|
currentPage={2}
|
|
4089
5156
|
totalCount={1000}
|
|
@@ -4096,7 +5163,8 @@ totalCount: number</code></pre>
|
|
|
4096
5163
|
<span class="badge ok">story ok</span>
|
|
4097
5164
|
</div>
|
|
4098
5165
|
<div>Left-side ellipsis only (current page near end)</div>
|
|
4099
|
-
<div class="hint">Current page sits near the end of the range — left ellipsis is shown, right
|
|
5166
|
+
<div class="hint">Current page sits near the end of the range — left ellipsis is shown, right
|
|
5167
|
+
ellipsis is hidden, and the first page button anchors the left edge.</div>
|
|
4100
5168
|
<pre><code>const DotsLeft = () => <Pagination
|
|
4101
5169
|
currentPage={99}
|
|
4102
5170
|
totalCount={1000}
|
|
@@ -4109,7 +5177,8 @@ totalCount: number</code></pre>
|
|
|
4109
5177
|
<span class="badge ok">story ok</span>
|
|
4110
5178
|
</div>
|
|
4111
5179
|
<div>Both ellipses visible (current page in middle)</div>
|
|
4112
|
-
<div class="hint">Current page sits in the middle of the range — both ellipses are visible,
|
|
5180
|
+
<div class="hint">Current page sits in the middle of the range — both ellipses are visible,
|
|
5181
|
+
with the first and last page buttons anchoring each edge.</div>
|
|
4113
5182
|
<pre><code>const DotsBoth = () => <Pagination
|
|
4114
5183
|
currentPage={50}
|
|
4115
5184
|
totalCount={1000}
|
|
@@ -4122,7 +5191,8 @@ totalCount: number</code></pre>
|
|
|
4122
5191
|
<span class="badge ok">story ok</span>
|
|
4123
5192
|
</div>
|
|
4124
5193
|
<div>Last page selected with disabled next button</div>
|
|
4125
|
-
<div class="hint">Last page selected — the next-page button is disabled and the active page
|
|
5194
|
+
<div class="hint">Last page selected — the next-page button is disabled and the active page
|
|
5195
|
+
indicator sits on the trailing number.</div>
|
|
4126
5196
|
<pre><code>const LastPage = () => <Pagination currentPage={100} totalCount={1000} pageSize={10} onPageChange={fn()} />;</code></pre>
|
|
4127
5197
|
</div>
|
|
4128
5198
|
<div class="note ok">
|
|
@@ -4131,7 +5201,9 @@ totalCount: number</code></pre>
|
|
|
4131
5201
|
<span class="badge ok">story ok</span>
|
|
4132
5202
|
</div>
|
|
4133
5203
|
<div>Interactive controlled example backed by `useState`</div>
|
|
4134
|
-
<div class="hint">Interactive controlled example. Local `useState` owns the page; clicking a
|
|
5204
|
+
<div class="hint">Interactive controlled example. Local `useState` owns the page; clicking a
|
|
5205
|
+
page, previous, or next button updates it so the active page indicator and
|
|
5206
|
+
entries summary follow along.</div>
|
|
4135
5207
|
<pre><code>const Controlled = ({ totalCount, pageSize }) => {
|
|
4136
5208
|
const [page, setPage] = useState(1);
|
|
4137
5209
|
|
|
@@ -4147,6 +5219,7 @@ totalCount: number</code></pre>
|
|
|
4147
5219
|
</div>
|
|
4148
5220
|
</div>
|
|
4149
5221
|
|
|
5222
|
+
|
|
4150
5223
|
</div>
|
|
4151
5224
|
</article>
|
|
4152
5225
|
<article
|
|
@@ -4161,16 +5234,32 @@ totalCount: number</code></pre>
|
|
|
4161
5234
|
<div class="title">
|
|
4162
5235
|
<h2><span class="status-dot dot-ok"></span> Popover.Root</h2>
|
|
4163
5236
|
<div class="badges">
|
|
4164
|
-
|
|
5237
|
+
<label for="c-15-components-popover-props" class="badge ok as-toggle">5 prop types</label>
|
|
4165
5238
|
|
|
4166
5239
|
<label for="c-15-components-popover-stories" class="badge ok as-toggle">4 stories</label>
|
|
4167
5240
|
|
|
5241
|
+
|
|
4168
5242
|
</div>
|
|
4169
5243
|
</div>
|
|
4170
5244
|
<div class="meta" title="./src/popover/popover.stories.tsx">components-popover · ./src/popover/popover.stories.tsx</div>
|
|
4171
|
-
|
|
4172
|
-
<div class="hint">Popover is a non-modal floating surface anchored to a trigger, used for
|
|
4173
|
-
|
|
5245
|
+
<div>Root provider for a floating interactive overlay</div>
|
|
5246
|
+
<div class="hint">Popover is a non-modal floating surface anchored to a trigger, used for
|
|
5247
|
+
rich interactive overlays such as forms, filters, and pickers. Compose it
|
|
5248
|
+
from `Root` / `Trigger` / `Content`, plus optional `Anchor` and `Close`.
|
|
5249
|
+
Built on Radix UI's Popover primitive, so focus management, dismissal, and
|
|
5250
|
+
collision detection come for free.</div>
|
|
5251
|
+
<div class="kv"><span class="chip">summary: Root provider for a floating interactive overlay</span><span class="chip">see: {@link https://www.radix-ui.com/primitives/docs/components/popover Radix UI Popover}</span><span class="chip">example: ```tsx
|
|
5252
|
+
import { Popover } from '@agentero/design-system/popover';
|
|
5253
|
+
|
|
5254
|
+
<Popover.Root>
|
|
5255
|
+
<Popover.Trigger asChild>
|
|
5256
|
+
<Button>Filters</Button>
|
|
5257
|
+
</Popover.Trigger>
|
|
5258
|
+
<Popover.Content align="start">
|
|
5259
|
+
<FiltersForm />
|
|
5260
|
+
</Popover.Content>
|
|
5261
|
+
</Popover.Root>
|
|
5262
|
+
```</span></div>
|
|
4174
5263
|
</div>
|
|
4175
5264
|
|
|
4176
5265
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -4179,11 +5268,31 @@ totalCount: number</code></pre>
|
|
|
4179
5268
|
<input id="c-15-components-popover-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4180
5269
|
|
|
4181
5270
|
|
|
5271
|
+
<input id="c-15-components-popover-props" class="tg tg-props" type="checkbox" hidden />
|
|
4182
5272
|
|
|
4183
5273
|
<div class="panels">
|
|
4184
5274
|
|
|
4185
5275
|
|
|
4186
5276
|
|
|
5277
|
+
<div class="panel panel-props">
|
|
5278
|
+
<div class="note ok">
|
|
5279
|
+
<div class="row">
|
|
5280
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
5281
|
+
<span class="badge ok">5 prop types</span>
|
|
5282
|
+
</div>
|
|
5283
|
+
<pre><code>Component: src/popover/index.ts::Popover</code></pre>
|
|
5284
|
+
<pre><code>Props:</code></pre>
|
|
5285
|
+
<pre><code>children?: ReactNode
|
|
5286
|
+
|
|
5287
|
+
defaultOpen?: boolean
|
|
5288
|
+
|
|
5289
|
+
modal?: boolean
|
|
5290
|
+
|
|
5291
|
+
onOpenChange?: (open: boolean) => void
|
|
5292
|
+
|
|
5293
|
+
open?: boolean</code></pre>
|
|
5294
|
+
</div>
|
|
5295
|
+
</div>
|
|
4187
5296
|
|
|
4188
5297
|
<div class="panel panel-stories">
|
|
4189
5298
|
|
|
@@ -4203,7 +5312,8 @@ totalCount: number</code></pre>
|
|
|
4203
5312
|
<span class="badge ok">story ok</span>
|
|
4204
5313
|
</div>
|
|
4205
5314
|
<div>Basic click-to-open popover surface</div>
|
|
4206
|
-
<div class="hint">A minimal Popover: a trigger button that reveals a short text surface on
|
|
5315
|
+
<div class="hint">A minimal Popover: a trigger button that reveals a short text surface on
|
|
5316
|
+
click and dismisses on outside click or Escape.</div>
|
|
4207
5317
|
<pre><code>const Default = () => (
|
|
4208
5318
|
<Popover.Root>
|
|
4209
5319
|
<Popover.Trigger asChild>
|
|
@@ -4245,7 +5355,8 @@ totalCount: number</code></pre>
|
|
|
4245
5355
|
<span class="badge ok">story ok</span>
|
|
4246
5356
|
</div>
|
|
4247
5357
|
<div>Popover holding an interactive form with a `Close` action</div>
|
|
4248
|
-
<div class="hint">Rich interactive content — the primary reason to reach for a Popover over a
|
|
5358
|
+
<div class="hint">Rich interactive content — the primary reason to reach for a Popover over a
|
|
5359
|
+
Tooltip. A `Close` inside the surface dismisses it after submitting.</div>
|
|
4249
5360
|
<pre><code>const WithForm = () => (
|
|
4250
5361
|
<Popover.Root>
|
|
4251
5362
|
<Popover.Trigger asChild>
|
|
@@ -4277,7 +5388,8 @@ totalCount: number</code></pre>
|
|
|
4277
5388
|
<span class="badge ok">story ok</span>
|
|
4278
5389
|
</div>
|
|
4279
5390
|
<div>Popover positioned against a separate `Anchor` element</div>
|
|
4280
|
-
<div class="hint">`Anchor` positions the Content against an element other than the Trigger —
|
|
5391
|
+
<div class="hint">`Anchor` positions the Content against an element other than the Trigger —
|
|
5392
|
+
useful when the visual anchor differs from the toggle button.</div>
|
|
4281
5393
|
<pre><code>const WithAnchor = () => (
|
|
4282
5394
|
<Popover.Root>
|
|
4283
5395
|
<div className="flex flex-col items-center gap-4">
|
|
@@ -4296,6 +5408,7 @@ totalCount: number</code></pre>
|
|
|
4296
5408
|
</div>
|
|
4297
5409
|
</div>
|
|
4298
5410
|
|
|
5411
|
+
|
|
4299
5412
|
</div>
|
|
4300
5413
|
</article>
|
|
4301
5414
|
<article
|
|
@@ -4314,12 +5427,18 @@ totalCount: number</code></pre>
|
|
|
4314
5427
|
|
|
4315
5428
|
<label for="c-16-components-progress-stories" class="badge ok as-toggle">4 stories</label>
|
|
4316
5429
|
|
|
5430
|
+
|
|
4317
5431
|
</div>
|
|
4318
5432
|
</div>
|
|
4319
5433
|
<div class="meta" title="./src/progress/progress.stories.tsx">components-progress · ./src/progress/progress.stories.tsx</div>
|
|
4320
|
-
|
|
4321
|
-
<div class="hint">Progress shows how far a bounded task has advanced. Pass `percentage`
|
|
4322
|
-
|
|
5434
|
+
<div>Horizontal progress bar with optional label</div>
|
|
5435
|
+
<div class="hint">Progress shows how far a bounded task has advanced. Pass `percentage`
|
|
5436
|
+
(0–100) and optionally a `label` rendered above the bar. The fill paints
|
|
5437
|
+
with `currentColor`, so recolor it with a plain text class — e.g.
|
|
5438
|
+
`className="text-brand-400"`.</div>
|
|
5439
|
+
<div class="kv"><span class="chip">summary: Horizontal progress bar with optional label</span><span class="chip">example: ```tsx
|
|
5440
|
+
<Progress percentage={62} label="Profile completion" className="text-brand-400" />
|
|
5441
|
+
```</span></div>
|
|
4323
5442
|
</div>
|
|
4324
5443
|
|
|
4325
5444
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -4327,6 +5446,7 @@ totalCount: number</code></pre>
|
|
|
4327
5446
|
|
|
4328
5447
|
<input id="c-16-components-progress-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4329
5448
|
|
|
5449
|
+
|
|
4330
5450
|
<input id="c-16-components-progress-props" class="tg tg-props" type="checkbox" hidden />
|
|
4331
5451
|
|
|
4332
5452
|
<div class="panels">
|
|
@@ -4336,7 +5456,7 @@ totalCount: number</code></pre>
|
|
|
4336
5456
|
<div class="panel panel-props">
|
|
4337
5457
|
<div class="note ok">
|
|
4338
5458
|
<div class="row">
|
|
4339
|
-
<span class="ex-name">Prop types <small>(react-
|
|
5459
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
4340
5460
|
<span class="badge ok">4 prop types</span>
|
|
4341
5461
|
</div>
|
|
4342
5462
|
<pre><code>Component: src/progress/progress.tsx::Progress</code></pre>
|
|
@@ -4429,6 +5549,7 @@ percentage: number</code></pre>
|
|
|
4429
5549
|
</div>
|
|
4430
5550
|
</div>
|
|
4431
5551
|
|
|
5552
|
+
|
|
4432
5553
|
</div>
|
|
4433
5554
|
</article>
|
|
4434
5555
|
<article
|
|
@@ -4447,12 +5568,16 @@ percentage: number</code></pre>
|
|
|
4447
5568
|
|
|
4448
5569
|
<label for="c-17-components-skeleton-stories" class="badge ok as-toggle">4 stories</label>
|
|
4449
5570
|
|
|
5571
|
+
|
|
4450
5572
|
</div>
|
|
4451
5573
|
</div>
|
|
4452
5574
|
<div class="meta" title="./src/skeleton/skeleton.stories.tsx">components-skeleton · ./src/skeleton/skeleton.stories.tsx</div>
|
|
4453
|
-
|
|
4454
|
-
<div class="hint">Skeleton renders a pulsing placeholder box while content loads. Size and
|
|
4455
|
-
|
|
5575
|
+
<div>Pulsing placeholder box for loading content</div>
|
|
5576
|
+
<div class="hint">Skeleton renders a pulsing placeholder box while content loads. Size and
|
|
5577
|
+
shape it with Tailwind classes to mirror the content it stands in for.</div>
|
|
5578
|
+
<div class="kv"><span class="chip">summary: Pulsing placeholder box for loading content</span><span class="chip">example: ```tsx
|
|
5579
|
+
<Skeleton className="h-4 w-30" />
|
|
5580
|
+
```</span></div>
|
|
4456
5581
|
</div>
|
|
4457
5582
|
|
|
4458
5583
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -4461,6 +5586,7 @@ percentage: number</code></pre>
|
|
|
4461
5586
|
<input id="c-17-components-skeleton-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4462
5587
|
|
|
4463
5588
|
|
|
5589
|
+
|
|
4464
5590
|
|
|
4465
5591
|
<div class="panels">
|
|
4466
5592
|
|
|
@@ -4538,6 +5664,7 @@ percentage: number</code></pre>
|
|
|
4538
5664
|
</div>
|
|
4539
5665
|
</div>
|
|
4540
5666
|
|
|
5667
|
+
|
|
4541
5668
|
</div>
|
|
4542
5669
|
</article>
|
|
4543
5670
|
<article
|
|
@@ -4552,16 +5679,19 @@ percentage: number</code></pre>
|
|
|
4552
5679
|
<div class="title">
|
|
4553
5680
|
<h2><span class="status-dot dot-ok"></span> Switch</h2>
|
|
4554
5681
|
<div class="badges">
|
|
4555
|
-
<label for="c-18-components-switch-props" class="badge ok as-toggle">
|
|
5682
|
+
<label for="c-18-components-switch-props" class="badge ok as-toggle">8 prop types</label>
|
|
4556
5683
|
|
|
4557
5684
|
<label for="c-18-components-switch-stories" class="badge ok as-toggle">7 stories</label>
|
|
4558
5685
|
|
|
5686
|
+
|
|
4559
5687
|
</div>
|
|
4560
5688
|
</div>
|
|
4561
5689
|
<div class="meta" title="./src/switch/switch.stories.tsx">components-switch · ./src/switch/switch.stories.tsx</div>
|
|
4562
|
-
|
|
4563
|
-
<div class="hint">Two-state toggle for a setting that takes effect immediately. Prefer it over
|
|
4564
|
-
|
|
5690
|
+
<div>Instant-effect on/off toggle built on Radix Switch</div>
|
|
5691
|
+
<div class="hint">Two-state toggle for a setting that takes effect immediately. Prefer it over
|
|
5692
|
+
a Checkbox for a single boolean that applies instantly, and pair it with a
|
|
5693
|
+
`<label htmlFor>` to give it an accessible name.</div>
|
|
5694
|
+
<div class="kv"><span class="chip">summary: Instant-effect on/off toggle built on Radix Switch</span><span class="chip">example: <Switch checked={enabled} onCheckedChange={setEnabled} /></span><span class="chip">example: <Switch id="email-notifications" label="Email" checked={on} onCheckedChange={setOn} /></span></div>
|
|
4565
5695
|
</div>
|
|
4566
5696
|
|
|
4567
5697
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -4569,6 +5699,7 @@ percentage: number</code></pre>
|
|
|
4569
5699
|
|
|
4570
5700
|
<input id="c-18-components-switch-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4571
5701
|
|
|
5702
|
+
|
|
4572
5703
|
<input id="c-18-components-switch-props" class="tg tg-props" type="checkbox" hidden />
|
|
4573
5704
|
|
|
4574
5705
|
<div class="panels">
|
|
@@ -4578,13 +5709,17 @@ percentage: number</code></pre>
|
|
|
4578
5709
|
<div class="panel panel-props">
|
|
4579
5710
|
<div class="note ok">
|
|
4580
5711
|
<div class="row">
|
|
4581
|
-
<span class="ex-name">Prop types <small>(react-
|
|
4582
|
-
<span class="badge ok">
|
|
5712
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
5713
|
+
<span class="badge ok">8 prop types</span>
|
|
4583
5714
|
</div>
|
|
4584
5715
|
<pre><code>Component: src/switch/switch.tsx::Switch</code></pre>
|
|
4585
5716
|
<pre><code>Props:</code></pre>
|
|
4586
5717
|
<pre><code>asChild?: boolean
|
|
4587
5718
|
|
|
5719
|
+
checked?: boolean
|
|
5720
|
+
|
|
5721
|
+
defaultChecked?: boolean
|
|
5722
|
+
|
|
4588
5723
|
/**
|
|
4589
5724
|
* Optional text rendered beside the toggle and associated with it via
|
|
4590
5725
|
* `htmlFor`. Provide an `id` so the association resolves. Omit it to keep
|
|
@@ -4592,6 +5727,10 @@ percentage: number</code></pre>
|
|
|
4592
5727
|
*/
|
|
4593
5728
|
label?: string
|
|
4594
5729
|
|
|
5730
|
+
onCheckedChange?: (checked: boolean) => void
|
|
5731
|
+
|
|
5732
|
+
required?: boolean
|
|
5733
|
+
|
|
4595
5734
|
reverse?: boolean
|
|
4596
5735
|
|
|
4597
5736
|
size?: "sm" | "md"</code></pre>
|
|
@@ -4695,7 +5834,8 @@ size?: "sm" | "md"</code></pre>
|
|
|
4695
5834
|
<span class="badge ok">story ok</span>
|
|
4696
5835
|
</div>
|
|
4697
5836
|
|
|
4698
|
-
<div class="hint">The built-in `label` prop renders an associated text label beside the toggle
|
|
5837
|
+
<div class="hint">The built-in `label` prop renders an associated text label beside the toggle
|
|
5838
|
+
(wired via `htmlFor`/`id`); `reverse` places the label before the toggle.</div>
|
|
4699
5839
|
<pre><code>const WithLabel = () => (
|
|
4700
5840
|
<div className="flex items-center gap-6">
|
|
4701
5841
|
<Switch id="with-label" label="Email" defaultChecked />
|
|
@@ -4726,6 +5866,7 @@ size?: "sm" | "md"</code></pre>
|
|
|
4726
5866
|
</div>
|
|
4727
5867
|
</div>
|
|
4728
5868
|
|
|
5869
|
+
|
|
4729
5870
|
</div>
|
|
4730
5871
|
</article>
|
|
4731
5872
|
<article
|
|
@@ -4740,16 +5881,34 @@ size?: "sm" | "md"</code></pre>
|
|
|
4740
5881
|
<div class="title">
|
|
4741
5882
|
<h2><span class="status-dot dot-ok"></span> Table.Root</h2>
|
|
4742
5883
|
<div class="badges">
|
|
4743
|
-
|
|
5884
|
+
<label for="c-19-components-table-props" class="badge ok as-toggle">6 prop types</label>
|
|
4744
5885
|
|
|
4745
5886
|
<label for="c-19-components-table-stories" class="badge ok as-toggle">9 stories</label>
|
|
4746
5887
|
|
|
5888
|
+
|
|
4747
5889
|
</div>
|
|
4748
5890
|
</div>
|
|
4749
5891
|
<div class="meta" title="./src/data-table/table.stories.tsx">components-table · ./src/data-table/table.stories.tsx</div>
|
|
4750
|
-
|
|
4751
|
-
<div class="hint">Low-level presentational table primitive: native `<table>` markup themed for
|
|
4752
|
-
|
|
5892
|
+
<div>Table root that owns the scroll viewport and `<table>` element</div>
|
|
5893
|
+
<div class="hint">Low-level presentational table primitive: native `<table>` markup themed for
|
|
5894
|
+
scrolling, sticky rows, cell padding, dividers, hover, and expandable rows.
|
|
5895
|
+
For sorting/toolbar/pagination, prefer `DataTable`.</div>
|
|
5896
|
+
<div class="kv"><span class="chip">summary: Table root that owns the scroll viewport and `<table>` element</span><span class="chip">example: ```tsx
|
|
5897
|
+
import { Table } from '@agentero/design-system/data-table';
|
|
5898
|
+
|
|
5899
|
+
<Table.Root size="md" sticky="head">
|
|
5900
|
+
<Table.Head>
|
|
5901
|
+
<Table.Row>
|
|
5902
|
+
<Table.Header>Name</Table.Header>
|
|
5903
|
+
</Table.Row>
|
|
5904
|
+
</Table.Head>
|
|
5905
|
+
<Table.Body>
|
|
5906
|
+
<Table.Row>
|
|
5907
|
+
<Table.Cell>Jane Doe</Table.Cell>
|
|
5908
|
+
</Table.Row>
|
|
5909
|
+
</Table.Body>
|
|
5910
|
+
</Table.Root>
|
|
5911
|
+
```</span></div>
|
|
4753
5912
|
</div>
|
|
4754
5913
|
|
|
4755
5914
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -4758,11 +5917,33 @@ size?: "sm" | "md"</code></pre>
|
|
|
4758
5917
|
<input id="c-19-components-table-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4759
5918
|
|
|
4760
5919
|
|
|
5920
|
+
<input id="c-19-components-table-props" class="tg tg-props" type="checkbox" hidden />
|
|
4761
5921
|
|
|
4762
5922
|
<div class="panels">
|
|
4763
5923
|
|
|
4764
5924
|
|
|
4765
5925
|
|
|
5926
|
+
<div class="panel panel-props">
|
|
5927
|
+
<div class="note ok">
|
|
5928
|
+
<div class="row">
|
|
5929
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
5930
|
+
<span class="badge ok">6 prop types</span>
|
|
5931
|
+
</div>
|
|
5932
|
+
<pre><code>Component: src/data-table/index.ts::Table</code></pre>
|
|
5933
|
+
<pre><code>Props:</code></pre>
|
|
5934
|
+
<pre><code>children?: ReactNode
|
|
5935
|
+
|
|
5936
|
+
embed?: boolean
|
|
5937
|
+
|
|
5938
|
+
enclosed?: boolean
|
|
5939
|
+
|
|
5940
|
+
ref?: Ref<HTMLDivElement> | undefined
|
|
5941
|
+
|
|
5942
|
+
size?: "sm" | "md" | "lg"
|
|
5943
|
+
|
|
5944
|
+
sticky?: "header" | "headerAndFooter"</code></pre>
|
|
5945
|
+
</div>
|
|
5946
|
+
</div>
|
|
4766
5947
|
|
|
4767
5948
|
<div class="panel panel-stories">
|
|
4768
5949
|
|
|
@@ -4837,7 +6018,8 @@ import { Fragment } from "react";</code></pre>
|
|
|
4837
6018
|
<span class="badge ok">story ok</span>
|
|
4838
6019
|
</div>
|
|
4839
6020
|
<div>enclosed — bordered, rounded card container</div>
|
|
4840
|
-
<div class="hint">`enclosed` wraps the table in a bordered, rounded container — the standalone
|
|
6021
|
+
<div class="hint">`enclosed` wraps the table in a bordered, rounded container — the standalone
|
|
6022
|
+
"card" look, as opposed to a full-bleed page table.</div>
|
|
4841
6023
|
<pre><code>const Enclosed = args => renderTable(args);</code></pre>
|
|
4842
6024
|
</div>
|
|
4843
6025
|
<div class="note ok">
|
|
@@ -4915,258 +6097,109 @@ import { Fragment } from "react";</code></pre>
|
|
|
4915
6097
|
</div>
|
|
4916
6098
|
</div>
|
|
4917
6099
|
|
|
6100
|
+
|
|
4918
6101
|
</div>
|
|
4919
6102
|
</article>
|
|
4920
6103
|
<article
|
|
4921
6104
|
class="card
|
|
4922
|
-
|
|
4923
|
-
|
|
6105
|
+
no-error
|
|
6106
|
+
no-info
|
|
4924
6107
|
no-story-error
|
|
4925
6108
|
no-doc-error"
|
|
4926
6109
|
role="listitem"
|
|
4927
6110
|
aria-label="Tabs.Root">
|
|
4928
6111
|
<div class="head">
|
|
4929
6112
|
<div class="title">
|
|
4930
|
-
<h2><span class="status-dot dot-
|
|
6113
|
+
<h2><span class="status-dot dot-ok"></span> Tabs.Root</h2>
|
|
4931
6114
|
<div class="badges">
|
|
4932
|
-
<label for="c-20-components-tabs-
|
|
4933
|
-
|
|
6115
|
+
<label for="c-20-components-tabs-props" class="badge ok as-toggle">9 prop types</label>
|
|
6116
|
+
|
|
4934
6117
|
<label for="c-20-components-tabs-stories" class="badge ok as-toggle">8 stories</label>
|
|
4935
6118
|
|
|
6119
|
+
|
|
4936
6120
|
</div>
|
|
4937
6121
|
</div>
|
|
4938
6122
|
<div class="meta" title="./src/tabs/tabs.stories.tsx">components-tabs · ./src/tabs/tabs.stories.tsx</div>
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
6123
|
+
<div>Root provider for a Tabs group</div>
|
|
6124
|
+
<div class="hint">Tabs is a compound built on Radix UI: `Root` owns the selected tab, `List`
|
|
6125
|
+
holds the `Trigger`s, and one `Content` renders per tab. `variant` picks the
|
|
6126
|
+
look — `line` (default) underlines the active tab, `enclosed` renders
|
|
6127
|
+
segmented pills, `button` renders button-like tabs.
|
|
6128
|
+
|
|
6129
|
+
`Label` is text styled as an inactive trigger, for a single title sitting in
|
|
6130
|
+
the same row as the tabs.</div>
|
|
6131
|
+
<div class="kv"><span class="chip">summary: Root provider for a Tabs group</span><span class="chip">example: ```tsx
|
|
6132
|
+
import { Tabs } from '@agentero/design-system/tabs';
|
|
6133
|
+
|
|
6134
|
+
<Tabs.Root defaultValue="overview">
|
|
6135
|
+
<Tabs.List>
|
|
6136
|
+
<Tabs.Trigger value="overview">Overview</Tabs.Trigger>
|
|
6137
|
+
<Tabs.Trigger value="activity">Activity</Tabs.Trigger>
|
|
6138
|
+
</Tabs.List>
|
|
6139
|
+
<Tabs.Content value="overview">…</Tabs.Content>
|
|
6140
|
+
<Tabs.Content value="activity">…</Tabs.Content>
|
|
6141
|
+
</Tabs.Root>
|
|
6142
|
+
```</span></div>
|
|
4942
6143
|
</div>
|
|
4943
6144
|
|
|
4944
6145
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
4945
|
-
|
|
4946
|
-
|
|
6146
|
+
|
|
6147
|
+
|
|
4947
6148
|
<input id="c-20-components-tabs-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4948
6149
|
|
|
4949
6150
|
|
|
6151
|
+
<input id="c-20-components-tabs-props" class="tg tg-props" type="checkbox" hidden />
|
|
4950
6152
|
|
|
4951
6153
|
<div class="panels">
|
|
4952
6154
|
|
|
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>
|
|
5161
6155
|
|
|
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>
|
|
5169
6156
|
|
|
6157
|
+
<div class="panel panel-props">
|
|
6158
|
+
<div class="note ok">
|
|
6159
|
+
<div class="row">
|
|
6160
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
6161
|
+
<span class="badge ok">9 prop types</span>
|
|
6162
|
+
</div>
|
|
6163
|
+
<pre><code>Component: src/tabs/index.ts::Tabs</code></pre>
|
|
6164
|
+
<pre><code>Props:</code></pre>
|
|
6165
|
+
<pre><code>/**
|
|
6166
|
+
* Whether a tab is activated automatically or manually.
|
|
6167
|
+
*/
|
|
6168
|
+
activationMode?: "manual" | "automatic" = automatic
|
|
6169
|
+
|
|
6170
|
+
asChild?: boolean
|
|
6171
|
+
|
|
6172
|
+
/**
|
|
6173
|
+
* The value of the tab to select by default, if uncontrolled
|
|
6174
|
+
*/
|
|
6175
|
+
defaultValue?: string
|
|
6176
|
+
|
|
6177
|
+
/**
|
|
6178
|
+
* The direction of navigation between toolbar items.
|
|
6179
|
+
*/
|
|
6180
|
+
dir?: "ltr" | "rtl"
|
|
6181
|
+
|
|
6182
|
+
/**
|
|
6183
|
+
* A function called when a new tab is selected
|
|
6184
|
+
*/
|
|
6185
|
+
onValueChange?: (value: string) => void
|
|
6186
|
+
|
|
6187
|
+
/**
|
|
6188
|
+
* The orientation the tabs are layed out.
|
|
6189
|
+
* Mainly so arrow navigation is done accordingly (left & right vs. up & down)
|
|
6190
|
+
*/
|
|
6191
|
+
orientation?: "horizontal" | "vertical" = horizontal
|
|
6192
|
+
|
|
6193
|
+
position?: "center" | "start" | "end" | "full"
|
|
6194
|
+
|
|
6195
|
+
/**
|
|
6196
|
+
* The value for the selected tab, if controlled
|
|
6197
|
+
*/
|
|
6198
|
+
value?: string
|
|
6199
|
+
|
|
6200
|
+
variant?: "enclosed" | "button" | "line"</code></pre>
|
|
6201
|
+
</div>
|
|
6202
|
+
</div>
|
|
5170
6203
|
|
|
5171
6204
|
<div class="panel panel-stories">
|
|
5172
6205
|
|
|
@@ -5268,7 +6301,9 @@ export const SingleTitle: Story = {
|
|
|
5268
6301
|
<span class="badge ok">story ok</span>
|
|
5269
6302
|
</div>
|
|
5270
6303
|
|
|
5271
|
-
<div class="hint">Triggers accept `asChild` to render as another element — e.g. a router link.
|
|
6304
|
+
<div class="hint">Triggers accept `asChild` to render as another element — e.g. a router link.
|
|
6305
|
+
The trigger resets the anchor's default underline, so link-based tabs match
|
|
6306
|
+
the button-based ones.</div>
|
|
5272
6307
|
<pre><code>const AsChildLinks = () => (
|
|
5273
6308
|
<Tabs.Root variant="line" defaultValue="overview">
|
|
5274
6309
|
<Tabs.List>
|
|
@@ -5302,7 +6337,11 @@ export const SingleTitle: Story = {
|
|
|
5302
6337
|
<span class="badge ok">story ok</span>
|
|
5303
6338
|
</div>
|
|
5304
6339
|
|
|
5305
|
-
<div class="hint">A standalone `Label` gives a panel with a single, non-interactive title the
|
|
6340
|
+
<div class="hint">A standalone `Label` gives a panel with a single, non-interactive title the
|
|
6341
|
+
inactive trigger's exact look: outside a `Root` it never gets the active
|
|
6342
|
+
data-state, and `pointer-events-none` keeps hover styles off. It is a plain
|
|
6343
|
+
`span`, so wrap it in a heading element for heading semantics. No tab or
|
|
6344
|
+
tablist role is announced.</div>
|
|
5306
6345
|
<pre><code>const SingleTitle = () => (
|
|
5307
6346
|
<div className="flex flex-col items-start gap-6">
|
|
5308
6347
|
{(['line', 'enclosed', 'button'] as const).map(variant => (
|
|
@@ -5315,6 +6354,7 @@ export const SingleTitle: Story = {
|
|
|
5315
6354
|
</div>
|
|
5316
6355
|
</div>
|
|
5317
6356
|
|
|
6357
|
+
|
|
5318
6358
|
</div>
|
|
5319
6359
|
</article>
|
|
5320
6360
|
<article
|
|
@@ -5329,16 +6369,22 @@ export const SingleTitle: Story = {
|
|
|
5329
6369
|
<div class="title">
|
|
5330
6370
|
<h2><span class="status-dot dot-ok"></span> Tag</h2>
|
|
5331
6371
|
<div class="badges">
|
|
5332
|
-
<label for="c-21-components-tag-props" class="badge ok as-toggle">
|
|
6372
|
+
<label for="c-21-components-tag-props" class="badge ok as-toggle">8 prop types</label>
|
|
5333
6373
|
|
|
5334
6374
|
<label for="c-21-components-tag-stories" class="badge ok as-toggle">10 stories</label>
|
|
5335
6375
|
|
|
6376
|
+
|
|
5336
6377
|
</div>
|
|
5337
6378
|
</div>
|
|
5338
6379
|
<div class="meta" title="./src/tag/tag.stories.tsx">components-tag · ./src/tag/tag.stories.tsx</div>
|
|
5339
|
-
|
|
5340
|
-
<div class="hint">Tag is a compact semantic label for statuses, categories, counts, and
|
|
5341
|
-
|
|
6380
|
+
<div>Compact semantic label; renders a static badge `<span>` or, with `asChild`, an interactive element</div>
|
|
6381
|
+
<div class="hint">Tag is a compact semantic label for statuses, categories, counts, and
|
|
6382
|
+
attributes. Pick `color` for meaning, `variant` for fill emphasis, and
|
|
6383
|
+
`size` for prominence. A plain Tag is a static badge; pass `asChild` to make
|
|
6384
|
+
it an interactive link or button, which adds the pointer cursor and hover fill.</div>
|
|
6385
|
+
<div class="kv"><span class="chip">summary: Compact semantic label; renders a static badge `<span>` or, with `asChild`, an interactive element</span><span class="chip">example: <Tag color="positive">Active</Tag></span><span class="chip">example: <Tag asChild color="informative">
|
|
6386
|
+
<a href="/carriers">View carriers</a>
|
|
6387
|
+
</Tag></span></div>
|
|
5342
6388
|
</div>
|
|
5343
6389
|
|
|
5344
6390
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -5346,6 +6392,7 @@ export const SingleTitle: Story = {
|
|
|
5346
6392
|
|
|
5347
6393
|
<input id="c-21-components-tag-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5348
6394
|
|
|
6395
|
+
|
|
5349
6396
|
<input id="c-21-components-tag-props" class="tg tg-props" type="checkbox" hidden />
|
|
5350
6397
|
|
|
5351
6398
|
<div class="panels">
|
|
@@ -5355,8 +6402,8 @@ export const SingleTitle: Story = {
|
|
|
5355
6402
|
<div class="panel panel-props">
|
|
5356
6403
|
<div class="note ok">
|
|
5357
6404
|
<div class="row">
|
|
5358
|
-
<span class="ex-name">Prop types <small>(react-
|
|
5359
|
-
<span class="badge ok">
|
|
6405
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
6406
|
+
<span class="badge ok">8 prop types</span>
|
|
5360
6407
|
</div>
|
|
5361
6408
|
<pre><code>Component: src/tag/tag.tsx::Tag</code></pre>
|
|
5362
6409
|
<pre><code>Props:</code></pre>
|
|
@@ -5367,10 +6414,19 @@ export const SingleTitle: Story = {
|
|
|
5367
6414
|
*/
|
|
5368
6415
|
asChild?: boolean
|
|
5369
6416
|
|
|
6417
|
+
children?: ReactNode
|
|
6418
|
+
|
|
5370
6419
|
color?: "neutral" | "danger" | "warning" | "creative" | "dynamic" | "playful" | "positive" | "informative"
|
|
5371
6420
|
|
|
5372
6421
|
pill?: boolean
|
|
5373
6422
|
|
|
6423
|
+
/**
|
|
6424
|
+
* Allows getting a ref to the component instance.
|
|
6425
|
+
* Once the component unmounts, React will set `ref.current` to `null`
|
|
6426
|
+
* (or call the ref with `null` if you passed a callback ref).
|
|
6427
|
+
*/
|
|
6428
|
+
ref?: ((((instance: HTMLSpanElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<HTMLSpanElement | null>) & (((instance: HTMLElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<...>)) | null | undefined
|
|
6429
|
+
|
|
5374
6430
|
size?: "sm" | "md" | "xs"
|
|
5375
6431
|
|
|
5376
6432
|
truncate?: boolean
|
|
@@ -5397,7 +6453,8 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5397
6453
|
<span class="badge ok">story ok</span>
|
|
5398
6454
|
</div>
|
|
5399
6455
|
<div>Default args playground for Tag</div>
|
|
5400
|
-
<div class="hint">Args-controlled playground. Toggle `color`, `variant`, `size`, `pill`, and
|
|
6456
|
+
<div class="hint">Args-controlled playground. Toggle `color`, `variant`, `size`, `pill`, and
|
|
6457
|
+
`truncate` from the Controls panel to explore every visual combination.</div>
|
|
5401
6458
|
<pre><code>const Default = () => <Tag color="neutral" variant="secondary" size="sm">Default</Tag>;</code></pre>
|
|
5402
6459
|
</div>
|
|
5403
6460
|
<div class="note ok">
|
|
@@ -5406,7 +6463,9 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5406
6463
|
<span class="badge ok">story ok</span>
|
|
5407
6464
|
</div>
|
|
5408
6465
|
<div>All three sizes across icon-only, icon + text, and text-only</div>
|
|
5409
|
-
<div class="hint">The three sizes — `xs` (20px), `sm` (24px, default), and `md` (32px) — each
|
|
6466
|
+
<div class="hint">The three sizes — `xs` (20px), `sm` (24px, default), and `md` (32px) — each
|
|
6467
|
+
shown icon-only, icon + text, and text-only so the type and icon scale are
|
|
6468
|
+
visible.</div>
|
|
5410
6469
|
<pre><code>const Sizes = () => (
|
|
5411
6470
|
<Stack>
|
|
5412
6471
|
{(['xs', 'sm', 'md'] as const).map(size => (
|
|
@@ -5440,7 +6499,8 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5440
6499
|
<span class="badge ok">story ok</span>
|
|
5441
6500
|
</div>
|
|
5442
6501
|
<div>Rounded (default) vs pill</div>
|
|
5443
|
-
<div class="hint">The `Style` axis: the default rounded corners (top row) versus `pill` fully
|
|
6502
|
+
<div class="hint">The `Style` axis: the default rounded corners (top row) versus `pill` fully
|
|
6503
|
+
rounded (bottom row), shown across every fill variant.</div>
|
|
5444
6504
|
<pre><code>const Styles = () => (
|
|
5445
6505
|
<Stack gap="0.5rem">
|
|
5446
6506
|
<Row>
|
|
@@ -5466,7 +6526,10 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5466
6526
|
<span class="badge ok">story ok</span>
|
|
5467
6527
|
</div>
|
|
5468
6528
|
<div>Static badge vs interactive (asChild) hover</div>
|
|
5469
|
-
<div class="hint">Static badge vs interactive Tag. A plain `<span>` badge has no hover; pass
|
|
6529
|
+
<div class="hint">Static badge vs interactive Tag. A plain `<span>` badge has no hover; pass
|
|
6530
|
+
`asChild` with a `<button>` (or `<a>`) to make it interactive — that adds the
|
|
6531
|
+
pointer cursor and reveals the hover fill on `:hover`. Hover the middle and
|
|
6532
|
+
right Tags to see it.</div>
|
|
5470
6533
|
<pre><code>const Interactive = () => (
|
|
5471
6534
|
<Row>
|
|
5472
6535
|
<Tag color="informative" variant="secondary">
|
|
@@ -5489,7 +6552,8 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5489
6552
|
<span class="badge ok">story ok</span>
|
|
5490
6553
|
</div>
|
|
5491
6554
|
<div>`secondary` variant across all colors</div>
|
|
5492
|
-
<div class="hint">`secondary` fills with a tinted background plus a matching border, shown
|
|
6555
|
+
<div class="hint">`secondary` fills with a tinted background plus a matching border, shown
|
|
6556
|
+
across every color.</div>
|
|
5493
6557
|
<pre><code>const Secondary = () => (
|
|
5494
6558
|
<Row>
|
|
5495
6559
|
{COLORS.map(color => (
|
|
@@ -5506,7 +6570,8 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5506
6570
|
<span class="badge ok">story ok</span>
|
|
5507
6571
|
</div>
|
|
5508
6572
|
<div>`tertiary` variant across all colors</div>
|
|
5509
|
-
<div class="hint">`tertiary` (default) fills with a tinted background and no border, shown
|
|
6573
|
+
<div class="hint">`tertiary` (default) fills with a tinted background and no border, shown
|
|
6574
|
+
across every color.</div>
|
|
5510
6575
|
<pre><code>const Tertiary = () => (
|
|
5511
6576
|
<Row>
|
|
5512
6577
|
{COLORS.map(color => (
|
|
@@ -5523,7 +6588,8 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5523
6588
|
<span class="badge ok">story ok</span>
|
|
5524
6589
|
</div>
|
|
5525
6590
|
<div>`ghost` variant across all colors</div>
|
|
5526
|
-
<div class="hint">`ghost` shows colored text alone with no background or border, across every
|
|
6591
|
+
<div class="hint">`ghost` shows colored text alone with no background or border, across every
|
|
6592
|
+
color.</div>
|
|
5527
6593
|
<pre><code>const Ghost = () => (
|
|
5528
6594
|
<Row>
|
|
5529
6595
|
{COLORS.map(color => (
|
|
@@ -5540,7 +6606,9 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5540
6606
|
<span class="badge ok">story ok</span>
|
|
5541
6607
|
</div>
|
|
5542
6608
|
<div>`invisible` variant as span and as interactive button</div>
|
|
5543
|
-
<div class="hint">`invisible` stays fully transparent until hovered, then reveals its fill.
|
|
6609
|
+
<div class="hint">`invisible` stays fully transparent until hovered, then reveals its fill.
|
|
6610
|
+
The top row renders plain `<span>` Tags; the bottom row renders interactive
|
|
6611
|
+
Tags via `asChild` with a `<button>` child.</div>
|
|
5544
6612
|
<pre><code>const Invisible = () => (
|
|
5545
6613
|
<Stack gap="0.5rem">
|
|
5546
6614
|
<Row>
|
|
@@ -5566,7 +6634,8 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5566
6634
|
<span class="badge ok">story ok</span>
|
|
5567
6635
|
</div>
|
|
5568
6636
|
<div>Variant × color grid with icons</div>
|
|
5569
|
-
<div class="hint">Every variant for every color rendered with a leading and trailing icon.
|
|
6637
|
+
<div class="hint">Every variant for every color rendered with a leading and trailing icon.
|
|
6638
|
+
Icons are tinted with each color's `icon-tag-*` token.</div>
|
|
5570
6639
|
<pre><code>const WithIcon = () => (
|
|
5571
6640
|
<Stack>
|
|
5572
6641
|
{COLORS.map(color => (
|
|
@@ -5589,7 +6658,9 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5589
6658
|
<span class="badge ok">story ok</span>
|
|
5590
6659
|
</div>
|
|
5591
6660
|
<div>Variant × color matrix — default, pill, button, and icon layouts</div>
|
|
5592
|
-
<div class="hint">Full matrix: every variant for every color, repeated as default, as `pill`,
|
|
6661
|
+
<div class="hint">Full matrix: every variant for every color, repeated as default, as `pill`,
|
|
6662
|
+
as an interactive `asChild` `<button>`, with a single leading icon, with
|
|
6663
|
+
leading + trailing icons, and icon-only.</div>
|
|
5593
6664
|
<pre><code>const Colors = () => (
|
|
5594
6665
|
<div style={{ display: 'flex', gap: '4rem', flexWrap: 'wrap' }}>
|
|
5595
6666
|
<Stack>
|
|
@@ -5689,6 +6760,7 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5689
6760
|
</div>
|
|
5690
6761
|
</div>
|
|
5691
6762
|
|
|
6763
|
+
|
|
5692
6764
|
</div>
|
|
5693
6765
|
</article>
|
|
5694
6766
|
<article
|
|
@@ -5707,12 +6779,18 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5707
6779
|
|
|
5708
6780
|
<label for="c-22-components-toast-stories" class="badge ok as-toggle">11 stories</label>
|
|
5709
6781
|
|
|
6782
|
+
|
|
5710
6783
|
</div>
|
|
5711
6784
|
</div>
|
|
5712
6785
|
<div class="meta" title="./src/toast/toast.stories.tsx">components-toast · ./src/toast/toast.stories.tsx</div>
|
|
5713
|
-
|
|
5714
|
-
<div class="hint">Toast renders transient feedback about an outcome — saved, failed, warning,
|
|
5715
|
-
|
|
6786
|
+
<div>Toast provider; mount once near the app root</div>
|
|
6787
|
+
<div class="hint">Toast renders transient feedback about an outcome — saved, failed, warning,
|
|
6788
|
+
info — without interrupting the user's flow. Mount `<Toast />` once near
|
|
6789
|
+
the app root to register the provider, then call the imperative `toast()`
|
|
6790
|
+
API from anywhere in the tree. Five semantic types (`neutral`, `success`,
|
|
6791
|
+
`error`, `warning`, `info`) × two layouts (`inline`, `expanded`) cover the
|
|
6792
|
+
common feedback patterns.</div>
|
|
6793
|
+
<div class="kv"><span class="chip">summary: Toast provider; mount once near the app root</span><span class="chip">example: <Toast /></span><span class="chip">example: <Toast position="top-center" duration={4000} /></span></div>
|
|
5716
6794
|
</div>
|
|
5717
6795
|
|
|
5718
6796
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -5720,6 +6798,7 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5720
6798
|
|
|
5721
6799
|
<input id="c-22-components-toast-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5722
6800
|
|
|
6801
|
+
|
|
5723
6802
|
<input id="c-22-components-toast-props" class="tg tg-props" type="checkbox" hidden />
|
|
5724
6803
|
|
|
5725
6804
|
<div class="panels">
|
|
@@ -5729,7 +6808,7 @@ variant?: "ghost" | "secondary" | "tertiary" | &qu
|
|
|
5729
6808
|
<div class="panel panel-props">
|
|
5730
6809
|
<div class="note ok">
|
|
5731
6810
|
<div class="row">
|
|
5732
|
-
<span class="ex-name">Prop types <small>(react-
|
|
6811
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
5733
6812
|
<span class="badge ok">11 prop types</span>
|
|
5734
6813
|
</div>
|
|
5735
6814
|
<pre><code>Component: src/toast/toast.tsx::Toast</code></pre>
|
|
@@ -5772,12 +6851,12 @@ invert?: boolean
|
|
|
5772
6851
|
/**
|
|
5773
6852
|
* Offset from the screen edge, in pixels or as a CSS length.
|
|
5774
6853
|
*/
|
|
5775
|
-
offset?: string | number
|
|
6854
|
+
offset?: string | number | undefined
|
|
5776
6855
|
|
|
5777
6856
|
/**
|
|
5778
6857
|
* Placement of the toaster on the screen. Defaults to `'bottom-right'`.
|
|
5779
6858
|
*/
|
|
5780
|
-
position?:
|
|
6859
|
+
position?: "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right" = 'bottom-right'
|
|
5781
6860
|
|
|
5782
6861
|
/**
|
|
5783
6862
|
* When `true`, sonner paints colored backgrounds per type (DS uses its own icon tokens by default).
|
|
@@ -5809,7 +6888,9 @@ visibleToasts?: number</code></pre>
|
|
|
5809
6888
|
<span class="badge ok">story ok</span>
|
|
5810
6889
|
</div>
|
|
5811
6890
|
<div>Default playground for the Toast provider</div>
|
|
5812
|
-
<div class="hint">Args-controlled playground. Click the button to fire a neutral toast; tweak
|
|
6891
|
+
<div class="hint">Args-controlled playground. Click the button to fire a neutral toast; tweak
|
|
6892
|
+
`position` and `duration` from the Controls panel to preview the provider
|
|
6893
|
+
defaults.</div>
|
|
5813
6894
|
<pre><code>const Default = () => (
|
|
5814
6895
|
<div style={{ minHeight: '240px' }}>
|
|
5815
6896
|
<Button variant="secondary" onClick={() => toast('Hello from Toast')}>
|
|
@@ -5824,7 +6905,9 @@ visibleToasts?: number</code></pre>
|
|
|
5824
6905
|
<span class="badge ok">story ok</span>
|
|
5825
6906
|
</div>
|
|
5826
6907
|
<div>Inline layout across all five semantic types</div>
|
|
5827
|
-
<div class="hint">Inline layout (default). Compact treatment — title with an optional
|
|
6908
|
+
<div class="hint">Inline layout (default). Compact treatment — title with an optional
|
|
6909
|
+
description stacked directly below it. The `type` drives the icon color.
|
|
6910
|
+
Use for short acknowledgments that don't need a colored rail.</div>
|
|
5828
6911
|
<pre><code>const Inline = () => (
|
|
5829
6912
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
|
|
5830
6913
|
<Button
|
|
@@ -5867,7 +6950,9 @@ visibleToasts?: number</code></pre>
|
|
|
5867
6950
|
<span class="badge ok">story ok</span>
|
|
5868
6951
|
</div>
|
|
5869
6952
|
<div>Expanded layout across all five semantic types</div>
|
|
5870
|
-
<div class="hint">Expanded layout. Multi-line treatment with a 0.375rem colored left rail
|
|
6953
|
+
<div class="hint">Expanded layout. Multi-line treatment with a 0.375rem colored left rail
|
|
6954
|
+
that tracks the toast's `type`. Use for feedback that benefits from a
|
|
6955
|
+
description on its own line or a trailing action button.</div>
|
|
5871
6956
|
<pre><code>const Expanded = () => (
|
|
5872
6957
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
|
|
5873
6958
|
<Button
|
|
@@ -5929,7 +7014,9 @@ visibleToasts?: number</code></pre>
|
|
|
5929
7014
|
<span class="badge ok">story ok</span>
|
|
5930
7015
|
</div>
|
|
5931
7016
|
<div>Toast with a structured action button</div>
|
|
5932
|
-
<div class="hint">Toast with a structured `action` object. Passing `{ label, onClick }`
|
|
7017
|
+
<div class="hint">Toast with a structured `action` object. Passing `{ label, onClick }`
|
|
7018
|
+
renders the built-in secondary Button; the handler runs and the toast
|
|
7019
|
+
auto-dismisses afterward.</div>
|
|
5933
7020
|
<pre><code>const WithActionObject = () => (
|
|
5934
7021
|
<Button
|
|
5935
7022
|
variant="secondary"
|
|
@@ -5950,7 +7037,9 @@ visibleToasts?: number</code></pre>
|
|
|
5950
7037
|
<span class="badge ok">story ok</span>
|
|
5951
7038
|
</div>
|
|
5952
7039
|
<div>Toast with a custom ReactNode action</div>
|
|
5953
|
-
<div class="hint">Toast with a raw-ReactNode `action`. Pass any JSX to render a custom
|
|
7040
|
+
<div class="hint">Toast with a raw-ReactNode `action`. Pass any JSX to render a custom
|
|
7041
|
+
trailing control — a link, a pair of buttons, etc. — when the default
|
|
7042
|
+
secondary Button doesn't fit.</div>
|
|
5954
7043
|
<pre><code>const WithActionNode = () => (
|
|
5955
7044
|
<Button
|
|
5956
7045
|
variant="secondary"
|
|
@@ -5974,7 +7063,8 @@ visibleToasts?: number</code></pre>
|
|
|
5974
7063
|
<span class="badge ok">story ok</span>
|
|
5975
7064
|
</div>
|
|
5976
7065
|
<div>Toast with an action and a cancel control</div>
|
|
5977
|
-
<div class="hint">Toast with both `action` and `cancel`. Cancel renders as a ghost Button
|
|
7066
|
+
<div class="hint">Toast with both `action` and `cancel`. Cancel renders as a ghost Button
|
|
7067
|
+
next to the action; its handler runs and the toast auto-dismisses.</div>
|
|
5978
7068
|
<pre><code>const WithActionAndCancel = () => (
|
|
5979
7069
|
<Button
|
|
5980
7070
|
variant="secondary"
|
|
@@ -5996,7 +7086,9 @@ visibleToasts?: number</code></pre>
|
|
|
5996
7086
|
<span class="badge ok">story ok</span>
|
|
5997
7087
|
</div>
|
|
5998
7088
|
<div>Non-dismissible toast (no close button)</div>
|
|
5999
|
-
<div class="hint">Non-dismissible toast. Setting `dismissible: false` hides the close button;
|
|
7089
|
+
<div class="hint">Non-dismissible toast. Setting `dismissible: false` hides the close button;
|
|
7090
|
+
the toast still auto-dismisses when its `duration` elapses, or
|
|
7091
|
+
programmatically via `toast.dismiss(id)`.</div>
|
|
6000
7092
|
<pre><code>const NonDismissible = () => (
|
|
6001
7093
|
<Button
|
|
6002
7094
|
variant="secondary"
|
|
@@ -6016,7 +7108,8 @@ visibleToasts?: number</code></pre>
|
|
|
6016
7108
|
<span class="badge ok">story ok</span>
|
|
6017
7109
|
</div>
|
|
6018
7110
|
<div>Toast with a custom `duration`</div>
|
|
6019
|
-
<div class="hint">Long-duration toast. `duration` (in ms) overrides the provider default so
|
|
7111
|
+
<div class="hint">Long-duration toast. `duration` (in ms) overrides the provider default so
|
|
7112
|
+
long-running operations stay visible until they're relevant.</div>
|
|
6020
7113
|
<pre><code>const LongDuration = () => (
|
|
6021
7114
|
<Button
|
|
6022
7115
|
variant="secondary"
|
|
@@ -6036,7 +7129,8 @@ visibleToasts?: number</code></pre>
|
|
|
6036
7129
|
<span class="badge ok">story ok</span>
|
|
6037
7130
|
</div>
|
|
6038
7131
|
<div>Dismiss a toast programmatically via its id</div>
|
|
6039
|
-
<div class="hint">Programmatic dismissal. `toast()` returns the toast id, which you can pass
|
|
7132
|
+
<div class="hint">Programmatic dismissal. `toast()` returns the toast id, which you can pass
|
|
7133
|
+
to `toast.dismiss(id)` to clear it before its duration elapses.</div>
|
|
6040
7134
|
<pre><code>const ProgrammaticDismiss = () => {
|
|
6041
7135
|
let toastId: string | number | undefined;
|
|
6042
7136
|
return (
|
|
@@ -6065,7 +7159,9 @@ visibleToasts?: number</code></pre>
|
|
|
6065
7159
|
<span class="badge ok">story ok</span>
|
|
6066
7160
|
</div>
|
|
6067
7161
|
<div>Wire a toast to an async operation via `toast.promise`</div>
|
|
6068
|
-
<div class="hint">`toast.promise` wires a toast to an async operation — loading while the
|
|
7162
|
+
<div class="hint">`toast.promise` wires a toast to an async operation — loading while the
|
|
7163
|
+
promise is pending, success or error when it settles. Useful for
|
|
7164
|
+
save/submit flows where the outcome feeds back into the same toast.</div>
|
|
6069
7165
|
<pre><code>const WithPromise = () => {
|
|
6070
7166
|
const fakeFetch = () =>
|
|
6071
7167
|
new Promise<string>((resolve, reject) => {
|
|
@@ -6095,7 +7191,9 @@ visibleToasts?: number</code></pre>
|
|
|
6095
7191
|
<span class="badge ok">story ok</span>
|
|
6096
7192
|
</div>
|
|
6097
7193
|
<div>Override the default type-based icon</div>
|
|
6098
|
-
<div class="hint">Custom `icon` override. Pass any ReactNode as `icon` to replace the
|
|
7194
|
+
<div class="hint">Custom `icon` override. Pass any ReactNode as `icon` to replace the
|
|
7195
|
+
type-based default — helpful when the toast reflects a domain-specific
|
|
7196
|
+
action (e.g., a sync icon for a sync-in-progress toast).</div>
|
|
6099
7197
|
<pre><code>const CustomIcon = () => (
|
|
6100
7198
|
<Button
|
|
6101
7199
|
variant="secondary"
|
|
@@ -6115,6 +7213,7 @@ visibleToasts?: number</code></pre>
|
|
|
6115
7213
|
</div>
|
|
6116
7214
|
</div>
|
|
6117
7215
|
|
|
7216
|
+
|
|
6118
7217
|
</div>
|
|
6119
7218
|
</article>
|
|
6120
7219
|
<article
|
|
@@ -6129,16 +7228,22 @@ visibleToasts?: number</code></pre>
|
|
|
6129
7228
|
<div class="title">
|
|
6130
7229
|
<h2><span class="status-dot dot-ok"></span> Tooltip</h2>
|
|
6131
7230
|
<div class="badges">
|
|
6132
|
-
<label for="c-23-components-tooltip-props" class="badge ok as-toggle">
|
|
7231
|
+
<label for="c-23-components-tooltip-props" class="badge ok as-toggle">12 prop types</label>
|
|
6133
7232
|
|
|
6134
7233
|
<label for="c-23-components-tooltip-stories" class="badge ok as-toggle">5 stories</label>
|
|
6135
7234
|
|
|
7235
|
+
|
|
6136
7236
|
</div>
|
|
6137
7237
|
</div>
|
|
6138
7238
|
<div class="meta" title="./src/tooltip/tooltip.stories.tsx">components-tooltip · ./src/tooltip/tooltip.stories.tsx</div>
|
|
6139
|
-
|
|
6140
|
-
<div class="hint">Tooltip reveals a short, non-essential hint anchored to a trigger element
|
|
6141
|
-
|
|
7239
|
+
<div>Hover/focus hint anchored to a trigger element</div>
|
|
7240
|
+
<div class="hint">Tooltip reveals a short, non-essential hint anchored to a trigger element
|
|
7241
|
+
on hover or focus.</div>
|
|
7242
|
+
<div class="kv"><span class="chip">summary: Hover/focus hint anchored to a trigger element</span><span class="chip">example: ```tsx
|
|
7243
|
+
<Tooltip content="Archive this carrier" asChild>
|
|
7244
|
+
<IconButton aria-label="Archive"><IconArchive /></IconButton>
|
|
7245
|
+
</Tooltip>
|
|
7246
|
+
```</span></div>
|
|
6142
7247
|
</div>
|
|
6143
7248
|
|
|
6144
7249
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -6146,6 +7251,7 @@ visibleToasts?: number</code></pre>
|
|
|
6146
7251
|
|
|
6147
7252
|
<input id="c-23-components-tooltip-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
6148
7253
|
|
|
7254
|
+
|
|
6149
7255
|
<input id="c-23-components-tooltip-props" class="tg tg-props" type="checkbox" hidden />
|
|
6150
7256
|
|
|
6151
7257
|
<div class="panels">
|
|
@@ -6155,8 +7261,8 @@ visibleToasts?: number</code></pre>
|
|
|
6155
7261
|
<div class="panel panel-props">
|
|
6156
7262
|
<div class="note ok">
|
|
6157
7263
|
<div class="row">
|
|
6158
|
-
<span class="ex-name">Prop types <small>(react-
|
|
6159
|
-
<span class="badge ok">
|
|
7264
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
7265
|
+
<span class="badge ok">12 prop types</span>
|
|
6160
7266
|
</div>
|
|
6161
7267
|
<pre><code>Component: src/tooltip/tooltip.tsx::Tooltip</code></pre>
|
|
6162
7268
|
<pre><code>Props:</code></pre>
|
|
@@ -6185,6 +7291,8 @@ className?: string
|
|
|
6185
7291
|
*/
|
|
6186
7292
|
content: ReactNode
|
|
6187
7293
|
|
|
7294
|
+
defaultOpen?: boolean
|
|
7295
|
+
|
|
6188
7296
|
/**
|
|
6189
7297
|
* Delay in ms before opening on hover. Defaults to `0`; focus always opens instantly.
|
|
6190
7298
|
*/
|
|
@@ -6195,10 +7303,14 @@ delayDuration?: number = 0
|
|
|
6195
7303
|
*/
|
|
6196
7304
|
hideWhenDetached?: boolean
|
|
6197
7305
|
|
|
7306
|
+
onOpenChange?: (open: boolean) => void
|
|
7307
|
+
|
|
7308
|
+
open?: boolean
|
|
7309
|
+
|
|
6198
7310
|
/**
|
|
6199
7311
|
* Preferred side of the trigger; flips on collision. Defaults to `'top'`.
|
|
6200
7312
|
*/
|
|
6201
|
-
side?: "
|
|
7313
|
+
side?: "right" | "top" | "bottom" | "left" = 'top'
|
|
6202
7314
|
|
|
6203
7315
|
/**
|
|
6204
7316
|
* Distance in pixels between the tooltip and its trigger. Defaults to `4`.
|
|
@@ -6297,6 +7409,7 @@ sideOffset?: number = 4</code></pre>
|
|
|
6297
7409
|
</div>
|
|
6298
7410
|
</div>
|
|
6299
7411
|
|
|
7412
|
+
|
|
6300
7413
|
</div>
|
|
6301
7414
|
</article>
|
|
6302
7415
|
<article
|
|
@@ -6315,12 +7428,20 @@ sideOffset?: number = 4</code></pre>
|
|
|
6315
7428
|
|
|
6316
7429
|
<label for="c-24-components-validationlist-stories" class="badge ok as-toggle">4 stories</label>
|
|
6317
7430
|
|
|
7431
|
+
|
|
6318
7432
|
</div>
|
|
6319
7433
|
</div>
|
|
6320
7434
|
<div class="meta" title="./src/validation-list/validation-list.stories.tsx">components-validationlist · ./src/validation-list/validation-list.stories.tsx</div>
|
|
6321
|
-
|
|
6322
|
-
<div class="hint">ValidationList renders a bulleted checklist of rules that light up as a value
|
|
6323
|
-
|
|
7435
|
+
<div>Checklist of rules that turn active as the value satisfies them</div>
|
|
7436
|
+
<div class="hint">ValidationList renders a bulleted checklist of rules that light up as a value
|
|
7437
|
+
satisfies them. Each rule's `pattern` is a `RegExp` or a predicate
|
|
7438
|
+
`(value) => boolean`, so character-class checks and arbitrary logic (length,
|
|
7439
|
+
membership, …) live in the same list. It is presentational — pair it with
|
|
7440
|
+
your form validation; it does not own the input or block submission.</div>
|
|
7441
|
+
<div class="kv"><span class="chip">summary: Checklist of rules that turn active as the value satisfies them</span><span class="chip">example: <ValidationList
|
|
7442
|
+
value={password}
|
|
7443
|
+
rules={[{ text: 'At least 10 characters', pattern: value => value.length >= 10 }]}
|
|
7444
|
+
/></span></div>
|
|
6324
7445
|
</div>
|
|
6325
7446
|
|
|
6326
7447
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
@@ -6328,6 +7449,7 @@ sideOffset?: number = 4</code></pre>
|
|
|
6328
7449
|
|
|
6329
7450
|
<input id="c-24-components-validationlist-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
6330
7451
|
|
|
7452
|
+
|
|
6331
7453
|
<input id="c-24-components-validationlist-props" class="tg tg-props" type="checkbox" hidden />
|
|
6332
7454
|
|
|
6333
7455
|
<div class="panels">
|
|
@@ -6337,7 +7459,7 @@ sideOffset?: number = 4</code></pre>
|
|
|
6337
7459
|
<div class="panel panel-props">
|
|
6338
7460
|
<div class="note ok">
|
|
6339
7461
|
<div class="row">
|
|
6340
|
-
<span class="ex-name">Prop types <small>(react-
|
|
7462
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
6341
7463
|
<span class="badge ok">2 prop types</span>
|
|
6342
7464
|
</div>
|
|
6343
7465
|
<pre><code>Component: src/validation-list/validation-list.tsx::ValidationList</code></pre>
|
|
@@ -6412,420 +7534,11 @@ value: string</code></pre>
|
|
|
6412
7534
|
</div>
|
|
6413
7535
|
</div>
|
|
6414
7536
|
|
|
6415
|
-
</div>
|
|
6416
|
-
</article>
|
|
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
7537
|
|
|
6449
7538
|
</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>
|
|
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>
|
|
7539
|
+
</article>
|
|
6674
7540
|
</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
7541
|
|
|
6825
|
-
</div>
|
|
6826
|
-
</article></div>
|
|
6827
|
-
</section>
|
|
6828
|
-
</div>
|
|
6829
7542
|
|
|
6830
7543
|
|
|
6831
7544
|
</div>
|