# @element-hq/web-shared-components Shared React components library for Element Web, Aurora, Element modules... This package provides opinionated UI components built on top of the [Compound Design System](https://compound.element.io) and [Compound Web](https://github.com/element-hq/compound-web). This is not a design system by itself, but rather a set of larger components. ## Installation in a new project When adding this library to a new project, as well as installing `@element-hq/web-shared-components` as normal, you will also need to add [compound-web](https://github.com/element-hq/compound-web) as a peer dependency: ```bash yarn add @element-hq/web-shared-components yarn add @vector-im/compound-web ``` (This avoids problems where we end up with different versions of compound-web in the top-level project and web-shared-components). ## Usage ### Basic Import Both JavaScript and CSS can be imported as follows: ```javascript import { RoomListHeaderView, useViewModel } from "@element-hq/web-shared-components"; import "@element-hq/web-shared-components/dist/element-web-shared-components.css"; ``` or in CSS file: ```css @import url("@element-hq/web-shared-components"); ``` ### Using Components There are two kinds of components in this library: - _regular_ react component which doesn't follow specific pattern. - _view_ component(MVVM pattern). > [!TIP] > These components are available in the project storybook. #### Regular Components These components can be used directly by passing props. Example: ```tsx import { Flex } from "@element-hq/web-shared-components"; function MyApp() { return ; } ``` #### View (MVVM) Components These components follow the [MVVM pattern](../../docs/MVVM.md). A ViewModel instance should be provided as a prop. Here's a basic example: ```jsx import { ViewExample } from "@element-hq/web-shared-components"; function MyApp() { const viewModel = new ViewModelExample(); return ; } ``` ### Utilities #### Internationalization - `useI18n()` - Hook for translations - `I18nApi` - Internationalization API utilities #### Date & Time - `DateUtils` - Date formatting and manipulation - `humanize` - Human-readable time formatting #### Formatting - `FormattingUtils` - Text and data formatting utilities - `numbers` - Number formatting utilities ## Development ### Prerequisites - Node.js >= 20.0.0 - Yarn 1.22.22+ ### Setup ```bash # Install dependencies yarn install # Build the library yarn prepare ``` ### Running Storybook ```bash yarn storybook ``` ### Write components Most components should be written as [MVVM pattern](../../docs/MVVM.md) view components. See existing components for examples. The exceptions are low level components that don't need a view model. ### Write Storybook Stories All components should have accompanying Storybook stories for documentation and visual testing. Stories are written in TypeScript using the [Component Story Format (CSF)](https://storybook.js.org/docs/api/csf). #### Story File Structure Place the story file next to the component with the `.stories.tsx` extension: ``` MyComponent/ ├── MyComponent.tsx ├── MyComponent.module.css └── MyComponent.stories.tsx ``` #### Regular Component Stories For regular React components (non-MVVM), create stories by defining a meta object and story variations: ```tsx import type { Meta, StoryObj } from "@storybook/react-vite"; import { fn } from "storybook/test"; import { MyComponent } from "./MyComponent"; const meta = { title: "Category/MyComponent", component: MyComponent, tags: ["autodocs"], args: { // Default args for all stories label: "Default Label", onClick: fn(), // Mock function for tracking interactions }, } satisfies Meta; export default meta; type Story = StoryObj; // Default story uses the default args export const Default: Story = {}; // Override specific args for variations export const WithCustomLabel: Story = { args: { label: "Custom Label", }, }; export const Disabled: Story = { args: { disabled: true, }, }; ``` #### MVVM Component Stories For MVVM components, create a wrapper component that uses `useMockedViewModel`: ```tsx import React, { type JSX } from "react"; import { fn } from "storybook/test"; import type { Meta, StoryFn } from "@storybook/react-vite"; import { MyComponentView, type MyComponentViewSnapshot, type MyComponentViewActions } from "./MyComponentView"; import { useMockedViewModel } from "../../useMockedViewModel"; // Combine snapshot and actions for easier typing type MyComponentProps = MyComponentViewSnapshot & MyComponentViewActions; // Wrapper component that creates a mocked ViewModel const MyComponentViewWrapper = ({ onAction, ...rest }: MyComponentProps): JSX.Element => { const vm = useMockedViewModel(rest, { onAction, }); return ; }; export default { title: "Category/MyComponentView", component: MyComponentViewWrapper, tags: ["autodocs"], args: { // Snapshot properties (state) title: "Default Title", isLoading: false, // Action properties (callbacks) onAction: fn(), }, } as Meta; const Template: StoryFn = (args) => ; export const Default = Template.bind({}); export const Loading = Template.bind({}); Loading.args = { isLoading: true, }; ``` Thanks to this approach, we can directly use primitives in the story arguments instead of a view model object. #### Linking Figma Designs This package uses [@storybook/addon-designs](https://github.com/storybookjs/addon-designs) to embed Figma designs directly in Storybook. This helps developers compare their implementation with the design specs. 1. **Get the Figma URL**: Open your design in Figma, click "Share" → "Copy link" 2. **Add to story parameters**: Include the `design` object in the meta's `parameters` 3. **Supported URL formats**: - File links: `https://www.figma.com/file/...` - Design links: `https://www.figma.com/design/...` - Specific node: `https://www.figma.com/design/...?node-id=123-456` Example with Figma integration: ```tsx export default { title: "Room List/RoomListSearchView", component: RoomListSearchViewWrapper, tags: ["autodocs"], args: { // ... your args }, parameters: { design: { type: "figma", url: "https://www.figma.com/design/vlmt46QDdE4dgXDiyBJXqp/ER-33-Left-Panel?node-id=98-1979", }, }, } as Meta; ``` The Figma design will appear in the "Design" tab in Storybook. ### Tests Two types of tests are available: unit tests and visual regression tests. ### Unit Tests These tests cover the logic of the components and utilities. Built with Jest and React Testing Library. ```bash yarn test ``` ### Visual Regression Tests These tests ensure the UI components render correctly. They need Storybook to be running and they will run in docker using [Playwright](../../playwright.md). First run storybook: ```bash yarn storybook ``` Then, in another terminal, run: ```bash yarn test:storybook:update ``` Each story will be rendered and a screenshot will be taken and compared to the existing baseline. If there are visual changes or AXE violation, the test will fail. ### Translations First see our [translation guide](../../docs/translation.md) and [translation dev guide](../../docs/translation-dev.md). To generate translation strings for this package, run: ```bash yarn i18n ```