diff --git a/about/button-showcase.page.tsx b/about/button-showcase-primary.page.tsx similarity index 54% rename from about/button-showcase.page.tsx rename to about/button-showcase-primary.page.tsx index e242eb2267..f963ca0b74 100644 --- a/about/button-showcase.page.tsx +++ b/about/button-showcase-primary.page.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Button } from 'shared/components/Button'; -import { PageGrid, PageGridCol, PageGridRow } from 'shared/components/page-grid'; +import { PageGrid, PageGridCol, PageGridRow } from 'shared/components/PageGrid/page-grid'; export const frontmatter = { seo: { @@ -11,19 +11,11 @@ export const frontmatter = { export default function ButtonShowcase() { const [clickCount, setClickCount] = React.useState(0); - const [isLoading, setIsLoading] = React.useState(false); const handleClick = () => { setClickCount((prev) => prev + 1); }; - const handleAsyncClick = async () => { - setIsLoading(true); - await new Promise((resolve) => setTimeout(resolve, 2000)); - setIsLoading(false); - setClickCount((prev) => prev + 1); - }; - return (
@@ -96,16 +88,96 @@ export default function ButtonShowcase() { - -
+ + + + {/* Black Color Variant */} +
+
+

Black Color Variant

+
Color Theme
+
+

+ Primary buttons can use a black color theme for dark backgrounds or alternative styling needs. +

+
+ + + +
+
+ + {/* Black Variant States */} +
+
+

Black Variant States

+
Interactive States
+
+ + + +
+
Enabled State
+

Black background with white text.

+ +
+
+ +
+
Disabled State
+

Same disabled styling as green variant.

+ +
+
+
+
+
+
Hover & Focus States
+

+ Hover over the buttons or use Tab to focus them. Notice the background darkens slightly on hover. +

+
+ +
+ {/* Green vs Black Comparison */} +
+
+

Green vs Black Comparison

+
Color Themes
+
+

Compare the green (default) and black color themes side by side.

+
+ + +
+
+ {/* Without Icon */}
@@ -149,23 +221,6 @@ export default function ButtonShowcase() {
- {/* Loading State Simulation */} -
-
-

Async Actions

-
Loading States
-
-

- Example of handling async actions. The button is disabled during the async operation. -

- - {clickCount > 0 && ( -

Async action completed {clickCount} time{clickCount !== 1 ? 's' : ''}

- )} -
- {/* Responsive Behavior */}
@@ -252,11 +307,16 @@ export default function ButtonShowcase() {
             {`import { Button } from 'shared/components/Button';
 
-// Basic usage
+// Basic usage (green theme - default)
 
 
+// Black color theme
+
+
 // Disabled state
 
diff --git a/about/button-showcase-secondary.page.tsx b/about/button-showcase-secondary.page.tsx new file mode 100644 index 0000000000..ce3ffc02df --- /dev/null +++ b/about/button-showcase-secondary.page.tsx @@ -0,0 +1,528 @@ +import * as React from 'react'; +import { Button } from 'shared/components/Button'; +import { PageGrid, PageGridCol, PageGridRow } from 'shared/components/PageGrid/page-grid'; + +export const frontmatter = { + seo: { + title: 'BDS Secondary Button Component Showcase', + description: 'Interactive showcase of the Brand Design System Secondary Button component with all states and variants.', + }, +}; + +export default function ButtonShowcaseSecondary() { + const [clickCount, setClickCount] = React.useState(0); + + const handleClick = () => { + setClickCount((prev) => prev + 1); + }; + + return ( +
+
+
+

BDS Secondary Button

+
Brand Design System
+
+

+ The Secondary button is an outline-style button used for secondary actions. It features a transparent + background with a green stroke/border, providing visual hierarchy below the Primary button while maintaining + brand consistency. +

+
+ + {/* Basic Usage */} +
+
+

Basic Usage

+
Secondary Variant
+
+
+ + + +
+ {clickCount > 0 && ( +

+ Button clicked {clickCount} time{clickCount !== 1 ? 's' : ''} +

+ )} +
+ + {/* Primary vs Secondary Comparison */} +
+
+

Primary vs Secondary

+
Visual Hierarchy
+
+

+ Use Primary for main actions and Secondary for supporting actions to create clear visual hierarchy. +

+
+ + +
+
+ + {/* States */} +
+
+

Button States

+
Interactive States
+
+ + + +
+
Enabled State
+

Default outline style with green border and text.

+ +
+
+ +
+
Disabled State
+

Gray border and text indicate non-interactive state.

+ +
+
+
+
+
+
Hover & Focus States
+

+ Hover over the buttons or use Tab to focus them. Notice the light green background fill and darker green + border on hover/focus. +

+
+ + +
+
+
+ + {/* Black Color Variant */} +
+
+

Black Color Variant

+
Color Theme
+
+

+ Secondary buttons can use a black color theme with black text and border instead of green. +

+
+ + + +
+
+ + {/* Black Variant States */} +
+
+

Black Variant States

+
Interactive States
+
+ + + +
+
Enabled State
+

Black border and text with transparent background.

+ +
+
+ +
+
Disabled State
+

Same disabled styling as green variant.

+ +
+
+
+
+
+
Hover & Focus States
+

+ Hover over the buttons or use Tab to focus them. Notice the subtle black background fill on hover. +

+
+ + +
+
+
+ + {/* Green vs Black Comparison */} +
+
+

Green vs Black Comparison

+
Color Themes
+
+

Compare the green (default) and black color themes side by side.

+
+ + +
+
+ + {/* Without Icon */} +
+
+

Without Icon

+
Icon Control
+
+

Secondary buttons can also be rendered without the arrow icon.

+
+ + +
+
+ + {/* Button Types */} +
+
+

Button Types

+
Form Integration
+
+

Secondary buttons can be used for form actions like cancel or reset.

+
{ + e.preventDefault(); + alert('Form submitted!'); + }} + className="d-flex flex-wrap" + > + + + +
+
+ + {/* Responsive Behavior */} +
+
+

Responsive Behavior

+
Breakpoint Adjustments
+
+

+ Button padding adjusts automatically across breakpoints. Resize your browser window to see the changes: +

+
    +
  • + Desktop (≥1024px): Padding: 6px 17px 6px 18px (compensates for 2px border) +
  • +
  • + Tablet/Mobile (≤1023px): Padding: 6px 13px 6px 14px +
  • +
  • + Hover/Focus: Gap increases (22px desktop, 21px mobile) with adjusted padding +
  • +
+
+ + +
+
+ + {/* Accessibility */} +
+
+

Accessibility Features

+
WCAG Compliance
+
+ + + +
Keyboard Navigation
+
    +
  • Tab to focus buttons
  • +
  • Enter or Space to activate
  • +
  • Focus indicator: 2px black outline (additional to green border)
  • +
  • Disabled buttons are not focusable
  • +
+
+ +
Screen Reader Support
+
    +
  • Button labels are announced
  • +
  • Disabled state communicated via aria-disabled
  • +
  • Icons are hidden from screen readers (aria-hidden)
  • +
  • Semantic button element used
  • +
+
+
+
+
+
Color Contrast
+
    +
  • + Enabled: Green 400 (#0DAA3E) on White = 4.52:1 (AA for large text) +
  • +
  • + Hover: Green 500 (#078139) on Green 100 (#EAFCF1) = 4.87:1 (AA) +
  • +
  • + Disabled: Gray 400 (#A2A2A4) on White = reduced contrast (acceptable for disabled state) +
  • +
+
+
+ + {/* Code Examples */} +
+
+

Code Examples

+
Implementation
+
+
+
+            {`import { Button } from 'shared/components/Button';
+
+// Basic secondary button (green theme - default)
+
+
+// Black color theme
+
+
+// Disabled state
+
+
+// Without icon
+
+
+// Primary + Secondary pairing
+
+`}
+          
+
+
+ + {/* Design Specifications */} +
+
+

Design Specifications

+
Visual Details
+
+ + + +
Typography
+
    +
  • Font: Booton, sans-serif
  • +
  • Size: 16px
  • +
  • Weight: 400
  • +
  • Line Height: 23.2px
  • +
  • Letter Spacing: 0px
  • +
+
+ +
Spacing & Layout
+
    +
  • Border Radius: 100px (fully rounded)
  • +
  • Border Width: 2px solid
  • +
  • Icon Size: 15px × 14px
  • +
  • Icon Gap: 16px (default), 22px (hover/focus desktop), 21px (hover/focus mobile)
  • +
  • Max Height: 40px
  • +
+
+
+
+
+
State Colors - Green Theme
+
+ {/* Header */} +
+
State
+
Text Color
+
Background
+
Border
+
+ {/* Rows */} +
+
Enabled
+
#0DAA3E (Green 400)
+
Transparent
+
2px #0DAA3E (Green 400)
+
+
+
Hover
+
#078139 (Green 500)
+
#EAFCF1 (Green 100)
+
2px #078139 (Green 500)
+
+
+
Focus
+
#078139 (Green 500)
+
#EAFCF1 (Green 100)
+
2px #078139 + 2px #141414 outline
+
+
+
Active
+
#0DAA3E (Green 400)
+
Transparent
+
2px #0DAA3E (Green 400)
+
+
+
Disabled
+
#A2A2A4 (Gray 400)
+
Transparent
+
2px #A2A2A4 (Gray 400)
+
+
+
+
+
State Colors - Black Theme
+
+ {/* Header */} +
+
State
+
Text Color
+
Background
+
Border
+
+ {/* Rows */} +
+
Enabled
+
#141414 (Neutral Black)
+
Transparent
+
2px #141414 (Neutral Black)
+
+
+
Hover
+
#141414 (Neutral Black)
+
rgba(20, 20, 20, 0.15) (15% Black)
+
2px #141414 (Neutral Black)
+
+
+
Focus
+
#141414 (Neutral Black)
+
rgba(20, 20, 20, 0.15) (15% Black)
+
2px #141414 + 2px #141414 outline
+
+
+
Active
+
#141414 (Neutral Black)
+
Transparent
+
2px #141414 (Neutral Black)
+
+
+
Disabled
+
#A2A2A4 (Gray 400)
+
Transparent
+
2px #A2A2A4 (Gray 400)
+
+
+
+
+ + {/* Key Differences from Primary */} +
+
+

Key Differences from Primary

+
Comparison
+
+
+ {/* Header */} +
+
Aspect
+
Primary
+
Secondary
+
+ {/* Rows */} +
+
Background (Enabled)
+
Green 300 (#21E46B)
+
Transparent
+
+
+
Background (Hover)
+
Green 200 (#70EE97)
+
Green 100 (#EAFCF1)
+
+
+
Border (Enabled)
+
None
+
2px Green 400
+
+
+
Text Color (Enabled)
+
Black (#141414)
+
Green 400 (#0DAA3E)
+
+
+
Disabled Background
+
Gray 200 (#E0E0E1)
+
Transparent
+
+
+
Arrow Icon
+
✅ Shared
+
✅ Shared
+
+
+
+
+ ); +} diff --git a/resources/button-showcase.page.tsx b/resources/button-showcase.page.tsx index e242eb2267..d6511ced78 100644 --- a/resources/button-showcase.page.tsx +++ b/resources/button-showcase.page.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Button } from 'shared/components/Button'; -import { PageGrid, PageGridCol, PageGridRow } from 'shared/components/page-grid'; +import { PageGrid, PageGridCol, PageGridRow } from 'shared/components/PageGrid/page-grid'; export const frontmatter = { seo: { diff --git a/secondary-button-logic.md b/secondary-button-logic.md new file mode 100644 index 0000000000..564c3c2c3e --- /dev/null +++ b/secondary-button-logic.md @@ -0,0 +1,494 @@ +# Secondary Button Logic + +> **Design Source:** [Figma - Button Component](https://www.figma.com/design/MZOPJQOw9oWC6NDxLRH4ws/Button?node-id=5226-8948&m=dev) (Second Column - Secondary) +> **Target Component:** `shared/components/Button/Button.tsx` & `Button.scss` + +--- + +## Overview + +The **Secondary Button** is an outline-style button used for secondary actions. It features a transparent background with a colored stroke/border, providing visual hierarchy below the Primary button while maintaining brand consistency. + +**Key Characteristics:** +- Outline/ghost style (transparent background in default states) +- Green stroke/border in enabled state +- Filled background appears on hover/focus states +- **Shares arrow icon & animation with Primary button** (no duplicate code) + +--- + +## Shared Code Architecture + +The Secondary button **inherits** all arrow icon logic from the base `.bds-btn` class. This ensures: +- ✅ No duplicate arrow animation code +- ✅ Consistent hover behavior across variants +- ✅ Single source of truth for icon styling + +### Already Shared in Base `.bds-btn` Class + +```scss +// These styles are already in the base class and apply to ALL variants: + +.bds-btn { + // Icon element (SVG container) - SHARED + &__icon { + width: 15px; + height: 14px; + flex-shrink: 0; + transition: opacity $bds-btn-transition-duration $bds-btn-transition-timing; + color: currentColor; // Inherits text color from parent + overflow: visible; + } + + // Arrow horizontal line - SHARED + &__icon-line { + transform-box: fill-box; + transform-origin: right center; + transform: scaleX(1); + transition: transform $bds-btn-transition-duration $bds-btn-transition-timing; + } + + // Arrow chevron - SHARED + &__icon-chevron { + transition: transform $bds-btn-transition-duration $bds-btn-transition-timing; + } + + // Hover/Focus animation - SHARED (applies to ALL variants) + &:hover:not(:disabled):not(.bds-btn--disabled), + &:focus-visible:not(:disabled):not(.bds-btn--disabled) { + .bds-btn__icon-line { + transform: scaleX(0); // Line shrinks from left-to-right + } + } +} +``` + +### What Secondary Button Needs to Define + +The `.bds-btn--secondary` class only needs to define: +1. **Colors** (text, background, border) - different from Primary +2. **Padding & Gap** values per state - adjusted for border width +3. **Border** styling (Primary has no border, Secondary has 2px border) + +The icon color automatically updates via `currentColor` inheritance from the text color + +--- + +## Visual Specifications + +### Button Structure + +``` +┌─────────────────────────────────────────────┐ +│ [Label Text] [gap] [Icon] │ +└─────────────────────────────────────────────┘ + ↑ ↑ + .bds-btn__label .bds-btn__icon +``` + +- **Border Radius:** `100px` (pill shape) +- **Border Width:** `2px` solid +- **Max Height:** `40px` +- **Typography:** Label R token (Booton, 16px, 400 weight, 23.2px line-height) + +--- + +## State Specifications + +### 1. Enabled State (Default) + +| Property | Value | SCSS Variable | +|----------|-------|---------------| +| **Text Color** | Green 400 `#0DAA3E` | `$green-400` | +| **Background** | Transparent | `transparent` | +| **Border Color** | Green 400 `#0DAA3E` | `$green-400` | +| **Border Width** | `2px` | - | + +> **Icon Color:** Inherits text color via `currentColor` (no separate definition needed) + +**Desktop Padding & Gap:** +| Property | With Icon | Without Icon | +|----------|-----------|--------------| +| Padding | `8px 19px 8px 20px` | `8px 20px` | +| Gap | `16px` | N/A | + +**Tablet/Mobile Padding & Gap (≤1023px):** +| Property | With Icon | Without Icon | +|----------|-----------|--------------| +| Padding | `8px 15px 8px 16px` | `8px 16px` | +| Gap | `16px` | N/A | + +--- + +### 2. Hover State + +| Property | Value | SCSS Variable | +|----------|-------|---------------| +| **Text Color** | Green 500 `#078139` | `$green-500` | +| **Background** | Green 100 `#EAFCF1` | `$green-100` | +| **Border Color** | Green 500 `#078139` | `$green-500` | +| **Border Width** | `2px` | - | + +> **Icon Color:** Inherits text color via `currentColor` (automatically becomes Green 500) + +**Desktop Padding & Gap:** +| Property | With Icon | Without Icon | +|----------|-----------|--------------| +| Padding | `8px 13px 8px 20px` | `8px 20px` | +| Gap | `22px` | N/A | + +**Tablet/Mobile Padding & Gap (≤1023px):** +| Property | With Icon | Without Icon | +|----------|-----------|--------------| +| Padding | `8px 10px 8px 16px` | `8px 16px` | +| Gap | `21px` | N/A | + +> **Arrow Animation:** Handled by base `.bds-btn` class - line shrinks from left-to-right (shared behavior) + +--- + +### 3. Focus State (Keyboard Navigation) + +| Property | Value | SCSS Variable | +|----------|-------|---------------| +| **Text Color** | Green 500 `#078139` | `$green-500` | +| **Background** | Green 100 `#EAFCF1` | `$green-100` | +| **Border Color** | Green 500 `#078139` | `$green-500` | +| **Border Width** | `2px` | - | +| **Focus Ring** | Black `#141414`, 2px | `$bds-btn-primary-focus-border` | + +> **Icon Color:** Inherits text color via `currentColor` (automatically becomes Green 500) + +The focus state shows a **double border** effect: +1. Inner border: Green 500 (the button's stroke) +2. Outer border: Black (focus indicator ring) + +**Desktop Padding & Gap:** +| Property | With Icon | Without Icon | +|----------|-----------|--------------| +| Padding | `6px 11px 6px 18px` | `6px 17px 6px 18px` | +| Gap | `22px` | N/A | + +> **Note:** Padding is reduced by 2px on all sides to compensate for the additional focus ring border. + +**Tablet/Mobile Padding & Gap (≤1023px):** +| Property | With Icon | Without Icon | +|----------|-----------|--------------| +| Padding | `6px 8px 6px 14px` | `6px 13px 6px 14px` | +| Gap | `21px` | N/A | + +--- + +### 4. Active State (Being Pressed) + +| Property | Value | SCSS Variable | +|----------|-------|---------------| +| **Text Color** | Green 400 `#0DAA3E` | `$green-400` | +| **Background** | Transparent | `transparent` | +| **Border Color** | Green 400 `#0DAA3E` | `$green-400` | +| **Border Width** | `2px` | - | +| **Transform** | `scale(0.98)` | - | + +> **Icon Color:** Inherits text color via `currentColor` (returns to Green 400) + +**Padding & Gap:** Returns to enabled state values +- Desktop: `8px 19px 8px 20px`, gap `16px` +- Tablet/Mobile: `8px 15px 8px 16px`, gap `16px` + +--- + +### 5. Disabled State + +| Property | Value | SCSS Variable | +|----------|-------|---------------| +| **Text Color** | Neutral 400 `#8A919A` | `$gray-400` ¹ | +| **Background** | Transparent | `transparent` | +| **Border Color** | Neutral 400 `#8A919A` | `$gray-400` ¹ | +| **Border Width** | `2px` | - | +| **Cursor** | `not-allowed` | - | +| **Pointer Events** | `none` | - | +| **Icon** | Hidden (removed) | - | + +> ¹ **Note:** The Figma design uses `#8A919A` for Neutral 400. The existing `_colors.scss` has `$gray-400: #A2A2A4`. Either use the existing variable for consistency or add a new token. Recommend using existing `$gray-400` for codebase consistency. + +**Padding & Gap:** Same as enabled state +- Desktop: `8px 19px 8px 20px`, gap `16px` +- Tablet/Mobile: `8px 15px 8px 16px`, gap `16px` + +--- + +## Color Token Mapping + +### Required Colors from `_colors.scss` + +```scss +// Already available in styles/_colors.scss +$green-100: #EAFCF1; // Hover/Focus background +$green-400: #0DAA3E; // Enabled state (text, border, icon) +$green-500: #078139; // Hover/Focus state (text, border, icon) +$gray-400: #A2A2A4; // Disabled state (text, border) - closest match +``` + +### Recommended SCSS Variables for Secondary Button + +```scss +// Colors - Secondary Button +$bds-btn-secondary-text: $green-400; // #0DAA3E - Enabled +$bds-btn-secondary-text-hover: $green-500; // #078139 - Hover/Focus +$bds-btn-secondary-border: $green-400; // #0DAA3E - Enabled +$bds-btn-secondary-border-hover: $green-500; // #078139 - Hover/Focus +$bds-btn-secondary-bg-hover: $green-100; // #EAFCF1 - Hover/Focus fill +$bds-btn-secondary-disabled-text: $gray-400; // Disabled text & border +$bds-btn-secondary-disabled-border: $gray-400; // Disabled border +``` + +--- + +## Implementation Structure + +### CSS Class Names (BEM) + +``` +// SHARED (already exist in base .bds-btn - DO NOT DUPLICATE) +.bds-btn // Base button layout, typography, transitions +.bds-btn__label // Label element +.bds-btn__icon // Icon container (uses currentColor) +.bds-btn__icon-line // Arrow line + hover animation +.bds-btn__icon-chevron // Arrow chevron +.bds-btn--disabled // Disabled state modifier +.bds-btn--no-icon // No icon modifier + +// VARIANT-SPECIFIC (add for secondary) +.bds-btn--secondary // Colors, borders, padding/gap values only +``` + +### Component Props + +The existing `ButtonProps` interface supports the secondary variant: + +```tsx +interface ButtonProps { + variant?: 'primary' | 'secondary'; // Add 'secondary' to union type + children: React.ReactNode; + onClick?: () => void; + disabled?: boolean; + type?: 'button' | 'submit' | 'reset'; + className?: string; + showIcon?: boolean; +} +``` + +--- + +## SCSS Implementation Guide + +> ⚠️ **Important:** Do NOT add any icon/arrow styles to `.bds-btn--secondary`. The icon inherits its color via `currentColor` and the hover animation is already handled in the base `.bds-btn` class. + +### Design Tokens to Add + +```scss +// ============================================================================= +// Design Tokens - Secondary Button +// ============================================================================= + +// Colors - Secondary Button +$bds-btn-secondary-text: $green-400; // #0DAA3E +$bds-btn-secondary-text-hover: $green-500; // #078139 +$bds-btn-secondary-bg: transparent; +$bds-btn-secondary-bg-hover: $green-100; // #EAFCF1 +$bds-btn-secondary-border: $green-400; // #0DAA3E +$bds-btn-secondary-border-hover: $green-500; // #078139 +$bds-btn-secondary-disabled-text: $gray-400; // Disabled state +$bds-btn-secondary-disabled-border: $gray-400; // Disabled border +``` + +### State Styles Structure + +```scss +// ============================================================================= +// Secondary Variant +// ============================================================================= +// NOTE: Arrow icon animation is inherited from base .bds-btn class. +// The icon color automatically follows text color via currentColor. +// Only define: colors, backgrounds, borders, padding, and gap. + +.bds-btn--secondary { + // Default/Enabled state + color: $bds-btn-secondary-text; + background-color: $bds-btn-secondary-bg; + border: 2px solid $bds-btn-secondary-border; + + // Desktop padding and gap (≥1024px) + padding: 6px 17px 6px 18px; // Compensate for 2px border + gap: 16px; + + // No icon - symmetric padding + &.bds-btn--no-icon { + padding: 6px 18px; + } + + // --------------------------------------------------------------------------- + // Hover State + // --------------------------------------------------------------------------- + &:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + color: $bds-btn-secondary-text-hover; + background-color: $bds-btn-secondary-bg-hover; + border-color: $bds-btn-secondary-border-hover; + padding: 6px 11px 6px 18px; + gap: 22px; + } + + &:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + color: $bds-btn-secondary-text-hover; + background-color: $bds-btn-secondary-bg-hover; + border-color: $bds-btn-secondary-border-hover; + } + + // --------------------------------------------------------------------------- + // Focus State (keyboard navigation) + // --------------------------------------------------------------------------- + &:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + color: $bds-btn-secondary-text-hover; + background-color: $bds-btn-secondary-bg-hover; + border-color: $bds-btn-secondary-border-hover; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 0; + padding: 6px 11px 6px 18px; + gap: 22px; + } + + &:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + color: $bds-btn-secondary-text-hover; + background-color: $bds-btn-secondary-bg-hover; + border-color: $bds-btn-secondary-border-hover; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 0; + padding: 6px 17px 6px 18px; + } + + // --------------------------------------------------------------------------- + // Active State (being pressed) + // --------------------------------------------------------------------------- + &:active:not(:disabled):not(.bds-btn--disabled) { + color: $bds-btn-secondary-text; + background-color: $bds-btn-secondary-bg; + border-color: $bds-btn-secondary-border; + transform: scale(0.98); + padding: 6px 17px 6px 18px; + gap: 16px; + } + + // --------------------------------------------------------------------------- + // Disabled State + // Note: Icon is hidden via component logic when disabled + // --------------------------------------------------------------------------- + &:disabled, + &.bds-btn--disabled { + color: $bds-btn-secondary-disabled-text; + background-color: transparent; + border-color: $bds-btn-secondary-disabled-border; + cursor: not-allowed; + pointer-events: none; + } + + // --------------------------------------------------------------------------- + // Tablet & Mobile Responsive Styles (≤1023px) + // --------------------------------------------------------------------------- + @media (max-width: 1023px) { + padding: 6px 13px 6px 14px; + gap: 16px; + + &.bds-btn--no-icon { + padding: 6px 14px; + } + + &:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + padding: 6px 8px 6px 14px; + gap: 21px; + } + + &:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + // Background and border color changes applied, padding stable + } + + &:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + padding: 6px 8px 6px 14px; + gap: 21px; + } + + &:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + padding: 6px 13px 6px 14px; + } + + &:active:not(:disabled):not(.bds-btn--disabled) { + padding: 6px 13px 6px 14px; + gap: 16px; + } + } +} +``` + +--- + +## Key Differences from Primary Button + +| Aspect | Primary | Secondary | +|--------|---------|-----------| +| **Background (Enabled)** | Green 300 `#21E46B` | Transparent | +| **Background (Hover/Focus)** | Green 200 `#70EE97` | Green 100 `#EAFCF1` | +| **Border (Enabled)** | None | 2px Green 400 `#0DAA3E` | +| **Border (Hover/Focus)** | None (only focus ring) | 2px Green 500 `#078139` | +| **Text Color (Enabled)** | Neutral Black `#141414` | Green 400 `#0DAA3E` | +| **Text Color (Hover/Focus)** | Neutral Black `#141414` | Green 500 `#078139` | +| **Disabled Background** | Gray 200 `#E0E0E1` | Transparent | +| **Disabled Border** | None | 2px Gray 400 | +| **Focus Ring** | 2px Black border | 2px Black outline (additional) | +| **Arrow Icon** | ✅ Shared (base class) | ✅ Shared (base class) | +| **Arrow Animation** | ✅ Shared (base class) | ✅ Shared (base class) | + +--- + +## Accessibility Notes + +1. **Color Contrast:** Green 400/500 on white background meets WCAG AA requirements +2. **Focus Indicator:** Black outline provides clear keyboard navigation visibility +3. **Disabled State:** Reduced opacity icon + muted colors clearly indicate non-interactive state +4. **Icon:** `aria-hidden="true"` on arrow icon (decorative) +5. **Button:** `aria-disabled` attribute mirrors disabled prop + +--- + +## Usage Example + +```tsx +// Secondary button with icon (default) + + +// Secondary button without icon + + +// Disabled secondary button + +``` + +--- + +## Checklist for Implementation + +- [ ] Add `'secondary'` to variant union type in `ButtonProps` +- [ ] Add Secondary button SCSS variables to design tokens section +- [ ] Implement `.bds-btn--secondary` styles (colors, borders, padding/gap only) +- [ ] Add responsive styles for tablet/mobile breakpoint +- [ ] **DO NOT duplicate arrow icon or animation styles** (inherited from base) +- [ ] Verify arrow icon color changes automatically via `currentColor` +- [ ] Test hover, focus, active, disabled states +- [ ] Verify arrow icon animation works correctly (inherited behavior) +- [ ] Test with and without icon (`showIcon` prop) +- [ ] Verify color contrast meets WCAG requirements +- [ ] Test keyboard navigation (Tab + Enter/Space) diff --git a/shared/components/Button/Button.scss b/shared/components/Button/Button.scss index 0761356990..c18c772bf9 100644 --- a/shared/components/Button/Button.scss +++ b/shared/components/Button/Button.scss @@ -2,13 +2,16 @@ // Brand Design System - Scalable button component // // Naming Convention: BEM with 'bds' namespace -// .bds-btn - Base button -// .bds-btn--primary - Primary variant modifier -// .bds-btn--secondary - (Future) Secondary variant +// .bds-btn - Base button (shared layout, typography, icon animation) +// .bds-btn--primary - Primary variant (solid background) +// .bds-btn--secondary - Secondary variant (outline style) +// .bds-btn--green - Green color theme (default) +// .bds-btn--black - Black color theme // .bds-btn--tertiary - (Future) Tertiary variant // .bds-btn__label - Label element -// .bds-btn__icon - Icon element +// .bds-btn__icon - Icon element (inherits color via currentColor) // .bds-btn--disabled - Disabled state modifier +// .bds-btn--no-icon - No icon modifier @import "../../../styles/colors"; @@ -16,27 +19,58 @@ // Design Tokens // ============================================================================= -// Colors - Primary Button +// Neutral Black (used across variants) +$bds-btn-neutral-black: #141414; +$bds-btn-neutral-black-80: rgba(20, 20, 20, 0.8); // 80% black for hover +$bds-btn-neutral-black-15: rgba(20, 20, 20, 0.15); // 15% black for secondary hover + +// Colors - Green Primary Button $bds-btn-primary-bg: $green-300; // #21E46B - Enabled $bds-btn-primary-bg-hover: $green-200; // #70EE97 - Hover/Focus -$bds-btn-primary-text: #141414; // Neutral Black -$bds-btn-primary-focus-border: #141414; // Black focus ring +$bds-btn-primary-text: $bds-btn-neutral-black; +$bds-btn-primary-focus-border: $bds-btn-neutral-black; -// Colors - Disabled State +// Colors - Black Primary Button +$bds-btn-primary-black-bg: $bds-btn-neutral-black; +$bds-btn-primary-black-bg-hover: $bds-btn-neutral-black-80; +$bds-btn-primary-black-text: $white; + +// Colors - Disabled State (shared) $bds-btn-disabled-bg: $gray-200; // #E0E0E1 $bds-btn-disabled-text: $gray-500; // #838386 +// Colors - Green Secondary Button +$bds-btn-secondary-text: $green-400; // #0DAA3E - Enabled +$bds-btn-secondary-text-hover: $green-500; // #078139 - Hover/Focus +$bds-btn-secondary-bg: transparent; +$bds-btn-secondary-bg-hover: $green-100; // #EAFCF1 - Hover/Focus fill +$bds-btn-secondary-border: $green-400; // #0DAA3E - Enabled +$bds-btn-secondary-border-hover: $green-500; // #078139 - Hover/Focus +$bds-btn-secondary-disabled-text: $gray-400; // Disabled text +$bds-btn-secondary-disabled-border: $gray-400; // Disabled border + +// Colors - Black Secondary Button +$bds-btn-secondary-black-text: $bds-btn-neutral-black; +$bds-btn-secondary-black-bg-hover: $bds-btn-neutral-black-15; +$bds-btn-secondary-black-border: $bds-btn-neutral-black; + // Spacing $bds-btn-border-radius: 100px; $bds-btn-focus-border-width: 2px; // Transitions +// Motion: Duration 150ms, Custom bezier for smooth in-out feel $bds-btn-transition-duration: 150ms; -$bds-btn-transition-timing: ease-in-out; +$bds-btn-transition-timing: cubic-bezier(0.98, 0.12, 0.12, 0.98); // ============================================================================= // Base Button Styles // ============================================================================= +// +// SHARED HOVER ANIMATION: +// - Background fills from bottom-to-top using ::before pseudo-element +// - On unhover: background empties top-to-bottom +// - Each variant defines its own ::before background-color .bds-btn { // Layout @@ -44,6 +78,7 @@ $bds-btn-transition-timing: ease-in-out; align-items: center; justify-content: center; max-height: 40px; + // Typography - Label R token font-family: 'Booton', sans-serif; font-size: 16px; @@ -59,14 +94,55 @@ $bds-btn-transition-timing: ease-in-out; // Interaction cursor: pointer; - // Transitions - transition-property: background-color, border-color, transform, padding, gap; - transition-duration: $bds-btn-transition-duration; - transition-timing-function: $bds-btn-transition-timing; + // Required for pseudo-element background animation (shared) + position: relative; + overflow: hidden; + z-index: 1; + + // Transitions (shared) + transition: color $bds-btn-transition-duration $bds-btn-transition-timing, + border-color $bds-btn-transition-duration $bds-btn-transition-timing, + padding $bds-btn-transition-duration $bds-btn-transition-timing, + gap $bds-btn-transition-duration $bds-btn-transition-timing, + transform $bds-btn-transition-duration $bds-btn-transition-timing; + + // Background fill pseudo-element (shared structure) + // Each variant sets its own background-color + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + + // Start scaled to 0 from bottom - fills bottom-to-top on hover + transform: scaleY(0); + transform-origin: bottom center; + transition: transform $bds-btn-transition-duration $bds-btn-transition-timing; + } + + // Hover/Focus state - animate background fill (shared) + &:hover:not(:disabled):not(.bds-btn--disabled), + &:focus-visible:not(:disabled):not(.bds-btn--disabled) { + &::before { + transform: scaleY(1); + } + } + + // Active state - reset background (shared) + &:active:not(:disabled):not(.bds-btn--disabled) { + &::before { + transform: scaleY(0); + } + } // Label element &__label { flex-shrink: 0; + position: relative; + z-index: 1; } // Icon element (SVG container) @@ -77,6 +153,8 @@ $bds-btn-transition-timing: ease-in-out; transition: opacity $bds-btn-transition-duration $bds-btn-transition-timing; color: currentColor; overflow: visible; + position: relative; + z-index: 1; } // Arrow horizontal line - shrinks on hover/focus @@ -104,12 +182,18 @@ $bds-btn-transition-timing: ease-in-out; // ============================================================================= // Primary Variant // ============================================================================= +// HOVER ANIMATION: Background fills bottom-to-top (Green 300 → Green 200) .bds-btn--primary { // Default/Enabled state colors color: $bds-btn-primary-text; background-color: $bds-btn-primary-bg; + // Set the hover background color for ::before pseudo-element + &::before { + background-color: $bds-btn-primary-bg-hover; + } + // Desktop padding and gap (default - ≥1024px) padding: 8px 19px 8px 20px; gap: 16px; @@ -123,51 +207,44 @@ $bds-btn-transition-timing: ease-in-out; // Hover State (with icon) // --------------------------------------------------------------------------- &:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { - background-color: $bds-btn-primary-bg-hover; - // Adjust padding to compensate for icon gap change (maintains button width) + // Background animation handled by shared ::before pseudo-element padding: 8px 13px 8px 20px; gap: 22px; } - // Hover State (no icon) - only change background, keep padding stable - &:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { - background-color: $bds-btn-primary-bg-hover; - } + // Hover State (no icon) - background animation only + // (no padding/gap changes needed) // --------------------------------------------------------------------------- // Focus State (keyboard navigation) - with icon // --------------------------------------------------------------------------- &:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { - background-color: $bds-btn-primary-bg-hover; - border: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; - outline: none; - // Compensate for 2px border on all sides - padding: 6px 11px 6px 18px; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 2px; + padding: 8px 13px 8px 20px; gap: 22px; } - // Focus State (no icon) - only change background and add border + // Focus State (no icon) - only add outline &:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { - background-color: $bds-btn-primary-bg-hover; - border: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; - outline: none; - // Compensate for 2px border but keep symmetric padding - padding: 6px 17px 6px 18px; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 2px; + padding: 8px 20px; } // --------------------------------------------------------------------------- // Active State (being pressed) // --------------------------------------------------------------------------- &:active:not(:disabled):not(.bds-btn--disabled) { - background-color: $bds-btn-primary-bg; - transform: scale(0.98); // Maintains default padding and gap padding: 8px 19px 8px 20px; gap: 16px; + // Background reset handled by shared ::before in base class } // --------------------------------------------------------------------------- // Disabled State + // Note: Icon is hidden via component logic when disabled // --------------------------------------------------------------------------- &:disabled, &.bds-btn--disabled { @@ -176,8 +253,9 @@ $bds-btn-transition-timing: ease-in-out; cursor: not-allowed; pointer-events: none; - .bds-btn__icon { - opacity: 0.5; + // Disable background animation on disabled + &::before { + display: none; } } @@ -200,20 +278,19 @@ $bds-btn-transition-timing: ease-in-out; gap: 21px; } - // Hover state - smaller screens (no icon) - &:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { - background-color: $bds-btn-primary-bg-hover; - } - // Focus state - smaller screens (with icon) &:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { - padding: 6px 8px 6px 14px; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 2px; + padding: 8px 10px 8px 16px; gap: 21px; } // Focus state - smaller screens (no icon) &:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { - padding: 6px 13px 6px 14px; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 2px; + padding: 8px 16px; } // Active state - smaller screens (maintains default padding) @@ -224,16 +301,231 @@ $bds-btn-transition-timing: ease-in-out; } } +// ============================================================================= +// Secondary Variant +// ============================================================================= +// HOVER ANIMATION: Background fills bottom-to-top (Transparent → Green 100) +// Text/arrow color fades from green-400 to green-500 via currentColor +// Animation structure inherited from base .bds-btn class + +.bds-btn--secondary { + // Default/Enabled state + color: $bds-btn-secondary-text; + background-color: transparent; + border: 2px solid $bds-btn-secondary-border; + + // Set the hover background color for ::before pseudo-element + &::before { + background-color: $bds-btn-secondary-bg-hover; + } + + // Desktop padding and gap (≥1024px) - compensate for 2px border + padding: 6px 17px 6px 18px; + gap: 16px; + + // No icon - symmetric padding + &.bds-btn--no-icon { + padding: 6px 18px; + } + + // --------------------------------------------------------------------------- + // Hover State + // --------------------------------------------------------------------------- + &:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + color: $bds-btn-secondary-text-hover; + border-color: $bds-btn-secondary-border-hover; + padding: 6px 11px 6px 18px; + gap: 22px; + // Background animation handled by shared ::before in base class + } + + &:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + color: $bds-btn-secondary-text-hover; + border-color: $bds-btn-secondary-border-hover; + } + + // --------------------------------------------------------------------------- + // Focus State (keyboard navigation) + // --------------------------------------------------------------------------- + &:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + color: $bds-btn-secondary-text-hover; + border: none; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 2px; + // Add 2px padding to compensate for removed border, maintain hover padding + padding: 6px 13px 6px 20px; + gap: 22px; + } + + &:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + color: $bds-btn-secondary-text-hover; + border: none; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 2px; + // Add 2px padding to compensate for removed border + padding: 6px 20px; + } + + // --------------------------------------------------------------------------- + // Active State (being pressed) + // --------------------------------------------------------------------------- + &:active:not(:disabled):not(.bds-btn--disabled) { + color: $bds-btn-secondary-text; + border-color: $bds-btn-secondary-border; + padding: 6px 17px 6px 18px; + gap: 16px; + // Background reset handled by shared ::before in base class + } + + // --------------------------------------------------------------------------- + // Disabled State + // Note: Icon is hidden via component logic when disabled + // --------------------------------------------------------------------------- + &:disabled, + &.bds-btn--disabled { + color: $bds-btn-secondary-disabled-text; + background-color: transparent; + border-color: $bds-btn-secondary-disabled-border; + cursor: not-allowed; + pointer-events: none; + + // Disable background animation on disabled + &::before { + display: none; + } + } + + // --------------------------------------------------------------------------- + // Tablet & Mobile Responsive Styles (≤1023px) + // --------------------------------------------------------------------------- + @media (max-width: 1023px) { + padding: 6px 13px 6px 14px; + gap: 16px; + + &.bds-btn--no-icon { + padding: 6px 14px; + } + + &:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + padding: 6px 8px 6px 14px; + gap: 21px; + } + + &:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + border: none; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 2px; + // Add 2px padding to compensate for removed border, maintain hover padding + padding: 6px 10px 6px 16px; + gap: 21px; + } + + &:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + border: none; + outline: $bds-btn-focus-border-width solid $bds-btn-primary-focus-border; + outline-offset: 2px; + // Add 2px padding to compensate for removed border + padding: 6px 16px; + } + + &:active:not(:disabled):not(.bds-btn--disabled) { + padding: 6px 13px 6px 14px; + gap: 16px; + } + } +} + +// ============================================================================= +// Color Themes +// ============================================================================= +// Green theme (.bds-btn--green) is the default - no overrides needed. +// Black theme (.bds-btn--black) overrides colors for both variants. + +// Black theme - overrides colors for primary and secondary variants +.bds-btn--black { + // --------------------------------------------------------------------------- + // Black Primary Button + // --------------------------------------------------------------------------- + &.bds-btn--primary { + color: $bds-btn-primary-black-text; + background-color: $bds-btn-primary-black-bg; + + // Set hover background for ::before pseudo-element + &::before { + background-color: $bds-btn-primary-black-bg-hover; + } + + // Hover state - background animates, colors stay same + &:hover:not(:disabled):not(.bds-btn--disabled) { + color: $bds-btn-primary-black-text; + } + + // Focus state + &:focus-visible:not(:disabled):not(.bds-btn--disabled) { + color: $bds-btn-primary-black-text; + outline: $bds-btn-focus-border-width solid $bds-btn-neutral-black; + outline-offset: 2px; + } + + // Active state + &:active:not(:disabled):not(.bds-btn--disabled) { + color: $bds-btn-primary-black-text; + } + + // Disabled state - same as green disabled + &:disabled, + &.bds-btn--disabled { + color: $bds-btn-disabled-text; + background-color: $bds-btn-disabled-bg; + } + } + + // --------------------------------------------------------------------------- + // Black Secondary Button + // --------------------------------------------------------------------------- + &.bds-btn--secondary { + color: $bds-btn-secondary-black-text; + border-color: $bds-btn-secondary-black-border; + + // Set hover background for ::before pseudo-element + &::before { + background-color: $bds-btn-secondary-black-bg-hover; + } + + // Hover state - text stays black, background fills with 15% black + &:hover:not(:disabled):not(.bds-btn--disabled) { + color: $bds-btn-secondary-black-text; + border-color: $bds-btn-secondary-black-border; + } + + // Focus state + &:focus-visible:not(:disabled):not(.bds-btn--disabled) { + color: $bds-btn-secondary-black-text; + border: none; + outline: $bds-btn-focus-border-width solid $bds-btn-neutral-black; + outline-offset: 2px; + } + + // Active state + &:active:not(:disabled):not(.bds-btn--disabled) { + color: $bds-btn-secondary-black-text; + border-color: $bds-btn-secondary-black-border; + } + + // Disabled state + &:disabled, + &.bds-btn--disabled { + color: $bds-btn-disabled-text; + border-color: $bds-btn-secondary-disabled-border; + } + } +} + // ============================================================================= // Future Variants (Placeholder structure for scalability) // ============================================================================= -// .bds-btn--secondary { -// // Outline style: green stroke, transparent fill -// // States: enabled, hover, focus, active, disabled -// } - // .bds-btn--tertiary { // // Text-only style: green text, no border/fill // // States: enabled, hover (underline), focus, active, disabled -// } +// } \ No newline at end of file diff --git a/shared/components/Button/Button.tsx b/shared/components/Button/Button.tsx index e9e8b29aad..b75ca58bae 100644 --- a/shared/components/Button/Button.tsx +++ b/shared/components/Button/Button.tsx @@ -2,7 +2,9 @@ import React from 'react'; export interface ButtonProps { /** Button variant - determines visual style */ - variant?: 'primary'; // Extensible: | 'secondary' | 'tertiary' + variant?: 'primary' | 'secondary'; + /** Color theme - green (default) or black */ + color?: 'green' | 'black'; /** Button content/label */ children: React.ReactNode; /** Click handler */ @@ -59,13 +61,16 @@ const ArrowIcon: React.FC = () => ( * BDS Button Component * * A scalable button component following the XRPL Brand Design System. - * Currently supports the Primary variant with plans for Secondary and Tertiary. + * Supports Primary and Secondary variants with green (default) or black color themes. * * @example * + * + * */ export const Button: React.FC = ({ variant = 'primary', + color = 'green', children, onClick, disabled = false, @@ -73,12 +78,16 @@ export const Button: React.FC = ({ className = '', showIcon = true, }) => { + // Hide icon when disabled (per design spec) + const shouldShowIcon = showIcon && !disabled; + // Build class names using BEM with bds namespace const classNames = [ 'bds-btn', `bds-btn--${variant}`, + `bds-btn--${color}`, disabled ? 'bds-btn--disabled' : '', - !showIcon ? 'bds-btn--no-icon' : '', + !shouldShowIcon ? 'bds-btn--no-icon' : '', className, ] .filter(Boolean) @@ -93,7 +102,7 @@ export const Button: React.FC = ({ aria-disabled={disabled} > {children} - {showIcon && } + {shouldShowIcon && } ); }; diff --git a/static/css/devportal2024-v1.css b/static/css/devportal2024-v1.css index 75d6199d2f..c32eb19325 100644 --- a/static/css/devportal2024-v1.css +++ b/static/css/devportal2024-v1.css @@ -11159,29 +11159,52 @@ button[disabled=disabled] { border: none; border-radius: 100px; cursor: pointer; - transition-property: background-color, border-color, transform, padding, gap; - transition-duration: 150ms; - transition-timing-function: ease-in-out; + position: relative; + overflow: hidden; + z-index: 1; + transition: color 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98), border-color 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98), padding 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98), gap 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98), transform 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98); +} +.bds-btn::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + transform: scaleY(0); + transform-origin: bottom center; + transition: transform 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98); +} +.bds-btn:hover:not(:disabled):not(.bds-btn--disabled)::before, .bds-btn:focus-visible:not(:disabled):not(.bds-btn--disabled)::before { + transform: scaleY(1); +} +.bds-btn:active:not(:disabled):not(.bds-btn--disabled)::before { + transform: scaleY(0); } .bds-btn__label { flex-shrink: 0; + position: relative; + z-index: 1; } .bds-btn__icon { width: 15px; height: 14px; flex-shrink: 0; - transition: opacity 150ms ease-in-out; + transition: opacity 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98); color: currentColor; overflow: visible; + position: relative; + z-index: 1; } .bds-btn__icon-line { transform-box: fill-box; transform-origin: right center; transform: scaleX(1); - transition: transform 150ms ease-in-out; + transition: transform 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98); } .bds-btn__icon-chevron { - transition: transform 150ms ease-in-out; + transition: transform 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98); } .bds-btn:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line, .bds-btn:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line { transform: scaleX(0); @@ -11190,6 +11213,11 @@ button[disabled=disabled] { .bds-btn--primary { color: #141414; background-color: #21E46B; +} +.bds-btn--primary::before { + background-color: #70EE97; +} +.bds-btn--primary { padding: 8px 19px 8px 20px; gap: 16px; } @@ -11197,29 +11225,21 @@ button[disabled=disabled] { padding: 8px 20px; } .bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { - background-color: #70EE97; padding: 8px 13px 8px 20px; gap: 22px; } -.bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { - background-color: #70EE97; -} .bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { - background-color: #70EE97; - border: 2px solid #141414; - outline: none; - padding: 6px 11px 6px 18px; + outline: 2px solid #141414; + outline-offset: 2px; + padding: 8px 13px 8px 20px; gap: 22px; } .bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { - background-color: #70EE97; - border: 2px solid #141414; - outline: none; - padding: 6px 17px 6px 18px; + outline: 2px solid #141414; + outline-offset: 2px; + padding: 8px 20px; } .bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) { - background-color: #21E46B; - transform: scale(0.98); padding: 8px 19px 8px 20px; gap: 16px; } @@ -11229,8 +11249,8 @@ button[disabled=disabled] { cursor: not-allowed; pointer-events: none; } -.bds-btn--primary:disabled .bds-btn__icon, .bds-btn--primary.bds-btn--disabled .bds-btn__icon { - opacity: 0.5; +.bds-btn--primary:disabled::before, .bds-btn--primary.bds-btn--disabled::before { + display: none; } @media (max-width: 1023px) { .bds-btn--primary { @@ -11244,15 +11264,16 @@ button[disabled=disabled] { padding: 8px 10px 8px 16px; gap: 21px; } - .bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { - background-color: #70EE97; - } .bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { - padding: 6px 8px 6px 14px; + outline: 2px solid #141414; + outline-offset: 2px; + padding: 8px 10px 8px 16px; gap: 21px; } .bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { - padding: 6px 13px 6px 14px; + outline: 2px solid #141414; + outline-offset: 2px; + padding: 8px 16px; } .bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) { padding: 8px 15px 8px 16px; @@ -11260,6 +11281,141 @@ button[disabled=disabled] { } } +.bds-btn--secondary { + color: #0DAA3E; + background-color: transparent; + border: 2px solid #0DAA3E; +} +.bds-btn--secondary::before { + background-color: #EAFCF1; +} +.bds-btn--secondary { + padding: 6px 17px 6px 18px; + gap: 16px; +} +.bds-btn--secondary.bds-btn--no-icon { + padding: 6px 18px; +} +.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + color: #078139; + border-color: #078139; + padding: 6px 11px 6px 18px; + gap: 22px; +} +.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + color: #078139; + border-color: #078139; +} +.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + color: #078139; + border: none; + outline: 2px solid #141414; + outline-offset: 2px; + padding: 6px 13px 6px 20px; + gap: 22px; +} +.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + color: #078139; + border: none; + outline: 2px solid #141414; + outline-offset: 2px; + padding: 6px 20px; +} +.bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) { + color: #0DAA3E; + border-color: #0DAA3E; + padding: 6px 17px 6px 18px; + gap: 16px; +} +.bds-btn--secondary:disabled, .bds-btn--secondary.bds-btn--disabled { + color: #A2A2A4; + background-color: transparent; + border-color: #A2A2A4; + cursor: not-allowed; + pointer-events: none; +} +.bds-btn--secondary:disabled::before, .bds-btn--secondary.bds-btn--disabled::before { + display: none; +} +@media (max-width: 1023px) { + .bds-btn--secondary { + padding: 6px 13px 6px 14px; + gap: 16px; + } + .bds-btn--secondary.bds-btn--no-icon { + padding: 6px 14px; + } + .bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + padding: 6px 8px 6px 14px; + gap: 21px; + } + .bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) { + border: none; + outline: 2px solid #141414; + outline-offset: 2px; + padding: 6px 10px 6px 16px; + gap: 21px; + } + .bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon { + border: none; + outline: 2px solid #141414; + outline-offset: 2px; + padding: 6px 16px; + } + .bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) { + padding: 6px 13px 6px 14px; + gap: 16px; + } +} + +.bds-btn--black.bds-btn--primary { + color: #FFFFFF; + background-color: #141414; +} +.bds-btn--black.bds-btn--primary::before { + background-color: rgba(20, 20, 20, 0.8); +} +.bds-btn--black.bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled) { + color: #FFFFFF; +} +.bds-btn--black.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled) { + color: #FFFFFF; + outline: 2px solid #141414; + outline-offset: 2px; +} +.bds-btn--black.bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) { + color: #FFFFFF; +} +.bds-btn--black.bds-btn--primary:disabled, .bds-btn--black.bds-btn--primary.bds-btn--disabled { + color: #838386; + background-color: #E0E0E1; +} +.bds-btn--black.bds-btn--secondary { + color: #141414; + border-color: #141414; +} +.bds-btn--black.bds-btn--secondary::before { + background-color: rgba(20, 20, 20, 0.15); +} +.bds-btn--black.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled) { + color: #141414; + border-color: #141414; +} +.bds-btn--black.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled) { + color: #141414; + border: none; + outline: 2px solid #141414; + outline-offset: 2px; +} +.bds-btn--black.bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) { + color: #141414; + border-color: #141414; +} +.bds-btn--black.bds-btn--secondary:disabled, .bds-btn--black.bds-btn--secondary.bds-btn--disabled { + color: #838386; + border-color: #A2A2A4; +} + /* TABLE STYLING */ article table { clear: right; diff --git a/styles/xrpl.scss b/styles/xrpl.scss index 25490014ec..1e3bcccedc 100644 --- a/styles/xrpl.scss +++ b/styles/xrpl.scss @@ -131,4 +131,4 @@ $grid-breakpoints: ( html.light { @import "light/_light-theme.scss"; -} +} \ No newline at end of file