* Exploration of a virtuoso-powered emoji picker moved to shared components Fable generated * fix pnpm lock * format & fix some lint issues * wrong import * fix lint warning * Fix off-by-one and remove manual overflow adjustment: let's leave the default unless it turns out to be necessary. Emoji should not take that long to load. * Convert to functional component * WIP: change to one big virtuoso scroller * Change to use virtuoso's own onRangeChanged and santitise category data and how it's passed around * Convert Tabs to functional component and put the focusing behaviour back with it just keeping track of refs by itself. * Absorb two line config file into main component * Actually add the config to the main file * Convert emoji to functional Also make selected always defined and use useCallback. * QuickReactions to functional component * Non-default exports & doc * Search to functional component * Well it seems to work just fine now * Use ref prop * fix lockfile AGAIN * lint * Remove default export * Remove some mx_ classnames and fix the inputRef to make the arrow keys in the search box work (well, work as much as they ever did). * Remove last of the mx_ id / classnames (except the one in the test) * Use useMemo to memoize * No need to export props interface (I think?) and fix comment now we don't do the mutation stuff anymore * Fix test * Fix axe violations & add screenshots * Avoid comparing dom snapshots in test * Allow more before or after, just compare order of the ones present in both. * Switch existing usages to new emoji picker and kill the old one with fire * Unused stuff * Remove i18n strings * Fix some tests * Update screenshots * Fix test by removing the last of the weird memoized-but-mutated data structure * Move the string somewhere more sensible than 'a11y' * i18n lint * Give the emojis IDs so aria-activedescendant works * Fix more tests * Add a small wrapper emoji picker component This lets us easily memoize the recent emojis when the emoji picker is opened. Also it saves a bit of boilerplate. * Remove old emojipicker css * Typos Co-authored-by: David Langley <davidl@element.io> * Use compound constants * Rethemendex * Use catalog version for emojibase * Add comments * More comments * Fix comment * More comments * more comments (and make them uniform) * More comments * Fix pnpm lock again * Another comment * Apply button types to new version * Add comment * Disable screenshot as per comment --------- Co-authored-by: Will Hunt <2072976+Half-Shot@users.noreply.github.com> Co-authored-by: David Langley <davidl@element.io>
113 lines
4.8 KiB
TypeScript
113 lines
4.8 KiB
TypeScript
/*
|
|
* Copyright 2025 New Vector Ltd.
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
* Please see LICENSE files in the repository root for full details.
|
|
*
|
|
*/
|
|
|
|
import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
import { defineConfig, esmExternalRequirePlugin, type Plugin } from "vite";
|
|
import dts from "unplugin-dts/vite";
|
|
import react from "@vitejs/plugin-react";
|
|
import path from "node:path";
|
|
|
|
const cssLayerOrder = "@layer compound-tokens, compound-web, shared-components, app-web;";
|
|
const sharedComponentsLayer = "shared-components";
|
|
|
|
const cssAssetFileName = "element-web-shared-components.css";
|
|
|
|
function layerCssAssets(): Plugin {
|
|
return {
|
|
name: "element-web-shared-components-css-layer",
|
|
// Rename + layer-wrap the emitted CSS file. With multi-entry lib mode,
|
|
// vite/rolldown derives CSS filenames from the unscoped package name (dropping
|
|
// the `element-` prefix), so we rename on disk to keep the path stable for
|
|
// consumers importing `@element-hq/web-shared-components/.../*.css`.
|
|
writeBundle(options): void {
|
|
const outDir = options.dir ?? fileURLToPath(import.meta.resolve("./dist"));
|
|
const expectedPath = path.resolve(outDir, cssAssetFileName);
|
|
const renamedFromPath = path.resolve(outDir, "web-shared-components.css");
|
|
|
|
if (existsSync(renamedFromPath)) {
|
|
renameSync(renamedFromPath, expectedPath);
|
|
}
|
|
|
|
// No CSS emitted in this build (e.g. storybook's vite build doesn't produce
|
|
// the library CSS bundle), or already renamed and layered on a prior pass.
|
|
if (!existsSync(expectedPath)) return;
|
|
|
|
const source = readFileSync(expectedPath, "utf-8");
|
|
if (source.startsWith(cssLayerOrder)) return;
|
|
writeFileSync(expectedPath, `${cssLayerOrder}\n@layer ${sharedComponentsLayer} {\n${source}\n}\n`);
|
|
},
|
|
};
|
|
}
|
|
|
|
export default defineConfig({
|
|
build: {
|
|
lib: {
|
|
// Two entries: the main bundle and a standalone `numbers` utility that callers
|
|
// running outside the browser DOM (e.g. AudioWorkletGlobalScope) can import without
|
|
// pulling in the rest of the package — which transitively loads dnd-kit and
|
|
// other window/document-dependent code.
|
|
entry: {
|
|
"element-web-shared-components": fileURLToPath(import.meta.resolve("./src/index.ts")),
|
|
"numbers": fileURLToPath(import.meta.resolve("./src/core/utils/numbers.ts")),
|
|
},
|
|
name: "Element Web Shared Components",
|
|
// Multi-entry mode needs both formats explicit; UMD doesn't support multi-entry
|
|
// (single global), so we ship ES + CJS and use the `.umd.cjs` extension for CJS
|
|
// to keep the existing package.json `require` paths working.
|
|
formats: ["es", "cjs"],
|
|
fileName: (format, entryName) => `${entryName}.${format === "es" ? "js" : "umd.cjs"}`,
|
|
},
|
|
outDir: "dist",
|
|
rolldownOptions: {
|
|
// make sure to externalize deps that shouldn't be bundled
|
|
// into your library
|
|
external: [
|
|
"@matrix-org/emojibase-bindings",
|
|
"@vector-im/compound-design-tokens",
|
|
"@vector-im/compound-web",
|
|
"react-virtuoso",
|
|
"react-resizable-panels",
|
|
],
|
|
plugins: [
|
|
esmExternalRequirePlugin({
|
|
external: ["react", "react-dom"],
|
|
}),
|
|
],
|
|
output: {
|
|
// Provide global variables to use in the UMD build
|
|
// for externalized deps
|
|
globals: {
|
|
"react": "react",
|
|
"@matrix-org/emojibase-bindings": "matrixEmojibaseBindings",
|
|
"@vector-im/compound-design-tokens": "compoundDesignTokens",
|
|
"@vector-im/compound-web": "compoundWeb",
|
|
"react-virtuoso": "reactVirtuoso",
|
|
"react-resizable-panels": "reactResizablePanels",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
plugins: [
|
|
react(),
|
|
layerCssAssets(),
|
|
dts({
|
|
bundleTypes: {
|
|
invokeOptions: {
|
|
localBuild: !!process.env.CI,
|
|
// oxlint-disable-next-line unicorn/prefer-module
|
|
typescriptCompilerFolder: path.resolve(require.resolve("@typescript/old"), "../.."),
|
|
},
|
|
},
|
|
include: ["src/**/*.{ts,tsx}"],
|
|
exclude: ["src/**/*.test.{ts,tsx}", "src/**/*.stories.{ts,tsx}"],
|
|
copyDtsFiles: false,
|
|
}),
|
|
],
|
|
});
|