This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

web/components: keep the selected ButtonGroup segment's border on sibling hover

Signed-off-by: eti <eti@eti.tf>

+32 -7
+9 -1
web/src/lib/components/ui/Button.svelte
··· 178 178 <a 179 179 {href} 180 180 class={classes} 181 + data-variant={variant} 181 182 aria-disabled={disabled || loading ? "true" : undefined} 182 183 tabindex={disabled ? -1 : undefined} 183 184 {...rest} ··· 185 186 {@render content()} 186 187 </a> 187 188 {:else} 188 - <button {type} disabled={disabled || loading} class={classes} aria-busy={loading} {...rest}> 189 + <button 190 + {type} 191 + disabled={disabled || loading} 192 + class={classes} 193 + data-variant={variant} 194 + aria-busy={loading} 195 + {...rest} 196 + > 189 197 {@render content()} 190 198 </button> 191 199 {/if}
+13 -4
web/src/lib/components/ui/ButtonGroup.stories.svelte
··· 54 54 `ghost`. Never plain `default` for unselected — that reads as the hovered state. 55 55 --> 56 56 <Story name="Tab Switcher"> 57 - <ButtonGroup> 58 - <Button {...segmentProps(true)}>Open</Button> 59 - <Button {...segmentProps(false)}>Closed</Button> 60 - </ButtonGroup> 57 + <div class="flex flex-col items-start gap-4"> 58 + <ButtonGroup> 59 + <Button {...segmentProps(true)}>Open</Button> 60 + <Button {...segmentProps(false)}>Closed</Button> 61 + </ButtonGroup> 62 + <!-- selected in the middle: hovering either neighbour used to rub out the border on the 63 + edge they share, so this is the case to check when touching the group's layering --> 64 + <ButtonGroup> 65 + <Button {...segmentProps(false)}>All</Button> 66 + <Button {...segmentProps(true)}>Push</Button> 67 + <Button {...segmentProps(false)}>Pull request</Button> 68 + </ButtonGroup> 69 + </div> 61 70 </Story>
+10 -2
web/src/lib/components/ui/ButtonGroup.svelte
··· 8 8 spaced: { 9 9 true: "gap-2", 10 10 false: [ 11 - "items-stretch gap-0 rounded-sm overflow-hidden border border-border-default bg-background-subtle dark:bg-background-canvas", 11 + "items-stretch gap-0 overflow-hidden rounded-sm border border-border-default bg-background-subtle dark:bg-background-canvas", 12 12 "*:relative *:border-y-0", 13 13 "[&>*:first-child]:-ml-px [&>*:last-child]:-mr-px", 14 14 "[&>*:not(:first-child)]:-ml-px [&>*:not(:first-child)]:[--btn-radius-l:0px]", 15 15 "[&>*:not(:last-child)]:[--btn-radius-r:0px]", 16 - "[&>*:focus-visible]:z-10 [&>*:hover]:z-10" 16 + // children overlap by 1px so adjacent borders collapse into a single seam, which 17 + // also means a child's fill paints into its neighbour's border column. ghost 18 + // segments have a transparent border and nothing to repaint there, so every 19 + // bordered child has to sit above them — otherwise hovering a ghost rubs out the 20 + // selected segment's border on whichever edge they share. 21 + "[&>*:not([data-variant=ghost])]:z-10", 22 + // the group clips overflow, so an outward focus ring gets cut off at its edges and 23 + // by bordered neighbours. draw it inside the child instead. 24 + "[&>*:focus-visible]:-outline-offset-2" 17 25 ] 18 26 } 19 27 },