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,559 @@
|
|
|
1
|
+
# Component Reusability Guidelines
|
|
2
|
+
|
|
3
|
+
This document provides comprehensive guidelines for creating reusable components, including using existing components, variant design patterns, and extensibility considerations.
|
|
4
|
+
|
|
5
|
+
## Core Principles
|
|
6
|
+
|
|
7
|
+
### Prioritize Existing Components
|
|
8
|
+
|
|
9
|
+
**Rule**: Always check for existing components before creating new ones.
|
|
10
|
+
|
|
11
|
+
**Process**:
|
|
12
|
+
1. Search codebase for similar components
|
|
13
|
+
2. Check component library (`@positivegrid/pg-react-ui-library`)
|
|
14
|
+
3. Review common components (`components/common/`)
|
|
15
|
+
4. If similar component exists, extend or compose it
|
|
16
|
+
5. Only create new component if no suitable option exists
|
|
17
|
+
|
|
18
|
+
### Component Discovery
|
|
19
|
+
|
|
20
|
+
**Where to Look**:
|
|
21
|
+
- `src/components/common/` - Shared utility components
|
|
22
|
+
- `next/components/common/` - Newer common components
|
|
23
|
+
- `src/components/dumbs/` - Presentational components
|
|
24
|
+
- `@positivegrid/pg-react-ui-library` - Internal component library
|
|
25
|
+
|
|
26
|
+
**Example**:
|
|
27
|
+
```typescript
|
|
28
|
+
// Before creating new button
|
|
29
|
+
import { AppButton } from '@/src/components/common';
|
|
30
|
+
// or
|
|
31
|
+
import { Button } from '@positivegrid/pg-react-ui-library';
|
|
32
|
+
|
|
33
|
+
// Use existing component
|
|
34
|
+
<AppButton onClick={handleClick} disabled={isDisabled}>
|
|
35
|
+
Click Me
|
|
36
|
+
</AppButton>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Variant Design Patterns
|
|
40
|
+
|
|
41
|
+
### When to Use Variants
|
|
42
|
+
|
|
43
|
+
Use variants when:
|
|
44
|
+
1. Component has multiple visual styles
|
|
45
|
+
2. Component has different behaviors based on props
|
|
46
|
+
3. Component needs to support different sizes, colors, or states
|
|
47
|
+
4. Component variations are related and share core functionality
|
|
48
|
+
|
|
49
|
+
### Variant Design Best Practices
|
|
50
|
+
|
|
51
|
+
#### Pattern 1: Union Type Variants
|
|
52
|
+
|
|
53
|
+
**Rule**: Use union types for simple, mutually exclusive variants.
|
|
54
|
+
|
|
55
|
+
**Example**:
|
|
56
|
+
```typescript
|
|
57
|
+
export interface ButtonProps {
|
|
58
|
+
variant?: 'primary' | 'secondary' | 'danger';
|
|
59
|
+
size?: 'small' | 'medium' | 'large';
|
|
60
|
+
disabled?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function Button({
|
|
64
|
+
variant = 'primary',
|
|
65
|
+
size = 'medium',
|
|
66
|
+
disabled = false,
|
|
67
|
+
...props
|
|
68
|
+
}: ButtonProps): JSX.Element {
|
|
69
|
+
return (
|
|
70
|
+
<button
|
|
71
|
+
className={clsx(
|
|
72
|
+
'btn',
|
|
73
|
+
`btn-${variant}`,
|
|
74
|
+
`btn-${size}`,
|
|
75
|
+
{ 'btn-disabled': disabled }
|
|
76
|
+
)}
|
|
77
|
+
disabled={disabled}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### Pattern 2: Discriminated Union for Complex Variants
|
|
85
|
+
|
|
86
|
+
**Rule**: Use discriminated unions when variants have different prop requirements.
|
|
87
|
+
|
|
88
|
+
**Example**:
|
|
89
|
+
```typescript
|
|
90
|
+
type BaseButtonProps = {
|
|
91
|
+
onClick: () => void;
|
|
92
|
+
disabled?: boolean;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
type IconButtonProps = BaseButtonProps & {
|
|
96
|
+
variant: 'icon';
|
|
97
|
+
icon: React.ReactNode;
|
|
98
|
+
'aria-label': string;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
type TextButtonProps = BaseButtonProps & {
|
|
102
|
+
variant: 'text';
|
|
103
|
+
label: string;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
type ButtonProps = IconButtonProps | TextButtonProps;
|
|
107
|
+
|
|
108
|
+
function Button(props: ButtonProps): JSX.Element {
|
|
109
|
+
if (props.variant === 'icon') {
|
|
110
|
+
return (
|
|
111
|
+
<button onClick={props.onClick} aria-label={props['aria-label']}>
|
|
112
|
+
{props.icon}
|
|
113
|
+
</button>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<button onClick={props.onClick}>
|
|
119
|
+
{props.label}
|
|
120
|
+
</button>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Pattern 3: Variant Combinations
|
|
126
|
+
|
|
127
|
+
**Rule**: Consider variant combinations and ensure they work together.
|
|
128
|
+
|
|
129
|
+
**Example**:
|
|
130
|
+
```typescript
|
|
131
|
+
export interface ButtonProps {
|
|
132
|
+
variant?: 'primary' | 'secondary' | 'outline';
|
|
133
|
+
size?: 'small' | 'medium' | 'large';
|
|
134
|
+
loading?: boolean;
|
|
135
|
+
disabled?: boolean;
|
|
136
|
+
fullWidth?: boolean;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function Button({
|
|
140
|
+
variant = 'primary',
|
|
141
|
+
size = 'medium',
|
|
142
|
+
loading = false,
|
|
143
|
+
disabled = false,
|
|
144
|
+
fullWidth = false,
|
|
145
|
+
children,
|
|
146
|
+
...props
|
|
147
|
+
}: ButtonProps): JSX.Element {
|
|
148
|
+
// Ensure variants work together
|
|
149
|
+
const isDisabled = disabled || loading;
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<button
|
|
153
|
+
className={clsx(
|
|
154
|
+
'btn',
|
|
155
|
+
`btn-${variant}`,
|
|
156
|
+
`btn-${size}`,
|
|
157
|
+
{
|
|
158
|
+
'btn-loading': loading,
|
|
159
|
+
'btn-disabled': isDisabled,
|
|
160
|
+
'btn-full-width': fullWidth,
|
|
161
|
+
}
|
|
162
|
+
)}
|
|
163
|
+
disabled={isDisabled}
|
|
164
|
+
{...props}
|
|
165
|
+
>
|
|
166
|
+
{loading ? <Spinner /> : children}
|
|
167
|
+
</button>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Variant Count Considerations
|
|
173
|
+
|
|
174
|
+
**Rule**: Limit variant combinations to prevent complexity explosion.
|
|
175
|
+
|
|
176
|
+
**Guidelines**:
|
|
177
|
+
- **2-3 variants per dimension**: Keep variant dimensions manageable
|
|
178
|
+
- **Total combinations < 20**: Avoid too many combinations
|
|
179
|
+
- **Document combinations**: Document which combinations are supported
|
|
180
|
+
|
|
181
|
+
**Example**:
|
|
182
|
+
```typescript
|
|
183
|
+
// Good: 3 variants × 3 sizes = 9 combinations (manageable)
|
|
184
|
+
type Variant = 'primary' | 'secondary' | 'outline';
|
|
185
|
+
type Size = 'small' | 'medium' | 'large';
|
|
186
|
+
|
|
187
|
+
// Bad: 5 variants × 5 sizes × 4 states = 100 combinations (too many)
|
|
188
|
+
type Variant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'link';
|
|
189
|
+
type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
190
|
+
type State = 'default' | 'hover' | 'active' | 'disabled';
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Variant Composition
|
|
194
|
+
|
|
195
|
+
**Rule**: Compose variants from smaller, reusable pieces.
|
|
196
|
+
|
|
197
|
+
**Example**:
|
|
198
|
+
```typescript
|
|
199
|
+
// Base button styles
|
|
200
|
+
const baseButtonStyles = 'px-4 py-2 rounded font-medium transition';
|
|
201
|
+
|
|
202
|
+
// Variant-specific styles
|
|
203
|
+
const variantStyles = {
|
|
204
|
+
primary: 'bg-blue-500 text-white hover:bg-blue-600',
|
|
205
|
+
secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
|
|
206
|
+
outline: 'border-2 border-blue-500 text-blue-500 hover:bg-blue-50',
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Size-specific styles
|
|
210
|
+
const sizeStyles = {
|
|
211
|
+
small: 'px-2 py-1 text-sm',
|
|
212
|
+
medium: 'px-4 py-2 text-base',
|
|
213
|
+
large: 'px-6 py-3 text-lg',
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
function Button({
|
|
217
|
+
variant = 'primary',
|
|
218
|
+
size = 'medium',
|
|
219
|
+
...props
|
|
220
|
+
}: ButtonProps): JSX.Element {
|
|
221
|
+
return (
|
|
222
|
+
<button
|
|
223
|
+
className={twMerge(
|
|
224
|
+
baseButtonStyles,
|
|
225
|
+
variantStyles[variant],
|
|
226
|
+
sizeStyles[size]
|
|
227
|
+
)}
|
|
228
|
+
{...props}
|
|
229
|
+
/>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Component Extensibility
|
|
235
|
+
|
|
236
|
+
### Props Extension Pattern
|
|
237
|
+
|
|
238
|
+
**Rule**: Allow component extension through props spreading (when intentional).
|
|
239
|
+
|
|
240
|
+
**Example**:
|
|
241
|
+
```typescript
|
|
242
|
+
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
243
|
+
variant?: 'primary' | 'secondary';
|
|
244
|
+
loading?: boolean;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function Button({
|
|
248
|
+
variant = 'primary',
|
|
249
|
+
loading = false,
|
|
250
|
+
className,
|
|
251
|
+
children,
|
|
252
|
+
...buttonProps
|
|
253
|
+
}: ButtonProps): JSX.Element {
|
|
254
|
+
return (
|
|
255
|
+
<button
|
|
256
|
+
className={twMerge('btn', `btn-${variant}`, className)}
|
|
257
|
+
disabled={loading || buttonProps.disabled}
|
|
258
|
+
{...buttonProps}
|
|
259
|
+
>
|
|
260
|
+
{loading ? <Spinner /> : children}
|
|
261
|
+
</button>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Composition Pattern
|
|
267
|
+
|
|
268
|
+
**Rule**: Prefer composition over complex variant systems.
|
|
269
|
+
|
|
270
|
+
**Example**:
|
|
271
|
+
```typescript
|
|
272
|
+
// Instead of one complex component with many variants
|
|
273
|
+
function ComplexButton({ variant, icon, label, badge, ... }) {
|
|
274
|
+
// Complex logic handling all combinations
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Use composition
|
|
278
|
+
interface ButtonGroupProps {
|
|
279
|
+
children: React.ReactNode;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface ButtonIconProps {
|
|
283
|
+
icon: React.ReactNode;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
interface ButtonBadgeProps {
|
|
287
|
+
count: number;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function ButtonGroup({ children }: ButtonGroupProps) {
|
|
291
|
+
return <div className="btn-group">{children}</div>;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function Button({ children, ...props }: ButtonProps) {
|
|
295
|
+
return <button {...props}>{children}</button>;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function ButtonIcon({ icon }: ButtonIconProps) {
|
|
299
|
+
return <span className="btn-icon">{icon}</span>;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function ButtonBadge({ count }: ButtonBadgeProps) {
|
|
303
|
+
return <span className="btn-badge">{count}</span>;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Usage: Compose as needed
|
|
307
|
+
<ButtonGroup>
|
|
308
|
+
<Button>
|
|
309
|
+
<ButtonIcon icon={<Icon />} />
|
|
310
|
+
Label
|
|
311
|
+
<ButtonBadge count={5} />
|
|
312
|
+
</Button>
|
|
313
|
+
</ButtonGroup>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Render Props Pattern
|
|
317
|
+
|
|
318
|
+
**Rule**: Use render props for maximum flexibility.
|
|
319
|
+
|
|
320
|
+
**Example**:
|
|
321
|
+
```typescript
|
|
322
|
+
interface AutomationWrapperProps {
|
|
323
|
+
parameterId: string;
|
|
324
|
+
children: (props: {
|
|
325
|
+
isHighlighted: boolean;
|
|
326
|
+
onClick: () => void;
|
|
327
|
+
onContextMenu: (e: React.MouseEvent) => void;
|
|
328
|
+
}) => React.ReactNode;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function AutomationWrapper({
|
|
332
|
+
parameterId,
|
|
333
|
+
children,
|
|
334
|
+
}: AutomationWrapperProps): JSX.Element {
|
|
335
|
+
const { isHighlighted, handleClick, handleContextMenu } = useAutomation(parameterId);
|
|
336
|
+
|
|
337
|
+
return (
|
|
338
|
+
<>
|
|
339
|
+
{children({
|
|
340
|
+
isHighlighted,
|
|
341
|
+
onClick: handleClick,
|
|
342
|
+
onContextMenu: handleContextMenu,
|
|
343
|
+
})}
|
|
344
|
+
</>
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Usage
|
|
349
|
+
<AutomationWrapper parameterId="gain">
|
|
350
|
+
{({ isHighlighted, onClick, onContextMenu }) => (
|
|
351
|
+
<Knob
|
|
352
|
+
value={value}
|
|
353
|
+
onChange={onChange}
|
|
354
|
+
onClick={onClick}
|
|
355
|
+
onContextMenu={onContextMenu}
|
|
356
|
+
className={clsx({ 'highlighted': isHighlighted })}
|
|
357
|
+
/>
|
|
358
|
+
)}
|
|
359
|
+
</AutomationWrapper>
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## Following Existing Component Design Rules
|
|
363
|
+
|
|
364
|
+
### Study Existing Patterns
|
|
365
|
+
|
|
366
|
+
**Rule**: Study existing components to understand design patterns.
|
|
367
|
+
|
|
368
|
+
**Checklist**:
|
|
369
|
+
- [ ] Review similar components in codebase
|
|
370
|
+
- [ ] Understand prop naming conventions
|
|
371
|
+
- [ ] Follow styling patterns (TailwindCSS classes)
|
|
372
|
+
- [ ] Match component structure (imports, types, hooks, handlers, render)
|
|
373
|
+
- [ ] Use same utility functions (`twMerge`, `clsx`)
|
|
374
|
+
|
|
375
|
+
### Example: Following Button Pattern
|
|
376
|
+
|
|
377
|
+
**Existing Pattern**:
|
|
378
|
+
```typescript
|
|
379
|
+
// Existing AppButton component
|
|
380
|
+
export interface AppButtonProps {
|
|
381
|
+
disable?: boolean;
|
|
382
|
+
selected?: boolean;
|
|
383
|
+
className?: string;
|
|
384
|
+
onClick?: () => void;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function AppButton({
|
|
388
|
+
disable = false,
|
|
389
|
+
selected = false,
|
|
390
|
+
className,
|
|
391
|
+
onClick,
|
|
392
|
+
children,
|
|
393
|
+
}: AppButtonProps): JSX.Element {
|
|
394
|
+
return (
|
|
395
|
+
<button
|
|
396
|
+
className={twMerge(
|
|
397
|
+
'x-btn',
|
|
398
|
+
{
|
|
399
|
+
'x-btn-disabled': disable,
|
|
400
|
+
'x-btn-selected': selected,
|
|
401
|
+
},
|
|
402
|
+
className
|
|
403
|
+
)}
|
|
404
|
+
disabled={disable}
|
|
405
|
+
onClick={onClick}
|
|
406
|
+
>
|
|
407
|
+
{children}
|
|
408
|
+
</button>
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**New Component Following Pattern**:
|
|
414
|
+
```typescript
|
|
415
|
+
// New IconButton following same pattern
|
|
416
|
+
export interface IconButtonProps {
|
|
417
|
+
disable?: boolean;
|
|
418
|
+
selected?: boolean;
|
|
419
|
+
className?: string;
|
|
420
|
+
onClick?: () => void;
|
|
421
|
+
icon: React.ReactNode;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function IconButton({
|
|
425
|
+
disable = false,
|
|
426
|
+
selected = false,
|
|
427
|
+
className,
|
|
428
|
+
onClick,
|
|
429
|
+
icon,
|
|
430
|
+
}: IconButtonProps): JSX.Element {
|
|
431
|
+
return (
|
|
432
|
+
<button
|
|
433
|
+
className={twMerge(
|
|
434
|
+
'x-btn-icon',
|
|
435
|
+
{
|
|
436
|
+
'x-btn-icon-disabled': disable,
|
|
437
|
+
'x-btn-icon-selected': selected,
|
|
438
|
+
},
|
|
439
|
+
className
|
|
440
|
+
)}
|
|
441
|
+
disabled={disable}
|
|
442
|
+
onClick={onClick}
|
|
443
|
+
>
|
|
444
|
+
{icon}
|
|
445
|
+
</button>
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## Component Library Integration
|
|
451
|
+
|
|
452
|
+
### Using Internal Component Library
|
|
453
|
+
|
|
454
|
+
**Rule**: Prefer components from `@positivegrid/pg-react-ui-library` when available.
|
|
455
|
+
|
|
456
|
+
**Example**:
|
|
457
|
+
```typescript
|
|
458
|
+
import { Button, Input, Select } from '@positivegrid/pg-react-ui-library';
|
|
459
|
+
|
|
460
|
+
function Form() {
|
|
461
|
+
return (
|
|
462
|
+
<form>
|
|
463
|
+
<Input placeholder="Name" />
|
|
464
|
+
<Select options={options} />
|
|
465
|
+
<Button onClick={handleSubmit}>Submit</Button>
|
|
466
|
+
</form>
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Extending Library Components
|
|
472
|
+
|
|
473
|
+
**Rule**: Extend library components when customization is needed.
|
|
474
|
+
|
|
475
|
+
**Example**:
|
|
476
|
+
```typescript
|
|
477
|
+
import { Button as BaseButton } from '@positivegrid/pg-react-ui-library';
|
|
478
|
+
import { twMerge } from 'tailwind-merge';
|
|
479
|
+
|
|
480
|
+
interface CustomButtonProps extends React.ComponentProps<typeof BaseButton> {
|
|
481
|
+
customVariant?: 'special';
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function CustomButton({
|
|
485
|
+
customVariant,
|
|
486
|
+
className,
|
|
487
|
+
...props
|
|
488
|
+
}: CustomButtonProps): JSX.Element {
|
|
489
|
+
return (
|
|
490
|
+
<BaseButton
|
|
491
|
+
className={twMerge(
|
|
492
|
+
customVariant === 'special' && 'custom-special-style',
|
|
493
|
+
className
|
|
494
|
+
)}
|
|
495
|
+
{...props}
|
|
496
|
+
/>
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## Avoiding Duplicate Development
|
|
502
|
+
|
|
503
|
+
### Component Search Checklist
|
|
504
|
+
|
|
505
|
+
Before creating a new component:
|
|
506
|
+
|
|
507
|
+
- [ ] Search codebase for similar functionality
|
|
508
|
+
- [ ] Check `components/common/` directory
|
|
509
|
+
- [ ] Review `components/dumbs/` for presentational components
|
|
510
|
+
- [ ] Check `@positivegrid/pg-react-ui-library`
|
|
511
|
+
- [ ] Review recent PRs for similar components
|
|
512
|
+
- [ ] Ask team if component exists elsewhere
|
|
513
|
+
|
|
514
|
+
### Refactoring Existing Components
|
|
515
|
+
|
|
516
|
+
**Rule**: Refactor existing components instead of creating duplicates.
|
|
517
|
+
|
|
518
|
+
**Example**:
|
|
519
|
+
```typescript
|
|
520
|
+
// Instead of creating new component
|
|
521
|
+
function NewButton() {
|
|
522
|
+
// Similar to existing AppButton
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Refactor existing component
|
|
526
|
+
export interface AppButtonProps {
|
|
527
|
+
variant?: 'primary' | 'secondary'; // Add variant support
|
|
528
|
+
size?: 'small' | 'medium' | 'large'; // Add size support
|
|
529
|
+
// ... existing props
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function AppButton({
|
|
533
|
+
variant = 'primary',
|
|
534
|
+
size = 'medium',
|
|
535
|
+
...existingProps
|
|
536
|
+
}: AppButtonProps): JSX.Element {
|
|
537
|
+
// Extend existing implementation
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
## Summary Checklist
|
|
542
|
+
|
|
543
|
+
When creating or using components, ensure:
|
|
544
|
+
|
|
545
|
+
- [ ] Existing components checked before creating new ones
|
|
546
|
+
- [ ] Variants designed with manageable combinations (< 20 total)
|
|
547
|
+
- [ ] Variant dimensions limited (2-3 per dimension)
|
|
548
|
+
- [ ] Component follows existing design patterns
|
|
549
|
+
- [ ] Props allow extension when needed
|
|
550
|
+
- [ ] Composition preferred over complex variants
|
|
551
|
+
- [ ] Component library components used when available
|
|
552
|
+
- [ ] No duplicate components created
|
|
553
|
+
- [ ] Existing components refactored instead of duplicated
|
|
554
|
+
|
|
555
|
+
## References
|
|
556
|
+
|
|
557
|
+
- Project Coding Standards: `desktop-team-documentation/instructions/coding-conventions/frontend.md`
|
|
558
|
+
- [Code Organization Guidelines](./code-organization.md)
|
|
559
|
+
- [Type Safety Guidelines](./type-safety.md)
|