desktop-team-doc 0.1.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 +89 -0
- package/content/docs/README.md +227 -0
- package/content/docs/index.md +352 -0
- package/content/docs/instructions/coding-conventions/.clang-format +65 -0
- package/content/docs/instructions/coding-conventions/cpp.md +132 -0
- package/content/docs/instructions/coding-conventions/frontend.md +612 -0
- package/content/docs/instructions/coding-conventions/team-wide.md +176 -0
- package/content/docs/instructions/workflows/assets/jira-1.png +0 -0
- package/content/docs/instructions/workflows/assets/jira-comment.png +0 -0
- package/content/docs/instructions/workflows/assets/jira-release-note.png +0 -0
- package/content/docs/instructions/workflows/assets/jira-tag.png +0 -0
- package/content/docs/instructions/workflows/code-review.md +451 -0
- package/content/docs/instructions/workflows/git-branch-convention.md +246 -0
- package/content/docs/instructions/workflows/git-commit.md +95 -0
- package/content/docs/instructions/workflows/jira-process.md +173 -0
- package/content/docs/instructions/workflows/jira-ticket-guide.md +105 -0
- package/content/docs/instructions/workflows/pull-request-generation.md +319 -0
- package/content/docs/instructions/workflows/scrum-process.md +104 -0
- package/content/docs/instructions/workflows/survey-project-setup.md +76 -0
- package/content/docs/knowledge/architecture/README.md +11 -0
- package/content/docs/knowledge/architecture/audio-plugin-architecture.md +213 -0
- package/content/docs/knowledge/architecture/cross-platform-design.md +176 -0
- package/content/docs/knowledge/architecture/frontend-native-bridge.md +193 -0
- package/content/docs/knowledge/architecture/native-command.md +189 -0
- package/content/docs/knowledge/architecture/state-management-architecture.md +105 -0
- package/content/docs/knowledge/component-library/ControlComponent/README.md +281 -0
- package/content/docs/knowledge/component-library/ControlComponent/accessibility/accessibility-implementation.md +503 -0
- package/content/docs/knowledge/component-library/ControlComponent/common-mechanisms.md +278 -0
- package/content/docs/knowledge/component-library/ControlComponent/core/error-handling.md +451 -0
- package/content/docs/knowledge/component-library/ControlComponent/core/native-interface.md +515 -0
- package/content/docs/knowledge/component-library/ControlComponent/core/state-management.md +509 -0
- package/content/docs/knowledge/component-library/ControlComponent/creating-new-controls.md +654 -0
- package/content/docs/knowledge/component-library/ControlComponent/design/api-design-reference.md +1142 -0
- package/content/docs/knowledge/component-library/ControlComponent/design/design-principles.md +336 -0
- package/content/docs/knowledge/component-library/ControlComponent/design/styling-architecture.md +595 -0
- package/content/docs/knowledge/component-library/ControlComponent/design/visual-feedback.md +456 -0
- package/content/docs/knowledge/component-library/ControlComponent/development-environment.md +213 -0
- package/content/docs/knowledge/component-library/ControlComponent/interaction/gesture-algorithms.md +705 -0
- package/content/docs/knowledge/component-library/ControlComponent/interaction/touch-support.md +525 -0
- package/content/docs/knowledge/component-library/ControlComponent/interaction/value-processing-patterns.md +801 -0
- package/content/docs/knowledge/component-library/ControlComponent/interaction/velocity-damping-systems.md +741 -0
- package/content/docs/knowledge/component-library/ControlComponent/knob/architecture.md +490 -0
- package/content/docs/knowledge/component-library/ControlComponent/knob/how-to-use.md +304 -0
- package/content/docs/knowledge/component-library/ControlComponent/knob/index.md +105 -0
- package/content/docs/knowledge/component-library/ControlComponent/optimization/performance-benchmarks.md +535 -0
- package/content/docs/knowledge/component-library/ControlComponent/optimization/performance-optimization.md +1092 -0
- package/content/docs/knowledge/component-library/ControlComponent/quick-start.md +345 -0
- package/content/docs/knowledge/component-library/ControlComponent/slider/architecture.md +444 -0
- package/content/docs/knowledge/component-library/ControlComponent/slider/how-to-use.md +470 -0
- package/content/docs/knowledge/component-library/ControlComponent/slider/index.md +107 -0
- package/content/docs/knowledge/component-library/ControlComponent/testing-guide.md +950 -0
- package/content/docs/knowledge/component-library/ControlComponent/troubleshooting.md +657 -0
- package/content/docs/knowledge/component-library/frontend-develop/LICENSE.txt +176 -0
- package/content/docs/knowledge/component-library/frontend-develop/SKILL.md +124 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/code-organization.md +620 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/coding-standards.md +275 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/component-reusability.md +559 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/examples.md +554 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/layout-separation.md +638 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/performance-optimization.md +678 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/state-management.md +331 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/styling-guidelines.md +349 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/type-safety.md +493 -0
- package/content/docs/knowledge/development/assets/cyberduck-aws-credentials.png +0 -0
- package/content/docs/knowledge/development/assets/postman-environment-setup.png +0 -0
- package/content/docs/knowledge/development/aws-storage.md +95 -0
- package/content/docs/knowledge/development/crm-system.md +22 -0
- package/content/docs/knowledge/development/glossary.md +246 -0
- package/content/docs/knowledge/development/pg-api-guide.md +71 -0
- package/content/docs/knowledge/development/staging-license-management.md +44 -0
- package/content/docs/knowledge/development/tech-stack.md +240 -0
- package/content/docs/knowledge/domain/popup-system.md +106 -0
- package/content/docs/knowledge/domain/sigpath.md +264 -0
- package/content/docs/knowledge/environment-setup/aax-signing-update.md +149 -0
- package/content/docs/knowledge/environment-setup/assets/aax-1.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-2.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-3.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-4.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-5.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-6.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-7.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-1.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-10.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-11.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-12.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-13.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-14.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-2.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-3.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-4.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-5.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-6.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-7.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-8.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-9.png +0 -0
- package/content/docs/knowledge/environment-setup/build-machine-setup.md +224 -0
- package/content/docs/knowledge/environment-setup/build-machine-troubleshooting.md +193 -0
- package/content/docs/knowledge/implementation-guides/adding-amp.md +190 -0
- package/content/docs/knowledge/implementation-guides/adding-fx.md +111 -0
- package/content/docs/knowledge/implementation-guides/cab-integration.md +194 -0
- package/content/docs/knowledge/implementation-guides/custom-pedal-integration.md +309 -0
- package/content/docs/knowledge/projects/BIAS_ONE_GUI/README.md +17 -0
- package/content/manifest.json +122 -0
- package/content/rules/cpp.mdc +135 -0
- package/content/rules/frontend.mdc +615 -0
- package/content/rules/index.mdc +256 -0
- package/content/rules/knowledge.mdc +46 -0
- package/content/rules/team-wide.mdc +179 -0
- package/content/rules/workflows.mdc +43 -0
- package/content/tools/agents/context-compressor.md +357 -0
- package/content/tools/agents/context-writer.md +328 -0
- package/content/tools/agents/release-notes-generator.md +389 -0
- package/content/tools/agents/srs-writer-agent.md +63 -0
- package/content/tools/mcp/README.md +25 -0
- package/content/tools/mcp/mcp-desktop-team.example.json +13 -0
- package/content/tools/skills/frontend-develop/LICENSE.txt +176 -0
- package/content/tools/skills/frontend-develop/SKILL.md +124 -0
- package/content/tools/skills/frontend-develop/references/code-organization.md +620 -0
- package/content/tools/skills/frontend-develop/references/coding-standards.md +275 -0
- package/content/tools/skills/frontend-develop/references/component-reusability.md +559 -0
- package/content/tools/skills/frontend-develop/references/examples.md +554 -0
- package/content/tools/skills/frontend-develop/references/layout-separation.md +638 -0
- package/content/tools/skills/frontend-develop/references/performance-optimization.md +678 -0
- package/content/tools/skills/frontend-develop/references/state-management.md +331 -0
- package/content/tools/skills/frontend-develop/references/styling-guidelines.md +349 -0
- package/content/tools/skills/frontend-develop/references/type-safety.md +493 -0
- package/content/tools/slash-commands/commit.md +17 -0
- package/content/tools/slash-commands/context-compress.md +149 -0
- package/content/tools/slash-commands/context-write.md +92 -0
- package/content/tools/slash-commands/jira.md +12 -0
- package/content/tools/slash-commands/pr-gen.md +12 -0
- package/content/tools/slash-commands/pr-review.md +12 -0
- package/dist/commands/detect.d.ts +1 -0
- package/dist/commands/detect.js +33 -0
- package/dist/commands/install.d.ts +1 -0
- package/dist/commands/install.js +100 -0
- package/dist/commands/uninstall.d.ts +1 -0
- package/dist/commands/uninstall.js +132 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -0
- package/dist/lib/detect-env.d.ts +3 -0
- package/dist/lib/detect-env.js +52 -0
- package/dist/lib/prompt-env.d.ts +3 -0
- package/dist/lib/prompt-env.js +16 -0
- package/dist/lib/resolve-doc-repo.d.ts +14 -0
- package/dist/lib/resolve-doc-repo.js +61 -0
- package/dist/lib/symlink.d.ts +7 -0
- package/dist/lib/symlink.js +60 -0
- package/dist/lib/sync-from-manifest.d.ts +8 -0
- package/dist/lib/sync-from-manifest.js +64 -0
- package/package.json +46 -0
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
# Frontend Coding Standards
|
|
2
|
+
|
|
3
|
+
*Last Updated: 2025-10-16*
|
|
4
|
+
|
|
5
|
+
This document outlines the frontend coding standards for the Desktop Team across all React/TypeScript projects.
|
|
6
|
+
|
|
7
|
+
## Formatting
|
|
8
|
+
|
|
9
|
+
* All frontend code formatting MUST adhere to the Prettier configuration located in `.prettierrc`.
|
|
10
|
+
* ESLint rules in `.eslintrc.json` must be followed for code quality.
|
|
11
|
+
* Ensure any generated or modified code passes both Prettier and ESLint checks.
|
|
12
|
+
|
|
13
|
+
### Key Formatting Rules (from `.prettierrc`)
|
|
14
|
+
|
|
15
|
+
* **Indentation**: 2 spaces (not tabs)
|
|
16
|
+
* **Line Length**: Maximum 120 characters
|
|
17
|
+
* **Semicolons**: Always use semicolons
|
|
18
|
+
* **Quotes**: Single quotes for strings
|
|
19
|
+
* **Trailing Commas**: As per Prettier defaults
|
|
20
|
+
* **No trailing whitespace**
|
|
21
|
+
* **No indentation on empty lines**
|
|
22
|
+
|
|
23
|
+
**Note**: Run `npm run eslint` before committing to ensure code quality.
|
|
24
|
+
|
|
25
|
+
## Technology Stack
|
|
26
|
+
|
|
27
|
+
### Core Technologies
|
|
28
|
+
|
|
29
|
+
* **React 18.2+**: Component-based UI library
|
|
30
|
+
* **TypeScript 5.0+**: Typed JavaScript for better code quality
|
|
31
|
+
* **Vite 4.4+**: Build tool and dev server
|
|
32
|
+
* **Vitest**: Testing framework
|
|
33
|
+
|
|
34
|
+
### State Management
|
|
35
|
+
|
|
36
|
+
* **Redux Toolkit (@reduxjs/toolkit)**: Primary global state management (preferred)
|
|
37
|
+
* **React Hooks**: Local component state
|
|
38
|
+
* **Zustand**: 僅既有功能保留,新 state 請使用 Redux 或 Local State。
|
|
39
|
+
|
|
40
|
+
### Styling
|
|
41
|
+
|
|
42
|
+
* **TailwindCSS 3.3+**: Utility-first CSS framework
|
|
43
|
+
* **Note**: 專案因效能考量已不再使用 styled-components 與 @emotion,新樣式請以 TailwindCSS 為主。
|
|
44
|
+
* **tailwind-merge**: For merging Tailwind classes
|
|
45
|
+
* **clsx**: For conditional class names
|
|
46
|
+
|
|
47
|
+
### UI Libraries
|
|
48
|
+
|
|
49
|
+
* **@positivegrid/pg-react-ui-library**: Internal component library
|
|
50
|
+
* **React Router DOM 5.x**: Client-side routing
|
|
51
|
+
* **React Beautiful DnD**: Drag and drop functionality
|
|
52
|
+
* **Framer Motion (motion)**: Animation library
|
|
53
|
+
|
|
54
|
+
## Naming Conventions
|
|
55
|
+
|
|
56
|
+
### Files and Directories
|
|
57
|
+
|
|
58
|
+
* **Components**: `PascalCase.tsx` for React components (e.g., `AppButton.tsx`, `EditableText.tsx`)
|
|
59
|
+
* **Hooks**: `camelCase.ts` starting with "use" (e.g., `useInputStatus.ts`, `useGearMenuStore.ts`)
|
|
60
|
+
* **Utilities**: `camelCase.ts` for utility files (e.g., `constants.ts`, `utils.ts`)
|
|
61
|
+
* **Stores**: `camelCase.ts` with "Store" suffix (e.g., `guitarMatchStore.ts`, `pedalGridStore.ts`)
|
|
62
|
+
* **Types/Interfaces**: `types.ts` or `interfaces.ts`
|
|
63
|
+
* **Command Files**: `camelCase.ts` with "Cmd" suffix (e.g., `initMainViewCmd.ts`)
|
|
64
|
+
|
|
65
|
+
### TypeScript/JavaScript
|
|
66
|
+
|
|
67
|
+
* **Variables**: `camelCase` (e.g., `userName`, `isLoading`)
|
|
68
|
+
* **Functions**: `camelCase` (e.g., `handleClick`, `fetchData`)
|
|
69
|
+
* **React Components**: `PascalCase` (e.g., `AppButton`, `EditableText`)
|
|
70
|
+
* **Interfaces/Types**: `PascalCase` with descriptive names (e.g., `AppButtonProps`, `EditableTextHandle`)
|
|
71
|
+
* **Type Aliases**: `PascalCase` starting with `T` prefix (e.g., `TKnobProps`)
|
|
72
|
+
* **Constants**: `UPPER_SNAKE_CASE` (e.g., `MAX_BUFFER_SIZE`, `DEFAULT_FRAMES`)
|
|
73
|
+
* Exception: Configuration objects use `camelCase` (e.g., `kDaysInAWeek` when porting from C++)
|
|
74
|
+
* **Enums**: `PascalCase` for enum name, `camelCase` for values
|
|
75
|
+
* **Props Types**: Component name + `Props` suffix (e.g., `AppButtonProps`)
|
|
76
|
+
* **Handler Types**: Component name + `Handle` suffix for refs (e.g., `EditableTextHandle`)
|
|
77
|
+
|
|
78
|
+
### CSS Classes (TailwindCSS)
|
|
79
|
+
|
|
80
|
+
* **Custom Components**: Use descriptive class names with prefixes
|
|
81
|
+
* `.x-` prefix for design system components (e.g., `.x-btn`, `.x-red-dot`)
|
|
82
|
+
* `.pg-` prefix for Positive Grid specific utilities (e.g., `.pg-scroll-bar`)
|
|
83
|
+
* **Typography Classes**: Semantic naming (e.g., `.heading-14`, `.body-16`, `.x-heading-4`)
|
|
84
|
+
|
|
85
|
+
## Code Style Conventions
|
|
86
|
+
|
|
87
|
+
### Braces (Always Use)
|
|
88
|
+
|
|
89
|
+
**Always use braces** for functions and control statements (if/else) for better readability, formatting, and flexibility when making changes.
|
|
90
|
+
|
|
91
|
+
**Bad**:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const openLoginWindow = (): StoreThunkAction<unknown> => (dispatch) => {
|
|
95
|
+
dispatch(openLoginModal());
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (isOpen) closeModal();
|
|
99
|
+
else if (isSaveDialogShowed) setIsSaveDialogShowed(false);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Good**:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const openLoginWindow = (): StoreThunkAction<unknown> => {
|
|
106
|
+
return (dispatch) => {
|
|
107
|
+
dispatch(openLoginModal());
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if (isOpen) {
|
|
112
|
+
closeModal();
|
|
113
|
+
} else if (isSaveDialogShowed) {
|
|
114
|
+
setIsSaveDialogShowed(false);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Exception**: Early returns or guards can be written on one line when used for quick preprocessing:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
if (!inputData) return;
|
|
122
|
+
processData1(inputData.data1);
|
|
123
|
+
processData2(inputData.data2);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This single-line format emphasizes the guard nature of the check.
|
|
127
|
+
|
|
128
|
+
### API Client Standards
|
|
129
|
+
|
|
130
|
+
* **Use Axios**: Standardize on `axios` for all API calls
|
|
131
|
+
* **Exception**: `XMLHttpRequest` is used for native command communication - do not modify this pattern without team discussion
|
|
132
|
+
* Gradually migrate legacy API call patterns to axios
|
|
133
|
+
|
|
134
|
+
**Example**:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import axios from 'axios';
|
|
138
|
+
|
|
139
|
+
const fetchUserData = async (userId: string) => {
|
|
140
|
+
try {
|
|
141
|
+
const response = await axios.get(`/api/users/${userId}`);
|
|
142
|
+
return response.data;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error('Failed to fetch user data:', error);
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## TypeScript Standards
|
|
151
|
+
|
|
152
|
+
### Type Safety
|
|
153
|
+
|
|
154
|
+
* **Strict Mode**: Enable `noImplicitAny: true`
|
|
155
|
+
* **Avoid `any`**: Use specific types or `unknown` when type is truly unknown
|
|
156
|
+
* **Type Imports**: Use `type` keyword for type-only imports
|
|
157
|
+
```typescript
|
|
158
|
+
import type { MousePos } from '@/src/utils/mouseRx/types';
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Interface vs Type
|
|
162
|
+
|
|
163
|
+
* **Interfaces**: For object shapes, especially props and public APIs
|
|
164
|
+
```typescript
|
|
165
|
+
export interface AppButtonProps {
|
|
166
|
+
disable?: boolean;
|
|
167
|
+
selected?: boolean;
|
|
168
|
+
className?: string;
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
* **Type Aliases**: For unions, intersections, and complex types
|
|
172
|
+
```typescript
|
|
173
|
+
export type TKnobProps = {
|
|
174
|
+
config: KnobConfig;
|
|
175
|
+
};
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Type Annotations
|
|
179
|
+
|
|
180
|
+
* **Function Return Types**: Explicitly define return types for functions
|
|
181
|
+
```typescript
|
|
182
|
+
const processData = (): string => {
|
|
183
|
+
return 'result';
|
|
184
|
+
};
|
|
185
|
+
```
|
|
186
|
+
* **Props Destructuring**: Type props inline or via interface
|
|
187
|
+
```typescript
|
|
188
|
+
const Component = ({ value, onChange }: EditableTextProps) => {
|
|
189
|
+
// Component logic
|
|
190
|
+
};
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Generics
|
|
194
|
+
|
|
195
|
+
* Use descriptive generic names: `<T>`, `<TItem>`, `<TData>`
|
|
196
|
+
* Constrain generics when possible
|
|
197
|
+
```typescript
|
|
198
|
+
function process<T extends object>(data: T): T {
|
|
199
|
+
return data;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## React Patterns
|
|
204
|
+
|
|
205
|
+
### Component Structure
|
|
206
|
+
|
|
207
|
+
1. **Imports**: Group by external libraries, internal utilities, types, styles
|
|
208
|
+
2. **Type Definitions**: Props interfaces, handler types
|
|
209
|
+
3. **Component Declaration**: Use arrow functions or `function` keyword with `forwardRef` when needed
|
|
210
|
+
4. **Hooks**: `useState`, `useRef`, `useEffect`, etc.
|
|
211
|
+
5. **Handlers**: Event handlers and callbacks
|
|
212
|
+
6. **Render Helpers**: Small render functions if needed
|
|
213
|
+
7. **Return Statement**: JSX
|
|
214
|
+
|
|
215
|
+
**Example**:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import React, { forwardRef, useState, useEffect } from 'react';
|
|
219
|
+
import { twMerge } from 'tailwind-merge';
|
|
220
|
+
import type { SomeType } from './types';
|
|
221
|
+
|
|
222
|
+
export type MyComponentProps = {
|
|
223
|
+
value: string;
|
|
224
|
+
onChange: (value: string) => void;
|
|
225
|
+
className?: string;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const MyComponent = forwardRef<HTMLDivElement, MyComponentProps>(
|
|
229
|
+
function MyComponent(props, ref) {
|
|
230
|
+
const { value, onChange, className } = props;
|
|
231
|
+
|
|
232
|
+
const [localState, setLocalState] = useState('');
|
|
233
|
+
|
|
234
|
+
useEffect(() => {
|
|
235
|
+
// Effect logic
|
|
236
|
+
}, []);
|
|
237
|
+
|
|
238
|
+
const handleClick = () => {
|
|
239
|
+
onChange(value);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
return (
|
|
243
|
+
<div ref={ref} className={twMerge('base-class', className)}>
|
|
244
|
+
{/* JSX content */}
|
|
245
|
+
</div>
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
export default MyComponent;
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Hooks Best Practices
|
|
254
|
+
|
|
255
|
+
* **Custom Hooks**: Start with `use` prefix
|
|
256
|
+
* **Dependencies**: Always specify complete dependency arrays
|
|
257
|
+
* **Hook Order**: Keep hook calls at the top level, same order every render
|
|
258
|
+
* **Ref Hooks**: Use `useRef` for mutable values that don't trigger re-renders
|
|
259
|
+
* **Imperative Handles**: Use `useImperativeHandle` to expose component methods via refs
|
|
260
|
+
|
|
261
|
+
### Props
|
|
262
|
+
|
|
263
|
+
* **Destructure Props**: Destructure in function parameters
|
|
264
|
+
* **Default Values**: Use destructuring defaults
|
|
265
|
+
```typescript
|
|
266
|
+
const Component = ({ value = '', disabled = false }: Props) => {
|
|
267
|
+
// Component logic
|
|
268
|
+
};
|
|
269
|
+
```
|
|
270
|
+
* **Spread Props**: Use `...others` or `...rest` for passing through props
|
|
271
|
+
* **Children**: Type as `React.ReactNode` for flexibility
|
|
272
|
+
|
|
273
|
+
#### Props Spreading (Use Sparingly)
|
|
274
|
+
|
|
275
|
+
**Avoid indiscriminate props spreading** - directly spreading props makes it difficult to quickly see what is being passed down.
|
|
276
|
+
|
|
277
|
+
**Bad**:
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
const color = (props) => getSyncButtonColor({ hover: true, ...props });
|
|
281
|
+
|
|
282
|
+
function Comp({ dataA, ...props }) {
|
|
283
|
+
return <div {...props} />;
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Good**:
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
// Explicitly list props for clarity
|
|
291
|
+
const color = ({ disabled, selected }) =>
|
|
292
|
+
getSyncButtonColor({ hover: true, disabled, selected });
|
|
293
|
+
|
|
294
|
+
function Comp({ dataA, onClick, onMouseMove, role }) {
|
|
295
|
+
return <div onClick={onClick} onMouseMove={onMouseMove} role={role} />;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Or use a named prop object for clarity
|
|
299
|
+
function Comp({ dataA, divProps }) {
|
|
300
|
+
return <div {...divProps} />;
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**When to use spreading**:
|
|
305
|
+
* Only when creating wrapper components that truly need to forward all props
|
|
306
|
+
* When using a named props object (e.g., `divProps`, `buttonProps`) to make intent clear
|
|
307
|
+
|
|
308
|
+
### State Management Patterns
|
|
309
|
+
|
|
310
|
+
**Priority Order**: Redux > Local State
|
|
311
|
+
|
|
312
|
+
#### 1. Redux (Preferred for Global State)
|
|
313
|
+
|
|
314
|
+
* **Primary choice** for global application state
|
|
315
|
+
* Use Redux Toolkit (`@reduxjs/toolkit`) for modern Redux patterns
|
|
316
|
+
* Use `useSelector` and `useDispatch` hooks in components
|
|
317
|
+
* Create slices with `createSlice` for state management
|
|
318
|
+
* Use `createAsyncThunk` for async operations
|
|
319
|
+
|
|
320
|
+
**Example**:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
324
|
+
|
|
325
|
+
interface AppState {
|
|
326
|
+
isOpen: boolean;
|
|
327
|
+
currentUser: string | null;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const initialState: AppState = {
|
|
331
|
+
isOpen: false,
|
|
332
|
+
currentUser: null,
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const appSlice = createSlice({
|
|
336
|
+
name: 'app',
|
|
337
|
+
initialState,
|
|
338
|
+
reducers: {
|
|
339
|
+
setOpen: (state, action: PayloadAction<boolean>) => {
|
|
340
|
+
state.isOpen = action.payload;
|
|
341
|
+
},
|
|
342
|
+
setUser: (state, action: PayloadAction<string>) => {
|
|
343
|
+
state.currentUser = action.payload;
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
export const { setOpen, setUser } = appSlice.actions;
|
|
349
|
+
export default appSlice.reducer;
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**Usage**:
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { useSelector, useDispatch } from 'react-redux';
|
|
356
|
+
import { setOpen } from './appSlice';
|
|
357
|
+
|
|
358
|
+
const Component = () => {
|
|
359
|
+
const isOpen = useSelector((state: RootState) => state.app.isOpen);
|
|
360
|
+
const dispatch = useDispatch();
|
|
361
|
+
|
|
362
|
+
const handleOpen = () => {
|
|
363
|
+
dispatch(setOpen(true));
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
return <div>{/* Component JSX */}</div>;
|
|
367
|
+
};
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
#### 2. Local State (Preferred for Component-Specific State)
|
|
371
|
+
|
|
372
|
+
* **Primary choice** for component-local state that doesn't need to be shared
|
|
373
|
+
* Use `useState` for simple component-local state
|
|
374
|
+
* Use `useReducer` for complex state logic with multiple sub-values
|
|
375
|
+
* Keep state as local as possible before lifting to Redux
|
|
376
|
+
|
|
377
|
+
**Example**:
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// Simple local state
|
|
381
|
+
const [isTypingMode, setIsTypingMode] = useState(false);
|
|
382
|
+
|
|
383
|
+
// Complex local state
|
|
384
|
+
const [state, dispatch] = useReducer(reducer, initialState);
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Zustand 政策**: Zustand 僅供既有模組保留使用,新功能不得新增 Zustand store。
|
|
388
|
+
|
|
389
|
+
**When to use each**:
|
|
390
|
+
|
|
391
|
+
* **Redux**: Global state, cross-feature state, persistent state
|
|
392
|
+
* **Local State**: UI state, form inputs, toggles, component-specific state
|
|
393
|
+
|
|
394
|
+
## Styling Conventions
|
|
395
|
+
|
|
396
|
+
### TailwindCSS
|
|
397
|
+
|
|
398
|
+
* **Utility-First**: Prefer Tailwind utilities over custom CSS
|
|
399
|
+
* **Class Merging**: Use `twMerge` to merge conflicting Tailwind classes
|
|
400
|
+
```typescript
|
|
401
|
+
className={twMerge('p-0 bg-transparent rounded-none', classes.input)}
|
|
402
|
+
```
|
|
403
|
+
* **Conditional Classes**: Use `clsx` for conditional class names
|
|
404
|
+
```typescript
|
|
405
|
+
className={clsx('x-btn', { 'x-btn-active': isActive }, className)}
|
|
406
|
+
```
|
|
407
|
+
* **Custom Utilities**: Define in `tailwind.config.js` using plugins
|
|
408
|
+
* **Design System Classes**: Use predefined typography classes (`.x-heading-14`, `.x-body-3`, etc.)
|
|
409
|
+
|
|
410
|
+
### 關於 Emotion / styled-components
|
|
411
|
+
|
|
412
|
+
專案已不再使用 Emotion 與 styled-components;既有程式若仍使用可暫時保留,新程式請使用 Tailwind。
|
|
413
|
+
|
|
414
|
+
### Style Organization
|
|
415
|
+
|
|
416
|
+
* **Global Styles**: Define in Tailwind config or global CSS files
|
|
417
|
+
* **Component Styles**: Inline with Tailwind classes
|
|
418
|
+
* **Theme Variables**: Use Tailwind theme configuration
|
|
419
|
+
* **Responsive Design**: Use Tailwind breakpoint prefixes (`sm:`, `md:`, `lg:`)
|
|
420
|
+
|
|
421
|
+
## Event Handlers
|
|
422
|
+
|
|
423
|
+
### Naming
|
|
424
|
+
|
|
425
|
+
* Prefix with `handle` for event handlers: `handleClick`, `handleChange`, `handleSubmit`
|
|
426
|
+
* Prefix with `on` for prop callbacks: `onClick`, `onChange`, `onSubmit`
|
|
427
|
+
|
|
428
|
+
### Async Handlers
|
|
429
|
+
|
|
430
|
+
* Mark as `async` when performing asynchronous operations
|
|
431
|
+
* Handle errors appropriately
|
|
432
|
+
```typescript
|
|
433
|
+
const handleSubmit = async () => {
|
|
434
|
+
try {
|
|
435
|
+
await submitData();
|
|
436
|
+
} catch (error) {
|
|
437
|
+
console.error('Submit failed:', error);
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Debouncing/Throttling
|
|
443
|
+
|
|
444
|
+
* Use `lodash/throttle` or `lodash/debounce` for expensive operations
|
|
445
|
+
* Use `@react-hook/throttle` for React-specific throttling
|
|
446
|
+
|
|
447
|
+
## Code Organization
|
|
448
|
+
|
|
449
|
+
### Directory Structure
|
|
450
|
+
|
|
451
|
+
```
|
|
452
|
+
next/
|
|
453
|
+
├── components/
|
|
454
|
+
│ ├── common/ # Reusable utility components
|
|
455
|
+
│ ├── dumbs/ # Presentational "dumb" components
|
|
456
|
+
│ ├── smarts/ # Smart/container components
|
|
457
|
+
│ └── module/ # Feature modules
|
|
458
|
+
├── api/ # API utilities
|
|
459
|
+
├── flow/ # Application flow logic
|
|
460
|
+
└── utils/ # Shared utilities
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Component Categories
|
|
464
|
+
|
|
465
|
+
* **Common**: Shared, reusable components (e.g., `EditableText`, `SvgIcon`)
|
|
466
|
+
* **Dumbs**: Presentational components without business logic
|
|
467
|
+
* **Smarts**: Container components with state and business logic
|
|
468
|
+
* **Module**: Feature-specific components grouped by functionality
|
|
469
|
+
|
|
470
|
+
### Barrel Exports
|
|
471
|
+
|
|
472
|
+
* Use `index.ts` for clean imports
|
|
473
|
+
```typescript
|
|
474
|
+
// index.ts
|
|
475
|
+
export { default as AppButton } from './AppButton';
|
|
476
|
+
export type { AppButtonProps } from './AppButton';
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Testing
|
|
480
|
+
|
|
481
|
+
### Test Files
|
|
482
|
+
|
|
483
|
+
* Co-locate tests with components: `ComponentName.test.tsx`
|
|
484
|
+
* Use Vitest for unit and integration tests
|
|
485
|
+
* Use `@testing-library/react` for component testing
|
|
486
|
+
|
|
487
|
+
### Testing Best Practices
|
|
488
|
+
|
|
489
|
+
* Test user behavior, not implementation details
|
|
490
|
+
* Use semantic queries (`getByRole`, `getByLabelText`)
|
|
491
|
+
* Mock external dependencies
|
|
492
|
+
* Test edge cases and error states
|
|
493
|
+
|
|
494
|
+
## Performance Optimization
|
|
495
|
+
|
|
496
|
+
### React Optimization
|
|
497
|
+
|
|
498
|
+
* Use `React.memo` for expensive pure components
|
|
499
|
+
* Use `useMemo` for expensive computations
|
|
500
|
+
* Use `useCallback` for stable function references
|
|
501
|
+
* Avoid inline object/array creation in props
|
|
502
|
+
|
|
503
|
+
### Code Splitting
|
|
504
|
+
|
|
505
|
+
* Use dynamic `import()` for lazy loading
|
|
506
|
+
* Split routes and large features
|
|
507
|
+
|
|
508
|
+
### Bundle Size
|
|
509
|
+
|
|
510
|
+
* Monitor bundle size with build tools
|
|
511
|
+
* Tree-shake unused code
|
|
512
|
+
* Use named imports from lodash: `import debounce from 'lodash/debounce'`
|
|
513
|
+
|
|
514
|
+
## Commenting Policy
|
|
515
|
+
|
|
516
|
+
See [Team-wide Coding Conventions](./team-wide.md#commenting-policy) for the team's minimalist commenting policy which applies to all languages including TypeScript/JavaScript.
|
|
517
|
+
|
|
518
|
+
### Frontend-Specific Guidelines
|
|
519
|
+
|
|
520
|
+
* **Complex State Logic**: Comment non-obvious state management patterns
|
|
521
|
+
* **Workarounds**: Document workarounds with explanation
|
|
522
|
+
```typescript
|
|
523
|
+
// WORKAROUND: without setTimeout, the focus won't work
|
|
524
|
+
setTimeout(() => {
|
|
525
|
+
inputRef.current.focus();
|
|
526
|
+
}, 0);
|
|
527
|
+
```
|
|
528
|
+
* **Type Assertions**: Explain why type assertion is necessary if non-obvious
|
|
529
|
+
* **Regex Patterns**: Comment complex regex with explanation
|
|
530
|
+
* **Magic Numbers**: Use named constants instead of comments
|
|
531
|
+
|
|
532
|
+
## Import Organization
|
|
533
|
+
|
|
534
|
+
### Import Order
|
|
535
|
+
|
|
536
|
+
1. External libraries (React, third-party)
|
|
537
|
+
2. Internal modules (aliased with `@/`)
|
|
538
|
+
3. Types (using `import type`)
|
|
539
|
+
4. Relative imports
|
|
540
|
+
5. Styles (if any)
|
|
541
|
+
|
|
542
|
+
**Example**:
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
import React, { useState, useEffect } from 'react';
|
|
546
|
+
import { twMerge } from 'tailwind-merge';
|
|
547
|
+
import clsx from 'clsx';
|
|
548
|
+
|
|
549
|
+
import ClickOutsideHandler from '@/src/components/dumbs/click-outside-handler';
|
|
550
|
+
import { useParameterComponentProps } from '@/src/components/shared/store';
|
|
551
|
+
|
|
552
|
+
import type { MousePos } from '@/src/utils/mouseRx/types';
|
|
553
|
+
import type { AppButtonProps } from './types';
|
|
554
|
+
|
|
555
|
+
import './styles.css';
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### Path Aliases
|
|
559
|
+
|
|
560
|
+
* **Configure `@/` to point to project root**: The `@/` alias should point to the project root directory in `tsconfig.json` and build tool configuration
|
|
561
|
+
* **Use `@/src/` for source imports**: Import from source code using `@/src/` prefix for semantic correctness
|
|
562
|
+
* **Avoid `@src/` pattern**: This pattern semantically represents `https://npmjs.com/org/src` (an npm organization package), which is incorrect for local paths
|
|
563
|
+
|
|
564
|
+
**tsconfig.json configuration**:
|
|
565
|
+
|
|
566
|
+
```json
|
|
567
|
+
{
|
|
568
|
+
"compilerOptions": {
|
|
569
|
+
"paths": {
|
|
570
|
+
"@/*": ["./*"]
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
**Example usage**:
|
|
577
|
+
|
|
578
|
+
```typescript
|
|
579
|
+
// Good - clear local path alias (@/ points to project root)
|
|
580
|
+
import { Component } from '@/src/components/AppButton';
|
|
581
|
+
import type { UserData } from '@/src/types/user';
|
|
582
|
+
|
|
583
|
+
// Bad - looks like npm org package
|
|
584
|
+
import { Component } from '@src/components/AppButton';
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
## Accessibility (a11y)
|
|
588
|
+
|
|
589
|
+
* Use semantic HTML elements
|
|
590
|
+
* Provide `aria-` attributes when needed
|
|
591
|
+
* Support keyboard navigation
|
|
592
|
+
* Test with screen readers
|
|
593
|
+
* Use ESLint plugin `jsx-a11y` rules
|
|
594
|
+
|
|
595
|
+
## Internationalization (i18n)
|
|
596
|
+
|
|
597
|
+
* Use translation keys, not hard-coded text
|
|
598
|
+
* Follow `@m6web/i18n` ESLint rules
|
|
599
|
+
* Avoid text as children or attributes without translation
|
|
600
|
+
|
|
601
|
+
## Error Handling
|
|
602
|
+
|
|
603
|
+
* Use try-catch for async operations
|
|
604
|
+
* Log errors appropriately
|
|
605
|
+
* Show user-friendly error messages
|
|
606
|
+
* Handle edge cases gracefully
|
|
607
|
+
|
|
608
|
+
## Related Resources
|
|
609
|
+
|
|
610
|
+
* [Team-wide Coding Conventions](./team-wide.md) - Universal coding standards
|
|
611
|
+
* [C++ Coding Standards](./cpp.md) - For native bridge integration
|
|
612
|
+
* [Tech Stack Overview](../../knowledge/development/tech-stack.md) - Frontend technologies
|