@ronnydrori/jupiter-ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +483 -0
- package/dist/index.d.ts +396 -0
- package/dist/index.js +4774 -0
- package/package.json +73 -0
package/README.md
ADDED
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
# Jupiter UI Design System
|
|
2
|
+
|
|
3
|
+
A comprehensive design system built with React, TypeScript, Mantine v7, and Storybook. This library provides a complete set of design tokens, themes, and reusable components for building consistent user interfaces.
|
|
4
|
+
|
|
5
|
+
## 🏗️ Architecture
|
|
6
|
+
|
|
7
|
+
### Directory Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
libs/jupiter-ui/
|
|
11
|
+
├── .storybook/ # Storybook configuration
|
|
12
|
+
│ ├── main.ts # Storybook main config
|
|
13
|
+
│ ├── preview.tsx # Global decorators & theme setup
|
|
14
|
+
│ └── preview.css # Preview styling
|
|
15
|
+
├── src/
|
|
16
|
+
│ ├── design-system/
|
|
17
|
+
│ │ ├── tokens/ # Design tokens (spacing, typography, etc.)
|
|
18
|
+
│ │ ├── theme/ # Theme system & providers
|
|
19
|
+
│ │ ├── components/ # React components
|
|
20
|
+
│ │ ├── hooks/ # Custom React hooks
|
|
21
|
+
│ │ └── utils/ # Utility functions
|
|
22
|
+
│ └── index.ts # Main export file
|
|
23
|
+
└── package.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 🛠️ Technology Choices
|
|
27
|
+
|
|
28
|
+
This design system was built with the following technologies, chosen for their balance of ease of use, customization, and team familiarity:
|
|
29
|
+
|
|
30
|
+
### UI Foundation: Mantine v7
|
|
31
|
+
- **Why Mantine?** Easy integration with 100+ pre-built components, flexible theme API with CSS variables, and 40+ included hooks. Provides good customization without fighting defaults, and excellent TypeScript support.
|
|
32
|
+
- **Benefits:** Faster development with ready-to-use components and extensible theming.
|
|
33
|
+
|
|
34
|
+
### CSS Strategy: Emotion
|
|
35
|
+
- **Why Emotion?** Zero learning curve for our CSS-in-JS experienced team. Works seamlessly with Mantine, provides type-safe styling, dynamic theming capabilities, and co-located styles with components.
|
|
36
|
+
- **Benefits:** Full JavaScript power for styling, theme access via props, and easy refactoring.
|
|
37
|
+
|
|
38
|
+
### File Organization: Feature-Based Structure
|
|
39
|
+
- **Why Feature-Based?** Components are self-contained in their own folders, making it easy to add, modify, or remove features without affecting others. Scales well for medium-sized component libraries.
|
|
40
|
+
- **Benefits:** Intuitive organization, easy maintenance, and clear boundaries between components.
|
|
41
|
+
|
|
42
|
+
### Icons: Lucide + Phosphor
|
|
43
|
+
- **Why These Libraries?** Both provide excellent style control (size, color, stroke), MIT license, and tree-shaking support. Lucide for general UI icons, Phosphor for weight variants when needed.
|
|
44
|
+
- **Benefits:** Consistent iconography, small bundle size (~200-250b per icon), and flexible styling.
|
|
45
|
+
|
|
46
|
+
### Overall Stack Rationale
|
|
47
|
+
- **Balanced Approach:** Prioritizes speed of development while maintaining design control and customization.
|
|
48
|
+
- **Team Fit:** Leverages existing CSS-in-JS expertise to minimize learning curve.
|
|
49
|
+
- **Scalability:** Feature-based organization supports growth from 20-40 components to more.
|
|
50
|
+
- **Modern Standards:** TypeScript-first, accessible components, and responsive design.
|
|
51
|
+
- **Dynamic Theming:** Supports runtime palette loading via environment variables for flexible theming (e.g., yanai.json, rotem.json).
|
|
52
|
+
|
|
53
|
+
## � Design Tokens
|
|
54
|
+
|
|
55
|
+
All design tokens are defined in `src/design-system/tokens/`:
|
|
56
|
+
|
|
57
|
+
- **Spacing** (`spacing.ts`) - Consistent spacing scale (0.25rem - 20rem)
|
|
58
|
+
- **Typography** (`typography.ts`) - Font families, sizes, weights, line heights
|
|
59
|
+
- **Radius** (`radius.ts`) - Border radius values (xs, sm, md, lg, xl)
|
|
60
|
+
- **Borders** (`borders.ts`) - Border width values
|
|
61
|
+
- **Shadows** (`shadows.ts`) - Box shadow definitions (xs, sm, md, lg, xl)
|
|
62
|
+
- **Breakpoints** (`breakpoints.ts`) - Responsive breakpoints (xs, sm, md, lg, xl)
|
|
63
|
+
|
|
64
|
+
### Example Token File: `spacing.ts`
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import type { TokenScaleKey } from './types';
|
|
68
|
+
|
|
69
|
+
export const spacing = {
|
|
70
|
+
0: '0px',
|
|
71
|
+
1: '4px',
|
|
72
|
+
2: '8px',
|
|
73
|
+
3: '12px',
|
|
74
|
+
4: '16px',
|
|
75
|
+
5: '20px',
|
|
76
|
+
6: '24px',
|
|
77
|
+
7: '28px',
|
|
78
|
+
8: '32px',
|
|
79
|
+
9: '36px',
|
|
80
|
+
} as const;
|
|
81
|
+
|
|
82
|
+
export const semanticSpacing: Partial<Record<TokenScaleKey, string>> = {
|
|
83
|
+
xs: spacing[1], // 4px
|
|
84
|
+
sm: spacing[2], // 8px
|
|
85
|
+
md: spacing[4], // 16px
|
|
86
|
+
lg: spacing[6], // 24px
|
|
87
|
+
xl: spacing[8], // 32px
|
|
88
|
+
} as const;
|
|
89
|
+
|
|
90
|
+
export type SpacingToken = keyof typeof spacing;
|
|
91
|
+
export type SemanticSpacingToken = keyof typeof semanticSpacing;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 🎭 Theme System
|
|
95
|
+
|
|
96
|
+
### Theme Structure
|
|
97
|
+
|
|
98
|
+
The theme system is located in `src/design-system/theme/`:
|
|
99
|
+
|
|
100
|
+
- **types.ts** - TypeScript types for theme structure
|
|
101
|
+
- **theme.ts** - Core theme creator using design tokens
|
|
102
|
+
- **mantine.ts** - Mantine theme configuration
|
|
103
|
+
- **ThemeProvider.tsx** - React context provider for theme management
|
|
104
|
+
|
|
105
|
+
### Dynamic Palette Loading
|
|
106
|
+
|
|
107
|
+
The design system supports dynamic color palette loading at runtime:
|
|
108
|
+
|
|
109
|
+
- **usePalette Hook**: Loads color palettes asynchronously from JSON files
|
|
110
|
+
- **Environment Variable**: Set `VITE_PROJECT_NAME` to specify the project name (e.g., `yanai` or `rotem`)
|
|
111
|
+
- **Palette Path**: Fetches from `/color-palettes/${VITE_PROJECT_NAME}.json`
|
|
112
|
+
- **Fallback**: Defaults to `defaultPalette.ts` if no environment variable is set or loading fails
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Example: Loading a palette
|
|
116
|
+
const colors = usePalette(); // Loads from /color-palettes/${VITE_PROJECT_NAME}.json or defaults to defaultPalette
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Using Themes
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { JupiterThemeProvider } from '@libraries/jupiter-ui';
|
|
123
|
+
|
|
124
|
+
function App() {
|
|
125
|
+
return (
|
|
126
|
+
<JupiterThemeProvider>
|
|
127
|
+
{/* Your app */}
|
|
128
|
+
</JupiterThemeProvider>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Theme Context Hook
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { useThemeContext } from '@libraries/jupiter-ui';
|
|
137
|
+
|
|
138
|
+
function MyComponent() {
|
|
139
|
+
const { mode, toggleMode, setMode } = useThemeContext();
|
|
140
|
+
// mode: 'light' | 'dark'
|
|
141
|
+
// toggleMode: () => void
|
|
142
|
+
// setMode: (mode: ThemeMode) => void
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 🧩 Components
|
|
147
|
+
|
|
148
|
+
### Component Guidelines
|
|
149
|
+
|
|
150
|
+
All components are located in `src/design-system/components/[ComponentName]/`:
|
|
151
|
+
|
|
152
|
+
1. **No index.ts files** - Import directly from component files
|
|
153
|
+
2. **Component file**: `ComponentName.tsx`
|
|
154
|
+
3. **Test file**: `ComponentName.test.tsx` - **REQUIRED** (enforced by ESLint)
|
|
155
|
+
4. **Stories file**: `ComponentName.stories.tsx`
|
|
156
|
+
5. **Export from main index**: Update `src/index.ts`
|
|
157
|
+
6. **Set `displayName`** on exported React components and higher-order components (e.g., `ComponentName.displayName = 'ComponentName'`; internal helper components don't need this)
|
|
158
|
+
|
|
159
|
+
> ⚠️ **Testing Requirement**: Every component must have a corresponding test file. This is enforced by ESLint's `require-test-file` rule and will prevent commits without tests.
|
|
160
|
+
|
|
161
|
+
### Component Structure
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// JpButton.tsx
|
|
165
|
+
import { Button as MantineButton } from '@mantine/core';
|
|
166
|
+
import type { ButtonProps as MantineButtonProps } from '@mantine/core';
|
|
167
|
+
import { buttonVariants, type JupiterVariant } from '../utils/variant-factory';
|
|
168
|
+
|
|
169
|
+
export interface JpButtonProps extends Omit<MantineButtonProps, 'variant'> {
|
|
170
|
+
variant?: JupiterVariant;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function JpButton({ variant = 'primary', ...props }: JpButtonProps) {
|
|
174
|
+
return (
|
|
175
|
+
<MantineButton
|
|
176
|
+
variant={buttonVariants[variant] ?? buttonVariants.primary}
|
|
177
|
+
{...props}
|
|
178
|
+
/>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Required: set the display name for better DX in React DevTools, Storybook, and logs
|
|
183
|
+
JpButton.displayName = 'JpButton';
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Custom Styling with Emotion (Function Syntax)
|
|
187
|
+
|
|
188
|
+
Always use Emotion's function form for `styled` components, not tagged template strings. This ensures better type safety, prop filtering, and consistent patterns across the library.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import styled from '@emotion/styled';
|
|
192
|
+
// Optional: filter invalid DOM props when styling host elements
|
|
193
|
+
// import isPropValid from '@emotion/is-prop-valid';
|
|
194
|
+
import { JpButton, useThemeContext } from '@libraries/jupiter-ui';
|
|
195
|
+
|
|
196
|
+
// Create a styled button with custom styles (function approach)
|
|
197
|
+
const StyledButton = styled(JpButton, { label: 'styled-button' })(() => ({
|
|
198
|
+
backgroundColor: 'hotpink',
|
|
199
|
+
color: 'white',
|
|
200
|
+
'&:hover': {
|
|
201
|
+
backgroundColor: 'deeppink',
|
|
202
|
+
},
|
|
203
|
+
// Use static selectors to style inner elements
|
|
204
|
+
'& .mantine-Button-label': {
|
|
205
|
+
fontWeight: 'bold',
|
|
206
|
+
textTransform: 'uppercase',
|
|
207
|
+
},
|
|
208
|
+
}));
|
|
209
|
+
|
|
210
|
+
// Create a themed button using design tokens (function approach)
|
|
211
|
+
const ThemedButton = styled(JpButton, { label: 'themed-button' })(({ theme }) => ({
|
|
212
|
+
backgroundColor: '#3b82f6',
|
|
213
|
+
color: 'white',
|
|
214
|
+
borderRadius: theme?.radius?.md || '0.5rem',
|
|
215
|
+
padding: `${theme?.spacing?.md || '0.75rem'} ${theme?.spacing?.lg || '1rem'}`,
|
|
216
|
+
fontWeight: theme?.typography?.fontWeights?.semibold || 600,
|
|
217
|
+
'&:hover': {
|
|
218
|
+
backgroundColor: '#2563eb',
|
|
219
|
+
transform: 'translateY(-1px)',
|
|
220
|
+
boxShadow: theme?.shadows?.md || '0 4px 6px rgba(0,0,0,0.1)',
|
|
221
|
+
},
|
|
222
|
+
// Style inner elements
|
|
223
|
+
'& .mantine-Button-label': {
|
|
224
|
+
fontFamily: theme?.typography?.fontFamilies?.body || 'system-ui',
|
|
225
|
+
},
|
|
226
|
+
}));
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
function Demo() {
|
|
230
|
+
return (
|
|
231
|
+
<div>
|
|
232
|
+
<StyledButton>Styled with Emotion</StyledButton>
|
|
233
|
+
<ThemedButton>
|
|
234
|
+
Themed Button
|
|
235
|
+
</ThemedButton>
|
|
236
|
+
</div>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Key Points**:
|
|
242
|
+
- Use Emotion's function syntax: `styled(Component, options)(props => styles)`
|
|
243
|
+
- Do not use tagged template strings (e.g., ``styled.div`...``, ``styled(Button)`...``)
|
|
244
|
+
- Use Mantine's class selectors (e.g., `.mantine-Button-label`) to target inner elements
|
|
245
|
+
- Access theme tokens via `props.theme` (pass theme from `useThemeContext()`)
|
|
246
|
+
- Use transient props (`$propName`) to avoid passing custom props to DOM
|
|
247
|
+
- All Mantine component props still work on styled components
|
|
248
|
+
- Styled components can be used in Storybook stories
|
|
249
|
+
|
|
250
|
+
### Storybook Stories
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
// ComponentName.stories.tsx
|
|
254
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
255
|
+
import { ComponentName } from './ComponentName';
|
|
256
|
+
|
|
257
|
+
const meta = {
|
|
258
|
+
title: 'Components/ComponentName',
|
|
259
|
+
component: ComponentName,
|
|
260
|
+
parameters: {
|
|
261
|
+
layout: 'centered',
|
|
262
|
+
},
|
|
263
|
+
tags: ['autodocs'],
|
|
264
|
+
argTypes: {
|
|
265
|
+
variant: {
|
|
266
|
+
control: 'select',
|
|
267
|
+
options: ['primary', 'secondary', 'outline', 'ghost'],
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
} satisfies Meta<typeof ComponentName>;
|
|
271
|
+
|
|
272
|
+
export default meta;
|
|
273
|
+
type Story = StoryObj<typeof meta>;
|
|
274
|
+
|
|
275
|
+
export const Primary: Story = {
|
|
276
|
+
args: {
|
|
277
|
+
variant: 'primary',
|
|
278
|
+
children: 'Component Text',
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## 📚 Storybook
|
|
284
|
+
|
|
285
|
+
### Configuration
|
|
286
|
+
|
|
287
|
+
- **Version**: v8.6.15
|
|
288
|
+
- **Framework**: React + Vite
|
|
289
|
+
- **Addons**:
|
|
290
|
+
- `storybook-addon-mantine` - Mantine theme integration
|
|
291
|
+
- Standard Storybook addons (essentials, interactions, etc.)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
### Running Storybook
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
npm run storybook
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Storybook will be available at http://localhost:6006
|
|
302
|
+
|
|
303
|
+
## 🔧 Technology Stack
|
|
304
|
+
|
|
305
|
+
- **React** v18.3.1
|
|
306
|
+
- **TypeScript** v5.5.4 (strict mode)
|
|
307
|
+
- **Mantine** v7.15.1 (UI component library)
|
|
308
|
+
- **Emotion** v11.13.5 (CSS-in-JS styling)
|
|
309
|
+
- **Storybook** v8.6.14
|
|
310
|
+
- **Vite** v5.4.11 (build tool)
|
|
311
|
+
- **Vitest** v3.2.4 (testing framework)
|
|
312
|
+
- **Lucide + Phosphor** (icons)
|
|
313
|
+
|
|
314
|
+
## 📝 Coding Conventions
|
|
315
|
+
|
|
316
|
+
### Imports
|
|
317
|
+
|
|
318
|
+
- Use named exports (not default exports except for Storybook meta)
|
|
319
|
+
- Import components directly: `import { Button } from './components/Button/Button'`
|
|
320
|
+
- No intermediate index files in component folders
|
|
321
|
+
|
|
322
|
+
### TypeScript
|
|
323
|
+
|
|
324
|
+
- Use explicit types for all public APIs
|
|
325
|
+
- Export interface definitions alongside components
|
|
326
|
+
- Use `type` for type aliases, `interface` for object shapes
|
|
327
|
+
- No `any` types allowed
|
|
328
|
+
|
|
329
|
+
### File Naming
|
|
330
|
+
|
|
331
|
+
- Components: PascalCase (e.g., `Button.tsx`)
|
|
332
|
+
- Stories: `ComponentName.stories.tsx`
|
|
333
|
+
- Utils/Tokens: camelCase (e.g., `colors.ts`)
|
|
334
|
+
|
|
335
|
+
### Component Variants
|
|
336
|
+
|
|
337
|
+
Use semantic variant names that describe intent, not implementation:
|
|
338
|
+
- ✅ `primary`, `secondary`, `outline`, `ghost`
|
|
339
|
+
- ❌ `filled`, `light`, `subtle` (Mantine internal variants)
|
|
340
|
+
|
|
341
|
+
Map semantic variants to Mantine variants inside components.
|
|
342
|
+
|
|
343
|
+
## 🎯 Best Practices
|
|
344
|
+
|
|
345
|
+
### Theme Provider
|
|
346
|
+
|
|
347
|
+
- Always wrap components in `JupiterThemeProvider` when using `useThemeContext()`
|
|
348
|
+
- ThemeProvider provides theme context and token access to all components
|
|
349
|
+
|
|
350
|
+
### Mantine Integration
|
|
351
|
+
|
|
352
|
+
- Extend Mantine components, don't replace them
|
|
353
|
+
- Override Mantine's theme through `createAppTheme()` function
|
|
354
|
+
- Use Mantine's utility functions (e.g., `rem()`, `em()`)
|
|
355
|
+
|
|
356
|
+
### State Management
|
|
357
|
+
|
|
358
|
+
- Avoid `useEffect` for syncing props to state
|
|
359
|
+
- Use render-time state updates: `if (prop !== state) setState(prop)`
|
|
360
|
+
- This prevents cascading renders and React act() warnings
|
|
361
|
+
|
|
362
|
+
## 🚀 Development Workflow
|
|
363
|
+
|
|
364
|
+
1. **Add new tokens** in `src/design-system/tokens/`
|
|
365
|
+
2. **Update theme** in `src/design-system/theme/` if needed
|
|
366
|
+
3. **Create component** in `src/design-system/components/[Name]/`
|
|
367
|
+
4. **Add stories** in same folder as component
|
|
368
|
+
5. **Export from main** in `src/index.ts`
|
|
369
|
+
6. **Test in Storybook** with `npm run storybook`
|
|
370
|
+
7. **Commit** using conventional commits format
|
|
371
|
+
|
|
372
|
+
## 📦 Export Pattern
|
|
373
|
+
|
|
374
|
+
All exports go through `src/index.ts`:
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
// Tokens
|
|
378
|
+
export * from './design-system/tokens/spacing';
|
|
379
|
+
export * from './design-system/tokens/radius';
|
|
380
|
+
export * from './design-system/tokens/borders';
|
|
381
|
+
export * from './design-system/tokens/typography';
|
|
382
|
+
export * from './design-system/tokens/shadows';
|
|
383
|
+
export * from './design-system/tokens/breakpoints';
|
|
384
|
+
|
|
385
|
+
// Theme
|
|
386
|
+
export * from './design-system/theme/types';
|
|
387
|
+
export * from './design-system/theme/mantine';
|
|
388
|
+
export {
|
|
389
|
+
JupiterThemeProvider,
|
|
390
|
+
useThemeContext,
|
|
391
|
+
} from './design-system/theme/ThemeProvider';
|
|
392
|
+
export type { JupiterThemeProviderProps } from './design-system/theme/ThemeProvider';
|
|
393
|
+
|
|
394
|
+
// Utils
|
|
395
|
+
export {
|
|
396
|
+
buttonVariants,
|
|
397
|
+
inputVariants,
|
|
398
|
+
selectVariants,
|
|
399
|
+
checkboxVariants,
|
|
400
|
+
} from './design-system/utils/variant-factory';
|
|
401
|
+
export type { JupiterVariant } from './design-system/utils/variant-factory';
|
|
402
|
+
|
|
403
|
+
// Components
|
|
404
|
+
export { JpButton } from './design-system/components/Button/JpButton';
|
|
405
|
+
export type { JpButtonProps } from './design-system/components/Button/JpButton';
|
|
406
|
+
|
|
407
|
+
// Hooks
|
|
408
|
+
export * from './design-system/hooks/usePalette';
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Scripts
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
# Development
|
|
415
|
+
npm run storybook # Start Storybook on localhost:6006
|
|
416
|
+
npm run build-storybook # Build static Storybook
|
|
417
|
+
|
|
418
|
+
# Linting
|
|
419
|
+
npm run lint # Run ESLint
|
|
420
|
+
npm run lint:fix # Fix ESLint issues
|
|
421
|
+
|
|
422
|
+
# Type Checking
|
|
423
|
+
npm run typecheck # Run TypeScript compiler check
|
|
424
|
+
|
|
425
|
+
# Testing
|
|
426
|
+
npm run test # Run unit tests with Vitest
|
|
427
|
+
npm run test-storybook # Run storybook tests in the cli
|
|
428
|
+
```
|
|
429
|
+
### 📖 Official Documentation
|
|
430
|
+
|
|
431
|
+
- **Storybook Interaction Tests**
|
|
432
|
+
https://storybook.js.org/docs/writing-tests/interaction-testing
|
|
433
|
+
|
|
434
|
+
- **Storybook Vitest Addon**
|
|
435
|
+
https://storybook.js.org/docs/8/writing-tests/test-addon
|
|
436
|
+
|
|
437
|
+
## 🔒 ESLint Rules
|
|
438
|
+
|
|
439
|
+
This library enforces strict rules to maintain quality and plug-and-play architecture:
|
|
440
|
+
|
|
441
|
+
### TypeScript Rules
|
|
442
|
+
- ❌ `@typescript-eslint/no-explicit-any`: No `any` types allowed
|
|
443
|
+
- ✅ `@typescript-eslint/consistent-type-imports`: Prefer type imports for better tree-shaking
|
|
444
|
+
- ✅ `@typescript-eslint/prefer-nullish-coalescing`: Use `??` over `||` for null/undefined checks
|
|
445
|
+
- ✅ `@typescript-eslint/prefer-optional-chain`: Use optional chaining (`?.`) instead of manual checks
|
|
446
|
+
- ⚠️ `@typescript-eslint/no-non-null-assertion`: Warn on non-null assertions (`!`)
|
|
447
|
+
|
|
448
|
+
### Import Restrictions
|
|
449
|
+
- ❌ No imports from other monorepo libraries (`@libraries/*` except `@libraries/jupiter-ui`)
|
|
450
|
+
- ❌ No imports from apps (`apps/*`)
|
|
451
|
+
- ❌ No imports from other libs (`libs/*`)
|
|
452
|
+
- ❌ No relative imports outside `src/` directory
|
|
453
|
+
- ✅ Only allowed external dependencies: `@mantine/*`, `@emotion/*`, `@phosphor-icons/react`, `lucide-react`, `vitest`, `react`, `react-dom`, `@testing-library/*`, `@storybook/*`, `@types/*`
|
|
454
|
+
|
|
455
|
+
### Component Requirements
|
|
456
|
+
- ✅ Every component must have a corresponding `.test.tsx` file (enforced by `test-file/require-test-file` rule)
|
|
457
|
+
- ✅ Set `displayName` on exported React components for better DX in DevTools and logs
|
|
458
|
+
|
|
459
|
+
### React Rules
|
|
460
|
+
- ✅ All React recommended rules
|
|
461
|
+
- ✅ React Hooks recommended rules
|
|
462
|
+
- ✅ JSX runtime rules
|
|
463
|
+
|
|
464
|
+
### Other
|
|
465
|
+
- ✅ Fully type-safe
|
|
466
|
+
- ✅ Plug-and-play architecture
|
|
467
|
+
|
|
468
|
+
## 🤝 Contributing
|
|
469
|
+
|
|
470
|
+
When adding components:
|
|
471
|
+
|
|
472
|
+
1. Create component folder in `src/design-system/components/[Name]/`
|
|
473
|
+
2. Create `Name.tsx` with component implementation
|
|
474
|
+
3. Create `Name.stories.tsx` with comprehensive stories
|
|
475
|
+
4. Export component and types from `src/index.ts`
|
|
476
|
+
5. Ensure no external monorepo dependencies
|
|
477
|
+
6. Follow semantic variant naming
|
|
478
|
+
7. Add proper TypeScript types
|
|
479
|
+
|
|
480
|
+
## 📖 Additional Resources
|
|
481
|
+
|
|
482
|
+
- [Mantine Documentation](https://mantine.dev/)
|
|
483
|
+
- [Storybook Documentation](https://storybook.js.org/)
|