UNPKG

raft-ui

Version:

React UI components for Raft.

465 lines (424 loc) 17.9 kB
/* FloatButton pure CSS styling following pattern/Button.css architecture - Local CSS variables (--r-float-button-*) declared on component root - Modifier classes rebind local variables - Component styles strictly consume local variables - Dual theme support (Brutal / Elegant) via CSS variable overrides */ /* ───────────────────────────────────────────────────────────────────────── 1. Local Variable Definitions & Modifier Overrides ───────────────────────────────────────────────────────────────────────── */ .r-float-button { /* Default local variables (Brutal theme defaults) */ --r-float-button-size: 32px; --r-float-button-width: var(--r-float-button-size); --r-float-button-padding-x: 0px; --r-float-button-border-radius: 9999px; --r-float-button-border-width: 2px; --r-float-button-border-style: solid; --r-float-button-border-color: var(--line-strong); --r-float-button-bg: var(--layer-panel); --r-float-button-bg-hover: var(--layer-panel); --r-float-button-text-color: var(--foreground-strong); --r-float-button-text-hover-color: var(--r-float-button-text-color); --r-float-button-text-disabled-color: var(--r-float-button-text-color); --r-float-button-box-shadow: var(--theme-shadow-md); --r-float-button-shadow-hover: var(--theme-shadow-lg); --r-float-button-shadow-active: var(--theme-shadow-sm); --r-float-button-transform-hover: translate(-1px, -1px); --r-float-button-transform-active: translate(0, 0); --r-float-button-outline: 2px solid var(--line-strong); --r-float-button-outline-offset: 2px; --r-float-button-font-size: 12px; --r-float-button-font-weight: 700; --r-float-button-desc-font-size: 10px; --r-float-button-icon-size: 16px; --r-float-button-opacity-disabled: 0.4; /* Sizes: xs (24px), sm (28px), md (32px), lg (36px) */ &.r-float-button--xs { --r-float-button-size: 24px; --r-float-button-icon-size: 12px; --r-float-button-font-size: 11px; --r-float-button-desc-font-size: 8px; --r-float-button-padding-x: 8px; } &.r-float-button--sm { --r-float-button-size: 28px; --r-float-button-icon-size: 14px; --r-float-button-font-size: 12px; --r-float-button-desc-font-size: 9px; --r-float-button-padding-x: 10px; } &.r-float-button--md { --r-float-button-size: 32px; --r-float-button-icon-size: 16px; --r-float-button-font-size: 12px; --r-float-button-desc-font-size: 10px; --r-float-button-padding-x: 12px; } &.r-float-button--lg { --r-float-button-size: 36px; --r-float-button-icon-size: 18px; --r-float-button-font-size: 14px; --r-float-button-desc-font-size: 11px; --r-float-button-padding-x: 14px; } /* Extended with text (adaptive width & horizontal padding) */ &.r-float-button--with-text { --r-float-button-width: auto; } /* Shapes */ &.r-float-button--circle { --r-float-button-border-radius: 9999px; } &.r-float-button--pill { --r-float-button-border-radius: 9999px; --r-float-button-width: auto; padding-left: var(--r-float-button-padding-x); padding-right: var(--r-float-button-padding-x); } &.r-float-button--square { --r-float-button-border-radius: 0px; } /* Variants (Brutal default) */ &.r-float-button--default { --r-float-button-border-color: var(--line-strong); --r-float-button-bg: var(--layer-panel); --r-float-button-bg-hover: var(--layer-panel); --r-float-button-text-color: var(--foreground-strong); } &.r-float-button--primary { --r-float-button-border-color: var(--line-strong); --r-float-button-bg: var(--color-brutal-yellow, var(--primary-400)); --r-float-button-bg-hover: var(--color-brutal-yellow, var(--primary-400)); --r-float-button-text-color: var(--foreground-strong); } &.r-float-button--accent { --r-float-button-border-color: var(--line-strong); --r-float-button-bg: var(--color-brutal-pink, var(--accent-400)); --r-float-button-bg-hover: var(--color-brutal-pink, var(--accent-400)); --r-float-button-text-color: var(--foreground-strong); } &.r-float-button--outline { --r-float-button-border-color: var(--line-strong); --r-float-button-bg: var(--layer-panel); --r-float-button-bg-hover: var(--layer-panel); --r-float-button-text-color: var(--foreground-strong); } &.r-float-button--ghost { --r-float-button-border-color: transparent; --r-float-button-bg: transparent; --r-float-button-text-color: var(--foreground-strong); --r-float-button-box-shadow: none; --r-float-button-bg-hover: var(--fill-muted); --r-float-button-shadow-hover: var(--theme-shadow-sm); } &.r-float-button--warning { --r-float-button-border-color: var(--line-strong); --r-float-button-bg: var(--color-brutal-orange, var(--warning)); --r-float-button-bg-hover: var(--color-brutal-orange, var(--warning)); --r-float-button-text-color: var(--foreground-strong); } &.r-float-button--danger { --r-float-button-border-color: var(--line-strong); --r-float-button-bg: var(--color-brutal-red, var(--danger)); --r-float-button-bg-hover: var(--color-brutal-red, var(--danger)); --r-float-button-text-color: var(--foreground-strong); } /* Theme: Elegant overrides */ &.r-float-button--elegant, :where([data-theme="elegant"]) & { --r-float-button-border-width: 1px; --r-float-button-font-weight: 500; --r-float-button-border-color: var(--line-muted); --r-float-button-bg: var(--layer-panel); --r-float-button-bg-hover: var(--fill-muted); --r-float-button-text-color: var(--foreground); --r-float-button-text-hover-color: var(--foreground); --r-float-button-box-shadow: var(--theme-shadow-md); --r-float-button-transform-hover: none; --r-float-button-transform-active: scale(0.97); --r-float-button-shadow-hover: var(--theme-shadow-md); --r-float-button-shadow-active: var(--theme-shadow-md); --r-float-button-outline: 2px solid color-mix(in oklch, var(--primary-400) 80%, transparent); --r-float-button-outline-offset: 2px; } &.r-float-button--elegant.r-float-button--square.r-float-button--xs, :where([data-theme="elegant"]) &.r-float-button--square.r-float-button--xs { --r-float-button-border-radius: 4px; } &.r-float-button--elegant.r-float-button--square.r-float-button--sm, :where([data-theme="elegant"]) &.r-float-button--square.r-float-button--sm { --r-float-button-border-radius: 4px; } &.r-float-button--elegant.r-float-button--square.r-float-button--md, :where([data-theme="elegant"]) &.r-float-button--square.r-float-button--md { --r-float-button-border-radius: 6px; } &.r-float-button--elegant.r-float-button--square.r-float-button--lg, :where([data-theme="elegant"]) &.r-float-button--square.r-float-button--lg { --r-float-button-border-radius: 8px; } &.r-float-button--elegant.r-float-button--default, :where([data-theme="elegant"]) &.r-float-button--default { --r-float-button-border-color: var(--line-muted); --r-float-button-bg: var(--layer-panel); --r-float-button-bg-hover: var(--fill-muted); --r-float-button-text-color: var(--foreground); } &.r-float-button--elegant.r-float-button--primary, :where([data-theme="elegant"]) &.r-float-button--primary { --r-float-button-border-color: transparent; --r-float-button-bg: var(--primary-400); --r-float-button-bg-hover: var(--primary-500); --r-float-button-text-color: var(--primary-950); } &.r-float-button--elegant.r-float-button--accent, :where([data-theme="elegant"]) &.r-float-button--accent { --r-float-button-border-color: transparent; --r-float-button-bg: var(--accent-400); --r-float-button-bg-hover: var(--accent-500); --r-float-button-text-color: var(--accent-950); } &.r-float-button--elegant.r-float-button--outline, :where([data-theme="elegant"]) &.r-float-button--outline { --r-float-button-border-color: var(--line-strong); --r-float-button-bg: var(--layer-panel); --r-float-button-bg-hover: var(--fill-muted); --r-float-button-text-color: var(--foreground); } &.r-float-button--elegant.r-float-button--ghost, :where([data-theme="elegant"]) &.r-float-button--ghost { --r-float-button-border-color: transparent; --r-float-button-bg: transparent; --r-float-button-bg-hover: var(--fill-muted); --r-float-button-text-color: var(--foreground); --r-float-button-box-shadow: none; --r-float-button-shadow-hover: var(--theme-shadow-sm); } &.r-float-button--elegant.r-float-button--warning, :where([data-theme="elegant"]) &.r-float-button--warning { --r-float-button-border-color: transparent; --r-float-button-bg: var(--warning); --r-float-button-bg-hover: var(--warning); --r-float-button-text-color: var(--warning-foreground); } &.r-float-button--elegant.r-float-button--danger, :where([data-theme="elegant"]) &.r-float-button--danger { --r-float-button-border-color: transparent; --r-float-button-bg: var(--danger); --r-float-button-bg-hover: var(--danger-hover); --r-float-button-text-color: var(--danger-foreground); } } /* ───────────────────────────────────────────────────────────────────────── 2. Base Element Rules Consuming Local Variables ───────────────────────────────────────────────────────────────────────── */ .r-float-button { position: relative; display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; user-select: none; cursor: pointer; box-sizing: border-box; padding: 0; width: var(--r-float-button-width, var(--r-float-button-size)); min-width: var(--r-float-button-size); height: var(--r-float-button-size); border-radius: var(--r-float-button-border-radius); border-width: var(--r-float-button-border-width); border-style: var(--r-float-button-border-style); border-color: var(--r-float-button-border-color); background-color: var(--r-float-button-bg); color: var(--r-float-button-text-color); box-shadow: var(--r-float-button-box-shadow); font-size: var(--r-float-button-font-size); font-weight: var(--r-float-button-font-weight); outline: none; transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1), box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1), background-color 150ms cubic-bezier(0.4, 0, 0.2, 1), border-color 150ms cubic-bezier(0.4, 0, 0.2, 1), color 150ms cubic-bezier(0.4, 0, 0.2, 1); @media (prefers-reduced-motion: reduce) { transition: none; } &.r-float-button--with-text, &.r-float-button--pill { padding-left: var(--r-float-button-padding-x); padding-right: var(--r-float-button-padding-x); } &:hover:not(:disabled) { background-color: var(--r-float-button-bg-hover); color: var(--r-float-button-text-hover-color); box-shadow: var(--r-float-button-shadow-hover); transform: var(--r-float-button-transform-hover); } &:active:not(:disabled) { box-shadow: var(--r-float-button-shadow-active); transform: var(--r-float-button-transform-active); } &:focus-visible { outline: var(--r-float-button-outline); outline-offset: var(--r-float-button-outline-offset); } &:disabled { pointer-events: none; opacity: var(--r-float-button-opacity-disabled); cursor: not-allowed; color: var(--r-float-button-text-disabled-color); } & svg { pointer-events: none; flex-shrink: 0; width: var(--r-float-button-icon-size); height: var(--r-float-button-icon-size); } & > .r-float-button__content { display: inline-flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap; &.r-float-button__content--with-desc { flex-direction: column; gap: 2px; } } &.r-float-button--square.r-float-button--with-desc { padding-top: 2px; padding-bottom: 2px; } & .r-float-button__text { display: inline-flex; align-items: center; line-height: 1; white-space: nowrap; } & .r-float-button__desc { font-size: var(--r-float-button-desc-font-size); text-align: center; line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } } /* ───────────────────────────────────────────────────────────────────────── 3. FloatButtonGroup ───────────────────────────────────────────────────────────────────────── */ .r-float-button-group { --r-float-button-group-gap: 10px; display: inline-flex; align-items: center; user-select: none; box-sizing: border-box; gap: var(--r-float-button-group-gap); &.r-float-button-group--vertical { flex-direction: column; } &.r-float-button-group--horizontal { flex-direction: row; } &.r-float-button-group--attached { --r-float-button-group-gap: 0px; gap: 0; } /* Attached: seamless borders */ &.r-float-button-group--attached.r-float-button-group--vertical > .r-float-button:not(:last-child) { border-bottom-width: 0; } &.r-float-button-group--attached.r-float-button-group--vertical > .r-float-button:not(:first-child):not(:last-child) { border-radius: 0; } &.r-float-button-group--attached.r-float-button-group--horizontal > .r-float-button:not(:last-child) { border-right-width: 0; } &.r-float-button-group--attached.r-float-button-group--horizontal > .r-float-button:not(:first-child):not(:last-child) { border-radius: 0; } /* Attached: vertical circle radii */ &.r-float-button-group--attached.r-float-button-group--vertical.r-float-button-group--circle > .r-float-button:first-child:not(:last-child) { border-top-left-radius: 9999px; border-top-right-radius: 9999px; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } &.r-float-button-group--attached.r-float-button-group--vertical.r-float-button-group--circle > .r-float-button:last-child:not(:first-child) { border-bottom-left-radius: 9999px; border-bottom-right-radius: 9999px; border-top-left-radius: 0; border-top-right-radius: 0; } /* Attached: horizontal circle radii */ &.r-float-button-group--attached.r-float-button-group--horizontal.r-float-button-group--circle > .r-float-button:first-child:not(:last-child) { border-top-left-radius: 9999px; border-bottom-left-radius: 9999px; border-top-right-radius: 0; border-bottom-right-radius: 0; } &.r-float-button-group--attached.r-float-button-group--horizontal.r-float-button-group--circle > .r-float-button:last-child:not(:first-child) { border-top-right-radius: 9999px; border-bottom-right-radius: 9999px; border-top-left-radius: 0; border-bottom-left-radius: 0; } /* Attached square: brutal has 0 radius everywhere */ &.r-float-button-group--attached.r-float-button-group--square:not( .r-float-button-group--elegant ):not([data-theme="elegant"] *) > .r-float-button { border-radius: 0; } /* Attached square: elegant has rounded outer corners */ &.r-float-button-group--attached.r-float-button-group--vertical.r-float-button-group--square.r-float-button-group--elegant > .r-float-button:first-child:not(:last-child), :where([data-theme="elegant"]) &.r-float-button-group--attached.r-float-button-group--vertical.r-float-button-group--square > .r-float-button:first-child:not(:last-child) { border-top-left-radius: 6px; border-top-right-radius: 6px; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } &.r-float-button-group--attached.r-float-button-group--vertical.r-float-button-group--square.r-float-button-group--elegant > .r-float-button:last-child:not(:first-child), :where([data-theme="elegant"]) &.r-float-button-group--attached.r-float-button-group--vertical.r-float-button-group--square > .r-float-button:last-child:not(:first-child) { border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border-top-left-radius: 0; border-top-right-radius: 0; } &.r-float-button-group--attached.r-float-button-group--horizontal.r-float-button-group--square.r-float-button-group--elegant > .r-float-button:first-child:not(:last-child), :where([data-theme="elegant"]) &.r-float-button-group--attached.r-float-button-group--horizontal.r-float-button-group--square > .r-float-button:first-child:not(:last-child) { border-top-left-radius: 6px; border-bottom-left-radius: 6px; border-top-right-radius: 0; border-bottom-right-radius: 0; } &.r-float-button-group--attached.r-float-button-group--horizontal.r-float-button-group--square.r-float-button-group--elegant > .r-float-button:last-child:not(:first-child), :where([data-theme="elegant"]) &.r-float-button-group--attached.r-float-button-group--horizontal.r-float-button-group--square > .r-float-button:last-child:not(:first-child) { border-top-right-radius: 6px; border-bottom-right-radius: 6px; border-top-left-radius: 0; border-bottom-left-radius: 0; } }