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>
475 lines
11 KiB
SCSS
475 lines
11 KiB
SCSS
// ==========================================================================
|
|
// BASE FORMS
|
|
// ==========================================================================
|
|
// Theme-agnostic form structures and behaviors
|
|
// Visual styling handled by themes
|
|
// ==========================================================================
|
|
|
|
// FORM CONTAINER
|
|
.form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--form-gap, 24px);
|
|
max-width: var(--form-max-width, 100%);
|
|
margin: var(--form-margin, 0);
|
|
|
|
&.form-inline {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: var(--form-inline-gap, 16px);
|
|
}
|
|
|
|
&.form-compact {
|
|
gap: var(--form-compact-gap, 16px);
|
|
}
|
|
|
|
&.form-spacious {
|
|
gap: var(--form-spacious-gap, 32px);
|
|
}
|
|
}
|
|
|
|
// FIELDSET
|
|
.fieldset {
|
|
border: var(--fieldset-border, 1px solid transparent);
|
|
border-radius: var(--fieldset-border-radius, 8px);
|
|
padding: var(--fieldset-padding, 24px);
|
|
margin: var(--fieldset-margin, 0 0 24px 0);
|
|
|
|
.fieldset-legend {
|
|
font-size: var(--fieldset-legend-size, 1.125rem);
|
|
font-weight: var(--fieldset-legend-weight, 600);
|
|
margin-bottom: var(--fieldset-legend-spacing, 16px);
|
|
padding: var(--fieldset-legend-padding, 0 8px);
|
|
}
|
|
}
|
|
|
|
// FORM FIELD
|
|
.form-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--form-field-gap, 8px);
|
|
position: relative;
|
|
|
|
&.form-field-inline {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
gap: var(--form-field-inline-gap, 12px);
|
|
|
|
.form-label {
|
|
flex-shrink: 0;
|
|
margin-bottom: 0;
|
|
min-width: var(--form-label-min-width, 120px);
|
|
}
|
|
|
|
.form-input-wrapper {
|
|
flex: 1;
|
|
}
|
|
}
|
|
|
|
&.form-field-checkbox,
|
|
&.form-field-radio {
|
|
flex-direction: row;
|
|
align-items: flex-start;
|
|
gap: var(--form-checkbox-gap, 8px);
|
|
|
|
.form-input {
|
|
flex-shrink: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.form-label {
|
|
flex: 1;
|
|
margin-bottom: 0;
|
|
cursor: pointer;
|
|
line-height: var(--form-checkbox-label-line-height, 1.5);
|
|
}
|
|
}
|
|
|
|
&.form-field-error {
|
|
.form-input {
|
|
border-color: var(--form-error-color, #dc3545);
|
|
}
|
|
|
|
.form-label {
|
|
color: var(--form-error-color, #dc3545);
|
|
}
|
|
}
|
|
|
|
&.form-field-success {
|
|
.form-input {
|
|
border-color: var(--form-success-color, #28a745);
|
|
}
|
|
}
|
|
|
|
&.form-field-disabled {
|
|
opacity: var(--form-disabled-opacity, 0.6);
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
|
|
// FORM LABEL
|
|
.form-label {
|
|
font-size: var(--form-label-size, 0.875rem);
|
|
font-weight: var(--form-label-weight, 500);
|
|
line-height: var(--form-label-line-height, 1.4);
|
|
margin-bottom: var(--form-label-spacing, 8px);
|
|
cursor: pointer;
|
|
|
|
&.form-label-required::after {
|
|
content: var(--form-required-indicator, ' *');
|
|
color: var(--form-required-color, #dc3545);
|
|
}
|
|
|
|
&.form-label-optional::after {
|
|
content: var(--form-optional-indicator, ' (optional)');
|
|
opacity: var(--form-optional-opacity, 0.6);
|
|
font-weight: normal;
|
|
}
|
|
}
|
|
|
|
// FORM INPUTS
|
|
.form-input {
|
|
width: 100%;
|
|
padding: var(--form-input-padding, 12px 16px);
|
|
border: var(--form-input-border, 1px solid #d1d5db);
|
|
border-radius: var(--form-input-border-radius, 6px);
|
|
font-family: inherit;
|
|
font-size: var(--form-input-font-size, 1rem);
|
|
line-height: var(--form-input-line-height, 1.5);
|
|
transition: all var(--form-input-transition-duration, 0.2s) var(--form-input-transition-easing, ease);
|
|
background: var(--form-input-background, transparent);
|
|
|
|
&:focus {
|
|
outline: var(--form-input-focus-outline, 2px solid transparent);
|
|
outline-offset: var(--form-input-focus-outline-offset, 2px);
|
|
border-color: var(--form-input-focus-border-color, #3b82f6);
|
|
}
|
|
|
|
&:disabled,
|
|
&[readonly] {
|
|
opacity: var(--form-input-disabled-opacity, 0.6);
|
|
cursor: not-allowed;
|
|
background: var(--form-input-disabled-background, #f9fafb);
|
|
}
|
|
|
|
&::placeholder {
|
|
color: var(--form-input-placeholder-color, #9ca3af);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
// INPUT SIZES
|
|
.form-input-sm {
|
|
--form-input-padding: 8px 12px;
|
|
--form-input-font-size: 0.875rem;
|
|
}
|
|
|
|
.form-input-lg {
|
|
--form-input-padding: 16px 20px;
|
|
--form-input-font-size: 1.125rem;
|
|
}
|
|
|
|
// TEXTAREA
|
|
.form-textarea {
|
|
min-height: var(--form-textarea-min-height, 120px);
|
|
resize: var(--form-textarea-resize, vertical);
|
|
line-height: var(--form-textarea-line-height, 1.6);
|
|
}
|
|
|
|
// SELECT
|
|
.form-select {
|
|
cursor: pointer;
|
|
appearance: none;
|
|
background-image: var(--form-select-arrow, url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E"));
|
|
background-position: right 12px center;
|
|
background-repeat: no-repeat;
|
|
background-size: 16px 12px;
|
|
padding-right: var(--form-select-padding-right, 40px);
|
|
|
|
&[multiple] {
|
|
background-image: none;
|
|
padding-right: var(--form-input-padding-right, 16px);
|
|
}
|
|
}
|
|
|
|
// CHECKBOX & RADIO
|
|
.form-checkbox,
|
|
.form-radio {
|
|
width: var(--form-checkbox-size, 18px);
|
|
height: var(--form-checkbox-size, 18px);
|
|
margin: var(--form-checkbox-margin, 2px 0 0 0);
|
|
cursor: pointer;
|
|
appearance: none;
|
|
border: var(--form-checkbox-border, 2px solid #d1d5db);
|
|
transition: all var(--form-checkbox-transition-duration, 0.2s) var(--form-checkbox-transition-easing, ease);
|
|
|
|
&:focus {
|
|
outline: var(--form-checkbox-focus-outline, 2px solid transparent);
|
|
outline-offset: var(--form-checkbox-focus-outline-offset, 2px);
|
|
}
|
|
|
|
&:checked {
|
|
background: var(--form-checkbox-checked-background, #3b82f6);
|
|
border-color: var(--form-checkbox-checked-border-color, #3b82f6);
|
|
}
|
|
|
|
&:disabled {
|
|
opacity: var(--form-checkbox-disabled-opacity, 0.5);
|
|
cursor: not-allowed;
|
|
}
|
|
}
|
|
|
|
.form-checkbox {
|
|
border-radius: var(--form-checkbox-border-radius, 3px);
|
|
|
|
&:checked {
|
|
background-image: var(--form-checkbox-check-icon, url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m13.854 3.646-7.5 7.5a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6 10.293l7.146-7.147a.5.5 0 0 1 .708.708z'/%3E%3C/svg%3E"));
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
background-size: 12px 12px;
|
|
}
|
|
|
|
&:indeterminate {
|
|
background: var(--form-checkbox-indeterminate-background, #3b82f6);
|
|
border-color: var(--form-checkbox-indeterminate-border-color, #3b82f6);
|
|
background-image: var(--form-checkbox-indeterminate-icon, url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E"));
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
background-size: 12px 12px;
|
|
}
|
|
}
|
|
|
|
.form-radio {
|
|
border-radius: 50%;
|
|
|
|
&:checked {
|
|
background-image: var(--form-radio-dot-icon, radial-gradient(circle at center, white 4px, transparent 4px));
|
|
}
|
|
}
|
|
|
|
// INPUT GROUPS
|
|
.form-input-group {
|
|
display: flex;
|
|
position: relative;
|
|
|
|
> .form-input {
|
|
position: relative;
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
|
|
&:not(:first-child) {
|
|
border-top-left-radius: 0;
|
|
border-bottom-left-radius: 0;
|
|
border-left: none;
|
|
}
|
|
|
|
&:not(:last-child) {
|
|
border-top-right-radius: 0;
|
|
border-bottom-right-radius: 0;
|
|
}
|
|
|
|
&:focus {
|
|
z-index: 2;
|
|
}
|
|
}
|
|
|
|
.form-input-addon,
|
|
.form-input-btn {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: var(--form-input-addon-padding, 12px 16px);
|
|
font-size: var(--form-input-addon-font-size, 1rem);
|
|
border: var(--form-input-border, 1px solid #d1d5db);
|
|
white-space: nowrap;
|
|
|
|
&:first-child {
|
|
border-top-left-radius: var(--form-input-border-radius, 6px);
|
|
border-bottom-left-radius: var(--form-input-border-radius, 6px);
|
|
border-right: none;
|
|
}
|
|
|
|
&:last-child {
|
|
border-top-right-radius: var(--form-input-border-radius, 6px);
|
|
border-bottom-right-radius: var(--form-input-border-radius, 6px);
|
|
border-left: none;
|
|
}
|
|
}
|
|
|
|
.form-input-btn {
|
|
cursor: pointer;
|
|
transition: all var(--form-input-btn-transition-duration, 0.2s);
|
|
|
|
&:hover {
|
|
z-index: 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
// FLOATING LABELS
|
|
.form-floating {
|
|
position: relative;
|
|
|
|
.form-input {
|
|
height: var(--form-floating-height, 56px);
|
|
padding: var(--form-floating-padding, 20px 16px 8px 16px);
|
|
|
|
&:focus,
|
|
&:not(:placeholder-shown) {
|
|
padding: var(--form-floating-padding-active, 20px 16px 8px 16px);
|
|
}
|
|
|
|
&::placeholder {
|
|
opacity: 0;
|
|
transition: opacity var(--form-floating-transition-duration, 0.2s);
|
|
}
|
|
|
|
&:focus::placeholder {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.form-label {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 16px;
|
|
margin-bottom: 0;
|
|
pointer-events: none;
|
|
transform: translateY(-50%);
|
|
transition: all var(--form-floating-transition-duration, 0.2s) var(--form-floating-transition-easing, ease);
|
|
transform-origin: left center;
|
|
cursor: text;
|
|
}
|
|
|
|
.form-input:focus ~ .form-label,
|
|
.form-input:not(:placeholder-shown) ~ .form-label {
|
|
top: 12px;
|
|
transform: translateY(0) scale(0.85);
|
|
opacity: var(--form-floating-label-opacity, 0.7);
|
|
}
|
|
}
|
|
|
|
// FORM FEEDBACK
|
|
.form-feedback {
|
|
font-size: var(--form-feedback-size, 0.875rem);
|
|
line-height: var(--form-feedback-line-height, 1.4);
|
|
margin-top: var(--form-feedback-spacing, 6px);
|
|
|
|
&.form-feedback-error {
|
|
color: var(--form-error-color, #dc3545);
|
|
}
|
|
|
|
&.form-feedback-success {
|
|
color: var(--form-success-color, #28a745);
|
|
}
|
|
|
|
&.form-feedback-warning {
|
|
color: var(--form-warning-color, #ffc107);
|
|
}
|
|
|
|
&.form-feedback-info {
|
|
color: var(--form-info-color, #17a2b8);
|
|
}
|
|
}
|
|
|
|
.form-help-text {
|
|
font-size: var(--form-help-size, 0.875rem);
|
|
line-height: var(--form-help-line-height, 1.4);
|
|
margin-top: var(--form-help-spacing, 6px);
|
|
opacity: var(--form-help-opacity, 0.7);
|
|
}
|
|
|
|
// FORM ACTIONS
|
|
.form-actions {
|
|
display: flex;
|
|
gap: var(--form-actions-gap, 12px);
|
|
align-items: center;
|
|
padding-top: var(--form-actions-padding, 16px);
|
|
margin-top: var(--form-actions-margin, 24px);
|
|
border-top: var(--form-actions-border, 1px solid transparent);
|
|
|
|
&.form-actions-center {
|
|
justify-content: center;
|
|
}
|
|
|
|
&.form-actions-end {
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
&.form-actions-between {
|
|
justify-content: space-between;
|
|
}
|
|
|
|
&.form-actions-stack {
|
|
flex-direction: column;
|
|
|
|
.btn {
|
|
width: 100%;
|
|
}
|
|
}
|
|
}
|
|
|
|
@media (max-width: 576px) {
|
|
.form-actions {
|
|
flex-direction: column;
|
|
|
|
.btn {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
.form-field-inline {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
|
|
.form-label {
|
|
min-width: auto;
|
|
}
|
|
}
|
|
}
|
|
|
|
// FORM VALIDATION
|
|
.was-validated {
|
|
.form-input {
|
|
&:valid {
|
|
border-color: var(--form-success-color, #28a745);
|
|
|
|
&:focus {
|
|
border-color: var(--form-success-color, #28a745);
|
|
box-shadow: var(--form-success-focus-shadow, 0 0 0 0.2rem rgba(40, 167, 69, 0.25));
|
|
}
|
|
}
|
|
|
|
&:invalid {
|
|
border-color: var(--form-error-color, #dc3545);
|
|
|
|
&:focus {
|
|
border-color: var(--form-error-color, #dc3545);
|
|
box-shadow: var(--form-error-focus-shadow, 0 0 0 0.2rem rgba(220, 53, 69, 0.25));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ACCESSIBILITY
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.form-input,
|
|
.form-checkbox,
|
|
.form-radio,
|
|
.form-floating .form-label {
|
|
transition: none;
|
|
}
|
|
}
|
|
|
|
@media (prefers-contrast: high) {
|
|
.form-input,
|
|
.form-select,
|
|
.form-textarea {
|
|
border-width: 2px;
|
|
}
|
|
|
|
.form-checkbox,
|
|
.form-radio {
|
|
border-width: 3px;
|
|
}
|
|
} |