UNPKG

@liveblocks/react-ui

Version:

A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.

2,130 lines (1,798 loc) 47.3 kB
@import "./utils"; @import "./constants"; .lb-root { /** * Basic */ --lb-radius: 0.5em; --lb-spacing: 1em; --lb-accent: #17f; --lb-accent-foreground: #fff; --lb-destructive: #f45; --lb-destructive-foreground: #fff; --lb-background: #fff; --lb-foreground: #111; /** * Advanced */ --lb-line-height: 1.5; --lb-icon-size: 20px; --lb-icon-weight: 1.5px; --lb-avatar-radius: 50%; --lb-button-radius: calc(0.75 * var(--lb-radius)); --lb-transition-duration: 0.1s; --lb-transition-easing: cubic-bezier(0.4, 0, 0.2, 1); --lb-highlight-shadow: inset 0 0 0 1px rgb(0 0 0 / 10%); --lb-elevation-shadow: $lb-elevation-shadow; --lb-tooltip-shadow: $lb-tooltip-shadow; --lb-accent-contrast: 8%; --lb-destructive-contrast: 8%; --lb-foreground-contrast: 8%; /** * Colors */ --lb-background-foreground-faint: color-mix-scale( var(--lb-background), var(--lb-foreground), var(--lb-foreground-contrast), 50 ); --lb-background-accent-faint: color-mix-scale( var(--lb-background), var(--lb-accent), var(--lb-accent-contrast), 50 ); --lb-background-accent-subtle: color-mix-scale( var(--lb-background), var(--lb-accent), var(--lb-accent-contrast), 100 ); --lb-background-destructive-faint: color-mix-scale( var(--lb-background), var(--lb-destructive), var(--lb-destructive-contrast), 50 ); --lb-background-destructive-subtle: color-mix-scale( var(--lb-background), var(--lb-destructive), var(--lb-destructive-contrast), 100 ); --lb-accent-subtle: color-mix-scale( var(--lb-dynamic-background), var(--lb-accent), var(--lb-accent-contrast), 100 ); --lb-accent-moderate: color-mix-scale( var(--lb-dynamic-background), var(--lb-accent), var(--lb-accent-contrast), 400 ); --lb-accent-tertiary: color-mix-scale( var(--lb-dynamic-background), var(--lb-accent), var(--lb-accent-contrast), 600 ); --lb-accent-secondary: color-mix-scale( var(--lb-dynamic-background), var(--lb-accent), var(--lb-accent-contrast), 800 ); --lb-destructive-subtle: color-mix-scale( var(--lb-dynamic-background), var(--lb-destructive), var(--lb-destructive-contrast), 100 ); --lb-destructive-moderate: color-mix-scale( var(--lb-dynamic-background), var(--lb-destructive), var(--lb-destructive-contrast), 400 ); --lb-destructive-tertiary: color-mix-scale( var(--lb-dynamic-background), var(--lb-destructive), var(--lb-destructive-contrast), 600 ); --lb-destructive-secondary: color-mix-scale( var(--lb-dynamic-background), var(--lb-destructive), var(--lb-destructive-contrast), 800 ); --lb-foreground-subtle: color-mix-scale( var(--lb-dynamic-background), var(--lb-foreground), var(--lb-foreground-contrast), 100 ); --lb-foreground-moderate: color-mix-scale( var(--lb-dynamic-background), var(--lb-foreground), var(--lb-foreground-contrast), 400 ); --lb-foreground-tertiary: color-mix-scale( var(--lb-dynamic-background), var(--lb-foreground), var(--lb-foreground-contrast), 600 ); --lb-foreground-secondary: color-mix-scale( var(--lb-dynamic-background), var(--lb-foreground), var(--lb-foreground-contrast), 800 ); --lb-selection: color-mix(in srgb, var(--lb-accent) 40%, transparent); overflow-wrap: break-word; accent-color: var(--lb-accent); text-size-adjust: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; &, *, ::before, ::after { box-sizing: border-box; transition: none var(--lb-transition-duration) var(--lb-transition-easing); } /* Define some variables only on first .lb-root instances */ &:where(:not(& &)) { --lb-dynamic-background: var(--lb-background); } } /************************************* * States * *************************************/ .lb-loading, .lb-empty, .lb-error { position: absolute; inset: 0; display: flex; justify-content: center; align-items: center; } .lb-loading { color: var(--lb-foreground-moderate); } .lb-empty, .lb-error { padding: var(--lb-spacing); color: var(--lb-foreground-tertiary); font-size: 0.875em; text-align: center; text-wrap: balance; } /************************************* * Icon * *************************************/ .lb-icon-container, .lb-icon { inline-size: var(--lb-icon-size); block-size: var(--lb-icon-size); } .lb-icon-container { display: flex; justify-content: center; align-items: center; } .lb-icon { --lb-icon-background: var(--lb-dynamic-background); * { stroke-width: var(--lb-icon-weight); vector-effect: non-scaling-stroke; } } .lb-icon-spinner { transform-origin: center; animation: lb-animation-spin 0.75s linear infinite; } /************************************* * Button * *************************************/ .lb-button { --lb-button-background: var(--lb-dynamic-background); @include button; display: flex; justify-content: center; align-items: center; padding: calc(0.25 * var(--lb-spacing)); border-radius: var(--lb-button-radius); background: var(--lb-button-background); color: var(--lb-foreground-moderate); &:where(.lb-button\:non-disableable:disabled) { cursor: default; } &:where(:not(.lb-button\:non-disableable):disabled) { opacity: 0.5; cursor: not-allowed; } &:where( :enabled:hover, :enabled:focus-visible, [aria-expanded="true"], [aria-selected="true"] ) { --lb-button-background: var(--lb-foreground-subtle); color: var(--lb-foreground-tertiary); } &:where( [data-variant="default"]:not( :is( :enabled:hover, :enabled:focus-visible, [aria-expanded="true"], [aria-selected="true"], [aria-pressed] ) ) ) { background: transparent; } &:where([data-variant="primary"]) { --lb-button-background: var(--lb-accent); color: var(--lb-accent-foreground); &:where( :enabled:hover, :enabled:focus-visible, [aria-expanded="true"], [aria-selected="true"] ) { --lb-button-background: var(--lb-accent-secondary); color: var(--lb-accent-foreground); } } &:where([data-variant="outline"]) { box-shadow: inset 0 0 0 1px var(--lb-foreground-subtle); transition-property: background, color, opacity, box-shadow; } &:where(:has(.lb-button-label)) { gap: calc(0.175 * var(--lb-spacing)); padding-inline: calc(0.55 * var(--lb-spacing)); &:where(:has(.lb-icon-container)) { padding-inline-start: calc(0.4 * var(--lb-spacing)); } } &:where([data-variant="toolbar"]) { color: var(--lb-foreground-tertiary); &:where([aria-pressed="true"]) { --lb-button-background: var(--lb-foreground-subtle); color: var(--lb-foreground-secondary); :where(.lb-icon *) { stroke-width: calc(1.25 * var(--lb-icon-weight)); } } } &:where([data-variant="secondary"]) { --lb-button-background: var(--lb-foreground-subtle); color: var(--lb-foreground-tertiary); &:where( :enabled:hover, :enabled:focus-visible, [aria-expanded="true"], [aria-selected="true"] ) { --lb-button-background: var(--lb-foreground); color: var(--lb-dynamic-background); } } &:where([data-size="large"]) { padding: calc(0.5 * var(--lb-spacing)); &:where(:has(.lb-button-label)) { gap: calc(0.35 * var(--lb-spacing)); padding-inline: calc(0.7 * var(--lb-spacing)); &:where(:has(.lb-icon-container)) { padding-inline-start: calc(0.6 * var(--lb-spacing)); } } } :where(.lb-icon-container) { flex: none; } :where(.lb-icon) { --lb-icon-background: var(--lb-button-background); } } .lb-button-label { display: inline-flex; flex: none; align-items: center; block-size: var(--lb-icon-size); font-weight: 500; font-size: calc(0.7 * var(--lb-icon-size)); line-height: 1; } /************************************* * Dropdown * *************************************/ .lb-dropdown { min-inline-size: 160px; } .lb-dropdown-label { padding: calc(0.875 * var(--lb-spacing)) calc(0.625 * var(--lb-spacing)) calc(0.125 * var(--lb-spacing)); color: var(--lb-foreground-tertiary); font-weight: 600; font-size: 0.675em; text-transform: uppercase; pointer-events: none; user-select: none; &:where(:first-child) { padding-block-start: var(--lb-spacing); } } .lb-dropdown-separator { block-size: 1px; margin: $lb-elevation-padding calc(-1 * $lb-elevation-padding); background: var(--lb-foreground-subtle); } .lb-dropdown-item { :where(.lb-icon-container) { margin-inline-start: calc(-0.125 * var(--lb-spacing)); margin-inline-end: calc(0.375 * var(--lb-spacing)); color: var(--lb-foreground-moderate); transition-property: color; } } .lb-dropdown-item:where( :is( [data-highlighted]:not([data-highlighted="false"]), [data-selected]:not([data-selected="false"]), [data-active]:not([data-active="false"]) ) ) { :where(.lb-icon-container) { color: var(--lb-foreground-tertiary); } } .lb-dropdown-item:where(:has(.lb-dropdown-item-accessory)) { :where(.lb-dropdown-item-label) { margin-inline-end: calc(0.375 * var(--lb-spacing)); } } .lb-dropdown-item-accessory { margin-inline-start: auto; margin-inline-end: calc(-0.25 * var(--lb-spacing)); } /* If a dropdown has at least one icon, all items should be aligned has if they had an icon */ .lb-dropdown:where(:has(.lb-dropdown-item-icon)) :where(.lb-dropdown-item:not(:has(.lb-dropdown-item-icon))) :where(.lb-dropdown-item-label) { margin-inline-start: calc( var(--lb-icon-size) + (0.375 - 0.125) * var(--lb-spacing) ); } /************************************* * Select * *************************************/ .lb-select-button { min-inline-size: 0; :where(.lb-button-label) { @include truncate; flex: 1; } } .lb-select-button-chevron { flex: none; margin-inline-end: calc(-0.25 * var(--lb-spacing)); opacity: 0.75; } /************************************* * Composer suggestions * *************************************/ .lb-composer-suggestions-list { margin: 0; padding: 0; list-style: none; } .lb-composer-suggestions-list-item { scroll-margin-block: $lb-elevation-padding; } /************************************* * Composer mention suggestions * *************************************/ .lb-composer-mention-suggestions { --lb-composer-mention-suggestion-avatar-size: 1.25rem; } .lb-composer-mention-suggestion { padding: calc(0.375 * var(--lb-spacing)) calc(0.625 * var(--lb-spacing)); } .lb-composer-mention-suggestion-avatar { inline-size: var(--lb-composer-mention-suggestion-avatar-size); margin-inline-start: calc(-0.125 * var(--lb-spacing)); margin-inline-end: calc(0.5 * var(--lb-spacing)); margin-block: calc(0.125 * var(--lb-spacing)); background: var(--lb-foreground-subtle); color: var(--lb-foreground-moderate); } /************************************* * List * *************************************/ .lb-list { display: contents; :where(:first-child) { @include capitalize; } } /************************************* * Date * *************************************/ .lb-date { @include capitalize; } /************************************* * Emoji * *************************************/ @include safari-only { .lb-emoji { transform: scale(0.825); will-change: transform; } } /************************************* * Emoji picker * *************************************/ .lb-emoji-picker { --lb-emoji-picker-padding: $lb-emoji-picker-padding; --lb-emoji-picker-offset-padding: calc( $lb-emoji-picker-padding + 0.375 * var(--lb-spacing) ); display: flex; flex-direction: column; inline-size: 100%; max-inline-size: var(--frimousse-viewport-width); block-size: 374px; color: var(--lb-foreground); } .lb-emoji-picker-header { flex: none; border-block-end: 1px solid var(--lb-foreground-subtle); } .lb-emoji-picker-footer { display: flex; flex: none; gap: calc(0.5 * var(--lb-spacing)); align-items: center; inline-size: 100%; padding: calc(0.5 * var(--lb-spacing)); border-block-start: 1px solid var(--lb-foreground-subtle); } .lb-emoji-picker-active-emoji { display: flex; flex: none; justify-content: center; align-items: center; inline-size: 1.25em; block-size: 1.25em; font-size: 1.25em; } .lb-emoji-picker-active-emoji-label { @include truncate; flex: 1; color: var(--lb-foreground-secondary); font-weight: 500; font-size: 0.8125em; } .lb-emoji-picker-active-emoji-label-placeholder { margin-inline-start: calc(0.5 * var(--lb-spacing)); color: var(--lb-foreground-moderate); } .lb-emoji-picker-skin-tone-selector { display: flex; flex: none; justify-content: center; align-items: center; inline-size: calc(1.75 * var(--lb-spacing)); block-size: calc(1.75 * var(--lb-spacing)); margin-inline-start: auto; } .lb-emoji-picker-search-container { position: relative; display: flex; align-items: center; :where(.lb-icon) { position: absolute; inset-inline-start: var(--lb-emoji-picker-offset-padding); color: var(--lb-foreground-moderate); pointer-events: none; } } .lb-emoji-picker-search { all: unset; box-sizing: inherit; inline-size: 100%; padding: var(--lb-emoji-picker-offset-padding); padding-inline-start: calc( var(--lb-icon-size) + var(--lb-emoji-picker-offset-padding) + 0.375 * var(--lb-spacing) ); background: transparent; outline: none; appearance: textfield; &::placeholder { color: var(--lb-foreground-moderate); } &::-webkit-search-cancel-button { display: none; } } .lb-emoji-picker-content { position: relative; flex: 1; outline: none; } .lb-emoji-picker-category-header { padding: var(--lb-emoji-picker-padding) var(--lb-emoji-picker-offset-padding); background: var(--lb-dynamic-background); } .lb-emoji-picker-category-header-title { color: var(--lb-foreground-tertiary); font-weight: 600; font-size: 0.675em; text-transform: uppercase; } .lb-emoji-picker-list { padding-block-end: var(--lb-emoji-picker-padding); animation: lb-animation-appear var(--lb-transition-duration) var(--lb-transition-easing) both; } .lb-emoji-picker-row { display: flex; padding-inline: var(--lb-emoji-picker-padding); scroll-margin-block-end: var(--lb-emoji-picker-padding); } .lb-emoji-picker-emoji { all: unset; display: flex; justify-content: center; align-items: center; overflow: hidden; box-sizing: inherit; aspect-ratio: 1; padding: calc(0.375 * var(--lb-spacing)); border-radius: calc(var(--lb-radius) - 0.75 * $lb-emoji-picker-padding); text-align: center; } /************************************* * Tooltip * *************************************/ .lb-tooltip { --lb-background: #222; --lb-foreground: #fff; --lb-foreground-contrast: 10%; position: relative; display: flex; align-items: center; max-inline-size: 300px; min-block-size: calc( $lb-tooltip-shortcut-height + 2 * $lb-tooltip-additional-padding ); padding-inline: $lb-tooltip-horizontal-padding; border-radius: var(--lb-radius); background: var(--lb-dynamic-background); color: var(--lb-foreground); box-shadow: var(--lb-tooltip-shadow); font-size: 0.75rem; line-height: 1; overflow-wrap: anywhere; pointer-events: none; &::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; box-shadow: var(--lb-inset-shadow); pointer-events: none; } } .lb-tooltip\:multiline { justify-content: center; padding-block: calc( $lb-tooltip-vertical-padding * (1 / $lb-tooltip-line-height) ); line-height: $lb-tooltip-line-height; text-align: center; } .lb-tooltip-shortcut { display: flex; gap: calc(0.125 * var(--lb-spacing)); justify-content: center; align-items: center; block-size: $lb-tooltip-shortcut-height; margin-inline-start: $lb-tooltip-horizontal-padding; margin-inline-end: calc( -1 * $lb-tooltip-horizontal-padding + $lb-tooltip-additional-padding ); padding-inline: calc(0.25 * var(--lb-spacing)); border-radius: calc( var(--lb-radius) - 0.625 * $lb-tooltip-additional-padding ); background: var(--lb-foreground-subtle); color: var(--lb-foreground-tertiary); font-family: inherit; line-height: 1; text-transform: uppercase; :where(abbr) { all: unset; } } /************************************* * Avatar * *************************************/ .lb-avatar { position: relative; container-type: inline-size; display: flex; justify-content: center; align-items: center; overflow: hidden; aspect-ratio: 1; border-radius: var(--lb-avatar-radius); background: var(--lb-foreground-subtle); color: var(--lb-foreground-moderate); &:where([data-loading]) { background: var(--lb-foreground); opacity: $lb-loading-opacity; } } .lb-avatar-image { position: absolute; inset: 0; object-fit: cover; inline-size: 100%; block-size: 100%; } .lb-avatar-fallback { font-weight: 500; font-size: 35cqi; white-space: nowrap; /** * Progressive enhancement: Only show the fallback when container queries are supported */ @supports not (container-type: inline-size) { display: none; } } /************************************* * Name * *************************************/ .lb-name { display: inline-block; &:where([data-loading]) { &::before { content: "\FEFF"; display: inline-block; vertical-align: middle; inline-size: 8ch; block-size: 1.75ex; border-radius: calc(0.5 * var(--lb-radius)); background: currentcolor; opacity: $lb-loading-opacity; user-select: none; } } } /************************************* * Loading * *************************************/ :is(.lb-avatar, .lb-name):where([data-loading]) { animation: lb-animation-shimmer 8s linear infinite; } /************************************* * Body * *************************************/ :is(.lb-comment-body, .lb-composer-editor) { color: var(--lb-foreground-secondary); &, * { line-height: var(--lb-line-height); } :where(p) { --lb-line-height-crop: calc(1lh - 1em) / -2; margin-block-start: 0.25em; margin-block-end: 0.25em; /* Cancel out the impact of line-height on margins/paddings */ &:where(:first-of-type) { margin-block-start: calc(0.125em + var(--lb-line-height-crop)); } /* Cancel out the impact of line-height on margins/paddings */ &:where(:last-of-type) { margin-block-end: calc(0.125em + var(--lb-line-height-crop)); } } :where(strong) { font-weight: 600; } } .lb-comment-mention, .lb-composer-mention { color: var(--lb-accent); box-decoration-break: clone; font-weight: 500; } :is(.lb-comment-link, .lb-composer-link) { color: var(--lb-foreground); outline: none; font-weight: 500; transition-property: color, text-decoration-color; text-decoration-line: underline; text-decoration-color: var(--lb-foreground-moderate); text-underline-offset: 2px; &:where([href]):where(:hover, :focus-visible) { color: var(--lb-accent); text-decoration-color: var(--lb-accent-moderate); } } .lb-comment-mention:where([data-self]), .lb-composer-mention { padding: 0.1em 0.3em; border-radius: calc(0.675 * var(--lb-radius)); background: var(--lb-accent-subtle); } /************************************* * Composer * *************************************/ .lb-composer { position: relative; background: var(--lb-dynamic-background); color: var(--lb-foreground); transition-property: background; } .lb-composer-form { margin: 0; } .lb-composer:where(:has(.lb-composer-editor:not(:focus-visible))) { :where(.lb-button[data-variant="primary"]) { --lb-button-background: var(--lb-foreground-subtle); color: var(--lb-foreground-tertiary); &:where(:enabled:hover, :enabled:focus-visible) { --lb-button-background: var(--lb-accent); color: var(--lb-accent-foreground); } } } .lb-composer-editor { padding: var(--lb-spacing); outline: none; &:where([data-disabled]:not([data-disabled="false"])) { opacity: 0.5; cursor: not-allowed; } :where(.lb-composer-editor-container:has(.lb-composer-attachments)) & { padding-block-end: calc(0.25 * var(--lb-spacing)); } :where([data-placeholder]) { color: var(--lb-foreground-moderate); } } .lb-composer-mention { @include invisible-selection; &:where([data-selected]:not([data-selected="false"])) { background: var(--lb-accent); color: var(--lb-accent-foreground); } } .lb-composer-footer { display: flex; gap: calc(0.75 * var(--lb-spacing)); align-items: center; block-size: calc($lb-button-size + var(--lb-spacing)); margin-block-start: calc(-0.125 * var(--lb-spacing)); padding: 0 var(--lb-spacing) var(--lb-spacing); } .lb-composer-actions, .lb-composer-editor-actions { display: flex; gap: calc(0.125 * var(--lb-spacing)); align-items: center; } .lb-composer-editor-actions { margin-inline-end: auto; } .lb-composer-attribution { color: var(--lb-foreground-moderate); outline: none; transition-property: color; &:where(:hover, :focus-visible) { color: var(--lb-foreground-tertiary); } :where(svg) { block-size: calc(0.75 * $lb-button-size); } } .lb-composer-attachments { padding-inline: var(--lb-spacing); padding-block-start: calc(0.75 * var(--lb-spacing)); padding-block-end: var(--lb-spacing); } .lb-composer-editor-container:where([data-drop]) * { pointer-events: none; } .lb-composer-attachments-drop-area { position: absolute; inset: 0; display: flex; place-content: center; place-items: center; color: var(--lb-accent); &::before, &::after { content: ""; position: absolute; inset: calc(0.5 * var(--lb-spacing)); z-index: 0; border-radius: calc(0.75 * var(--lb-radius)); } &::before { background: currentcolor; opacity: calc(1 * var(--lb-accent-contrast)); } &::after { border: 2px dashed currentcolor; opacity: calc(2 * var(--lb-accent-contrast)); } } .lb-composer-attachments-drop-area-label { position: relative; display: flex; gap: calc(0.25 * var(--lb-spacing)); place-items: center; padding: calc(0.375 * var(--lb-spacing)) calc(0.5 * var(--lb-spacing)); border-radius: calc(0.75 * var(--lb-radius)); background: var(--lb-accent); color: var(--lb-accent-foreground); font-weight: 500; pointer-events: none; } /************************************* * Floating Toolbar * *************************************/ .lb-composer-floating-toolbar { display: flex; flex-direction: row; gap: $lb-elevation-padding; padding: $lb-elevation-padding; user-select: none; /* Invisibly increase the buttons' hit target size */ :where(.lb-button) { &::before { content: ""; position: absolute; inset: calc(-1 * $lb-elevation-padding); z-index: -1; border-radius: inherit; } &:where(:not(:first-of-type))::before { inset-inline-start: calc(-0.5 * $lb-elevation-padding); } &:where(:not(:last-of-type))::before { inset-inline-end: calc(-0.5 * $lb-elevation-padding); } } } /************************************* * Comment * *************************************/ .lb-comment { --lb-comment-avatar-size: $lb-button-size; position: relative; padding: var(--lb-spacing); background: var(--lb-dynamic-background); color: var(--lb-foreground); font-weight: 400; scroll-margin: var(--lb-spacing); @media (hover: hover) { &:where(.lb-comment\:show-actions-hover) { :where(.lb-comment-actions) { position: absolute; inset-inline-end: 0; opacity: 0; transition-property: opacity; } &:where(:is(:hover, :focus-within, .lb-comment\:action-open)) { :where(.lb-comment-actions) { position: relative; opacity: 1; } } } } &:where(:target, [data-target]) { --lb-dynamic-background: var(--lb-background-accent-faint); } &:where([data-editing]) { --lb-dynamic-background: var(--lb-background-foreground-faint); } } .lb-comment-header { position: relative; display: flex; gap: calc(0.75 * var(--lb-spacing)); align-items: center; block-size: var(--lb-comment-avatar-size); margin-block-end: calc(0.75 * var(--lb-spacing)); } .lb-comment-details { display: flex; gap: calc(0.75 * var(--lb-spacing)); align-items: center; min-inline-size: 0; } .lb-comment-avatar { flex: none; inline-size: var(--lb-comment-avatar-size); } .lb-comment-details-labels { display: flex; gap: calc(0.5 * var(--lb-spacing)); align-items: baseline; min-inline-size: 0; } .lb-comment-author, .lb-comment-date { @include truncate; @include capitalize; } .lb-comment-author { font-weight: 500; } .lb-comment-date { color: var(--lb-foreground-tertiary); font-size: 0.875em; } .lb-comment-date-created, .lb-comment-date-edited { display: contents; } .lb-comment-actions { display: flex; gap: calc(0.125 * var(--lb-spacing)); margin-inline-start: auto; } .lb-comment-composer { margin: calc(-1 * var(--lb-spacing)); background: unset; } .lb-comment-body { /** * Prevent empty lines from collapsing */ :where(p span:only-child:empty)::before { content: "\FEFF"; user-select: none; } } .lb-comment-attachments { margin-block-start: calc(0.75 * var(--lb-spacing)); } .lb-comment-reactions { display: flex; flex-wrap: wrap; gap: calc(0.375 * var(--lb-spacing)); margin-block-start: calc(0.75 * var(--lb-spacing)); } .lb-comment-reaction { gap: calc(0.375 * var(--lb-spacing)); block-size: $lb-button-size; padding-inline: calc(0.575 * var(--lb-spacing)); border-radius: $lb-radius-full; &:where([data-self]) { background: var(--lb-accent-subtle); color: var(--lb-accent-secondary); box-shadow: inset 0 0 0 1px var(--lb-accent-moderate); &:where( :enabled:hover, :enabled:focus-visible, [aria-expanded="true"], [aria-selected="true"] ) { color: var(--lb-accent); } } } .lb-comment-reaction-count { font-weight: 500; font-size: 0.75em; font-variant-numeric: tabular-nums; } .lb-comment-reaction-tooltip { max-inline-size: 200px; } .lb-comment-deleted { color: var(--lb-foreground-tertiary); font-size: 0.875em; } .lb-comment\:indent-content { min-block-size: calc(var(--lb-comment-avatar-size) + 2 * var(--lb-spacing)); :where(.lb-comment-header) { block-size: $lb-button-size; margin-block-end: calc(0.25 * var(--lb-spacing)); } :where(.lb-comment-avatar) { position: absolute; inset-inline-start: 0; inset-block-start: 0; } :where(.lb-comment-details-labels) { margin-inline-start: calc( var(--lb-comment-avatar-size) + 0.75 * var(--lb-spacing) ); } :where(.lb-comment-content) { padding-inline-start: calc( var(--lb-comment-avatar-size) + 0.75 * var(--lb-spacing) ); } } /************************************* * Thread * *************************************/ .lb-thread { background: var(--lb-dynamic-background); color: var(--lb-foreground); transition-property: background; @media (hover: hover) { &:where(.lb-thread\:show-actions-hover :is(:hover, :focus-within)) { :where(.lb-thread-actions) { opacity: 1; } } } } .lb-thread-comments { position: relative; z-index: 0; display: flex; flex-direction: column; } .lb-thread-comment { z-index: 0; padding-block: calc(0.6 * var(--lb-spacing)); transition-property: background; &:where(.lb-comment\:indent-content) { min-block-size: calc(var(--lb-comment-avatar-size) + var(--lb-spacing)); } &:where(:first-of-type, [data-editing]) { padding-block-start: var(--lb-spacing); &:where(.lb-comment\:indent-content) { min-block-size: calc( var(--lb-comment-avatar-size) + 1.5 * var(--lb-spacing) ); } } &:where(:last-of-type, [data-editing]) { padding-block-end: var(--lb-spacing); &:where(.lb-comment\:indent-content) { min-block-size: calc( var(--lb-comment-avatar-size) + 1.75 * var(--lb-spacing) ); } } } .lb-thread-new-indicator { position: relative; z-index: 1; display: flex; justify-content: center; align-items: center; block-size: 0; &::before, &::after { content: ""; z-index: 0; flex: 1; block-size: 0; border-block-start: 1px solid var(--lb-foreground-subtle); transition-property: border; } } .lb-thread-new-indicator-label { z-index: 1; display: flex; flex: none; gap: calc(0.325 * var(--lb-spacing)); align-items: center; padding: calc(0.25 * var(--lb-spacing)) var(--lb-spacing); color: var(--lb-accent); font-weight: 600; font-size: 0.675em; text-transform: uppercase; } .lb-thread-new-indicator-label-icon { inline-size: calc(0.6 * var(--lb-icon-size)); block-size: calc(0.6 * var(--lb-icon-size)); } .lb-thread-composer { position: relative; &::after { content: ""; position: absolute; inset: 0; inline-size: 100%; block-size: 100%; border-block-start: 1px solid var(--lb-foreground-subtle); pointer-events: none; transition-property: border; } } /************************************* * Attachments * *************************************/ .lb-comment-attachments, .lb-composer-attachments { display: flex; flex-direction: column; gap: calc(0.75 * var(--lb-spacing)); } .lb-attachments { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); gap: calc(0.75 * var(--lb-spacing)); } .lb-attachment, .lb-attachment-delete { @include button; } .lb-attachment { position: relative; display: flex; inline-size: 100%; min-inline-size: 0; border-radius: var(--lb-radius); background: var(--lb-dynamic-background); box-shadow: inset 0 0 0 1px var(--lb-foreground-subtle); &:where([tabindex="-1"]) { cursor: default; } &:where(:not([tabindex="-1"])) { &:where(:hover, :focus-visible) { background: var(--lb-foreground-subtle); } } } .lb-attachment-delete { position: absolute; inset-inline-end: -0.35rem; inset-block-start: -0.35rem; z-index: 2; display: flex; justify-content: center; align-items: center; inline-size: 1.1rem; block-size: 1.1rem; border-radius: 50%; background: var(--lb-foreground-subtle); color: var(--lb-foreground-secondary); box-shadow: 0 0 0 2px var(--lb-dynamic-background); opacity: 0; /* Invisibly increase the button's hit target size */ &::before { content: ""; position: absolute; inset: -4px; z-index: -1; border-radius: inherit; } &:where(:hover, :focus-visible) { background: var(--lb-foreground-secondary); color: var(--lb-dynamic-background); } :where(.lb-attachment:focus-within, .lb-attachment:hover) & { opacity: 1; } :where(.lb-icon) { inline-size: 0.75rem; } } .lb-attachment-details { position: relative; display: flex; flex-direction: column; gap: calc(0.25 * var(--lb-spacing)); justify-content: center; min-inline-size: 0; font-size: 0.875em; } .lb-attachment-name { display: flex; font-weight: 500; } .lb-attachment-name-base, .lb-attachment-description { @include truncate; transition-property: color; } .lb-attachment-preview { position: relative; display: flex; flex: none; justify-content: center; align-items: center; overflow: hidden; background: color-mix( in srgb, transparent, var(--lb-foreground) var(--lb-foreground-contrast) ); color: var(--lb-foreground-tertiary); transition-property: background, color; } .lb-attachment-preview-media { border-radius: inherit; transition-property: opacity; &, &::after, img, video { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; } img, video { object-fit: cover; pointer-events: none; } &::after { content: ""; border-radius: inherit; box-shadow: var(--lb-highlight-shadow); pointer-events: none; } &:where([data-hidden]) { opacity: 0; } } .lb-attachment-icon { flex: none; overflow: visible; color: var(--lb-foreground); } .lb-attachment-icon-glyph { fill: var(--lb-foreground-moderate); } .lb-attachment-icon-background { fill: var(--lb-background); } .lb-attachment-icon-fold { fill-opacity: calc(0.75 * var(--lb-foreground-contrast)); } .lb-attachment-icon-shadow { filter: blur(6px); fill-opacity: var(--lb-foreground-contrast); } .lb-file-attachment { gap: calc(0.5 * var(--lb-spacing)); padding: calc(0.5 * var(--lb-spacing)); padding-inline-end: calc(0.65 * var(--lb-spacing)); :where(.lb-attachment-preview) { aspect-ratio: 1; inline-size: 2.5rem; border-radius: calc(0.5 * var(--lb-radius)); } :where(.lb-attachment-name) { color: var(--lb-foreground-secondary); } :where(.lb-attachment-description) { color: var(--lb-foreground-tertiary); } &:where(:not([tabindex="-1"])) { &:where(:hover, :focus-visible, :focus-within) { :where(.lb-attachment-name) { color: var(--lb-foreground); } :where(.lb-attachment-description) { color: var(--lb-foreground-secondary); } } } } .lb-media-attachment { aspect-ratio: 16 / 10; :where(.lb-attachment-preview) { position: absolute; inset: 0; border-radius: inherit; } :where(.lb-attachment-details) { position: absolute; inset-inline: 0; inset-block-end: 0; padding: calc(0.75 * var(--lb-spacing)); border-end-start-radius: inherit; border-end-end-radius: inherit; background: linear-gradient(to bottom, transparent, rgba(0 0 0 / 80%)); text-shadow: 0 0 2px rgba(0 0 0 / 40%); opacity: 0; transition-property: opacity; } :where(.lb-attachment-name) { color: #fff; } :where(.lb-attachment-description) { color: rgba(255 255 255 / 80%); } &:where(:not([tabindex="-1"])) { &:where(:hover, :focus-visible, :focus-within) { :where(.lb-attachment-details) { opacity: 1; } } } } .lb-attachment:where([data-error]) { :where(.lb-attachment-preview) { background: var(--lb-destructive); color: var(--lb-destructive-foreground); } } /************************************* * Inbox Notification * *************************************/ .lb-inbox-notification { --lb-inbox-notification-aside-size: 36px; position: relative; display: flex; gap: calc(0.75 * var(--lb-spacing)); overflow: hidden; padding: var(--lb-spacing); background: var(--lb-dynamic-background); color: var(--lb-foreground); font-weight: 400; text-decoration: inherit; transition-property: background; /* Highlight missing notifications during development */ &:where([data-missing]) { --lb-accent: var(--lb-destructive) !important; --lb-accent-foreground: var(--lb-destructive-foreground) !important; --lb-accent-contrast: var(--lb-destructive-contrast) !important; --lb-dynamic-background: var(--lb-background-accent-faint); } &:where([data-unread]) { --lb-dynamic-background: var(--lb-background-accent-faint); } &:where([href]) { cursor: pointer; &:where(:hover, :focus-visible, :focus-within) { --lb-dynamic-background: var(--lb-background-foreground-faint); } &:where([data-unread]) { &:where(:hover, :focus-visible, :focus-within) { --lb-dynamic-background: var(--lb-background-accent-subtle); } } } @media (hover: hover) { &:where(.lb-inbox-notification\:show-actions-hover) { :where(.lb-inbox-notification-header) { display: grid; grid-template: "title secondary" / 1fr max-content; } :where(.lb-inbox-notification-details) { opacity: 1; transition-property: opacity; } :where(.lb-inbox-notification-actions) { opacity: 0; transition-property: opacity; } &:where(:is(:hover, :focus-within, .lb-inbox-notification\:action-open)) { :where(.lb-inbox-notification-details) { opacity: 0; } :where(.lb-inbox-notification-actions) { opacity: 1; } } :where(.lb-inbox-notification-details), :where(.lb-inbox-notification-actions) { grid-area: secondary; justify-self: end; } } } } .lb-inbox-notification-aside { flex: none; inline-size: var(--lb-inbox-notification-aside-size); } .lb-inbox-notification-icon { display: flex; justify-content: center; place-items: center; aspect-ratio: 1; border-radius: 50%; background: var(--lb-foreground-subtle); .lb-inbox-notification:where([data-missing]) :where(&) { background: var(--lb-accent-subtle); color: var(--lb-accent); } } .lb-inbox-notification-content { flex: 1; } .lb-inbox-notification-content, .lb-inbox-notification-body { min-inline-size: 0; max-inline-size: 100%; } .lb-inbox-notification-header { display: flex; gap: calc(0.75 * var(--lb-spacing)); align-items: center; margin-block-start: calc(0.25 * var(--lb-spacing)); margin-block-end: calc(0.5 * var(--lb-spacing)); } .lb-inbox-notification-title { @include capitalize; min-block-size: $lb-button-size; :where(strong, .lb-list, .lb-name) { font-weight: 500; } } .lb-inbox-notification-details { flex: none; align-self: start; min-inline-size: 0; block-size: $lb-button-size; margin-inline-start: auto; } .lb-inbox-notification-details-labels { display: flex; align-items: baseline; min-inline-size: 0; &::before { content: "\FEFF"; } } .lb-inbox-notification-actions { display: flex; grid-area: actions; gap: calc(0.125 * var(--lb-spacing)); align-self: start; } .lb-inbox-notification-comments { display: flex; flex-direction: column; gap: var(--lb-spacing); } .lb-inbox-notification-comment { padding: 0; background: transparent; :where(.lb-comment-header) { block-size: auto; color: var(--lb-foreground-tertiary); font-size: 0.875rem; } :where(.lb-comment-reaction), :where(.lb-comment-attachment) { pointer-events: none; } } .lb-inbox-notification-date { color: var(--lb-foreground-tertiary); font-size: 0.875em; } .lb-inbox-notification-unread-indicator { align-self: center; inline-size: 10px; block-size: 10px; margin-inline-start: calc(0.5 * var(--lb-spacing)); border-radius: 50%; background: var(--lb-accent); } /************************************* * History Version Summary * *************************************/ .lb-history-version-summary { position: relative; display: flex; flex-direction: column; gap: calc(0.25 * var(--lb-spacing)); justify-content: center; inline-size: 100%; min-inline-size: 0; padding: var(--lb-spacing); background: var(--lb-dynamic-background); transition-property: background; &:where( :hover, :focus-visible, :focus-within, [data-selected]:not([data-selected="false"]) ) { --lb-dynamic-background: var(--lb-background-foreground-faint); } } .lb-history-version-summary-date, .lb-history-version-summary-authors { @include truncate; @include capitalize; min-inline-size: 0; max-inline-size: 100%; } .lb-history-version-summary-date { color: var(--lb-foreground-secondary); font-weight: 500; } .lb-history-version-summary-authors { color: var(--lb-foreground-tertiary); } /************************************* * History Version Previe * *************************************/ .lb-history-version-preview { position: relative; display: flex; flex-direction: column; background: var(--lb-dynamic-background); /* overflow-block: auto; doesn't work as expected */ /* stylelint-disable-next-line plugin/use-logical-properties-and-values */ overflow-y: auto; } .lb-history-version-preview-content { flex: 1 0 auto; padding: var(--lb-spacing); } .lb-history-version-preview-footer { position: sticky; inset-block-end: 0; display: flex; flex: none; gap: var(--lb-spacing); align-items: center; margin-block-start: auto; padding: var(--lb-spacing); border-block-start: 1px solid var(--lb-foreground-subtle); background: var(--lb-dynamic-background); } .lb-history-version-preview-authors { @include truncate; flex: 1 1 auto; min-inline-size: 0; color: var(--lb-foreground-tertiary); } .lb-history-version-preview-actions { display: flex; flex: none; gap: calc(0.35 * var(--lb-spacing)); align-items: center; margin-inline-start: auto; } /************************************* * Lists * *************************************/ .lb-inbox-notification-list, .lb-history-version-summary-list { margin: 0; padding: 0; list-style: none; } .lb-inbox-notification-list-item, .lb-history-version-summary-list-item { &:where(:not(:last-of-type)) { border-block-end: 1px solid var(--lb-foreground-subtle); } } /************************************* * Inline code * *************************************/ :is(.lb-root) { :where(code) { padding: 0.2em 0.4em; border-radius: calc(0.75 * var(--lb-radius)); background: var(--lb-foreground-subtle); box-decoration-break: clone; font-size: 85%; line-height: 1; } /** * Merge adjacent inline code elements */ :where(span:has(code) + span code) { padding-inline-start: 0; border-start-start-radius: 0; border-end-start-radius: 0; } :where(span:has(code):has(+ span code) code) { padding-inline-end: 0; border-start-end-radius: 0; border-end-end-radius: 0; } } /* 0,0,0 specificity to inherit any styles applied to `code` elements */ :where(:is(.lb-root) code) { font-family: ui-monospace, Menlo, Monaco, "Roboto Mono", "Cascadia Code", "Source Code Pro", Consolas, "DejaVu Sans Mono", monospace; } /************************************* * Elevation * *************************************/ .lb-elevation { position: relative; overflow: hidden; border-radius: var(--lb-radius); background: var(--lb-dynamic-background); box-shadow: var(--lb-elevation-shadow); &::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; box-shadow: var(--lb-inset-shadow); pointer-events: none; } } /************************************* * Elevation lists * *************************************/ .lb-dropdown, .lb-composer-suggestions { padding: $lb-elevation-padding; /* overflow-block: auto; doesn't work as expected */ /* stylelint-disable-next-line plugin/use-logical-properties-and-values */ overflow-y: auto; &:where([data-hidden]) { opacity: 0; } } .lb-dropdown-item, .lb-composer-suggestions-list-item { display: flex; align-items: center; padding: calc(0.25 * var(--lb-spacing)) calc(0.5 * var(--lb-spacing)); font-size: 0.875rem; } .lb-dropdown-item, .lb-composer-suggestions-list-item, .lb-emoji-picker-emoji { border-radius: calc(var(--lb-radius) - 0.75 * $lb-elevation-padding); color: var(--lb-foreground-secondary); outline: none; cursor: pointer; user-select: none; transition-property: background, color, opacity; } :is( .lb-dropdown-item, .lb-composer-suggestions-list-item, .lb-emoji-picker-emoji ) { &:where( [data-highlighted]:not([data-highlighted="false"]), [data-selected]:not([data-selected="false"]), [data-active]:not([data-active="false"]) ) { background: var(--lb-foreground-subtle); transition-duration: calc(var(--lb-transition-duration) / 2); } &:where(:disabled, [data-disabled]:not([data-disabled="false"])) { opacity: 0.5; cursor: not-allowed; } } /************************************* * Floating animations * *************************************/ .lb-dropdown, .lb-composer-suggestions, .lb-composer-floating-toolbar, .lb-tooltip, .lb-emoji-picker { animation-duration: var(--lb-transition-duration); animation-timing-function: var(--lb-transition-easing); will-change: transform, opacity; } :is( .lb-dropdown, .lb-emoji-picker, .lb-tooltip:where([data-state="delayed-open"]), .lb-composer-suggestions, .lb-composer-floating-toolbar ) { &:where([data-side="top"]) { animation-name: lb-animation-slide-up; } &:where([data-side="bottom"]) { animation-name: lb-animation-slide-down; } } :is( .lb-dropdown, .lb-emoji-picker, .lb-tooltip, .lb-composer-suggestions, .lb-composer-floating-toolbar ) { &:where([data-state="closed"]) { animation-name: lb-animation-disappear; } } @media (prefers-reduced-motion) { .lb-dropdown:where(:not([data-state="closed"])), .lb-emoji-picker:where(:not([data-state="closed"])), .lb-tooltip:where([data-state="delayed-open"]:not([data-state="closed"])), .lb-composer-suggestions:where(:not([data-state="closed"])) { animation-name: lb-animation-appear; } } /************************************* * Animations * *************************************/ @keyframes lb-animation-slide-down { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } } @keyframes lb-animation-slide-up { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } } @keyframes lb-animation-appear { from { opacity: 0; } to { opacity: 1; } } @keyframes lb-animation-disappear { from { opacity: 1; } to { opacity: 0; } } @keyframes lb-animation-shimmer { from, to { mask-image: linear-gradient( 90deg, rgb(0 0 0 / 50%), #000, #000, rgb(0 0 0 / 50%) ); mask-size: 400% 100%; } from { mask-position: 200% 0; } to { mask-position: -200% 0; } } @keyframes lb-animation-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }