Files
metabuilder/qml/hybrid/Button/Button.module.scss
johndoe6345789 c406b8df96 refactor: Reorganize FakeMUI by implementation type
Move FakeMUI content to appropriate root-level folders by implementation:

**React Components → components/fakemui/**
- 537 components (inputs, surfaces, layout, data-display, feedback,
  navigation, utils, atoms, lab, x, email, workflows)
- 416 SVG icons
- Full barrel exports in components/fakemui/index.ts

**QML Components → qml/**
- 104 Material Design 3 components (11 categories)
- 7 hybrid application views
- 8 desktop widgets
- qmldir module registration

**Python Bindings → python/fakemui/**
- 15 PyQt6 modules (120+ components)
- Full Python package structure with pyproject.toml

**SCSS/Styles → fakemui/** (renamed purpose)
- scss/ - Material Design 3 stylesheets
- styles/ - Component SCSS modules
- src/utils/ - Accessibility utilities
- index.ts now re-exports from components/fakemui/

This separation allows:
- React: import { Button } from '@metabuilder/components/fakemui'
- QML: import QmlComponents 1.0
- Python: from fakemui import Button, Card
- Backward compat: import { Button } from '@metabuilder/fakemui'

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 12:59:24 +00:00

330 lines
6.8 KiB
SCSS

// Button Component - Material Design 3
// =====================================
// Implements M3 button specifications using official M3 tokens
// https://m3.material.io/components/buttons/specs
@use '../tokens' as m3;
// Base button styles
.button {
// Layout
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
border: none;
border-radius: m3.$corner-full;
cursor: pointer;
text-decoration: none;
overflow: hidden;
user-select: none;
vertical-align: middle;
-webkit-appearance: none;
// Typography (M3 label-large)
@include m3.typography(label-large);
// Transitions
transition:
background-color m3.$motion-duration-short4 m3.$motion-easing-standard,
box-shadow m3.$motion-duration-short4 m3.$motion-easing-standard,
border-color m3.$motion-duration-short4 m3.$motion-easing-standard;
// Touch target (48px minimum)
&::after {
content: '';
position: absolute;
inset: 50% auto auto 50%;
transform: translate(-50%, -50%);
width: 48px;
height: 48px;
}
// Focus ring
&:focus-visible {
outline: 2px solid m3.$primary;
outline-offset: 2px;
}
// Disabled base state
&:disabled {
@include m3.disabled;
}
// Icon sizing
.icon {
display: inline-flex;
font-size: 1.125rem;
width: 1.125rem;
height: 1.125rem;
}
// ============================================
// Size Variants
// ============================================
&--small {
height: 32px;
padding: 0 16px;
font-size: 0.75rem;
.icon {
font-size: 1rem;
width: 1rem;
height: 1rem;
}
}
&--medium {
height: 40px;
padding: 0 24px;
}
&--large {
height: 48px;
padding: 0 32px;
font-size: 1rem;
.icon {
font-size: 1.25rem;
width: 1.25rem;
height: 1.25rem;
}
}
// ============================================
// Filled Button (High Emphasis)
// ============================================
&--filled {
background: m3.$primary;
color: m3.$on-primary;
&:hover:not(:disabled) {
// M3: state layer with on-primary color at hover opacity
background: color-mix(
in srgb,
m3.$primary calc(100% - 8%),
m3.$on-primary
);
}
&:focus-visible:not(:disabled) {
background: color-mix(
in srgb,
m3.$primary calc(100% - 12%),
m3.$on-primary
);
}
&:active:not(:disabled) {
background: color-mix(
in srgb,
m3.$primary calc(100% - 12%),
m3.$on-primary
);
}
&:disabled {
background: color-mix(
in srgb,
m3.$on-surface #{m3.$disabled-container-opacity * 100%},
transparent
);
color: color-mix(
in srgb,
m3.$on-surface #{m3.$disabled-content-opacity * 100%},
transparent
);
}
}
// ============================================
// Outlined Button (Medium Emphasis)
// ============================================
&--outlined {
background: transparent;
color: m3.$primary;
border: 1px solid m3.$outline;
&:hover:not(:disabled) {
background: color-mix(
in srgb,
m3.$primary 8%,
transparent
);
}
&:focus-visible:not(:disabled) {
background: color-mix(
in srgb,
m3.$primary 12%,
transparent
);
border-color: m3.$primary;
}
&:active:not(:disabled) {
background: color-mix(
in srgb,
m3.$primary 12%,
transparent
);
}
&:disabled {
color: color-mix(
in srgb,
m3.$on-surface #{m3.$disabled-content-opacity * 100%},
transparent
);
border-color: color-mix(
in srgb,
m3.$on-surface #{m3.$disabled-container-opacity * 100%},
transparent
);
}
}
// ============================================
// Text Button (Low Emphasis)
// ============================================
&--text {
background: transparent;
color: m3.$primary;
padding: 0 12px;
&:hover:not(:disabled) {
background: color-mix(
in srgb,
m3.$primary 8%,
transparent
);
}
&:focus-visible:not(:disabled) {
background: color-mix(
in srgb,
m3.$primary 12%,
transparent
);
}
&:active:not(:disabled) {
background: color-mix(
in srgb,
m3.$primary 12%,
transparent
);
}
&:disabled {
color: color-mix(
in srgb,
m3.$on-surface #{m3.$disabled-content-opacity * 100%},
transparent
);
}
}
// ============================================
// Tonal Button (Secondary Container)
// ============================================
&--tonal {
background: m3.$secondary-container;
color: m3.$on-secondary-container;
&:hover:not(:disabled) {
background: color-mix(
in srgb,
m3.$secondary-container calc(100% - 8%),
m3.$on-secondary-container
);
}
&:focus-visible:not(:disabled) {
background: color-mix(
in srgb,
m3.$secondary-container calc(100% - 12%),
m3.$on-secondary-container
);
}
&:active:not(:disabled) {
background: color-mix(
in srgb,
m3.$secondary-container calc(100% - 12%),
m3.$on-secondary-container
);
}
&:disabled {
background: color-mix(
in srgb,
m3.$on-surface #{m3.$disabled-container-opacity * 100%},
transparent
);
color: color-mix(
in srgb,
m3.$on-surface #{m3.$disabled-content-opacity * 100%},
transparent
);
}
}
// ============================================
// Elevated Button (With Shadow)
// ============================================
&--elevated {
background: m3.$surface-container-low;
color: m3.$primary;
box-shadow: m3.$elevation-level1;
&:hover:not(:disabled) {
background: color-mix(
in srgb,
m3.$surface-container-low calc(100% - 8%),
m3.$primary
);
box-shadow: m3.$elevation-level2;
}
&:focus-visible:not(:disabled) {
background: color-mix(
in srgb,
m3.$surface-container-low calc(100% - 12%),
m3.$primary
);
box-shadow: m3.$elevation-level1;
}
&:active:not(:disabled) {
background: color-mix(
in srgb,
m3.$surface-container-low calc(100% - 12%),
m3.$primary
);
box-shadow: m3.$elevation-level1;
}
&:disabled {
background: color-mix(
in srgb,
m3.$on-surface #{m3.$disabled-container-opacity * 100%},
transparent
);
color: color-mix(
in srgb,
m3.$on-surface #{m3.$disabled-content-opacity * 100%},
transparent
);
box-shadow: m3.$elevation-level0;
}
}
}