@agentero/design-system 0.8.4 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -576,13 +576,13 @@
576
576
  <header>
577
577
  <div class="wrap">
578
578
  <h1>Manifest Debugger</h1>
579
- <div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><span class="filter-pill ok" aria-disabled="true">9 components ok</span><span class="filter-pill ok" aria-disabled="true">109 stories ok</span></div>
579
+ <div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><span class="filter-pill ok" aria-disabled="true">10 components ok</span><span class="filter-pill ok" aria-disabled="true">108 stories ok</span></div>
580
580
  </div>
581
581
  </header>
582
582
  <main>
583
583
  <div class="wrap">
584
584
  <div class="note ok" style="margin-bottom: 16px;">
585
- Using <code>react-docgen-typescript</code>. Generation took <strong>2.3s</strong>.
585
+ Using <code>react-docgen-typescript</code>. Generation took <strong>1.9s</strong>.
586
586
  </div>
587
587
  <h2 class="section-title">Components</h2>
588
588
  <div class="grid" role="list">
@@ -1923,6 +1923,137 @@ variant?: ButtonVariantType</code></pre>
1923
1923
 
1924
1924
  </div>
1925
1925
  </article>
1926
+ <article
1927
+ class="card
1928
+ no-error
1929
+ no-info
1930
+ no-story-error
1931
+ no-doc-error"
1932
+ role="listitem"
1933
+ aria-label="DataTable.Root">
1934
+ <div class="head">
1935
+ <div class="title">
1936
+ <h2><span class="status-dot dot-ok"></span> DataTable.Root</h2>
1937
+ <div class="badges">
1938
+
1939
+
1940
+ <label for="c-3-components-datatable-stories" class="badge ok as-toggle">3 stories</label>
1941
+
1942
+ </div>
1943
+ </div>
1944
+ <div class="meta" title="./src/data-table/data-table.stories.tsx">components-datatable · ./src/data-table/data-table.stories.tsx</div>
1945
+
1946
+ <div class="hint">DataTable is the data-driven table compound built on TanStack Table. This story shows a representative leads table: an `Applicant` column with a name + address, contact info, insurance type with an icon, a sortable `Created` column, a status badge, and hover-revealed row actions (open + a kebab menu). The toolbar (search + filters) and the footer pagination are **separate components** composed inside `ToolBar` / `Footer`.</div>
1947
+
1948
+ </div>
1949
+
1950
+ <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
1951
+
1952
+
1953
+ <input id="c-3-components-datatable-stories" class="tg tg-stories" type="checkbox" hidden />
1954
+
1955
+
1956
+
1957
+ <div class="panels">
1958
+
1959
+
1960
+
1961
+
1962
+ <div class="panel panel-stories">
1963
+
1964
+
1965
+
1966
+ <div class="note ok">
1967
+ <div class="row">
1968
+ <span class="ex-name">Imports</span>
1969
+ </div>
1970
+ <pre><code>import { Button, DataTable, DropdownMenu, Pagination, Table } from "@agentero/design-system";</code></pre>
1971
+ </div>
1972
+
1973
+
1974
+ <div class="note ok">
1975
+ <div class="row">
1976
+ <span class="ex-name">Leads</span>
1977
+ <span class="badge ok">story ok</span>
1978
+ </div>
1979
+ <div>Representative leads table composition</div>
1980
+ <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>
1981
+ <pre><code>const Leads = () =&gt; {
1982
+ const [sorting, setSorting] = useState&lt;SortingState&gt;([]);
1983
+ const [page, setPage] = useState(1);
1984
+ const [search, setSearch] = useState(&#39;&#39;);
1985
+
1986
+ const data = useMemo(
1987
+ () =&gt; LEADS.filter(l =&gt; l.contact.toLowerCase().includes(search.toLowerCase())),
1988
+ [search]
1989
+ );
1990
+
1991
+ return (
1992
+ &lt;DataTable.Root
1993
+ data={data}
1994
+ columns={columns}
1995
+ state={{ sorting }}
1996
+ onSortingChange={setSorting}
1997
+ getSortedRowModel={getSortedRowModel()}
1998
+ enableSortingRemoval={false}
1999
+ rowHref={lead =&gt; `/leads/${lead.leadId}`}&gt;
2000
+ &lt;DataTable.ToolBar&gt;
2001
+ &lt;input
2002
+ value={search}
2003
+ onChange={e =&gt; setSearch(e.target.value)}
2004
+ placeholder=&quot;Search...&quot;
2005
+ aria-label=&quot;Search leads&quot;
2006
+ className=&quot;h-8 w-60 rounded-md border border-border-default-base-primary px-3 text-sm outline-none&quot;
2007
+ /&gt;
2008
+ &lt;Button variant=&quot;secondary&quot; size=&quot;sm&quot;&gt;
2009
+ Filters
2010
+ &lt;/Button&gt;
2011
+ &lt;/DataTable.ToolBar&gt;
2012
+
2013
+ &lt;DataTable.Table /&gt;
2014
+
2015
+ &lt;DataTable.Footer&gt;
2016
+ &lt;Pagination
2017
+ totalCount={LEADS.length}
2018
+ currentPage={page}
2019
+ pageSize={10}
2020
+ onPageChange={setPage}
2021
+ /&gt;
2022
+ &lt;/DataTable.Footer&gt;
2023
+ &lt;/DataTable.Root&gt;
2024
+ );
2025
+ };</code></pre>
2026
+ </div>
2027
+ <div class="note ok">
2028
+ <div class="row">
2029
+ <span class="ex-name">Empty</span>
2030
+ <span class="badge ok">story ok</span>
2031
+ </div>
2032
+ <div>Empty state when there are no rows</div>
2033
+ <div class="hint">No rows: the table renders its default empty state instead of body rows.</div>
2034
+ <pre><code>const Empty = () =&gt; (
2035
+ &lt;DataTable.Root data={[] as Lead[]} columns={columns}&gt;
2036
+ &lt;DataTable.Table /&gt;
2037
+ &lt;/DataTable.Root&gt;
2038
+ );</code></pre>
2039
+ </div>
2040
+ <div class="note ok">
2041
+ <div class="row">
2042
+ <span class="ex-name">Loading</span>
2043
+ <span class="badge ok">story ok</span>
2044
+ </div>
2045
+ <div>Loading state dims the table and hides the empty state</div>
2046
+ <div class="hint">Loading: the body is dimmed and the empty state is suppressed while data is in flight.</div>
2047
+ <pre><code>const Loading = () =&gt; (
2048
+ &lt;DataTable.Root data={[] as Lead[]} columns={columns} isLoading&gt;
2049
+ &lt;DataTable.Table /&gt;
2050
+ &lt;/DataTable.Root&gt;
2051
+ );</code></pre>
2052
+ </div>
2053
+ </div>
2054
+
2055
+ </div>
2056
+ </article>
1926
2057
  <article
1927
2058
  class="card
1928
2059
  no-error
@@ -1935,9 +2066,9 @@ variant?: ButtonVariantType</code></pre>
1935
2066
  <div class="title">
1936
2067
  <h2><span class="status-dot dot-ok"></span> Divider</h2>
1937
2068
  <div class="badges">
1938
- <label for="c-3-components-divider-props" class="badge ok as-toggle">2 prop types</label>
2069
+ <label for="c-4-components-divider-props" class="badge ok as-toggle">2 prop types</label>
1939
2070
 
1940
- <label for="c-3-components-divider-stories" class="badge ok as-toggle">10 stories</label>
2071
+ <label for="c-4-components-divider-stories" class="badge ok as-toggle">10 stories</label>
1941
2072
 
1942
2073
  </div>
1943
2074
  </div>
@@ -1950,9 +2081,9 @@ variant?: ButtonVariantType</code></pre>
1950
2081
  <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
1951
2082
 
1952
2083
 
1953
- <input id="c-3-components-divider-stories" class="tg tg-stories" type="checkbox" hidden />
2084
+ <input id="c-4-components-divider-stories" class="tg tg-stories" type="checkbox" hidden />
1954
2085
 
1955
- <input id="c-3-components-divider-props" class="tg tg-props" type="checkbox" hidden />
2086
+ <input id="c-4-components-divider-props" class="tg tg-props" type="checkbox" hidden />
1956
2087
 
1957
2088
  <div class="panels">
1958
2089
 
@@ -2232,7 +2363,7 @@ label?: ReactNode</code></pre>
2232
2363
  <div class="badges">
2233
2364
 
2234
2365
 
2235
- <label for="c-4-components-dropdownmenu-stories" class="badge ok as-toggle">7 stories</label>
2366
+ <label for="c-5-components-dropdownmenu-stories" class="badge ok as-toggle">7 stories</label>
2236
2367
 
2237
2368
  </div>
2238
2369
  </div>
@@ -2245,7 +2376,7 @@ label?: ReactNode</code></pre>
2245
2376
  <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
2246
2377
 
2247
2378
 
2248
- <input id="c-4-components-dropdownmenu-stories" class="tg tg-stories" type="checkbox" hidden />
2379
+ <input id="c-5-components-dropdownmenu-stories" class="tg tg-stories" type="checkbox" hidden />
2249
2380
 
2250
2381
 
2251
2382
 
@@ -2614,9 +2745,9 @@ label?: ReactNode</code></pre>
2614
2745
  <div class="title">
2615
2746
  <h2><span class="status-dot dot-ok"></span> Loading</h2>
2616
2747
  <div class="badges">
2617
- <label for="c-5-components-loading-props" class="badge ok as-toggle">1 prop type</label>
2748
+ <label for="c-6-components-loading-props" class="badge ok as-toggle">1 prop type</label>
2618
2749
 
2619
- <label for="c-5-components-loading-stories" class="badge ok as-toggle">7 stories</label>
2750
+ <label for="c-6-components-loading-stories" class="badge ok as-toggle">7 stories</label>
2620
2751
 
2621
2752
  </div>
2622
2753
  </div>
@@ -2629,9 +2760,9 @@ label?: ReactNode</code></pre>
2629
2760
  <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
2630
2761
 
2631
2762
 
2632
- <input id="c-5-components-loading-stories" class="tg tg-stories" type="checkbox" hidden />
2763
+ <input id="c-6-components-loading-stories" class="tg tg-stories" type="checkbox" hidden />
2633
2764
 
2634
- <input id="c-5-components-loading-props" class="tg tg-props" type="checkbox" hidden />
2765
+ <input id="c-6-components-loading-props" class="tg tg-props" type="checkbox" hidden />
2635
2766
 
2636
2767
  <div class="panels">
2637
2768
 
@@ -2771,9 +2902,9 @@ size?: &quot;sm&quot; | &quot;md&quot; | &quot;lg&quot;</code></pre>
2771
2902
  <div class="title">
2772
2903
  <h2><span class="status-dot dot-ok"></span> Pagination</h2>
2773
2904
  <div class="badges">
2774
- <label for="c-6-components-pagination-props" class="badge ok as-toggle">5 prop types</label>
2905
+ <label for="c-7-components-pagination-props" class="badge ok as-toggle">5 prop types</label>
2775
2906
 
2776
- <label for="c-6-components-pagination-stories" class="badge ok as-toggle">7 stories</label>
2907
+ <label for="c-7-components-pagination-stories" class="badge ok as-toggle">7 stories</label>
2777
2908
 
2778
2909
  </div>
2779
2910
  </div>
@@ -2786,9 +2917,9 @@ size?: &quot;sm&quot; | &quot;md&quot; | &quot;lg&quot;</code></pre>
2786
2917
  <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
2787
2918
 
2788
2919
 
2789
- <input id="c-6-components-pagination-stories" class="tg tg-stories" type="checkbox" hidden />
2920
+ <input id="c-7-components-pagination-stories" class="tg tg-stories" type="checkbox" hidden />
2790
2921
 
2791
- <input id="c-6-components-pagination-props" class="tg tg-props" type="checkbox" hidden />
2922
+ <input id="c-7-components-pagination-props" class="tg tg-props" type="checkbox" hidden />
2792
2923
 
2793
2924
  <div class="panels">
2794
2925
 
@@ -2927,27 +3058,27 @@ totalCount: number</code></pre>
2927
3058
  no-story-error
2928
3059
  no-doc-error"
2929
3060
  role="listitem"
2930
- aria-label="StatusBall">
3061
+ aria-label="Table.Root">
2931
3062
  <div class="head">
2932
3063
  <div class="title">
2933
- <h2><span class="status-dot dot-ok"></span> StatusBall</h2>
3064
+ <h2><span class="status-dot dot-ok"></span> Table.Root</h2>
2934
3065
  <div class="badges">
2935
3066
 
2936
3067
 
2937
- <label for="c-7-components-statusball-stories" class="badge ok as-toggle">12 stories</label>
3068
+ <label for="c-8-components-table-stories" class="badge ok as-toggle">8 stories</label>
2938
3069
 
2939
3070
  </div>
2940
3071
  </div>
2941
- <div class="meta" title="./src/status-ball/status-ball.stories.tsx">components-statusball · ./src/status-ball/status-ball.stories.tsx</div>
3072
+ <div class="meta" title="./src/data-table/table.stories.tsx">components-table · ./src/data-table/table.stories.tsx</div>
2942
3073
 
2943
- <div class="hint">StatusBall renders a small colored dot that marks the state of an adjacent label — appointment confirmation, license validity, availability, or any list row where a single glyph of color communicates status. Pair it with text; the dot alone is not announced to assistive technologies, so the surrounding label must carry the meaning.</div>
3074
+ <div class="hint">Low-level presentational table primitive: native `&lt;table&gt;` markup themed for scrolling, sticky rows, cell padding, dividers, hover, and expandable rows. For sorting/toolbar/pagination, prefer `DataTable`.</div>
2944
3075
 
2945
3076
  </div>
2946
3077
 
2947
3078
  <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
2948
3079
 
2949
3080
 
2950
- <input id="c-7-components-statusball-stories" class="tg tg-stories" type="checkbox" hidden />
3081
+ <input id="c-8-components-table-stories" class="tg tg-stories" type="checkbox" hidden />
2951
3082
 
2952
3083
 
2953
3084
 
@@ -2964,7 +3095,8 @@ totalCount: number</code></pre>
2964
3095
  <div class="row">
2965
3096
  <span class="ex-name">Imports</span>
2966
3097
  </div>
2967
- <pre><code>import { StatusBall } from "@agentero/design-system";</code></pre>
3098
+ <pre><code>import { Button, Table } from "@agentero/design-system";
3099
+ import { Fragment } from "react";</code></pre>
2968
3100
  </div>
2969
3101
 
2970
3102
 
@@ -2973,169 +3105,128 @@ totalCount: number</code></pre>
2973
3105
  <span class="ex-name">Default</span>
2974
3106
  <span class="badge ok">story ok</span>
2975
3107
  </div>
2976
- <div>Default neutral dot representing an inactive status</div>
2977
- <div class="hint">The default dot — `color=&quot;neutral&quot;` for an unknown or inactive status. Drop next to a text label to surface state at a glance.</div>
2978
- <pre><code>const Default = () =&gt; &lt;div className=&quot;flex items-center gap-2&quot;&gt;
2979
- &lt;StatusBall color=&quot;neutral&quot; /&gt;
2980
- &lt;/div&gt;;</code></pre>
2981
- </div>
2982
- <div class="note ok">
2983
- <div class="row">
2984
- <span class="ex-name">Intents</span>
2985
- <span class="badge ok">story ok</span>
2986
- </div>
2987
- <div>Every intent paired with a representative status label</div>
2988
- <div class="hint">All 8 semantic intents rendered in a single grid, each paired with a sample label. Consumers typically drive the `color` prop from a domain-specific status → intent lookup table.</div>
2989
- <pre><code>const Intents = () =&gt; {
2990
- const samples: { color: (typeof INTENTS)[number]; label: string }[] = [
2991
- { color: &#39;success&#39;, label: &#39;Active&#39; },
2992
- { color: &#39;info&#39;, label: &#39;Scheduled&#39; },
2993
- { color: &#39;warning&#39;, label: &#39;Pending&#39; },
2994
- { color: &#39;danger&#39;, label: &#39;Expired&#39; },
2995
- { color: &#39;creative&#39;, label: &#39;In review&#39; },
2996
- { color: &#39;playful&#39;, label: &#39;Flagged&#39; },
2997
- { color: &#39;dynamic&#39;, label: &#39;Needs attention&#39; },
2998
- { color: &#39;neutral&#39;, label: &#39;Inactive&#39; }
2999
- ];
3000
-
3001
- return (
3002
- &lt;div className=&quot;grid grid-cols-2 gap-x-8 gap-y-3&quot;&gt;
3003
- {samples.map(({ color, label }) =&gt; (
3004
- &lt;div key={color} className=&quot;flex items-center gap-2&quot;&gt;
3005
- &lt;StatusBall color={color} /&gt;
3006
- &lt;span className=&quot;text-sm text-text-default-base-primary&quot;&gt;{label}&lt;/span&gt;
3007
- &lt;/div&gt;
3008
- ))}
3009
- &lt;/div&gt;
3010
- );
3011
- };</code></pre>
3012
- </div>
3013
- <div class="note ok">
3014
- <div class="row">
3015
- <span class="ex-name">Success</span>
3016
- <span class="badge ok">story ok</span>
3017
- </div>
3018
- <div>Success dot for positive or active statuses</div>
3019
- <div class="hint">Success dot for positive / active states — the most common pairing for &quot;live&quot; records such as active licenses or confirmed appointments.</div>
3020
- <pre><code>const Success = () =&gt; &lt;StatusBall color=&quot;success&quot; data-testid=&quot;status-ball-success&quot; /&gt;;</code></pre>
3021
- </div>
3022
- <div class="note ok">
3023
- <div class="row">
3024
- <span class="ex-name">Info</span>
3025
- <span class="badge ok">story ok</span>
3026
- </div>
3027
- <div>Info dot for informational statuses</div>
3028
- <div class="hint">Info dot for informational or neutral-positive states — e.g., scheduled or queued records that are progressing normally.</div>
3029
- <pre><code>const Info = () =&gt; &lt;StatusBall color=&quot;info&quot; /&gt;;</code></pre>
3108
+ <div>Default table</div>
3109
+ <div class="hint">Default args playground.</div>
3110
+ <pre><code>const Default = args =&gt; renderTable(args);</code></pre>
3030
3111
  </div>
3031
3112
  <div class="note ok">
3032
3113
  <div class="row">
3033
- <span class="ex-name">Warning</span>
3114
+ <span class="ex-name">Sizes</span>
3034
3115
  <span class="badge ok">story ok</span>
3035
3116
  </div>
3036
- <div>Warning dot for pending or approaching-deadline statuses</div>
3037
- <div class="hint">Warning dot for pending states or records approaching a deadline — e.g., a license nearing expiration or an appointment awaiting confirmation.</div>
3038
- <pre><code>const Warning = () =&gt; &lt;StatusBall color=&quot;warning&quot; /&gt;;</code></pre>
3117
+ <div>size — sm / md / lg</div>
3118
+ <div class="hint">The three row densities. `size` sets row min-height: sm 48 / md 64 / lg 88px.</div>
3119
+ <pre><code>const Sizes = () =&gt; (
3120
+ &lt;div className=&quot;flex flex-col gap-6&quot;&gt;
3121
+ {([&#39;sm&#39;, &#39;md&#39;, &#39;lg&#39;] as const).map(size =&gt; (
3122
+ &lt;div key={size} className=&quot;flex flex-col gap-1&quot;&gt;
3123
+ &lt;span className=&quot;text-xs text-text-default-base-tertiary&quot;&gt;size=&amp;quot;{size}&amp;quot;&lt;/span&gt;
3124
+ {renderTable({ size })}
3125
+ &lt;/div&gt;
3126
+ ))}
3127
+ &lt;/div&gt;
3128
+ );</code></pre>
3039
3129
  </div>
3040
3130
  <div class="note ok">
3041
3131
  <div class="row">
3042
- <span class="ex-name">Danger</span>
3132
+ <span class="ex-name">Sticky Header</span>
3043
3133
  <span class="badge ok">story ok</span>
3044
3134
  </div>
3045
- <div>Danger dot for error or expired statuses</div>
3046
- <div class="hint">Danger dot for error / expired / blocking states — e.g., an expired license or a failed payment that blocks progress.</div>
3047
- <pre><code>const Danger = () =&gt; &lt;StatusBall color=&quot;danger&quot; /&gt;;</code></pre>
3135
+ <div>sticky=&quot;header&quot; with a scrolling body</div>
3136
+ <div class="hint">`sticky=&quot;header&quot;` pins the header while the body scrolls. Needs a bounded-height parent.</div>
3137
+ <pre><code>const StickyHeader = args =&gt; renderTable(args);</code></pre>
3048
3138
  </div>
3049
3139
  <div class="note ok">
3050
3140
  <div class="row">
3051
- <span class="ex-name">Creative</span>
3141
+ <span class="ex-name">Sticky Header And Footer</span>
3052
3142
  <span class="badge ok">story ok</span>
3053
3143
  </div>
3054
- <div>Creative dot for category-specific statuses</div>
3055
- <div class="hint">Creative dot for category-specific statuses without a direct success/info/ warning/danger mapping — often used for &quot;in review&quot; or &quot;under assessment&quot; domain states.</div>
3056
- <pre><code>const Creative = () =&gt; &lt;StatusBall color=&quot;creative&quot; /&gt;;</code></pre>
3144
+ <div>sticky=&quot;headerAndFooter&quot; with a pinned totals row</div>
3145
+ <div class="hint">`sticky=&quot;headerAndFooter&quot;` pins the header and the last body row (totals here).</div>
3146
+ <pre><code>const StickyHeaderAndFooter = args =&gt; renderTable(args, { totals: true });</code></pre>
3057
3147
  </div>
3058
3148
  <div class="note ok">
3059
3149
  <div class="row">
3060
- <span class="ex-name">Dynamic</span>
3150
+ <span class="ex-name">Embed</span>
3061
3151
  <span class="badge ok">story ok</span>
3062
3152
  </div>
3063
- <div>Dynamic dot for attention-needed statuses</div>
3064
- <div class="hint">Dynamic dot for attention-worthy states that sit between warning and danger — e.g., records that need action soon but are not yet failed.</div>
3065
- <pre><code>const Dynamic = () =&gt; &lt;StatusBall color=&quot;dynamic&quot; /&gt;;</code></pre>
3153
+ <div>embed — no row dividers, 1rem edge gutter</div>
3154
+ <div class="hint">`embed` drops the per-row dividers and tightens the edge gutter to 1rem.</div>
3155
+ <pre><code>const Embed = args =&gt; renderTable(args);</code></pre>
3066
3156
  </div>
3067
3157
  <div class="note ok">
3068
3158
  <div class="row">
3069
- <span class="ex-name">Playful</span>
3159
+ <span class="ex-name">With Checkbox</span>
3070
3160
  <span class="badge ok">story ok</span>
3071
3161
  </div>
3072
- <div>Playful dot for flagged or priority statuses</div>
3073
- <div class="hint">Playful dot for flagged or priority domain states that need to stand out from warnings with a distinct hue.</div>
3074
- <pre><code>const Playful = () =&gt; &lt;StatusBall color=&quot;playful&quot; /&gt;;</code></pre>
3162
+ <div>Selectable rows with a collapsing checkbox column</div>
3163
+ <div class="hint">A leading checkbox column; checkbox cells collapse to zero width.</div>
3164
+ <pre><code>const WithCheckbox = args =&gt; renderTable(args, { checkbox: true });</code></pre>
3075
3165
  </div>
3076
3166
  <div class="note ok">
3077
3167
  <div class="row">
3078
- <span class="ex-name">Neutral</span>
3168
+ <span class="ex-name">With Row Actions</span>
3079
3169
  <span class="badge ok">story ok</span>
3080
3170
  </div>
3081
- <div>Neutral dot for inactive or unknown statuses</div>
3082
- <div class="hint">Neutral dot for inactive, unknown, or default states — the fallback when no other intent applies.</div>
3083
- <pre><code>const Neutral = () =&gt; &lt;StatusBall color=&quot;neutral&quot; /&gt;;</code></pre>
3171
+ <div>Hover-revealed row actions</div>
3172
+ <div class="hint">Hover-revealed row actions pinned to the trailing edge.</div>
3173
+ <pre><code>const WithRowActions = args =&gt; renderTable(args, { actions: true });</code></pre>
3084
3174
  </div>
3085
3175
  <div class="note ok">
3086
3176
  <div class="row">
3087
- <span class="ex-name">In List</span>
3177
+ <span class="ex-name">Expandable Rows</span>
3088
3178
  <span class="badge ok">story ok</span>
3089
3179
  </div>
3090
- <div>StatusBall paired with labels inside a list</div>
3091
- <div class="hint">StatusBall inside a list row — the canonical production usage, mirroring the appointment and license list patterns in `producerflow/mono`. Each row pairs a dot with a label and supporting text.</div>
3092
- <pre><code>const InList = () =&gt; {
3093
- const rows = [
3094
- { color: &#39;success&#39;, name: &#39;Ada Lovelace&#39;, status: &#39;Active&#39; },
3095
- { color: &#39;warning&#39;, name: &#39;Grace Hopper&#39;, status: &#39;Pending renewal&#39; },
3096
- { color: &#39;danger&#39;, name: &#39;Alan Turing&#39;, status: &#39;Expired&#39; },
3097
- { color: &#39;neutral&#39;, name: &#39;Katherine Johnson&#39;, status: &#39;Inactive&#39; }
3098
- ] as const;
3099
-
3100
- return (
3101
- &lt;ul className=&quot;w-80 divide-y divide-border-default-base-primary rounded-lg border border-border-default-base-primary bg-bg-default-base-primary&quot;&gt;
3102
- {rows.map(row =&gt; (
3103
- &lt;li key={row.name} className=&quot;flex items-center gap-3 px-4 py-3&quot;&gt;
3104
- &lt;StatusBall color={row.color} /&gt;
3105
- &lt;div className=&quot;flex flex-col&quot;&gt;
3106
- &lt;span className=&quot;text-sm font-medium text-text-default-base-primary&quot;&gt;{row.name}&lt;/span&gt;
3107
- &lt;span className=&quot;text-xs text-text-default-base-secondary&quot;&gt;{row.status}&lt;/span&gt;
3108
- &lt;/div&gt;
3109
- &lt;/li&gt;
3110
- ))}
3111
- &lt;/ul&gt;
3112
- );
3180
+ <div>Expandable rows with a detail panel</div>
3181
+ <div class="hint">`Table.ExpandButton` toggles a `Table.ExpandedRow` detail panel under its row.</div>
3182
+ <pre><code>const ExpandableRows = args =&gt; {
3183
+ const Demo = () =&gt; {
3184
+ const [openId, setOpenId] = useState&lt;string | null&gt;(ROWS[0]!.id);
3185
+ return (
3186
+ &lt;Table.Root {...args}&gt;
3187
+ &lt;Table.Head&gt;
3188
+ &lt;Table.Row&gt;
3189
+ &lt;Table.Header&gt;
3190
+ &lt;span className=&quot;sr-only&quot;&gt;Expand&lt;/span&gt;
3191
+ &lt;/Table.Header&gt;
3192
+ &lt;Table.Header&gt;Name&lt;/Table.Header&gt;
3193
+ &lt;Table.Header&gt;Email&lt;/Table.Header&gt;
3194
+ &lt;Table.Header&gt;Role&lt;/Table.Header&gt;
3195
+ &lt;/Table.Row&gt;
3196
+ &lt;/Table.Head&gt;
3197
+ &lt;Table.Body&gt;
3198
+ {ROWS.slice(0, 4).map(row =&gt; (
3199
+ &lt;Fragment key={row.id}&gt;
3200
+ &lt;Table.Row&gt;
3201
+ &lt;Table.Cell&gt;
3202
+ &lt;Table.ExpandButton
3203
+ isExpanded={openId === row.id}
3204
+ toggleExpanded={() =&gt; setOpenId(openId === row.id ? null : row.id)}
3205
+ aria-label={`Toggle ${row.name}`}
3206
+ /&gt;
3207
+ &lt;/Table.Cell&gt;
3208
+ &lt;Table.Cell className=&quot;font-bold&quot;&gt;{row.name}&lt;/Table.Cell&gt;
3209
+ &lt;Table.Cell className=&quot;text-text-default-base-secondary&quot;&gt;{row.email}&lt;/Table.Cell&gt;
3210
+ &lt;Table.Cell&gt;{row.role}&lt;/Table.Cell&gt;
3211
+ &lt;/Table.Row&gt;
3212
+ {openId === row.id &amp;&amp; (
3213
+ &lt;Table.ExpandedRow&gt;
3214
+ &lt;Table.Cell colSpan={4}&gt;
3215
+ &lt;div className=&quot;py-2 text-text-default-base-secondary&quot;&gt;
3216
+ Extended details for {row.name} — {row.amount} lifetime value.
3217
+ &lt;/div&gt;
3218
+ &lt;/Table.Cell&gt;
3219
+ &lt;/Table.ExpandedRow&gt;
3220
+ )}
3221
+ &lt;/Fragment&gt;
3222
+ ))}
3223
+ &lt;/Table.Body&gt;
3224
+ &lt;/Table.Root&gt;
3225
+ );
3226
+ };
3227
+ return &lt;Demo /&gt;;
3113
3228
  };</code></pre>
3114
3229
  </div>
3115
- <div class="note ok">
3116
- <div class="row">
3117
- <span class="ex-name">In Pill</span>
3118
- <span class="badge ok">story ok</span>
3119
- </div>
3120
- <div>StatusBall inside a rounded status pill</div>
3121
- <div class="hint">StatusBall inside a status pill — a tinted badge that pairs the dot with a label in a single rounded container. Use when the status needs more visual weight than a bare list row provides.</div>
3122
- <pre><code>const InPill = () =&gt; (
3123
- &lt;div className=&quot;flex flex-wrap items-center gap-2&quot;&gt;
3124
- &lt;span className=&quot;inline-flex items-center gap-1.5 rounded-full border border-border-default-base-primary bg-bg-default-base-primary px-2.5 py-1 text-xs text-text-default-base-primary&quot;&gt;
3125
- &lt;StatusBall color=&quot;success&quot; /&gt;
3126
- Active
3127
- &lt;/span&gt;
3128
- &lt;span className=&quot;inline-flex items-center gap-1.5 rounded-full border border-border-default-base-primary bg-bg-default-base-primary px-2.5 py-1 text-xs text-text-default-base-primary&quot;&gt;
3129
- &lt;StatusBall color=&quot;warning&quot; /&gt;
3130
- Pending
3131
- &lt;/span&gt;
3132
- &lt;span className=&quot;inline-flex items-center gap-1.5 rounded-full border border-border-default-base-primary bg-bg-default-base-primary px-2.5 py-1 text-xs text-text-default-base-primary&quot;&gt;
3133
- &lt;StatusBall color=&quot;danger&quot; /&gt;
3134
- Expired
3135
- &lt;/span&gt;
3136
- &lt;/div&gt;
3137
- );</code></pre>
3138
- </div>
3139
3230
  </div>
3140
3231
 
3141
3232
  </div>
@@ -3152,9 +3243,9 @@ totalCount: number</code></pre>
3152
3243
  <div class="title">
3153
3244
  <h2><span class="status-dot dot-ok"></span> Toast</h2>
3154
3245
  <div class="badges">
3155
- <label for="c-8-components-toast-props" class="badge ok as-toggle">11 prop types</label>
3246
+ <label for="c-9-components-toast-props" class="badge ok as-toggle">11 prop types</label>
3156
3247
 
3157
- <label for="c-8-components-toast-stories" class="badge ok as-toggle">11 stories</label>
3248
+ <label for="c-9-components-toast-stories" class="badge ok as-toggle">11 stories</label>
3158
3249
 
3159
3250
  </div>
3160
3251
  </div>
@@ -3167,9 +3258,9 @@ totalCount: number</code></pre>
3167
3258
  <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
3168
3259
 
3169
3260
 
3170
- <input id="c-8-components-toast-stories" class="tg tg-stories" type="checkbox" hidden />
3261
+ <input id="c-9-components-toast-stories" class="tg tg-stories" type="checkbox" hidden />
3171
3262
 
3172
- <input id="c-8-components-toast-props" class="tg tg-props" type="checkbox" hidden />
3263
+ <input id="c-9-components-toast-props" class="tg tg-props" type="checkbox" hidden />
3173
3264
 
3174
3265
  <div class="panels">
3175
3266