add proper focus and active / hover states

This commit is contained in:
akcodez
2025-12-01 13:45:21 -08:00
parent 32b309c878
commit 73b2127f87
8 changed files with 1733 additions and 153 deletions

View File

@@ -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 (
<div className="landing">
<section className="container-new py-26">
@@ -96,16 +88,96 @@ export default function ButtonShowcase() {
<Button variant="primary" onClick={handleClick} className="me-4 mb-4">
Hover Me
</Button>
<Button variant="primary" onClick={handleClick} className="me-4 mb-4">
<Button variant="primary" onClick={handleClick} className="mb-4">
Focus Me (Tab)
</Button>
<Button variant="primary" onClick={handleClick} className="mb-4">
Active State (Click)
</div>
</div>
</section>
{/* Black Color Variant */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Black Color Variant</h2>
<h6 className="eyebrow mb-3">Color Theme</h6>
</div>
<p className="mb-4 text-muted">
Primary buttons can use a black color theme for dark backgrounds or alternative styling needs.
</p>
<div className="d-flex flex-wrap align-items-center">
<Button variant="primary" color="black" onClick={handleClick} className="me-4 mb-4">
Black Primary
</Button>
<Button variant="primary" color="black" onClick={handleClick} className="me-4 mb-4">
Dark Button
</Button>
<Button variant="primary" color="black" onClick={handleClick} className="mb-4">
Get Started
</Button>
</div>
</section>
{/* Black Variant States */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Black Variant States</h2>
<h6 className="eyebrow mb-3">Interactive States</h6>
</div>
<PageGrid>
<PageGridRow>
<PageGridCol span={{ base: 4, lg: 6 }}>
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
<h5 className="mb-4">Enabled State</h5>
<p className="mb-4 text-muted">Black background with white text.</p>
<Button variant="primary" color="black" onClick={handleClick}>
Enabled Button
</Button>
</div>
</PageGridCol>
<PageGridCol span={{ base: 4, lg: 6 }}>
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
<h5 className="mb-4">Disabled State</h5>
<p className="mb-4 text-muted">Same disabled styling as green variant.</p>
<Button variant="primary" color="black" disabled>
Disabled Button
</Button>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<div className="mt-10">
<h5 className="mb-4">Hover & Focus States</h5>
<p className="mb-4 text-muted">
Hover over the buttons or use Tab to focus them. Notice the background darkens slightly on hover.
</p>
<div className="d-flex flex-wrap">
<Button variant="primary" color="black" onClick={handleClick} className="me-4 mb-4">
Hover Me
</Button>
<Button variant="primary" color="black" onClick={handleClick} className="mb-4">
Focus Me (Tab)
</Button>
</div>
</div>
</section>
{/* Green vs Black Comparison */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Green vs Black Comparison</h2>
<h6 className="eyebrow mb-3">Color Themes</h6>
</div>
<p className="mb-4 text-muted">Compare the green (default) and black color themes side by side.</p>
<div className="d-flex flex-wrap align-items-center">
<Button variant="primary" color="green" onClick={handleClick} className="me-4 mb-4">
Green Primary
</Button>
<Button variant="primary" color="black" onClick={handleClick} className="mb-4">
Black Primary
</Button>
</div>
</section>
{/* Without Icon */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
@@ -149,23 +221,6 @@ export default function ButtonShowcase() {
</form>
</section>
{/* Loading State Simulation */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Async Actions</h2>
<h6 className="eyebrow mb-3">Loading States</h6>
</div>
<p className="mb-4 text-muted">
Example of handling async actions. The button is disabled during the async operation.
</p>
<Button variant="primary" disabled={isLoading} onClick={handleAsyncClick}>
{isLoading ? 'Loading...' : 'Async Action'}
</Button>
{clickCount > 0 && (
<p className="mt-4 text-muted">Async action completed {clickCount} time{clickCount !== 1 ? 's' : ''}</p>
)}
</section>
{/* Responsive Behavior */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
@@ -252,11 +307,16 @@ export default function ButtonShowcase() {
<pre style={{ margin: 0, overflow: 'auto' }}>
<code>{`import { Button } from 'shared/components/Button';
// Basic usage
// Basic usage (green theme - default)
<Button variant="primary" onClick={handleClick}>
Get Started
</Button>
// Black color theme
<Button variant="primary" color="black" onClick={handleClick}>
Dark Button
</Button>
// Disabled state
<Button variant="primary" disabled>
Submit
@@ -305,49 +365,90 @@ export default function ButtonShowcase() {
</PageGridRow>
</PageGrid>
<div className="mt-10">
<h5 className="mb-4">State Colors</h5>
<table className="table" style={{ width: '100%' }}>
<thead>
<tr>
<th>State</th>
<th>Text Color</th>
<th>Background Color</th>
<th>Border</th>
</tr>
</thead>
<tbody>
<tr>
<td>Enabled</td>
<td>#141414 (Neutral Black)</td>
<td>#21E46B (Green 300)</td>
<td>None</td>
</tr>
<tr>
<td>Hover</td>
<td>#141414 (Neutral Black)</td>
<td>#70EE97 (Green 200)</td>
<td>None</td>
</tr>
<tr>
<td>Focus</td>
<td>#141414 (Neutral Black)</td>
<td>#70EE97 (Green 200)</td>
<td>2px solid #141414</td>
</tr>
<tr>
<td>Active</td>
<td>#141414 (Neutral Black)</td>
<td>#21E46B (Green 300)</td>
<td>None</td>
</tr>
<tr>
<td>Disabled</td>
<td>#838386 (Gray 500)</td>
<td>#E0E0E1 (Gray 200)</td>
<td>None</td>
</tr>
</tbody>
</table>
<h5 className="mb-4">State Colors - Green Theme</h5>
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
{/* Header */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background Color</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Border</div>
</div>
{/* Rows */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Enabled</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>#21E46B (Green 300)</div>
<div style={{ padding: '12px' }}>None</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Hover</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>#70EE97 (Green 200)</div>
<div style={{ padding: '12px' }}>None</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Focus</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>#70EE97 (Green 200)</div>
<div style={{ padding: '12px' }}>2px solid #141414</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Active</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>#21E46B (Green 300)</div>
<div style={{ padding: '12px' }}>None</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
<div style={{ padding: '12px' }}>Disabled</div>
<div style={{ padding: '12px' }}>#838386 (Gray 500)</div>
<div style={{ padding: '12px' }}>#E0E0E1 (Gray 200)</div>
<div style={{ padding: '12px' }}>None</div>
</div>
</div>
</div>
<div className="mt-10">
<h5 className="mb-4">State Colors - Black Theme</h5>
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
{/* Header */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background Color</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Border</div>
</div>
{/* Rows */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Enabled</div>
<div style={{ padding: '12px' }}>#FFFFFF (White)</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>None</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Hover</div>
<div style={{ padding: '12px' }}>#FFFFFF (White)</div>
<div style={{ padding: '12px' }}>rgba(20, 20, 20, 0.8) (80% Black)</div>
<div style={{ padding: '12px' }}>None</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Focus</div>
<div style={{ padding: '12px' }}>#FFFFFF (White)</div>
<div style={{ padding: '12px' }}>rgba(20, 20, 20, 0.8) (80% Black)</div>
<div style={{ padding: '12px' }}>2px solid #141414</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Active</div>
<div style={{ padding: '12px' }}>#FFFFFF (White)</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>None</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
<div style={{ padding: '12px' }}>Disabled</div>
<div style={{ padding: '12px' }}>#838386 (Gray 500)</div>
<div style={{ padding: '12px' }}>#E0E0E1 (Gray 200)</div>
<div style={{ padding: '12px' }}>None</div>
</div>
</div>
</div>
</section>
</div>

View File

@@ -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 (
<div className="landing">
<section className="container-new py-26">
<div className="d-flex flex-column-reverse col-lg-8 mx-auto">
<h1 className="mb-0">BDS Secondary Button</h1>
<h6 className="eyebrow mb-3">Brand Design System</h6>
</div>
<p className="col-lg-8 mx-auto mt-10">
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.
</p>
</section>
{/* Basic Usage */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Basic Usage</h2>
<h6 className="eyebrow mb-3">Secondary Variant</h6>
</div>
<div className="d-flex flex-wrap align-items-center">
<Button variant="secondary" onClick={handleClick} className="me-4 mb-4">
Learn More
</Button>
<Button variant="secondary" onClick={handleClick} className="me-4 mb-4">
View Details
</Button>
<Button variant="secondary" onClick={handleClick} className="mb-4">
Explore
</Button>
</div>
{clickCount > 0 && (
<p className="mt-4 text-muted">
Button clicked {clickCount} time{clickCount !== 1 ? 's' : ''}
</p>
)}
</section>
{/* Primary vs Secondary Comparison */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Primary vs Secondary</h2>
<h6 className="eyebrow mb-3">Visual Hierarchy</h6>
</div>
<p className="mb-4 text-muted">
Use Primary for main actions and Secondary for supporting actions to create clear visual hierarchy.
</p>
<div className="d-flex flex-wrap align-items-center">
<Button variant="primary" onClick={handleClick} className="me-4 mb-4">
Get Started
</Button>
<Button variant="secondary" onClick={handleClick} className="mb-4">
Learn More
</Button>
</div>
</section>
{/* States */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Button States</h2>
<h6 className="eyebrow mb-3">Interactive States</h6>
</div>
<PageGrid>
<PageGridRow>
<PageGridCol span={{ base: 4, lg: 6 }}>
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
<h5 className="mb-4">Enabled State</h5>
<p className="mb-4 text-muted">Default outline style with green border and text.</p>
<Button variant="secondary" onClick={handleClick}>
Enabled Button
</Button>
</div>
</PageGridCol>
<PageGridCol span={{ base: 4, lg: 6 }}>
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
<h5 className="mb-4">Disabled State</h5>
<p className="mb-4 text-muted">Gray border and text indicate non-interactive state.</p>
<Button variant="secondary" disabled>
Disabled Button
</Button>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<div className="mt-10">
<h5 className="mb-4">Hover & Focus States</h5>
<p className="mb-4 text-muted">
Hover over the buttons or use Tab to focus them. Notice the light green background fill and darker green
border on hover/focus.
</p>
<div className="d-flex flex-wrap">
<Button variant="secondary" onClick={handleClick} className="me-4 mb-4">
Hover Me
</Button>
<Button variant="secondary" onClick={handleClick} className="mb-4">
Focus Me (Tab)
</Button>
</div>
</div>
</section>
{/* Black Color Variant */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Black Color Variant</h2>
<h6 className="eyebrow mb-3">Color Theme</h6>
</div>
<p className="mb-4 text-muted">
Secondary buttons can use a black color theme with black text and border instead of green.
</p>
<div className="d-flex flex-wrap align-items-center">
<Button variant="secondary" color="black" onClick={handleClick} className="me-4 mb-4">
Black Secondary
</Button>
<Button variant="secondary" color="black" onClick={handleClick} className="me-4 mb-4">
Learn More
</Button>
<Button variant="secondary" color="black" onClick={handleClick} className="mb-4">
View Details
</Button>
</div>
</section>
{/* Black Variant States */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Black Variant States</h2>
<h6 className="eyebrow mb-3">Interactive States</h6>
</div>
<PageGrid>
<PageGridRow>
<PageGridCol span={{ base: 4, lg: 6 }}>
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
<h5 className="mb-4">Enabled State</h5>
<p className="mb-4 text-muted">Black border and text with transparent background.</p>
<Button variant="secondary" color="black" onClick={handleClick}>
Enabled Button
</Button>
</div>
</PageGridCol>
<PageGridCol span={{ base: 4, lg: 6 }}>
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
<h5 className="mb-4">Disabled State</h5>
<p className="mb-4 text-muted">Same disabled styling as green variant.</p>
<Button variant="secondary" color="black" disabled>
Disabled Button
</Button>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<div className="mt-10">
<h5 className="mb-4">Hover & Focus States</h5>
<p className="mb-4 text-muted">
Hover over the buttons or use Tab to focus them. Notice the subtle black background fill on hover.
</p>
<div className="d-flex flex-wrap">
<Button variant="secondary" color="black" onClick={handleClick} className="me-4 mb-4">
Hover Me
</Button>
<Button variant="secondary" color="black" onClick={handleClick} className="mb-4">
Focus Me (Tab)
</Button>
</div>
</div>
</section>
{/* Green vs Black Comparison */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Green vs Black Comparison</h2>
<h6 className="eyebrow mb-3">Color Themes</h6>
</div>
<p className="mb-4 text-muted">Compare the green (default) and black color themes side by side.</p>
<div className="d-flex flex-wrap align-items-center">
<Button variant="secondary" color="green" onClick={handleClick} className="me-4 mb-4">
Green Secondary
</Button>
<Button variant="secondary" color="black" onClick={handleClick} className="mb-4">
Black Secondary
</Button>
</div>
</section>
{/* Without Icon */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Without Icon</h2>
<h6 className="eyebrow mb-3">Icon Control</h6>
</div>
<p className="mb-4 text-muted">Secondary buttons can also be rendered without the arrow icon.</p>
<div className="d-flex flex-wrap">
<Button variant="secondary" showIcon={false} onClick={handleClick} className="me-4 mb-4">
No Icon Button
</Button>
<Button variant="secondary" showIcon={true} onClick={handleClick} className="mb-4">
With Icon Button
</Button>
</div>
</section>
{/* Button Types */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Button Types</h2>
<h6 className="eyebrow mb-3">Form Integration</h6>
</div>
<p className="mb-4 text-muted">Secondary buttons can be used for form actions like cancel or reset.</p>
<form
onSubmit={(e) => {
e.preventDefault();
alert('Form submitted!');
}}
className="d-flex flex-wrap"
>
<Button variant="primary" type="submit" className="me-4 mb-4">
Submit
</Button>
<Button variant="secondary" type="reset" className="me-4 mb-4">
Reset
</Button>
<Button variant="secondary" type="button" onClick={() => alert('Cancelled!')} className="mb-4">
Cancel
</Button>
</form>
</section>
{/* Responsive Behavior */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Responsive Behavior</h2>
<h6 className="eyebrow mb-3">Breakpoint Adjustments</h6>
</div>
<p className="mb-4 text-muted">
Button padding adjusts automatically across breakpoints. Resize your browser window to see the changes:
</p>
<ul className="mb-4">
<li>
<strong>Desktop (1024px):</strong> Padding: 6px 17px 6px 18px (compensates for 2px border)
</li>
<li>
<strong>Tablet/Mobile (1023px):</strong> Padding: 6px 13px 6px 14px
</li>
<li>
<strong>Hover/Focus:</strong> Gap increases (22px desktop, 21px mobile) with adjusted padding
</li>
</ul>
<div className="d-flex flex-wrap">
<Button variant="secondary" onClick={handleClick} className="me-4 mb-4">
Responsive Button
</Button>
<Button variant="secondary" onClick={handleClick} className="mb-4">
Long Button Label Example
</Button>
</div>
</section>
{/* Accessibility */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Accessibility Features</h2>
<h6 className="eyebrow mb-3">WCAG Compliance</h6>
</div>
<PageGrid>
<PageGridRow>
<PageGridCol span={{ base: 4, lg: 6 }}>
<h5 className="mb-4">Keyboard Navigation</h5>
<ul>
<li>Tab to focus buttons</li>
<li>Enter or Space to activate</li>
<li>Focus indicator: 2px black outline (additional to green border)</li>
<li>Disabled buttons are not focusable</li>
</ul>
</PageGridCol>
<PageGridCol span={{ base: 4, lg: 6 }}>
<h5 className="mb-4">Screen Reader Support</h5>
<ul>
<li>Button labels are announced</li>
<li>Disabled state communicated via aria-disabled</li>
<li>Icons are hidden from screen readers (aria-hidden)</li>
<li>Semantic button element used</li>
</ul>
</PageGridCol>
</PageGridRow>
</PageGrid>
<div className="mt-10">
<h5 className="mb-4">Color Contrast</h5>
<ul>
<li>
<strong>Enabled:</strong> Green 400 (#0DAA3E) on White = 4.52:1 (AA for large text)
</li>
<li>
<strong>Hover:</strong> Green 500 (#078139) on Green 100 (#EAFCF1) = 4.87:1 (AA)
</li>
<li>
<strong>Disabled:</strong> Gray 400 (#A2A2A4) on White = reduced contrast (acceptable for disabled state)
</li>
</ul>
</div>
</section>
{/* Code Examples */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Code Examples</h2>
<h6 className="eyebrow mb-3">Implementation</h6>
</div>
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#1e1e1e', color: '#d4d4d4' }}>
<pre style={{ margin: 0, overflow: 'auto' }}>
<code>{`import { Button } from 'shared/components/Button';
// Basic secondary button (green theme - default)
<Button variant="secondary" onClick={handleClick}>
Learn More
</Button>
// Black color theme
<Button variant="secondary" color="black" onClick={handleClick}>
Learn More
</Button>
// Disabled state
<Button variant="secondary" disabled>
Unavailable
</Button>
// Without icon
<Button variant="secondary" showIcon={false}>
Cancel
</Button>
// Primary + Secondary pairing
<Button variant="primary" type="submit">
Submit
</Button>
<Button variant="secondary" type="button">
Cancel
</Button>`}</code>
</pre>
</div>
</section>
{/* Design Specifications */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Design Specifications</h2>
<h6 className="eyebrow mb-3">Visual Details</h6>
</div>
<PageGrid>
<PageGridRow>
<PageGridCol span={{ base: 4, lg: 6 }}>
<h5 className="mb-4">Typography</h5>
<ul>
<li>Font: Booton, sans-serif</li>
<li>Size: 16px</li>
<li>Weight: 400</li>
<li>Line Height: 23.2px</li>
<li>Letter Spacing: 0px</li>
</ul>
</PageGridCol>
<PageGridCol span={{ base: 4, lg: 6 }}>
<h5 className="mb-4">Spacing & Layout</h5>
<ul>
<li>Border Radius: 100px (fully rounded)</li>
<li>Border Width: 2px solid</li>
<li>Icon Size: 15px × 14px</li>
<li>Icon Gap: 16px (default), 22px (hover/focus desktop), 21px (hover/focus mobile)</li>
<li>Max Height: 40px</li>
</ul>
</PageGridCol>
</PageGridRow>
</PageGrid>
<div className="mt-10">
<h5 className="mb-4">State Colors - Green Theme</h5>
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
{/* Header */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Border</div>
</div>
{/* Rows */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Enabled</div>
<div style={{ padding: '12px' }}>#0DAA3E (Green 400)</div>
<div style={{ padding: '12px' }}>Transparent</div>
<div style={{ padding: '12px' }}>2px #0DAA3E (Green 400)</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Hover</div>
<div style={{ padding: '12px' }}>#078139 (Green 500)</div>
<div style={{ padding: '12px' }}>#EAFCF1 (Green 100)</div>
<div style={{ padding: '12px' }}>2px #078139 (Green 500)</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Focus</div>
<div style={{ padding: '12px' }}>#078139 (Green 500)</div>
<div style={{ padding: '12px' }}>#EAFCF1 (Green 100)</div>
<div style={{ padding: '12px' }}>2px #078139 + 2px #141414 outline</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Active</div>
<div style={{ padding: '12px' }}>#0DAA3E (Green 400)</div>
<div style={{ padding: '12px' }}>Transparent</div>
<div style={{ padding: '12px' }}>2px #0DAA3E (Green 400)</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
<div style={{ padding: '12px' }}>Disabled</div>
<div style={{ padding: '12px' }}>#A2A2A4 (Gray 400)</div>
<div style={{ padding: '12px' }}>Transparent</div>
<div style={{ padding: '12px' }}>2px #A2A2A4 (Gray 400)</div>
</div>
</div>
</div>
<div className="mt-10">
<h5 className="mb-4">State Colors - Black Theme</h5>
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
{/* Header */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Border</div>
</div>
{/* Rows */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Enabled</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>Transparent</div>
<div style={{ padding: '12px' }}>2px #141414 (Neutral Black)</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Hover</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>rgba(20, 20, 20, 0.15) (15% Black)</div>
<div style={{ padding: '12px' }}>2px #141414 (Neutral Black)</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Focus</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>rgba(20, 20, 20, 0.15) (15% Black)</div>
<div style={{ padding: '12px' }}>2px #141414 + 2px #141414 outline</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Active</div>
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
<div style={{ padding: '12px' }}>Transparent</div>
<div style={{ padding: '12px' }}>2px #141414 (Neutral Black)</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
<div style={{ padding: '12px' }}>Disabled</div>
<div style={{ padding: '12px' }}>#A2A2A4 (Gray 400)</div>
<div style={{ padding: '12px' }}>Transparent</div>
<div style={{ padding: '12px' }}>2px #A2A2A4 (Gray 400)</div>
</div>
</div>
</div>
</section>
{/* Key Differences from Primary */}
<section className="container-new py-26">
<div className="d-flex flex-column-reverse">
<h2 className="h4 mb-8">Key Differences from Primary</h2>
<h6 className="eyebrow mb-3">Comparison</h6>
</div>
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
{/* Header */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Aspect</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Primary</div>
<div style={{ padding: '12px', fontWeight: 'bold' }}>Secondary</div>
</div>
{/* Rows */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Background (Enabled)</div>
<div style={{ padding: '12px' }}>Green 300 (#21E46B)</div>
<div style={{ padding: '12px' }}>Transparent</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Background (Hover)</div>
<div style={{ padding: '12px' }}>Green 200 (#70EE97)</div>
<div style={{ padding: '12px' }}>Green 100 (#EAFCF1)</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Border (Enabled)</div>
<div style={{ padding: '12px' }}>None</div>
<div style={{ padding: '12px' }}>2px Green 400</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Text Color (Enabled)</div>
<div style={{ padding: '12px' }}>Black (#141414)</div>
<div style={{ padding: '12px' }}>Green 400 (#0DAA3E)</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
<div style={{ padding: '12px' }}>Disabled Background</div>
<div style={{ padding: '12px' }}>Gray 200 (#E0E0E1)</div>
<div style={{ padding: '12px' }}>Transparent</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr' }}>
<div style={{ padding: '12px' }}>Arrow Icon</div>
<div style={{ padding: '12px' }}> Shared</div>
<div style={{ padding: '12px' }}> Shared</div>
</div>
</div>
</section>
</div>
);
}

View File

@@ -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: {

494
secondary-button-logic.md Normal file
View File

@@ -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)
<Button variant="secondary" onClick={handleClick}>
Learn More
</Button>
// Secondary button without icon
<Button variant="secondary" showIcon={false} onClick={handleClick}>
Cancel
</Button>
// Disabled secondary button
<Button variant="secondary" disabled>
Unavailable
</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)

View File

@@ -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,15 +301,230 @@ $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

View File

@@ -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
* <Button variant="primary" onClick={handleClick}>Get Started</Button>
* <Button variant="secondary" onClick={handleClick}>Learn More</Button>
* <Button variant="primary" color="black" onClick={handleClick}>Dark Button</Button>
*/
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
color = 'green',
children,
onClick,
disabled = false,
@@ -73,12 +78,16 @@ export const Button: React.FC<ButtonProps> = ({
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<ButtonProps> = ({
aria-disabled={disabled}
>
<span className="bds-btn__label">{children}</span>
{showIcon && <ArrowIcon />}
{shouldShowIcon && <ArrowIcon />}
</button>
);
};

View File

@@ -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;