mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 22:04:56 +00:00
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>
330 lines
6.8 KiB
SCSS
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;
|
|
}
|
|
}
|
|
}
|