Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/workflows/shared-component-visual-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ jobs:
- name: Install element web dependencies
run: yarn install --frozen-lockfile

- name: Build Element Web resources
# Needed to prepare language files
run: "yarn build:res"

- name: Install dependencies
working-directory: packages/shared-components
run: yarn install --frozen-lockfile
Expand Down
8 changes: 0 additions & 8 deletions .github/workflows/static_analysis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ jobs:
- name: Typecheck
run: "yarn run lint:types"

- name: Build Element Web resources
# Needed to prepare language files for shared components
run: "yarn build:res"

- name: Install Shared Component Dependencies
run: "yarn --cwd packages/shared-components install"

Expand Down Expand Up @@ -91,10 +87,6 @@ jobs:
- name: Run Linter
run: "yarn run lint:js"

- name: Build Element Web resources
# Needed to prepare language files for shared components
run: "yarn build:res"

- name: Install Shared Component Deps
run: "yarn --cwd packages/shared-components install --frozen-lockfile"

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ storybook-static

/packages/shared-components/node_modules
/packages/shared-components/dist
/packages/shared-components/i18n
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"dependencies": {
"@babel/runtime": "^7.12.5",
"@element-hq/element-web-module-api": "1.4.1",
"@element-hq/web-shared-components": "file:packages/shared-components",
"@fontsource/inconsolata": "^5",
"@fontsource/inter": "^5",
"@formatjs/intl-segmenter": "^11.5.7",
Expand Down
1 change: 1 addition & 0 deletions packages/shared-components/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
root: true,
plugins: ["matrix-org", "eslint-plugin-react-compiler"],
extends: [
"plugin:matrix-org/babel",
Expand Down
18 changes: 16 additions & 2 deletions packages/shared-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
],
"scripts": {
"postinstall": "patch-package",
"prepare": "vite build",
"prepare": "yarn --cwd ../.. build:res && ts-node scripts/gatherTranslationKeys.ts && vite build",
"storybook": "storybook dev -p 6007",
"build-storybook": "storybook build",
"lint": "yarn lint:types && yarn lint:js",
Expand All @@ -42,9 +42,15 @@
"test:storybook:update": "playwright-screenshots --entrypoint yarn --with-node-modules && playwright-screenshots --entrypoint /work/node_modules/.bin/test-storybook --with-node-modules --url http://host.docker.internal:6007/ --updateSnapshot"
},
"dependencies": {
"@vector-im/compound-design-tokens": "^6.0.0",
"@vector-im/compound-web": "^8.2.4",
"classnames": "^2.5.1",
"counterpart": "^0.18.6",
"lodash": "^4.17.21",
"matrix-web-i18n": "^3.4.0",
"patch-package": "^8.0.1",
"counterpart": "^0.18.6"
"react-merge-refs": "^3.0.2",
"temporal-polyfill": "^0.3.0"
},
"devDependencies": {
"@storybook/addon-a11y": "^9.1.10",
Expand All @@ -53,13 +59,21 @@
"@storybook/icons": "^1.6.0",
"@storybook/react-vite": "^9.1.10",
"@storybook/test-runner": "^0.23.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/react": "^16.3.0",
"@types/counterpart": "^0.18.4",
"@types/lodash": "^4.17.20",
"@types/react": "^19.2.2",
"concurrently": "^9.2.1",
"eslint": "8",
"eslint-plugin-matrix-org": "^3.0.0",
"eslint-plugin-storybook": "^9.1.10",
"jest": "^30.2.0",
"jest-image-snapshot": "^6.5.1",
"patch-package": "^8.0.1",
"prettier": "^3.6.2",
"storybook": "^9.1.10",
"ts-node": "^10.9.2",
"typescript": "^5.9.3",
"vite": "^7.1.9",
"vite-plugin-dts": "^4.5.4",
Expand Down
46 changes: 0 additions & 46 deletions packages/shared-components/patches/@types+mdx+2.0.13.patch

This file was deleted.

54 changes: 54 additions & 0 deletions packages/shared-components/scripts/gatherTranslationKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
Copyright 2025 Element Creations 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.
*/

// Gathers all the translation keys from element-web's en_EN.json into a TypeScript type definition file
// that exports a type `TranslationKey` which is a union of all supported translation keys.
// This prevents having to import the json file and make typescript do the work as this results in vite-dts
// generating an import to the json file in the .d.ts which doesn't work at runtime: this way, the type
// gets put into the bundle.

import * as fs from "fs";
import * as path from "path";

const i18nStringsPath = path.resolve(__dirname, "../../../src/i18n/strings/en_EN.json");
const outPath = path.resolve(__dirname, "../i18n/i18nKeys.d.ts");

function gatherKeys(obj: any, prefix: string[] = []): string[] {
if (typeof obj !== "object" || obj === null) return [];
let keys: string[] = [];
for (const key of Object.keys(obj)) {
const value = obj[key];

// add the path (for both leaves and intermediates as then we include plurals)
keys.push([...prefix, key].join("|"));
if (typeof value === "object" && value !== null) {
// If the value is an object, recurse
keys = keys.concat(gatherKeys(value, [...prefix, key]));
}
}
return keys;
}

function main() {
const json = JSON.parse(fs.readFileSync(i18nStringsPath, "utf8"));
const keys = gatherKeys(json);
const typeDef =
"// This file is auto-generated by gatherTranslationKeys.ts\n" +
"// Do not edit manually.\n\n" +
"export type TranslationKey =\n" +
keys.map((k) => ` | \"${k}\"`).join("\n") +
"\n;\n";
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, typeDef, "utf8");
console.log(`Wrote ${keys.length} keys to ${outPath}`);
}

if (require.main === module) {
main();
}


Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/

export { TextualEventView } from "./TextualEventView";
export { TextualEventView, type TextualEventViewSnapshot } from "./TextualEventView";
6 changes: 5 additions & 1 deletion packages/shared-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ export * from "./utils/Box";
export * from "./utils/Flex";

// Utils
export { setLanguage } from "./utils/i18n";
export * from "./utils/i18n";
export * from "./utils/humanize";
export * from "./utils/DateUtils";
export * from "./utils/numbers";
export * from "./utils/FormattingUtils";

// MVVM
export * from "./viewmodel";
export * from "./useMockedViewModel";
export * from "./useViewModel";

// i18n
export type { TranslationKey } from "../i18n/i18nKeys.d.ts";
13 changes: 1 addition & 12 deletions packages/shared-components/src/utils/i18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
* @return a React <span> component if any non-strings were used in substitutions, otherwise a string
*/
import React from "react";
import { type TranslationKey as _TranslationKey, KEY_SEPARATOR } from "matrix-web-i18n";

Check failure on line 25 in packages/shared-components/src/utils/i18n.tsx

View workflow job for this annotation

GitHub Actions / ESLint

'_TranslationKey' is defined but never used
import counterpart from "counterpart";

import type Translations from "../../../../src/i18n/strings/en_EN.json";
import { type TranslationKey } from "../../i18n/i18nKeys";

// @ts-ignore - $webapp is a webpack resolve alias pointing to the output directory, see webpack config
import webpackLangJsonUrl from "$webapp/i18n/languages.json";
Expand All @@ -45,17 +45,6 @@
const FALLBACK_LOCALE = "en";
counterpart.setFallbackLocale(FALLBACK_LOCALE);

/**
* A type representing the union of possible keys into the translation file using `|` delimiter to access nested fields.
* @example `common|error` to access `error` within the `common` sub-object.
* {
* "common": {
* "error": "Error"
* }
* }
*/
export type TranslationKey = _TranslationKey<typeof Translations>;

// Function which only purpose is to mark that a string is translatable
// Does not actually do anything. It's helpful for automatic extraction of translatable strings
export function _td(s: TranslationKey): TranslationKey {
Expand Down
9 changes: 8 additions & 1 deletion packages/shared-components/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,12 @@ export default defineConfig({
$webapp: resolve(__dirname, "..", "..", "webapp"),
},
},
plugins: [dts({ rollupTypes: true, include: ["src/**/*.{ts,tsx}"], copyDtsFiles: true })],
plugins: [
dts({
rollupTypes: true,
include: ["src/**/*.{ts,tsx}"],
exclude: ["src/**/*.test.{ts,tsx}"],
copyDtsFiles: true,
}),
],
});
Loading
Loading