mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-29 17:49:02 +00:00
Add CSS cascade layers for Compound, shared components, and app/web styles (#33302)
* Layer Compound and shared component CSS * Layer app theme CSS * Remove !important flags from ActionBarView * Remove unnecessary !important statements from shared components * Avoid dead code errors for *.pcss just because layer is specified after @import url * Remove unnecessary !important styling * Override Banner defaults in RoomStatusBarView * Updated snaps * Updated snaps * Fix styling of media body in app/web * Fix styling for Compound anchors * Fix styling issues in app/web * More styling fixes * Fix a problem extracting css for HTMLExport * Revert changes * Fix for theme styling * Add test to improve coverage * Prettier * Fix styling issues * Add data-kind attribute to avoid global styling override * Update screenshot that now is correct * Revert data-kind attribute * Handle LinkPreview styling in .pcss * Fix flaky test: Avoid racing the lazy-loaded ManageEventIndexDialog * Take care of review comments * Updated snaps * Updated snaps again after merge * Remove !important from RoomStatusBar
This commit is contained in:
@@ -5,5 +5,8 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@import url("@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css") layer(compound);
|
||||
@import url("@vector-im/compound-web/dist/style.css");
|
||||
/* Shared cascade order: Compound tokens, Compound Web, shared components, then app overrides. */
|
||||
@layer compound-tokens, compound-web, shared-components, app-web;
|
||||
|
||||
@import url("@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css") layer(compound-tokens);
|
||||
@import url("@vector-im/compound-web/dist/style.css") layer(compound-web);
|
||||
|
||||
@@ -8,11 +8,13 @@ Please see LICENSE files in the repository root for full details.
|
||||
import type { StorybookConfig } from "@storybook/react-vite";
|
||||
import fs from "node:fs";
|
||||
import { nodePolyfills } from "vite-plugin-node-polyfills";
|
||||
import { mergeConfig } from "vite";
|
||||
import { mergeConfig, normalizePath, type Plugin } from "vite";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const srcRoot = normalizePath(join(__dirname, "..", "src"));
|
||||
const sharedComponentsLayer = "shared-components";
|
||||
|
||||
// Get a list of available languages so the language selector can display them at runtime
|
||||
const languageFiles = fs.readdirSync(join(__dirname, "..", "src", "i18n", "strings")).map((f) => f.slice(0, -5));
|
||||
@@ -36,6 +38,24 @@ function getAbsolutePath(value: string): any {
|
||||
return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)));
|
||||
}
|
||||
|
||||
function layerSharedComponentCssModules(): Plugin {
|
||||
return {
|
||||
name: "element-web-shared-components-storybook-css-layer",
|
||||
enforce: "pre",
|
||||
transform(code, id) {
|
||||
const cssPath = normalizePath(id.split("?")[0]);
|
||||
if (!cssPath.startsWith(srcRoot) || !cssPath.endsWith(".module.css")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
code: `@layer ${sharedComponentsLayer} {\n${code}\n}\n`,
|
||||
map: null,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ["../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
|
||||
addons: [
|
||||
@@ -61,6 +81,7 @@ const config: StorybookConfig = {
|
||||
async viteFinal(config) {
|
||||
return mergeConfig(config, {
|
||||
plugins: [
|
||||
layerSharedComponentCssModules(),
|
||||
// Needed for counterpart to work
|
||||
nodePolyfills({ include: ["util"], globals: { global: false } }),
|
||||
{
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
*/
|
||||
|
||||
.button {
|
||||
border-radius: 32px !important;
|
||||
background-color: var(--cpd-color-bg-subtle-primary) !important;
|
||||
border-radius: 32px;
|
||||
background-color: var(--cpd-color-bg-subtle-primary);
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,5 +7,5 @@
|
||||
|
||||
.title {
|
||||
/* For first title, there is already enough space at the top */
|
||||
margin-top: 0 !important;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
+2
-3
@@ -16,9 +16,8 @@
|
||||
.search {
|
||||
/* The search button should take all the remaining space */
|
||||
flex: 1;
|
||||
/* !important is needed to override compound button in EW */
|
||||
font: var(--cpd-font-body-md-regular) !important;
|
||||
color: var(--cpd-color-text-secondary) !important;
|
||||
font: var(--cpd-font-body-md-regular);
|
||||
color: var(--cpd-color-text-secondary);
|
||||
min-width: 0;
|
||||
|
||||
svg {
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
|
||||
.container {
|
||||
color: var(--cpd-color-text-primary);
|
||||
svg {
|
||||
/* Ensure button icons are primary too */
|
||||
color: var(--cpd-color-text-primary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.secondaryAction svg {
|
||||
color: var(--cpd-color-text-secondary) !important;
|
||||
.container svg {
|
||||
color: var(--cpd-color-text-primary);
|
||||
}
|
||||
|
||||
.primaryAction svg {
|
||||
color: var(--cpd-color-text-on-solid-primary) !important;
|
||||
.secondaryAction.secondaryAction[data-kind="secondary"] > svg {
|
||||
color: var(--cpd-color-text-secondary);
|
||||
}
|
||||
|
||||
.primaryAction.primaryAction[data-kind="primary"] > svg {
|
||||
color: var(--cpd-color-text-on-solid-primary);
|
||||
}
|
||||
|
||||
.title {
|
||||
|
||||
+5
-5
@@ -6,15 +6,15 @@
|
||||
*/
|
||||
|
||||
.picker_menu {
|
||||
max-inline-size: none !important;
|
||||
padding: 0 !important;
|
||||
gap: 0 !important;
|
||||
max-inline-size: none;
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.picker_menu_item {
|
||||
padding: var(--cpd-space-3x) var(--cpd-space-5x) !important;
|
||||
padding: var(--cpd-space-3x) var(--cpd-space-5x);
|
||||
}
|
||||
|
||||
.picker_separator {
|
||||
margin-inline: 0 !important;
|
||||
margin-inline: 0;
|
||||
}
|
||||
|
||||
+6
-6
@@ -6,15 +6,15 @@
|
||||
*/
|
||||
|
||||
.picker_menu_item {
|
||||
padding: var(--cpd-space-3x) var(--cpd-space-5x) !important;
|
||||
padding: var(--cpd-space-3x) var(--cpd-space-5x);
|
||||
}
|
||||
|
||||
.picker_form {
|
||||
display: flex;
|
||||
flex-direction: row !important;
|
||||
flex-wrap: wrap !important;
|
||||
padding: 0 !important;
|
||||
gap: var(--cpd-space-2x) !important;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
padding: 0;
|
||||
gap: var(--cpd-space-2x);
|
||||
color: var(--cpd-color-text-primary);
|
||||
font: var(--cpd-font-body-md-medium);
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
.picker_input_date {
|
||||
font: inherit;
|
||||
color-scheme: light;
|
||||
padding: var(--cpd-space-2x) !important;
|
||||
padding: var(--cpd-space-2x);
|
||||
|
||||
:global(.cpd-theme-dark) &,
|
||||
:global(.cpd-theme-dark-hc) & {
|
||||
|
||||
+9
-2
@@ -25,7 +25,14 @@ export interface UrlPreviewGroupViewSnapshot {
|
||||
}
|
||||
|
||||
export interface UrlPreviewGroupViewProps {
|
||||
/**
|
||||
* The view model for the component.
|
||||
*/
|
||||
vm: ViewModel<UrlPreviewGroupViewSnapshot> & UrlPreviewGroupViewActions;
|
||||
/**
|
||||
* Extra CSS classes to apply to the component.
|
||||
*/
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface UrlPreviewGroupViewActions {
|
||||
@@ -42,7 +49,7 @@ export type UrlPreviewGroupViewModel = ViewModel<UrlPreviewGroupViewSnapshot, Ur
|
||||
* The view lays out one or more link previews, can collapse or expand
|
||||
* overflowed previews, and exposes a control to hide the group.
|
||||
*/
|
||||
export function UrlPreviewGroupView({ vm }: UrlPreviewGroupViewProps): JSX.Element | null {
|
||||
export function UrlPreviewGroupView({ vm, className }: UrlPreviewGroupViewProps): JSX.Element | null {
|
||||
const { translate: _t } = useI18n();
|
||||
const { previews, totalPreviewCount, previewsLimited, overPreviewLimit, compactLayout } = useViewModel(vm);
|
||||
if (previews.length === 0) {
|
||||
@@ -61,7 +68,7 @@ export function UrlPreviewGroupView({ vm }: UrlPreviewGroupViewProps): JSX.Eleme
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<div className={classNames(className, styles.wrapper)}>
|
||||
<div className={classNames(styles.previewGroup, compactLayout && styles.compactLayout)}>
|
||||
{previews.map((preview) => (
|
||||
<LinkPreview key={preview.link} onImageClick={() => vm.onImageClick(preview)} {...preview} />
|
||||
|
||||
+11
-11
@@ -14,31 +14,31 @@
|
||||
.toolbar_item {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 !important;
|
||||
min-block-size: 0 !important;
|
||||
padding: 0;
|
||||
min-block-size: 0;
|
||||
|
||||
margin: 3px !important;
|
||||
border-radius: 6px !important;
|
||||
margin: 3px;
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--cpd-color-bg-subtle-secondary) !important;
|
||||
background-color: var(--cpd-color-bg-subtle-secondary);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar_item[data-presentation="icon"] {
|
||||
block-size: 28px !important;
|
||||
inline-size: 28px !important;
|
||||
block-size: 28px;
|
||||
inline-size: 28px;
|
||||
|
||||
color: var(--cpd-color-icon-secondary) !important;
|
||||
color: var(--cpd-color-icon-secondary);
|
||||
}
|
||||
|
||||
.toolbar_item[data-presentation="label"] {
|
||||
padding-inline-start: var(--cpd-space-2x) !important;
|
||||
padding-inline-end: var(--cpd-space-2x) !important;
|
||||
padding-inline-start: var(--cpd-space-2x);
|
||||
padding-inline-end: var(--cpd-space-2x);
|
||||
|
||||
font: var(--cpd-font-body-md-regular);
|
||||
text-decoration: none !important;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
.audioPlayer {
|
||||
padding: var(--cpd-space-4x) var(--cpd-space-3x) var(--cpd-space-3x) var(--cpd-space-3x) !important;
|
||||
border-radius: 8px !important;
|
||||
padding: var(--cpd-space-4x) var(--cpd-space-3x) var(--cpd-space-3x) var(--cpd-space-3x);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.mediaInfo {
|
||||
|
||||
+2
-3
@@ -26,8 +26,8 @@
|
||||
|
||||
& button {
|
||||
display: flex;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
width: 100%;
|
||||
min-block-size: unset;
|
||||
@@ -57,7 +57,6 @@
|
||||
|
||||
.content [data-type="download"] {
|
||||
align-items: center;
|
||||
color: var(--cpd-color-text-action-accent);
|
||||
|
||||
& iframe {
|
||||
margin: 0;
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
.content {
|
||||
color: var(--cpd-color-text-secondary) !important; /* override anchor color */
|
||||
color: var(--cpd-color-text-secondary); /* override anchor color */
|
||||
font-size: var(--cpd-font-size-body-xs);
|
||||
font-variant-numeric: tabular-nums;
|
||||
display: inline-block;
|
||||
|
||||
@@ -6,12 +6,36 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync } from "node:fs";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { defineConfig, esmExternalRequirePlugin } from "vite";
|
||||
import { defineConfig, esmExternalRequirePlugin, type Plugin } from "vite";
|
||||
import dts from "unplugin-dts/vite";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const cssLayerOrder = "@layer compound-tokens, compound-web, shared-components, app-web;";
|
||||
const sharedComponentsLayer = "shared-components";
|
||||
|
||||
function layerCssAssets(): Plugin {
|
||||
return {
|
||||
name: "element-web-shared-components-css-layer",
|
||||
writeBundle(_options, bundle): void {
|
||||
for (const asset of Object.values(bundle)) {
|
||||
if (asset.type !== "asset" || asset.fileName !== "element-web-shared-components.css") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const cssPath = resolve(__dirname, "dist", asset.fileName);
|
||||
const source = readFileSync(cssPath, "utf-8");
|
||||
if (source.startsWith(cssLayerOrder)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
writeFileSync(cssPath, `${cssLayerOrder}\n@layer ${sharedComponentsLayer} {\n${source}\n}\n`);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
@@ -50,6 +74,7 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
layerCssAssets(),
|
||||
dts({
|
||||
bundleTypes: true,
|
||||
include: ["src/**/*.{ts,tsx}"],
|
||||
|
||||
Reference in New Issue
Block a user