This repository has been archived on 2026-06-18. You can view files and clone it, but cannot push or open issues or pull requests.
Files
ui-essentials/projects/shared-ui/src/styles/commons/patterns/_interaction-patterns.scss
skyai_dev c803831f60 Add comprehensive semantic design token system
Implement complete semantic layer for all design tokens including typography, spacing, motion, colors, borders, shadows, z-index, opacity, and glass effects. Each semantic token maps base design tokens to contextual usage patterns for improved maintainability and developer experience.

Features:
- Complete semantic typography system with font weights, sizes, line heights, and letter spacing
- Comprehensive spacing tokens for components, layouts, and interactions
- Full motion system with durations, easing, transitions, and hover transforms
- Semantic color system with individual access to all Material Design 3 colors
- Border tokens with widths, radius, and styles for all use cases
- Shadow system including standard and AI-themed shadows
- Z-index layering system for proper stacking context
- Opacity tokens for transparency and visibility states
- Glass morphism tokens with blur, opacity, and theming support

All semantic tokens provide direct access to base token values while offering meaningful contextual aliases for common UI patterns.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 10:24:04 +10:00

452 lines
11 KiB
SCSS

// ==========================================================================
// INTERACTION PATTERNS
// ==========================================================================
// Common interaction and state patterns
// Theme-agnostic behavioral styles
// ==========================================================================
// HOVER EFFECTS
.hover-lift {
transition: transform var(--hover-transition-duration, 0.2s) var(--hover-transition-easing, ease);
&:hover {
transform: var(--hover-lift-transform, translateY(-4px));
}
}
.hover-scale {
transition: transform var(--hover-transition-duration, 0.2s) var(--hover-transition-easing, ease);
&:hover {
transform: var(--hover-scale-transform, scale(1.05));
}
}
.hover-glow {
transition: box-shadow var(--hover-transition-duration, 0.2s) var(--hover-transition-easing, ease);
&:hover {
box-shadow: var(--hover-glow-shadow, 0 0 20px rgba(0, 0, 0, 0.15));
}
}
.hover-fade {
transition: opacity var(--hover-transition-duration, 0.2s) var(--hover-transition-easing, ease);
&:hover {
opacity: var(--hover-fade-opacity, 0.8);
}
}
.hover-brighten {
transition: filter var(--hover-transition-duration, 0.2s) var(--hover-transition-easing, ease);
&:hover {
filter: brightness(var(--hover-brighten-value, 1.1));
}
}
.hover-darken {
transition: filter var(--hover-transition-duration, 0.2s) var(--hover-transition-easing, ease);
&:hover {
filter: brightness(var(--hover-darken-value, 0.9));
}
}
// FOCUS STATES
.focus-ring {
&:focus,
&:focus-visible {
outline: var(--focus-ring-width, 2px) solid var(--focus-ring-color, #007bff);
outline-offset: var(--focus-ring-offset, 2px);
}
}
.focus-ring-inset {
&:focus,
&:focus-visible {
outline: var(--focus-ring-width, 2px) solid var(--focus-ring-color, #007bff);
outline-offset: var(--focus-ring-inset-offset, -2px);
}
}
.focus-glow {
&:focus,
&:focus-visible {
box-shadow: var(--focus-glow-shadow, 0 0 0 3px rgba(0, 123, 255, 0.25));
outline: none;
}
}
// ACTIVE STATES
.active-press {
transition: transform var(--active-transition-duration, 0.1s) var(--active-transition-easing, ease);
&:active {
transform: var(--active-press-transform, scale(0.98));
}
}
.active-sink {
transition: transform var(--active-transition-duration, 0.1s) var(--active-transition-easing, ease);
&:active {
transform: var(--active-sink-transform, translateY(2px));
}
}
// LOADING STATES
.loading {
position: relative;
pointer-events: none;
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: var(--loading-spinner-size, 20px);
height: var(--loading-spinner-size, 20px);
margin-top: calc(var(--loading-spinner-size, 20px) / -2);
margin-left: calc(var(--loading-spinner-size, 20px) / -2);
border: 2px solid var(--loading-spinner-color, rgba(0, 0, 0, 0.3));
border-top-color: var(--loading-spinner-active-color, #007bff);
border-radius: 50%;
animation: loading-spin var(--loading-spin-duration, 1s) linear infinite;
z-index: 1;
}
&.loading-overlay::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--loading-overlay-bg, rgba(255, 255, 255, 0.8));
z-index: 0;
}
}
@keyframes loading-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-pulse {
animation: loading-pulse var(--loading-pulse-duration, 2s) infinite;
}
@keyframes loading-pulse {
0%, 100% { opacity: 1; }
50% { opacity: var(--loading-pulse-opacity, 0.5); }
}
.loading-skeleton {
background: var(--skeleton-bg, #f0f0f0);
background-image: linear-gradient(
90deg,
var(--skeleton-bg, #f0f0f0),
var(--skeleton-highlight, #e0e0e0),
var(--skeleton-bg, #f0f0f0)
);
background-size: 200px 100%;
background-repeat: no-repeat;
animation: loading-shimmer var(--skeleton-duration, 1.5s) infinite;
border-radius: var(--skeleton-border-radius, 4px);
}
@keyframes loading-shimmer {
0% { background-position: -200px 0; }
100% { background-position: calc(200px + 100%) 0; }
}
// DISABLED STATES
.disabled,
[disabled] {
opacity: var(--disabled-opacity, 0.6);
pointer-events: none;
cursor: not-allowed;
}
.disabled-loading {
opacity: var(--disabled-loading-opacity, 0.8);
pointer-events: none;
cursor: wait;
}
// SUCCESS STATES
.success-flash {
animation: success-flash var(--success-flash-duration, 0.5s) ease-in-out;
}
@keyframes success-flash {
0%, 100% { background-color: transparent; }
50% { background-color: var(--success-flash-color, rgba(40, 167, 69, 0.2)); }
}
.success-checkmark {
position: relative;
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: var(--success-color, #28a745);
font-size: var(--success-checkmark-size, 1.5rem);
font-weight: bold;
animation: success-checkmark-appear var(--success-checkmark-duration, 0.3s) ease-in-out;
}
}
@keyframes success-checkmark-appear {
0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
100% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
// ERROR STATES
.error-shake {
animation: error-shake var(--error-shake-duration, 0.5s) ease-in-out;
}
@keyframes error-shake {
0%, 20%, 40%, 60%, 80%, 100% { transform: translateX(0); }
10%, 50%, 90% { transform: translateX(-5px); }
30%, 70% { transform: translateX(5px); }
}
.error-flash {
animation: error-flash var(--error-flash-duration, 0.5s) ease-in-out;
}
@keyframes error-flash {
0%, 100% { background-color: transparent; }
50% { background-color: var(--error-flash-color, rgba(220, 53, 69, 0.2)); }
}
// WARNING STATES
.warning-pulse {
animation: warning-pulse var(--warning-pulse-duration, 2s) infinite;
}
@keyframes warning-pulse {
0%, 100% { opacity: 1; }
50% { opacity: var(--warning-pulse-opacity, 0.7); }
}
// DRAG AND DROP STATES
.draggable {
cursor: grab;
user-select: none;
transition: transform var(--draggable-transition-duration, 0.2s) var(--draggable-transition-easing, ease);
&:active {
cursor: grabbing;
}
&.dragging {
cursor: grabbing;
opacity: var(--dragging-opacity, 0.8);
transform: var(--dragging-transform, rotate(5deg));
z-index: var(--z-dragging, 1000);
}
}
.drop-zone {
transition: all var(--drop-zone-transition-duration, 0.2s) var(--drop-zone-transition-easing, ease);
border: 2px dashed transparent;
border-radius: var(--drop-zone-border-radius, 8px);
padding: var(--drop-zone-padding, 20px);
&.drop-zone-active {
border-color: var(--drop-zone-active-border, #007bff);
background-color: var(--drop-zone-active-bg, rgba(0, 123, 255, 0.05));
}
&.drop-zone-invalid {
border-color: var(--drop-zone-invalid-border, #dc3545);
background-color: var(--drop-zone-invalid-bg, rgba(220, 53, 69, 0.05));
}
}
// SELECTION STATES
.selectable {
cursor: pointer;
transition: all var(--selectable-transition-duration, 0.2s) var(--selectable-transition-easing, ease);
border: var(--selectable-border-width, 2px) solid transparent;
border-radius: var(--selectable-border-radius, 4px);
&:hover {
border-color: var(--selectable-hover-border, rgba(0, 123, 255, 0.5));
}
&.selected {
border-color: var(--selectable-selected-border, #007bff);
background-color: var(--selectable-selected-bg, rgba(0, 123, 255, 0.05));
}
&.selecting {
opacity: var(--selecting-opacity, 0.7);
transform: var(--selecting-transform, scale(0.98));
}
}
// EXPANDABLE CONTENT
.expandable {
overflow: hidden;
transition: height var(--expandable-transition-duration, 0.3s) var(--expandable-transition-easing, ease);
&.expanding {
transition: height var(--expanding-transition-duration, 0.3s) var(--expanding-transition-easing, ease-out);
}
&.collapsing {
transition: height var(--collapsing-transition-duration, 0.3s) var(--collapsing-transition-easing, ease-in);
}
}
.expandable-trigger {
cursor: pointer;
display: flex;
align-items: center;
gap: var(--expandable-trigger-gap, 8px);
.expand-icon {
transition: transform var(--expand-icon-transition-duration, 0.2s) var(--expand-icon-transition-easing, ease);
}
&.expanded .expand-icon {
transform: var(--expand-icon-expanded-transform, rotate(180deg));
}
}
// SORTABLE LISTS
.sortable {
.sortable-item {
cursor: move;
user-select: none;
transition: all var(--sortable-transition-duration, 0.2s) var(--sortable-transition-easing, ease);
&.sortable-ghost {
opacity: var(--sortable-ghost-opacity, 0.5);
background: var(--sortable-ghost-bg, rgba(0, 123, 255, 0.1));
}
&.sortable-chosen {
opacity: var(--sortable-chosen-opacity, 0.8);
transform: var(--sortable-chosen-transform, scale(1.02));
}
}
.sortable-handle {
cursor: grab;
display: flex;
align-items: center;
justify-content: center;
padding: var(--sortable-handle-padding, 8px);
opacity: var(--sortable-handle-opacity, 0.6);
transition: opacity var(--sortable-handle-transition-duration, 0.2s);
&:hover {
opacity: 1;
}
&:active {
cursor: grabbing;
}
}
}
// RIPPLE EFFECT
.ripple-effect {
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: var(--ripple-color, rgba(255, 255, 255, 0.3));
transform: translate(-50%, -50%);
transition: width var(--ripple-duration, 0.6s), height var(--ripple-duration, 0.6s);
pointer-events: none;
}
&.ripple-active::before {
width: var(--ripple-size, 200px);
height: var(--ripple-size, 200px);
}
}
// FLOATING ELEMENTS
.floating {
animation: floating var(--floating-duration, 3s) ease-in-out infinite;
}
@keyframes floating {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(var(--floating-distance, -10px)); }
}
.bob {
animation: bob var(--bob-duration, 2s) ease-in-out infinite;
}
@keyframes bob {
0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
40% { transform: translateY(var(--bob-distance, -10px)); }
60% { transform: translateY(var(--bob-distance-small, -5px)); }
}
// ACCESSIBILITY ENHANCEMENTS
@media (prefers-reduced-motion: reduce) {
.hover-lift,
.hover-scale,
.hover-glow,
.hover-fade,
.hover-brighten,
.hover-darken,
.active-press,
.active-sink,
.expandable,
.expandable-trigger .expand-icon,
.sortable .sortable-item,
.ripple-effect,
.floating,
.bob {
transition: none;
animation: none;
}
.loading::after {
animation: none;
}
.loading-pulse,
.loading-skeleton,
.warning-pulse {
animation: none;
}
}
@media (prefers-contrast: high) {
.focus-ring:focus,
.focus-ring:focus-visible {
outline-width: 3px;
}
.selectable {
border-width: 3px;
}
.drop-zone {
border-width: 3px;
}
}