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
29 changes: 29 additions & 0 deletions .cursor/rules/component-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,35 @@ export {
} from '@metamask/design-system-shared';
```

## Where to Import Shared Types

**Always import shared consts and types directly from `@metamask/design-system-shared`**, never through a sibling component's index.

```tsx
// ✅ Correct - import from shared (the owner)
import { TextVariant } from '@metamask/design-system-shared';

// ❌ Wrong - import through a sibling component's index
import { TextVariant } from '../Text';
```

**Why not `../Text`?**

Both `Input` and `Text` are _consumers_ of `TextVariant` — neither owns it. Importing through `../Text` creates:

1. **False semantic coupling** — implies `Input` is built on top of `Text`, which it isn't
2. **Fragile circular-dep risk** — if `Text` ever renders an `Input` internally, you get `Input → Text → Input 💥`
3. **Misleading dependency graph** — obscures that the real source is `@metamask/design-system-shared`

**The rule:**

| What you need | Import from |
| ------------------------------------------------------------------ | -------------------------------------------- |
| Shared const/type (`TextVariant`, `TextColor`, `FontWeight`, etc.) | `@metamask/design-system-shared` |
| A sibling component to render it | `'../ComponentName'` |
| A sibling component's platform-specific props type | `'../ComponentName'` |
| A sibling component's mapping constants | `'../ComponentName/ComponentName.constants'` |

## Cross-Platform Consistency

**Required consistency:**
Expand Down
1 change: 1 addition & 0 deletions apps/storybook-react/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const designSystemPreset = require('@metamask/design-system-tailwind-preset');
module.exports = {
presets: [designSystemPreset],
content: [
'../../packages/design-system-shared/src/**/*.{js,jsx,ts,tsx}',
'../../packages/design-system-react/src/**/*.{js,jsx,ts,tsx}',
'../../packages/design-tokens/stories/**/*.{js,jsx,ts,tsx,mdx}',
'./src/**/*.{js,jsx,ts,tsx}',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FontWeight, TextVariant } from '@metamask/design-system-shared';
import React from 'react';
import { GestureResponderEvent } from 'react-native';

Expand All @@ -6,10 +7,8 @@ import {
BoxBackgroundColor,
ButtonIconSize,
ButtonSize,
FontWeight,
BoxFlexDirection,
IconName,
TextVariant,
} from '../../types';
import { Box } from '../Box';
import { Button } from '../Button';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TextColor } from '@metamask/design-system-shared';
import type { Meta, StoryObj } from '@storybook/react-native';
import React from 'react';
import { ScrollView } from 'react-native';
Expand All @@ -9,7 +10,6 @@ import {
BoxJustifyContent,
BoxBackgroundColor,
BoxBorderColor,
TextColor,
} from '../../types';
import { Text } from '../Text';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { TextVariant } from '@metamask/design-system-shared';
import { typography } from '@metamask/design-tokens';

import { TextVariant } from '../../types';

/**
* Typographic metrics for Input: same tokens as `text-*` utilities but **without** `lineHeight`.
* React Native `TextInput` aligns single-line text more predictably when line height is not set
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { TextVariant } from '@metamask/design-system-shared';
import type { Meta, StoryObj } from '@storybook/react-native';
import { useEffect, useState } from 'react';
import { View } from 'react-native';

import { TextVariant } from '../../types';

import { Input } from './Input';
import type { InputProps } from './Input.types';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TextVariant } from '@metamask/design-system-shared';
import {
Theme,
ThemeProvider,
Expand All @@ -11,8 +12,6 @@ import { Platform, TextInput } from 'react-native';
import type { StyleProp, TextStyle } from 'react-native';
import { create } from 'react-test-renderer';

import { TextVariant } from '../../types';

import { Input } from './Input';

const TEST_ID = 'input';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FontFamily, TextVariant } from '@metamask/design-system-shared';
import {
Theme,
useTailwind,
Expand All @@ -7,7 +8,6 @@ import { darkTheme, lightTheme } from '@metamask/design-tokens';
import { forwardRef, useCallback, useMemo, useState } from 'react';
import { Platform, TextInput } from 'react-native';

import { FontFamily, TextVariant } from '../../types';
import {
MAP_TEXT_VARIANT_FONTWEIGHT,
TWCLASSMAP_TEXT_FONTWEIGHT,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { TextVariant } from '@metamask/design-system-shared';
import type { TextInputProps } from 'react-native';

import type { TextVariant } from '../../types';

export type InputProps = Omit<
TextInputProps,
'editable' | 'value' | 'defaultValue'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { typography } from '@metamask/design-tokens';

import { FontWeight, TextVariant } from '../../types';
import { FontWeight, TextVariant } from '@metamask/design-system-shared';

// Mappings
export const TWCLASSMAP_TEXT_FONTWEIGHT: {
Expand All @@ -14,22 +12,18 @@ export const TWCLASSMAP_TEXT_FONTWEIGHT: {
export const MAP_TEXT_VARIANT_FONTWEIGHT: {
[key in TextVariant]: FontWeight;
} = {
[TextVariant.DisplayLg]: typography.sDisplayLG.fontWeight as FontWeight,
[TextVariant.DisplayMd]: typography.sDisplayMD.fontWeight as FontWeight,
[TextVariant.HeadingLg]: typography.sHeadingLG.fontWeight as FontWeight,
[TextVariant.HeadingMd]: typography.sHeadingMD.fontWeight as FontWeight,
[TextVariant.HeadingSm]: typography.sHeadingSM.fontWeight as FontWeight,
[TextVariant.BodyLg]: typography.sBodyLGMedium.fontWeight as FontWeight,
[TextVariant.BodyMd]: typography.sBodyMD.fontWeight as FontWeight,
[TextVariant.BodySm]: typography.sBodySM.fontWeight as FontWeight,
[TextVariant.BodyXs]: typography.sBodyXS.fontWeight as FontWeight,
[TextVariant.PageHeading]: typography.sPageHeading.fontWeight as FontWeight,
[TextVariant.SectionHeading]: typography.sSectionHeading
.fontWeight as FontWeight,
[TextVariant.ButtonLabelMd]: typography.sButtonLabelMd
.fontWeight as FontWeight,
[TextVariant.ButtonLabelLg]: typography.sButtonLabelLg
.fontWeight as FontWeight,
[TextVariant.AmountDisplayLg]: typography.sAmountDisplayLg
.fontWeight as FontWeight,
[TextVariant.DisplayLg]: FontWeight.Bold,
[TextVariant.DisplayMd]: FontWeight.Bold,
[TextVariant.HeadingLg]: FontWeight.Bold,
[TextVariant.HeadingMd]: FontWeight.Bold,
[TextVariant.HeadingSm]: FontWeight.Bold,
[TextVariant.BodyLg]: FontWeight.Medium,
[TextVariant.BodyMd]: FontWeight.Regular,
[TextVariant.BodySm]: FontWeight.Regular,
[TextVariant.BodyXs]: FontWeight.Regular,
[TextVariant.PageHeading]: FontWeight.Bold,
[TextVariant.SectionHeading]: FontWeight.Bold,
[TextVariant.ButtonLabelMd]: FontWeight.Medium,
[TextVariant.ButtonLabelLg]: FontWeight.Medium,
[TextVariant.AmountDisplayLg]: FontWeight.Bold,
};
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import {
FontFamily,
FontStyle,
FontWeight,
TextColor,
TextVariant,
} from '@metamask/design-system-shared';
import { useTailwind } from '@metamask/design-system-twrnc-preset';
import type { Meta, StoryObj } from '@storybook/react-native';
import React from 'react';
import { View, ScrollView } from 'react-native';

import {
TextVariant,
TextColor,
FontWeight,
FontFamily,
FontStyle,
} from '../../types';

import { Text } from './Text';
import type { TextProps } from './Text.types';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { useTailwind } from '@metamask/design-system-twrnc-preset';
import { render } from '@testing-library/react-native';
import React from 'react';

import {
TextVariant,
TextColor,
FontWeight,
FontFamily,
FontStyle,
} from '../../types';
FontWeight,
TextColor,
TextVariant,
} from '@metamask/design-system-shared';
import { useTailwind } from '@metamask/design-system-twrnc-preset';
import { render } from '@testing-library/react-native';
import React from 'react';

import { Text } from './Text';
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import {
FontFamily,
FontStyle,
TextColor,
TextVariant,
} from '@metamask/design-system-shared';
import { useTailwind } from '@metamask/design-system-twrnc-preset';
import React, { useMemo } from 'react';
import { Text as RNText } from 'react-native';

import { FontFamily, FontStyle, TextVariant, TextColor } from '../../types';

import {
MAP_TEXT_VARIANT_FONTWEIGHT,
TWCLASSMAP_TEXT_FONTWEIGHT,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,13 @@
// Third party dependencies.
import type { TextPropsShared } from '@metamask/design-system-shared';
import type { TextProps as RNTextProps } from 'react-native';

import type {
TextVariant,
TextColor,
FontWeight,
FontFamily,
FontStyle,
} from '../../types';

/**
* Text component props.
*/
export type TextProps = {
/**
* Optional enum to select between Typography variants.
*
* @default BodyMD
*/
variant?: TextVariant;
/**
* Text to be displayed.
*/
children: React.ReactNode;
/**
* Optional prop to add color to text.
*/
color?: TextColor;
/**
* Optional prop to control the font weight of the text.
* Normal: 400
* Medium: 500
* Bold: 600
*/
fontWeight?: FontWeight;
/**
* Optional prop to adjust the font family.
* Default: Geist
* Accent: MM Sans
* Hero: MM Poly
*/
fontFamily?: FontFamily;
/**
* Optional prop to adjust the style of the font.
*/
fontStyle?: FontStyle;
/**
* Optional prop to add twrnc overriding classNames.
*/
twClassName?: string;
} & RNTextProps;
export type TextProps = TextPropsShared &
RNTextProps & {
/**
* Optional prop to add twrnc overriding classNames.
*/
twClassName?: string;
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
export {
TextVariant,
TextColor,
TextVariant,
FontWeight,
FontFamily,
FontStyle,
} from '../../types';
type TextPropsShared,
} from '@metamask/design-system-shared';
export { Text } from './Text';
export type { TextProps } from './Text.types';
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// import figma needs to remain as figma otherwise it breaks code connect
// eslint-disable-next-line import-x/no-named-as-default
import figma from '@figma/code-connect';
import { TextVariant } from '@metamask/design-system-shared';
import React from 'react';

import { TextVariant } from '../../types';

import { TextButton } from './TextButton';

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TextVariant } from '@metamask/design-system-shared';
import type { Meta, StoryObj } from '@storybook/react-native';
import { View } from 'react-native';

import { TextVariant } from '../../types';
import { Text } from '../Text';

import { TextButton } from './TextButton';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { TextVariant } from '@metamask/design-system-shared';
import { useTailwind } from '@metamask/design-system-twrnc-preset';
import { renderHook } from '@testing-library/react-hooks';
import { render, fireEvent } from '@testing-library/react-native';
import React from 'react';

import { TextVariant } from '../../types';

import { TextButton } from './TextButton';

const noopPress = () => undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TextColor, TextVariant } from '@metamask/design-system-shared';
import React, { useState } from 'react';

import { TextVariant, TextColor } from '../../types';
import { Text, FontWeight } from '../Text';

import type { TextButtonProps } from './TextButton.types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TextVariant } from '@metamask/design-system-shared';
import { useTailwind } from '@metamask/design-system-twrnc-preset';
import {
forwardRef,
Expand All @@ -9,7 +10,6 @@ import {
} from 'react';
import { Pressable, TextInput, View } from 'react-native';

import { TextVariant } from '../../types';
import { Input } from '../Input';

import type { TextFieldProps } from './TextField.types';
Expand Down
Loading
Loading