docs: Motion System v1 + Button gold standard + Component Template + Decision Tree
- Motion System v1 (chapter 5):
- Motion principles: when to animate, when NOT to animate
- Duration scale (instant to slower: 0ms to 500ms)
- Easing functions (linear, in, out, in-out, spring)
- Component-specific motion: Button, Modal, Drawer, Map, Skeleton,
Progress, Error/Success
- Reduced motion support (prefers-reduced-motion)
- Interruption rules (animations must be interruptible)
- Error/success animations (shake, checkmark, pulse)
- Button gold standard (chapter 8.3.1):
- Full specification: purpose, design goal, token dependencies,
layout, sizes, variants, states, keyboard, touch, accessibility,
anti-patterns, related components, DDR references
- Sets the bar for all future component specifications
- COMPONENT_TEMPLATE.md (v1.0, LOCKED):
- Standard template for all component specifications
- Sections: purpose, tokens, layout, sizes, variants, states,
keyboard, touch, accessibility, motion, acceptance criteria,
anti-patterns, related components, DDR references
- COMPONENT_DECISION_TREE.md (v1.0, LOCKED):
- Decision trees for: user actions, information display, user input,
feedback, navigation, Landvex-specific
- Quick reference table mapping needs to components
- Prevents invention of unnecessary components
Rationale: Motion before brand (affects every interaction). Button as
reference implementation. Template ensures consistency. Decision tree
guides AI agents and developers to correct component choice.
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
# COMPONENT DECISION TREE
|
||||
|
||||
**Which Component Should I Use?**
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Version** | 1.0 |
|
||||
| **Status** | LOCKED |
|
||||
| **Scope** | All Landvex & quiXzoom products |
|
||||
|
||||
---
|
||||
|
||||
## How to Use This Document
|
||||
|
||||
Start at the top. Answer each question. Follow the path to the recommended component.
|
||||
|
||||
If no existing component fits, apply the **New Component Rule** (see Design Specification §8.2):
|
||||
1. Can an existing component be used?
|
||||
2. Can a variant be created?
|
||||
3. Can a modifier be used?
|
||||
4. Can a new state solve the problem?
|
||||
|
||||
Only then define a new component.
|
||||
|
||||
---
|
||||
|
||||
## User Actions
|
||||
|
||||
```
|
||||
Need user action?
|
||||
├── Yes → Primary action?
|
||||
│ ├── Yes → Button (Primary)
|
||||
│ └── No → Multiple options?
|
||||
│ ├── Yes → Select / Dropdown
|
||||
│ └── No → Toggle state?
|
||||
│ ├── Yes → Switch / Checkbox
|
||||
│ └── No → Navigation?
|
||||
│ ├── Yes → Navigation / Sidebar
|
||||
│ └── No → Search?
|
||||
│ ├── Yes → Search
|
||||
│ └── No → Command Palette
|
||||
└── No → Need information display?
|
||||
└── Yes → See Information Display
|
||||
```
|
||||
|
||||
## Information Display
|
||||
|
||||
```
|
||||
Need to display information?
|
||||
├── Yes → Tabular data?
|
||||
│ ├── Yes → Simple table?
|
||||
│ │ ├── Yes → Table
|
||||
│ │ └── No → Sorting, filtering, pagination?
|
||||
│ │ ├── Yes → Data Grid
|
||||
│ │ └── No → Table
|
||||
│ └── No → Spatial data?
|
||||
│ ├── Yes → Map Panel
|
||||
│ └── No → Summary metric?
|
||||
│ ├── Yes → KPI Card
|
||||
│ └── No → Grouped content?
|
||||
│ ├── Yes → Card / Accordion
|
||||
│ └── No → Single item?
|
||||
│ ├── Yes → Badge / Alert
|
||||
│ └── No → Tooltip
|
||||
└── No → Need user input?
|
||||
└── Yes → See User Input
|
||||
```
|
||||
|
||||
## User Input
|
||||
|
||||
```
|
||||
Need user input?
|
||||
├── Yes → Text input?
|
||||
│ ├── Yes → Single line?
|
||||
│ │ ├── Yes → Input
|
||||
│ │ └── No → Textarea
|
||||
│ └── No → Choice from options?
|
||||
│ ├── Yes → Single choice?
|
||||
│ │ ├── Yes → Radio / Select
|
||||
│ │ └── No → Multiple choice?
|
||||
│ │ ├── Yes → Checkbox / Multi-select
|
||||
│ │ └── No → Toggle?
|
||||
│ │ ├── Yes → Switch
|
||||
│ │ └── No → Date / time?
|
||||
│ │ ├── Yes → Date Picker
|
||||
│ │ └── No → Coordinate?
|
||||
│ │ ├── Yes → Coordinate Picker
|
||||
│ │ └── No → File?
|
||||
│ │ ├── Yes → File Upload
|
||||
│ │ └── No → Input (custom)
|
||||
│ └── No → Search / filter?
|
||||
│ ├── Yes → Search
|
||||
│ └── No → Command Palette
|
||||
└── No → Need feedback?
|
||||
└── Yes → See Feedback
|
||||
```
|
||||
|
||||
## Feedback
|
||||
|
||||
```
|
||||
Need to provide feedback?
|
||||
├── Yes → Blocking action?
|
||||
│ ├── Yes → Modal / Dialog
|
||||
│ └── No → Transient notification?
|
||||
│ ├── Yes → Toast
|
||||
│ └── No → Contextual message?
|
||||
│ ├── Yes → Alert (inline) / Tooltip
|
||||
│ └── No → Status indicator?
|
||||
│ ├── Yes → Badge
|
||||
│ └── No → Progress?
|
||||
│ ├── Yes → Progress / Skeleton
|
||||
│ └── No → Empty State
|
||||
└── No → Navigation or structure?
|
||||
└── Yes → See Navigation
|
||||
```
|
||||
|
||||
## Navigation
|
||||
|
||||
```
|
||||
Need navigation?
|
||||
├── Yes → Primary navigation?
|
||||
│ ├── Yes → Top-level sections?
|
||||
│ │ ├── Yes → Navigation
|
||||
│ │ └── No → Sidebar
|
||||
│ └── No → Secondary navigation?
|
||||
│ ├── Yes → Tabs / Breadcrumb
|
||||
│ └── No → Contextual navigation?
|
||||
│ ├── Yes → Pagination / Menu
|
||||
│ └── No → Command Palette
|
||||
└── No → Consider: is this a new component?
|
||||
└── Apply New Component Rule
|
||||
```
|
||||
|
||||
## Landvex-Specific (Domain Components)
|
||||
|
||||
```
|
||||
Need Landvex-specific component?
|
||||
├── Yes → Geospatial data?
|
||||
│ ├── Yes → Map visualization?
|
||||
│ │ ├── Yes → Map Panel
|
||||
│ │ └── No → Layer control?
|
||||
│ │ ├── Yes → Layer Selector
|
||||
│ │ └── No → Feature inspection?
|
||||
│ │ ├── Yes → Geospatial Inspector
|
||||
│ │ └── No → Coordinate input?
|
||||
│ │ └── Yes → Coordinate Picker
|
||||
│ └── No → Mission data?
|
||||
│ ├── Yes → Mission status?
|
||||
│ │ ├── Yes → Mission Status
|
||||
│ │ └── No → Mission timeline?
|
||||
│ │ └── Yes → Timeline Panel
|
||||
│ └── No → Asset data?
|
||||
│ ├── Yes → Asset summary?
|
||||
│ │ ├── Yes → Asset Summary
|
||||
│ │ └── No → Dataset preview?
|
||||
│ │ └── Yes → Dataset Card
|
||||
│ └── No → KPI display?
|
||||
│ └── Yes → KPI Card
|
||||
└── No → See general decision trees above
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Table
|
||||
|
||||
| Need | Component | Tier |
|
||||
|------|-----------|------|
|
||||
| Primary action | Button | 1 |
|
||||
| Text input | Input | 1 |
|
||||
| Choice from list | Select | 1 |
|
||||
| Content container | Card | 1 |
|
||||
| Overlay dialog | Modal | 1 |
|
||||
| Navigation | Navigation / Sidebar | 1 |
|
||||
| Tabular data | Table / Data Grid | 1 |
|
||||
| Search | Search | 1 |
|
||||
| Map display | Map Panel | 1 |
|
||||
| Status indicator | Badge | 2 |
|
||||
| Message | Alert / Toast | 2 |
|
||||
| Help text | Tooltip | 2 |
|
||||
| Collapsible content | Accordion | 2 |
|
||||
| Content switching | Tabs | 2 |
|
||||
| Location indicator | Breadcrumb | 2 |
|
||||
| Page navigation | Pagination | 2 |
|
||||
| No content | Empty State | 2 |
|
||||
| Loading | Skeleton | 2 |
|
||||
| Key metric | KPI Card | 3 |
|
||||
| Map tools | Map Overlay Panel | 3 |
|
||||
| Layer control | Layer Selector | 3 |
|
||||
| Mission state | Mission Status | 3 |
|
||||
| Data preview | Dataset Card | 3 |
|
||||
| Feature details | Geospatial Inspector | 3 |
|
||||
| Asset overview | Asset Summary | 3 |
|
||||
| Coordinate input | Coordinate Picker | 3 |
|
||||
| Time data | Timeline Panel | 3 |
|
||||
|
||||
---
|
||||
|
||||
## Relationship to Other Documents
|
||||
|
||||
| Document | Role |
|
||||
|----------|------|
|
||||
| `LANDVEX_DESIGN_SPECIFICATION.md` §8 | Component tiers and inheritance |
|
||||
| `COMPONENT_TEMPLATE.md` | How to document a component |
|
||||
| `DESIGN_ANTI_PATTERNS.md` | What not to do |
|
||||
| `COMPONENT_DECISION_TREE.md` | Which component to use |
|
||||
|
||||
---
|
||||
|
||||
## ÄNDRINGSHISTORIA
|
||||
|
||||
| Version | Datum | Beskrivning |
|
||||
|---------|-------|-------------|
|
||||
| 1.0 | 2026-07-02 | Initial decision trees for actions, information, input, feedback, navigation, and Landvex-specific |
|
||||
|
||||
---
|
||||
|
||||
## STATUS
|
||||
|
||||
**LOCKED**
|
||||
|
||||
- Mindre revideringar: 1.x-serien
|
||||
- Brytande ändringar: Kräver Architecture Review, ny major-version (2.0+)
|
||||
@@ -0,0 +1,143 @@
|
||||
# COMPONENT TEMPLATE
|
||||
|
||||
**Template for All Component Specifications**
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Version** | 1.0 |
|
||||
| **Status** | LOCKED |
|
||||
| **Scope** | All Landvex & quiXzoom components |
|
||||
|
||||
---
|
||||
|
||||
## Instructions
|
||||
|
||||
Copy this template for each new component. Remove sections that do not apply. Add sections that are component-specific.
|
||||
|
||||
---
|
||||
|
||||
## [Component Name]
|
||||
|
||||
**Purpose:** One sentence describing what this component does.
|
||||
|
||||
**Design Goal:** One sentence describing the ideal user experience.
|
||||
|
||||
**Tier:** [1 (Canonical) / 2 (Derived) / 3 (Domain)]
|
||||
|
||||
**Inherits From:** [Parent component, or "—" if canonical]
|
||||
|
||||
---
|
||||
|
||||
### Token Dependencies
|
||||
|
||||
| Token | Semantic Reference | Usage |
|
||||
|-------|-------------------|-------|
|
||||
| `component-token-1` | `semantic-token-1` | Description |
|
||||
| `component-token-2` | `semantic-token-2` | Description |
|
||||
|
||||
---
|
||||
|
||||
### Layout
|
||||
|
||||
- Dimensions
|
||||
- Padding
|
||||
- Margins
|
||||
- Border radius
|
||||
- Internal structure
|
||||
|
||||
---
|
||||
|
||||
### Sizes
|
||||
|
||||
| Size | Dimensions | Usage |
|
||||
|------|-----------|-------|
|
||||
| Small | [dimensions] | [context] |
|
||||
| Default | [dimensions] | [context] |
|
||||
| Large | [dimensions] | [context] |
|
||||
|
||||
---
|
||||
|
||||
### Variants
|
||||
|
||||
| Variant | Visual | Usage |
|
||||
|---------|--------|-------|
|
||||
| Variant 1 | [description] | [context] |
|
||||
| Variant 2 | [description] | [context] |
|
||||
|
||||
---
|
||||
|
||||
### States
|
||||
|
||||
| State | Visual | Motion |
|
||||
|-------|--------|--------|
|
||||
| Default | [description] | [animation] |
|
||||
| Hover | [description] | [animation] |
|
||||
| Focus | [description] | [animation] |
|
||||
| Active | [description] | [animation] |
|
||||
| Disabled | [description] | [animation] |
|
||||
| Loading | [description] | [animation] |
|
||||
| Error | [description] | [animation] |
|
||||
|
||||
---
|
||||
|
||||
### Keyboard
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `Tab` | [behavior] |
|
||||
| `Enter` / `Space` | [behavior] |
|
||||
| `Escape` | [behavior] |
|
||||
| Arrow keys | [behavior] |
|
||||
|
||||
---
|
||||
|
||||
### Touch
|
||||
|
||||
- Touch target size
|
||||
- Active state behavior
|
||||
- Gesture support (if any)
|
||||
|
||||
---
|
||||
|
||||
### Accessibility
|
||||
|
||||
- ARIA roles
|
||||
- ARIA states
|
||||
- Screen reader behavior
|
||||
- Focus management
|
||||
|
||||
---
|
||||
|
||||
### Motion
|
||||
|
||||
| Transition | Animation | Duration | Easing |
|
||||
|-----------|-----------|----------|--------|
|
||||
| [state change] | [description] | [duration] | [easing] |
|
||||
|
||||
---
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
- [ ] Criterion 1
|
||||
- [ ] Criterion 2
|
||||
- [ ] Criterion 3
|
||||
|
||||
---
|
||||
|
||||
### Anti-Patterns
|
||||
|
||||
- ❌ [What not to do]
|
||||
- ❌ [What not to do]
|
||||
|
||||
---
|
||||
|
||||
### Related Components
|
||||
|
||||
- [Component A] — [relationship]
|
||||
- [Component B] — [relationship]
|
||||
|
||||
---
|
||||
|
||||
### DDR References
|
||||
|
||||
- DDR-XXX: [Decision rationale]
|
||||
@@ -511,29 +511,129 @@ Dedicated palette for geospatial visualization. Defined by **layer**, not indivi
|
||||
|
||||
## 5. Motion System
|
||||
|
||||
> **Status:** ⏳ Ej påbörjad
|
||||
> **Status:** ✅ Specified
|
||||
> **Principle:** Motion supports understanding. It never decorates.
|
||||
|
||||
### 5.1 Duration Scale
|
||||
### 5.1 Motion Principles
|
||||
|
||||
**When to animate:**
|
||||
- State changes that need attention (modal open, toast appear)
|
||||
- Spatial relationships (drawer slide, page transition)
|
||||
- Feedback on user action (button press, form submit)
|
||||
- Loading and progress (skeleton, progress bar)
|
||||
|
||||
**When NOT to animate:**
|
||||
- Static content that does not change
|
||||
- Data updates that are frequent (live dashboards)
|
||||
- Elements entering viewport on scroll (use Intersection Observer, not animation)
|
||||
- Anything that delays user action
|
||||
|
||||
**Rules:**
|
||||
- Animations must be interruptible
|
||||
- Multiple animations must not conflict
|
||||
- Motion must respect `prefers-reduced-motion`
|
||||
|
||||
### 5.2 Duration Scale
|
||||
|
||||
| Token | Value | Usage |
|
||||
|-------|-------|-------|
|
||||
| `duration-instant` | 0ms | No animation |
|
||||
| `duration-fast` | 100ms | Hover states |
|
||||
| `duration-fast` | 100ms | Hover states, focus rings |
|
||||
| `duration-normal` | 200ms | Standard transitions |
|
||||
| `duration-slow` | 300ms | Page transitions |
|
||||
| `duration-slower` | 500ms | Complex animations |
|
||||
| `duration-slow` | 300ms | Page transitions, drawers |
|
||||
| `duration-slower` | 500ms | Complex animations, modals |
|
||||
|
||||
### 5.2 Easing Functions
|
||||
### 5.3 Easing Functions
|
||||
|
||||
| Token | Value | Usage |
|
||||
|-------|-------|-------|
|
||||
| `ease-linear` | linear | Continuous motion |
|
||||
| `ease-in` | cubic-bezier(0.4, 0, 1, 1) | Exit animations |
|
||||
| `ease-out` | cubic-bezier(0, 0, 0.2, 1) | Enter animations |
|
||||
| `ease-in-out` | cubic-bezier(0.4, 0, 0.2, 1) | Standard |
|
||||
| `ease-spring` | cubic-bezier(0.34, 1.56, 0.64, 1) | Playful interactions |
|
||||
| `ease-linear` | linear | Continuous motion, progress bars |
|
||||
| `ease-in` | cubic-bezier(0.4, 0, 1, 1) | Exit animations, dismiss |
|
||||
| `ease-out` | cubic-bezier(0, 0, 0.2, 1) | Enter animations, appear |
|
||||
| `ease-in-out` | cubic-bezier(0.4, 0, 0.2, 1) | Standard, symmetric |
|
||||
| `ease-spring` | cubic-bezier(0.34, 1.56, 0.64, 1) | Playful, overshoot |
|
||||
|
||||
### 5.3 Motion Principles
|
||||
### 5.4 Component-Specific Motion
|
||||
|
||||
#### 5.4.1 Button
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Hover | Background color shift | 100ms | ease-out |
|
||||
| Press | Scale to 0.98 | 50ms | ease-in |
|
||||
| Release | Scale to 1.0 | 100ms | ease-out |
|
||||
| Loading | Spinner rotation | 1s | linear infinite |
|
||||
| Disabled | Opacity to 0.5 | 100ms | ease-in-out |
|
||||
|
||||
#### 5.4.2 Modal
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Open | Fade in + scale from 0.95 | 300ms | ease-out |
|
||||
| Close | Fade out + scale to 0.95 | 200ms | ease-in |
|
||||
| Backdrop | Fade to 50% opacity | 300ms | ease-in-out |
|
||||
|
||||
#### 5.4.3 Drawer
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Open | Slide from edge | 300ms | ease-out |
|
||||
| Close | Slide to edge | 200ms | ease-in |
|
||||
| Backdrop | Fade to 50% opacity | 300ms | ease-in-out |
|
||||
|
||||
#### 5.4.4 Map Transitions
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Pan | None (instant) | 0ms | — |
|
||||
| Zoom | Smooth interpolation | 300ms | ease-in-out |
|
||||
| Layer toggle | Cross-fade | 200ms | ease-in-out |
|
||||
| Feature select | Highlight pulse | 300ms | ease-out |
|
||||
|
||||
**Rule:** Map panning is never animated. Users need instant feedback on drag.
|
||||
|
||||
#### 5.4.5 Skeleton
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Loading | Shimmer sweep | 1.5s | ease-in-out infinite |
|
||||
| Complete | Fade to content | 200ms | ease-out |
|
||||
|
||||
#### 5.4.6 Progress
|
||||
|
||||
| State | Animation | Duration | Easing |
|
||||
|-------|-----------|----------|--------|
|
||||
| Indeterminate | Sweep | 1s | linear infinite |
|
||||
| Determinate | Width growth | 300ms | ease-out |
|
||||
| Complete | Checkmark draw | 200ms | ease-out |
|
||||
|
||||
### 5.5 Reduced Motion
|
||||
|
||||
When `prefers-reduced-motion: reduce` is active:
|
||||
|
||||
- All animations become instant (0ms)
|
||||
- Skeleton shows static placeholder (no shimmer)
|
||||
- Progress shows static bar (no sweep)
|
||||
- Map zoom uses instant jump (no interpolation)
|
||||
- Modals and drawers appear instantly (no fade/scale)
|
||||
|
||||
**Exception:** Loading spinners may rotate slowly (2s per rotation) to indicate activity without motion.
|
||||
|
||||
### 5.6 Interruptions
|
||||
|
||||
**Rule:** Animations must be interruptible.
|
||||
|
||||
- If a modal is closing and user opens another, the first must complete or reverse instantly
|
||||
- If a drawer is sliding and user taps backdrop, it must reverse direction
|
||||
- No animation queue buildup
|
||||
|
||||
### 5.7 Error and Success Animations
|
||||
|
||||
| Type | Animation | Duration | Purpose |
|
||||
|------|-----------|----------|---------|
|
||||
| Error | Subtle shake (4px, 3 cycles) | 300ms | Indicate invalid input |
|
||||
| Success | Checkmark draw + fade | 400ms | Confirm completion |
|
||||
| Warning | Pulse border color | 2s | Draw attention without alarm |
|
||||
|
||||
---
|
||||
|
||||
@@ -666,46 +766,86 @@ Only then may a new component be defined.
|
||||
|
||||
### 8.3.1 Button
|
||||
|
||||
**States:**
|
||||
- Default
|
||||
- Hover
|
||||
- Focus
|
||||
- Pressed (Active)
|
||||
- Loading
|
||||
- Disabled
|
||||
**Purpose:** Trigger primary user actions. The most used interactive element.
|
||||
|
||||
**Design Goal:** Immediately recognizable, consistently responsive, accessible without thought.
|
||||
|
||||
**Token Dependencies:**
|
||||
- `button-primary-bg` → `brand-500`
|
||||
- `button-primary-bg-hover` → `brand-600`
|
||||
- `button-primary-text` → `text-inverse`
|
||||
- `button-secondary-bg` → `surface-secondary`
|
||||
- `button-secondary-border` → `border-default`
|
||||
- `button-ghost-text` → `brand-500`
|
||||
- `space-padding-button` → `space-3` (12px vertical, `space-4` horizontal)
|
||||
- `radius-button` → `radius-2` (4px)
|
||||
|
||||
**Layout:**
|
||||
- Height: 40px (default), 32px (small), 48px (large)
|
||||
- Padding: 12px vertical, 16px horizontal
|
||||
- Icon + text gap: 8px
|
||||
- Border radius: 4px
|
||||
|
||||
**Sizes:**
|
||||
|
||||
| Size | Height | Padding | Font | Usage |
|
||||
|------|--------|---------|------|-------|
|
||||
| Small | 32px | 8px 12px | `text-sm` | Dense UIs, tables |
|
||||
| Default | 40px | 12px 16px | `text-base` | Standard |
|
||||
| Large | 48px | 16px 24px | `text-lg` | Hero actions, mobile |
|
||||
|
||||
**Variants:**
|
||||
- Primary
|
||||
- Secondary
|
||||
- Tertiary (Ghost)
|
||||
- Danger
|
||||
- Icon-only
|
||||
|
||||
**ARIA:**
|
||||
| Variant | Background | Border | Text | Usage |
|
||||
|---------|------------|--------|------|-------|
|
||||
| Primary | `brand-500` | None | White | Main action |
|
||||
| Secondary | `surface-secondary` | `border-default` | `text-primary` | Alternative action |
|
||||
| Ghost | Transparent | None | `brand-500` | Low emphasis |
|
||||
| Danger | `semantic-red-500` | None | White | Destructive action |
|
||||
| Icon-only | Any above | None | CurrentColor | Toolbar, compact |
|
||||
|
||||
**States:**
|
||||
|
||||
| State | Visual | Motion |
|
||||
|-------|--------|--------|
|
||||
| Default | As variant | None |
|
||||
| Hover | Darken 10% | Background shift 100ms ease-out |
|
||||
| Focus | 2px ring `border-focus` | Ring appear 100ms ease-out |
|
||||
| Pressed | Scale 0.98 | Scale 50ms ease-in |
|
||||
| Loading | Spinner replaces text | Spinner 1s linear infinite |
|
||||
| Disabled | Opacity 0.5, no pointer | None |
|
||||
|
||||
**Keyboard:**
|
||||
- `Tab`: Focus
|
||||
- `Enter` / `Space`: Activate
|
||||
- Disabled: Not focusable
|
||||
|
||||
**Touch:**
|
||||
- Min 44x44px touch target
|
||||
- Active state on press (immediate)
|
||||
- No hover state on touch
|
||||
|
||||
**Accessibility:**
|
||||
- `role="button"`
|
||||
- `aria-label` for icon-only
|
||||
- `aria-disabled` for disabled
|
||||
- `aria-busy` for loading
|
||||
- Focus ring always visible
|
||||
|
||||
**Keyboard:**
|
||||
- `Enter` / `Space` to activate
|
||||
- `Tab` to focus
|
||||
**Anti-Patterns:**
|
||||
- ❌ Two primary buttons in same view
|
||||
- ❌ Disabled button without explanation
|
||||
- ❌ Button that looks like link
|
||||
- ❌ Loading button that remains clickable
|
||||
|
||||
**Touch:**
|
||||
- Min 44x44px touch target
|
||||
- Active state on press
|
||||
**Related Components:**
|
||||
- Split Button (extends Button)
|
||||
- Icon Button (extends Button)
|
||||
- Floating Action Button (extends Button)
|
||||
|
||||
**Animation:**
|
||||
- Hover: background-color 100ms ease-out
|
||||
- Press: scale(0.98) 50ms
|
||||
- Loading: spinner rotation 1s linear infinite
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- [ ] All states are visually distinct
|
||||
- [ ] Focus ring is visible
|
||||
- [ ] Loading state prevents double-submit
|
||||
- [ ] Disabled state is not focusable
|
||||
- [ ] Touch target meets 44px minimum
|
||||
**DDR References:**
|
||||
- DDR-001: Why buttons use brand color for primary action
|
||||
- DDR-002: Why ghost variant exists (low emphasis without border)
|
||||
|
||||
### 8.3.2 Input / Text Field
|
||||
|
||||
|
||||
Reference in New Issue
Block a user