@@ -323,7 +323,7 @@ export const Status: Story = {
323323 * Demo 2 — **Labels**. Multi-select: each row is a `DropdownCheckboxItem` (the propel
324324 * `Checkbox` as the leading control) plus a color swatch, with a search header. When
325325 * the typed query has no exact match, an "Add label" option (Figma `64-626`) appears,
326- * separated from the search by a double divider line.
326+ * separated from the search by a single divider line.
327327 */
328328export const Labels : Story = {
329329 render : function LabelsStory ( ) {
@@ -344,18 +344,15 @@ export const Labels: Story = {
344344 search = { < DropdownSearch value = { query } onValueChange = { setQuery } /> }
345345 >
346346 { canAdd ? (
347- < >
348- { /* Two horizontal divider lines between the search and the new-label
349- item (Figma 64-626): the sticky search already draws a bottom rule;
350- this adds the second one directly above the add-label row. */ }
351- < div className = "-mx-1 mb-1 border-t border-subtle" />
352- < DropdownItem
353- variant = "default"
354- icon = { < Plus className = "text-icon-secondary" /> }
355- label = { `Add label "${ trimmed } "` }
356- closeOnClick = { false }
357- />
358- </ >
347+ // A single horizontal divider separates the search from the new-label item
348+ // (Figma 64-626): the sticky DropdownSearch already draws its own bottom
349+ // rule, so the "Add label" row mounts directly beneath it with no extra line.
350+ < DropdownItem
351+ variant = "default"
352+ icon = { < Plus className = "text-icon-secondary" /> }
353+ label = { `Add label "${ trimmed } "` }
354+ closeOnClick = { false }
355+ />
359356 ) : null }
360357 { visible . map ( ( l ) => (
361358 < DropdownCheckboxItem
@@ -656,6 +653,10 @@ export const Priority: Story = {
656653 } ,
657654} ;
658655
656+ // How many rows a `viewAll` section shows before the "View all" toggle. The rest stay
657+ // collapsed inline until the toggle is activated.
658+ const VIEW_ALL_PREVIEW = 2 ;
659+
659660/**
660661 * Regression — **CheckedFillVisible**. Locks in the fix for the invisible
661662 * checked checkbox: a tone-less `CheckboxVisual` (as rendered by
@@ -729,13 +730,15 @@ export const CheckedFillVisible: Story = {
729730 * Demo 8 — **Filters**. Multi-select across several titled, collapsible sections
730731 * (Priority, State, Assignee, …). Each item carries a leading icon; a chevron on the
731732 * heading collapses/expands the category; categories are separated by a divider; and
732- * the "View all" link sits in the heading's trailing slot (no hover background,
733- * `cursor-pointer` ).
733+ * a long category previews only its first few rows with a "View all" toggle that
734+ * expands the remaining rows inline (and collapses back to "Show less" ).
734735 */
735736export const Filters : Story = {
736737 render : function FiltersStory ( ) {
737738 const [ checked , setChecked ] = React . useState < Record < string , boolean > > ( { } ) ;
738739 const [ collapsed , setCollapsed ] = React . useState < Record < string , boolean > > ( { } ) ;
740+ // Which `viewAll` sections have been expanded to show every row.
741+ const [ expandedAll , setExpandedAll ] = React . useState < Record < string , boolean > > ( { } ) ;
739742 const [ query , setQuery ] = React . useState ( "" ) ;
740743 const toggle = ( key : string ) => ( next : boolean ) => setChecked ( ( c ) => ( { ...c , [ key ] : next } ) ) ;
741744 const match = ( label : string ) => label . toLowerCase ( ) . includes ( query . toLowerCase ( ) ) ;
@@ -771,6 +774,12 @@ export const Filters: Story = {
771774 const items = section . items . filter ( ( i ) => match ( i . label ) ) ;
772775 if ( items . length === 0 ) return null ;
773776 const isCollapsed = Boolean ( collapsed [ section . title ] ) ;
777+ const isExpandedAll = Boolean ( expandedAll [ section . title ] ) ;
778+ // A `viewAll` section previews only its first rows until expanded; the
779+ // toggle appears only when there are more rows than the preview shows.
780+ const hasOverflow = Boolean ( section . viewAll ) && items . length > VIEW_ALL_PREVIEW ;
781+ const visibleItems =
782+ hasOverflow && ! isExpandedAll ? items . slice ( 0 , VIEW_ALL_PREVIEW ) : items ;
774783 return (
775784 < React . Fragment key = { section . title } >
776785 { /* Divider between categories. */ }
@@ -794,7 +803,7 @@ export const Filters: Story = {
794803 onClick = { ( ) => setCollapsed ( ( c ) => ( { ...c , [ section . title ] : ! isCollapsed } ) ) }
795804 />
796805 { ! isCollapsed
797- ? items . map ( ( i ) => (
806+ ? visibleItems . map ( ( i ) => (
798807 < DropdownCheckboxItem
799808 key = { i . key }
800809 icon = { i . icon }
@@ -804,14 +813,24 @@ export const Filters: Story = {
804813 />
805814 ) )
806815 : null }
807- { /* "View all" is its own menuitem with link emphasis: no hover
808- background + cursor-pointer. */ }
809- { ! isCollapsed && section . viewAll ? (
816+ { /* "View all" is its own menuitem (keyboard-focusable like any row)
817+ with link emphasis: no hover background + cursor-pointer. Clicking
818+ it reveals the remaining rows inline; once expanded it becomes
819+ "Show less". `aria-expanded` reflects the inline-expansion state. */ }
820+ { ! isCollapsed && hasOverflow ? (
810821 < DropdownItem
811822 variant = "default"
812823 emphasis = "link"
813- label = { < span className = "text-accent-primary" > View all</ span > }
824+ aria-expanded = { isExpandedAll }
825+ label = {
826+ < span className = "text-accent-primary" >
827+ { isExpandedAll ? "Show less" : `View all (${ items . length } )` }
828+ </ span >
829+ }
814830 closeOnClick = { false }
831+ onClick = { ( ) =>
832+ setExpandedAll ( ( s ) => ( { ...s , [ section . title ] : ! isExpandedAll } ) )
833+ }
815834 />
816835 ) : null }
817836 </ DropdownGroup >
@@ -827,7 +846,23 @@ export const Filters: Story = {
827846 await openMenu ( canvas , "Filters" ) ;
828847 await waitFor ( ( ) => expect ( findItem ( "menuitemcheckbox" , "Urgent" ) ) . toBeDefined ( ) ) ;
829848 await expect ( findItem ( "menuitemcheckbox" , "Backlog" ) ) . toBeDefined ( ) ;
830- await expect ( findItem ( "menuitemcheckbox" , "David Wilson" ) ) . toBeDefined ( ) ;
849+ // The Assignee section previews only its first rows; later assignees are hidden
850+ // behind "View all" until it is activated.
851+ await expect ( findItem ( "menuitemcheckbox" , "Amelia Parker" ) ) . toBeDefined ( ) ;
852+ await expect ( findItem ( "menuitemcheckbox" , "Ethan Parker" ) ) . toBeUndefined ( ) ;
853+ } ) ;
854+ await step ( "View all expands the remaining rows inline" , async ( ) => {
855+ const viewAll = ( await waitFor ( ( ) => findItem ( "menuitem" , "View all" ) ) ) as HTMLElement ;
856+ await expect ( viewAll ) . toHaveAttribute ( "aria-expanded" , "false" ) ;
857+ // Keyboard-accessible: activate the menuitem with Enter rather than a pointer.
858+ viewAll . focus ( ) ;
859+ await userEvent . keyboard ( "{Enter}" ) ;
860+ await waitFor ( ( ) => expect ( findItem ( "menuitemcheckbox" , "Ethan Parker" ) ) . toBeDefined ( ) ) ;
861+ // The toggle now offers to collapse again.
862+ const showLess = findItem ( "menuitem" , "Show less" ) as HTMLElement ;
863+ await expect ( showLess ) . toHaveAttribute ( "aria-expanded" , "true" ) ;
864+ await userEvent . click ( showLess ) ;
865+ await waitFor ( ( ) => expect ( findItem ( "menuitemcheckbox" , "Ethan Parker" ) ) . toBeUndefined ( ) ) ;
831866 } ) ;
832867 await step ( "collapse a category from its heading" , async ( ) => {
833868 const heading = ( await waitFor ( ( ) =>
0 commit comments