From b087e1f332936a50ff88b4e85053d9d783ce2cb5 Mon Sep 17 00:00:00 2001 From: Adam Bull Date: Tue, 7 Oct 2025 12:54:31 +0100 Subject: [PATCH 1/2] fix: the rainbow --- src/components/Button/index.stories.tsx | 197 ++++++++++++++++++++++++ src/components/Button/index.tsx | 9 +- 2 files changed, 204 insertions(+), 2 deletions(-) diff --git a/src/components/Button/index.stories.tsx b/src/components/Button/index.stories.tsx index a871c0fd..0e40a22b 100644 --- a/src/components/Button/index.stories.tsx +++ b/src/components/Button/index.stories.tsx @@ -411,3 +411,200 @@ export const WithStates: Story = { ), } + +export const RainbowButtonZIndexFix: Story = { + render: () => ( +
+ +
+ ), +} + +export const BrandButtonInStackingContexts: Story = { + name: 'Brand Button in Various Stacking Contexts', + render: () => ( +
+
+

+ ✅ Brand Button Working in All Contexts +

+

+ The brand button now works correctly in all stacking contexts thanks + to built-in fixes. +

+
+ +
+
+

Flex Containers

+
+
+ Navigation: + +
+ +
+ + Home + + / + + Projects + +
+ +
+
+
+
+ +
+

Grid Layouts

+
+
+
Project Settings
+

Configure your project

+
+ +
+
+ +
+

High Z-Index Contexts

+
+
+ Modal Header + +
+
+
+ +
+

Transform Contexts

+
+
+ Transformed container: + +
+
+
+ +
+

+ Overflow Hidden Containers +

+
+
+ Clipped container: + +
+
+
+ +
+

Complex Nested Layouts

+
+
+
+
+ Complex Layout +
+ +
+
+
+ + Workspace + + / + + Project + + / + Current +
+ +
+
+
+
+
+
+
+
+ ), + parameters: { + docs: { + description: { + story: ` +This story demonstrates the brand button working correctly in various stacking contexts that previously caused issues with the rainbow outline. + +**Fixed Issues:** +- ✅ Flex containers with \`items-center\` +- ✅ Containers with \`overflow: hidden\` +- ✅ High z-index contexts +- ✅ Transform contexts +- ✅ Complex nested layouts +- ✅ Grid layouts + +**Technical Solution:** +The component now uses \`transform: translateZ(0)\` to create an isolated stacking context and a separate background span element to ensure proper layering of the rainbow outline pseudo-elements. + `, + }, + }, + }, +} diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 65323684..226e1e3a 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -107,7 +107,7 @@ const buttonVariants = cva( }, variant: { brand: - 'relative bg-btn-brand hover:bg-btn-brand-hover text-btn-brand hover:text-btn-brand-hover disabled:bg-btn-brand-disabled disabled:text-btn-brand-disabled before:absolute before:content-[""] before:-z-10 before:pointer-events-none [--gradient-rotation:220deg] before:bg-[conic-gradient(from_var(--gradient-rotation),hsl(334,54%,13%),hsl(4,67%,47%),hsl(23,96%,62%),hsl(68,52%,72%),hsl(108,24%,41%),hsl(154,100%,7%),hsl(220,100%,12%),hsl(214,69%,50%),hsl(216,100%,80%),hsl(334,54%,13%))] after:absolute after:content-[""] after:-z-20 after:pointer-events-none after:opacity-0 after:transition-opacity after:duration-300 hover:after:opacity-100 after:bg-[conic-gradient(from_var(--gradient-rotation),hsl(334,54%,13%),hsl(4,67%,47%),hsl(23,96%,62%),hsl(68,52%,72%),hsl(108,24%,41%),hsl(154,100%,7%),hsl(220,100%,12%),hsl(214,69%,50%),hsl(216,100%,80%),hsl(334,54%,13%))] after:blur-[2px] focus-visible:ring-2 focus-visible:ring-offset-3 focus-visible:ring-[var(--border-focus)] focus-visible:ring-offset-[var(--bg-surface-primary-default)]', + 'relative text-btn-brand hover:text-btn-brand-hover disabled:text-btn-brand-disabled [transform:translateZ(0)] before:absolute before:content-[""] before:-z-10 before:pointer-events-none [--gradient-rotation:220deg] before:bg-[conic-gradient(from_var(--gradient-rotation),hsl(334,54%,13%),hsl(4,67%,47%),hsl(23,96%,62%),hsl(68,52%,72%),hsl(108,24%,41%),hsl(154,100%,7%),hsl(220,100%,12%),hsl(214,69%,50%),hsl(216,100%,80%),hsl(334,54%,13%))] after:absolute after:content-[""] after:-z-20 after:pointer-events-none after:opacity-0 after:transition-opacity after:duration-300 hover:after:opacity-100 after:bg-[conic-gradient(from_var(--gradient-rotation),hsl(334,54%,13%),hsl(4,67%,47%),hsl(23,96%,62%),hsl(68,52%,72%),hsl(108,24%,41%),hsl(154,100%,7%),hsl(220,100%,12%),hsl(214,69%,50%),hsl(216,100%,80%),hsl(334,54%,13%))] after:blur-[2px] focus-visible:ring-2 focus-visible:ring-offset-3 focus-visible:ring-[var(--border-focus)] focus-visible:ring-offset-[var(--bg-surface-primary-default)]', primary: 'bg-btn-primary text-btn-primary shadow-[0px_2px_1px_0px_rgba(255,255,255,0.1)_inset,0px_-2px_1px_0px_rgba(0,0,0,0.2)_inset] hover:bg-btn-primary-hover hover:text-btn-primary-hover hover:shadow-[0px_2px_1px_0px_rgba(255,255,255,0.08)_inset,0px_-2px_1px_0px_rgba(0,0,0,0.25)_inset] active:bg-btn-primary-active active:text-btn-primary-active active:shadow-none disabled:bg-btn-primary-disabled disabled:text-btn-primary-disabled', secondary: @@ -430,7 +430,12 @@ const Button = React.forwardRef( onMouseUp={handleMouseUp} {...props} > - {processedChildren} + {isBrandVariant && ( + + )} + + {processedChildren} + ) } From 3e18b8ce310c4189f9597af4f2c70b15577e5e73 Mon Sep 17 00:00:00 2001 From: Adam Bull Date: Mon, 20 Oct 2025 14:07:22 +0100 Subject: [PATCH 2/2] fix: button --- src/components/Button/index.tsx | 38 ++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 226e1e3a..977965f8 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -249,6 +249,22 @@ const Button = React.forwardRef( const isBrandVariant = variant === 'brand' + // Get gap class for the current size + const getGapClass = (size: ButtonSize) => { + switch (size) { + case 'xs': + return 'gap-1' + case 'sm': + return 'gap-1.5' + case 'md': + return 'gap-2' + case 'lg': + return 'gap-2.5' + default: + return 'gap-2' + } + } + // Only run animation frame when brand variant is active useAnimationFrame( React.useCallback( @@ -430,12 +446,24 @@ const Button = React.forwardRef( onMouseUp={handleMouseUp} {...props} > - {isBrandVariant && ( - + {asChild ? ( + props.children + ) : ( + <> + {isBrandVariant && ( + + )} + + {processedChildren} + + )} - - {processedChildren} - ) }