@spaced-out/ui-design-system 0.5.21 → 0.5.22

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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [0.5.22](https://github.com/spaced-out/ui-design-system/compare/v0.5.21...v0.5.22) (2025-11-12)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * add context aware results and utils and types info ([#431](https://github.com/spaced-out/ui-design-system/issues/431)) ([743fecf](https://github.com/spaced-out/ui-design-system/commit/743fecf93625edd13800e345c408343eff773748))
11
+
5
12
  ### [0.5.21](https://github.com/spaced-out/ui-design-system/compare/v0.5.20...v0.5.21) (2025-11-12)
6
13
 
7
14
 
@@ -42,7 +42,34 @@ function getDirectories(path) {
42
42
  }
43
43
 
44
44
  /**
45
- * Extract all components with their files
45
+ * Get all files recursively in a directory
46
+ */
47
+ function getAllFilesRecursively(dirPath, filesList = [], baseDir = dirPath) {
48
+ try {
49
+ const files = readdirSync(dirPath);
50
+
51
+ files.forEach(file => {
52
+ if (file.startsWith('.')) return;
53
+
54
+ const filePath = join(dirPath, file);
55
+ const stat = statSync(filePath);
56
+
57
+ if (stat.isDirectory()) {
58
+ getAllFilesRecursively(filePath, filesList, baseDir);
59
+ } else {
60
+ const relativePath = filePath.replace(baseDir + '/', '');
61
+ filesList.push(relativePath);
62
+ }
63
+ });
64
+ } catch (error) {
65
+ // Ignore errors for non-existent directories
66
+ }
67
+
68
+ return filesList;
69
+ }
70
+
71
+ /**
72
+ * Extract all components with their files (including sub-components)
46
73
  */
47
74
  function buildComponentsData() {
48
75
  console.log('📦 Extracting components...');
@@ -59,24 +86,58 @@ function buildComponentsData() {
59
86
  for (const componentName of componentDirs) {
60
87
  const componentDir = join(componentsPath, componentName);
61
88
 
89
+ // Get all files in the component directory
90
+ const allFiles = getAllFilesRecursively(componentDir);
91
+
92
+ // Extract main component files
62
93
  const mainTsx = join(componentDir, `${componentName}.tsx`);
63
94
  const mainTs = join(componentDir, `${componentName}.ts`);
95
+ const mainContent = safeReadFile(mainTsx) || safeReadFile(mainTs);
64
96
 
97
+ // Extract story files
65
98
  const storyTsx = join(componentDir, `${componentName}.stories.tsx`);
66
99
  const storyTs = join(componentDir, `${componentName}.stories.ts`);
100
+ const storyContent = safeReadFile(storyTsx) || safeReadFile(storyTs);
67
101
 
102
+ // Extract CSS file
68
103
  const cssFile = join(componentDir, `${componentName}.module.css`);
104
+ const cssContent = safeReadFile(cssFile);
69
105
 
106
+ // Extract index file
70
107
  const indexFile = join(componentDir, 'index.ts');
71
-
72
- const mainContent = safeReadFile(mainTsx) || safeReadFile(mainTs);
73
- const storyContent = safeReadFile(storyTsx) || safeReadFile(storyTs);
74
- const cssContent = safeReadFile(cssFile);
75
108
  const indexContent = safeReadFile(indexFile);
76
109
 
77
- const allFiles = existsSync(componentDir)
78
- ? readdirSync(componentDir).filter(f => !f.startsWith('.'))
79
- : [];
110
+ // Extract all additional TypeScript/TSX files (sub-components)
111
+ const additionalFiles = {};
112
+ for (const file of allFiles) {
113
+ // Skip main files we already extracted
114
+ if (
115
+ file === `${componentName}.tsx` ||
116
+ file === `${componentName}.ts` ||
117
+ file === `${componentName}.stories.tsx` ||
118
+ file === `${componentName}.stories.ts` ||
119
+ file === `${componentName}.module.css` ||
120
+ file === 'index.ts' ||
121
+ file.endsWith('.module.css') ||
122
+ file.endsWith('.stories.tsx') ||
123
+ file.endsWith('.stories.ts') ||
124
+ file.endsWith('.stories.module.css')
125
+ ) {
126
+ continue;
127
+ }
128
+
129
+ // Only include .tsx and .ts files (sub-components)
130
+ if (file.endsWith('.tsx') || file.endsWith('.ts')) {
131
+ const fullPath = join(componentDir, file);
132
+ const content = safeReadFile(fullPath);
133
+ if (content) {
134
+ additionalFiles[file] = {
135
+ path: file,
136
+ content: content
137
+ };
138
+ }
139
+ }
140
+ }
80
141
 
81
142
  components[componentName] = {
82
143
  name: componentName,
@@ -86,6 +147,7 @@ function buildComponentsData() {
86
147
  story: storyContent ? { path: `${componentName}.stories.tsx`, content: storyContent } : null,
87
148
  css: cssContent ? { path: `${componentName}.module.css`, content: cssContent } : null,
88
149
  index: indexContent ? { path: 'index.ts', content: indexContent } : null,
150
+ additional: additionalFiles,
89
151
  },
90
152
  allFiles,
91
153
  };
@@ -190,6 +252,94 @@ function buildTokensData() {
190
252
  return tokens;
191
253
  }
192
254
 
255
+ /**
256
+ * Extract all utils
257
+ */
258
+ function buildUtilsData() {
259
+ console.log('🔧 Extracting utils...');
260
+ const utilsPath = join(DESIGN_SYSTEM_PATH, 'src/utils');
261
+ const utils = {};
262
+
263
+ if (!existsSync(utilsPath)) {
264
+ console.warn('⚠️ Utils path not found');
265
+ return utils;
266
+ }
267
+
268
+ const utilDirs = getDirectories(utilsPath);
269
+
270
+ for (const utilName of utilDirs) {
271
+ const utilDir = join(utilsPath, utilName);
272
+
273
+ // Get all files in the util directory
274
+ const allFiles = getAllFilesRecursively(utilDir);
275
+
276
+ // Read all TypeScript files
277
+ const files = {};
278
+ for (const file of allFiles) {
279
+ if ((file.endsWith('.ts') || file.endsWith('.tsx')) && !file.endsWith('.d.ts')) {
280
+ const fullPath = join(utilDir, file);
281
+ const content = safeReadFile(fullPath);
282
+ if (content) {
283
+ files[file] = {
284
+ path: file,
285
+ content: content
286
+ };
287
+ }
288
+ }
289
+ }
290
+
291
+ utils[utilName] = {
292
+ name: utilName,
293
+ path: `src/utils/${utilName}`,
294
+ files: files,
295
+ allFiles: allFiles,
296
+ };
297
+ }
298
+
299
+ console.log(` ✅ Extracted ${Object.keys(utils).length} util modules`);
300
+ return utils;
301
+ }
302
+
303
+ /**
304
+ * Extract all types
305
+ */
306
+ function buildTypesData() {
307
+ console.log('📐 Extracting types...');
308
+ const typesPath = join(DESIGN_SYSTEM_PATH, 'src/types');
309
+ const types = {};
310
+
311
+ if (!existsSync(typesPath)) {
312
+ console.warn('⚠️ Types path not found');
313
+ return types;
314
+ }
315
+
316
+ try {
317
+ const files = readdirSync(typesPath).filter(f =>
318
+ !f.startsWith('.') &&
319
+ (f.endsWith('.ts') || f.endsWith('.tsx')) &&
320
+ !f.endsWith('.d.ts')
321
+ );
322
+
323
+ for (const file of files) {
324
+ const filePath = join(typesPath, file);
325
+ const content = safeReadFile(filePath);
326
+ if (content) {
327
+ const typeName = file.replace(/\.(ts|tsx)$/, '');
328
+ types[typeName] = {
329
+ name: typeName,
330
+ path: `src/types/${file}`,
331
+ content: content,
332
+ };
333
+ }
334
+ }
335
+ } catch (error) {
336
+ console.warn(` ⚠️ Error reading types:`, error.message);
337
+ }
338
+
339
+ console.log(` ✅ Extracted ${Object.keys(types).length} type files`);
340
+ return types;
341
+ }
342
+
193
343
  /**
194
344
  * Get package version
195
345
  */
@@ -217,6 +367,8 @@ function build() {
217
367
  components: buildComponentsData(),
218
368
  hooks: buildHooksData(),
219
369
  tokens: buildTokensData(),
370
+ utils: buildUtilsData(),
371
+ types: buildTypesData(),
220
372
  };
221
373
 
222
374
  // Create output directory if it doesn't exist
@@ -232,6 +384,8 @@ function build() {
232
384
  console.log(` - Components: ${Object.keys(data.components).length}`);
233
385
  console.log(` - Hooks: ${Object.keys(data.hooks).length}`);
234
386
  console.log(` - Token categories: ${Object.keys(data.tokens).length}`);
387
+ console.log(` - Utils: ${Object.keys(data.utils).length}`);
388
+ console.log(` - Types: ${Object.keys(data.types).length}`);
235
389
  console.log(` - Version: ${data.metadata.version}`);
236
390
  console.log(` - Output: ${OUTPUT_FILE}`);
237
391
  console.log(` - Size: ${(Buffer.byteLength(JSON.stringify(data)) / 1024 / 1024).toFixed(2)} MB\n`);
package/mcp/index.js CHANGED
@@ -51,6 +51,8 @@ console.error('✅ Loaded Genesis design system data');
51
51
  console.error(` Version: ${designSystemData.metadata.version}`);
52
52
  console.error(` Components: ${Object.keys(designSystemData.components).length}`);
53
53
  console.error(` Hooks: ${Object.keys(designSystemData.hooks).length}`);
54
+ console.error(` Utils: ${Object.keys(designSystemData.utils || {}).length}`);
55
+ console.error(` Types: ${Object.keys(designSystemData.types || {}).length}`);
54
56
  console.error(` Built: ${designSystemData.metadata.buildDate}`);
55
57
 
56
58
  /**
@@ -67,6 +69,20 @@ function getAllHooks() {
67
69
  return Object.keys(designSystemData.hooks).sort();
68
70
  }
69
71
 
72
+ /**
73
+ * Get all utils
74
+ */
75
+ function getAllUtils() {
76
+ return Object.keys(designSystemData.utils || {}).sort();
77
+ }
78
+
79
+ /**
80
+ * Get all types
81
+ */
82
+ function getAllTypes() {
83
+ return Object.keys(designSystemData.types || {}).sort();
84
+ }
85
+
70
86
  /**
71
87
  * Get component details
72
88
  */
@@ -81,6 +97,20 @@ function getHookDetails(hookName) {
81
97
  return designSystemData.hooks[hookName] || null;
82
98
  }
83
99
 
100
+ /**
101
+ * Get util details
102
+ */
103
+ function getUtilDetails(utilName) {
104
+ return designSystemData.utils?.[utilName] || null;
105
+ }
106
+
107
+ /**
108
+ * Get type details
109
+ */
110
+ function getTypeDetails(typeName) {
111
+ return designSystemData.types?.[typeName] || null;
112
+ }
113
+
84
114
  /**
85
115
  * Get all design tokens
86
116
  */
@@ -126,8 +156,35 @@ function searchComponents(query) {
126
156
  function getCSSModuleGuidelines() {
127
157
  return {
128
158
  description: 'Comprehensive CSS Module guidelines and best practices for the Genesis Design System',
159
+ contextNote: {
160
+ critical: '⚠️ IMPORTANT: Patterns differ based on context',
161
+ insideDesignSystem: 'Use .module.css files with PascalCase naming and relative token imports',
162
+ usingDesignSystem: 'Use .css files (no .module) with kebab-case naming and @spaced-out/ui-design-system imports',
163
+ recommendation: 'Call get_css_module_import_patterns tool for detailed context-specific examples',
164
+ },
129
165
  typescriptRequirement: '⚠️ CRITICAL: Use pure TypeScript only. NO Flow types (Flow.AbstractComponent). Use React.forwardRef<HTMLElement, Props> pattern.',
166
+ cssModuleImportPattern: {
167
+ critical: '🚨 MANDATORY: ALWAYS import CSS Modules as a default import with "css" as the variable name',
168
+ insideDesignSystem: 'import css from \'./ComponentName.module.css\';',
169
+ usingDesignSystem: 'import css from \'./component-name.css\';',
170
+ incorrect: [
171
+ 'import \'./ComponentName.module.css\'; // ❌ WRONG - No side-effect imports',
172
+ 'import * as css from \'./ComponentName.module.css\'; // ❌ WRONG - No namespace imports',
173
+ 'import styles from \'./ComponentName.module.css\'; // ❌ WRONG - Must use "css" as variable name',
174
+ ],
175
+ classNameUsage: {
176
+ correct: 'className={css.tableHeaderContent} // Use camelCase property access',
177
+ incorrect: [
178
+ 'className="table-header-content" // ❌ WRONG - No string literals',
179
+ 'className="tableHeaderContent" // ❌ WRONG - No string literals',
180
+ 'className={\'table-header-content\'} // ❌ WRONG - No string literals in braces',
181
+ ],
182
+ },
183
+ explanation: 'CSS Modules require a default import to access class names as properties. The variable MUST be named "css" for consistency across the codebase. Class names are accessed as camelCase properties (css.myClass) not as string literals.',
184
+ },
130
185
  criticalRules: [
186
+ '🚨 MANDATORY: Import CSS Modules as: import css from \'./Component.module.css\'',
187
+ '🚨 MANDATORY: Use className={css.className} NOT className="class-name"',
131
188
  '⚠️ ALWAYS use design tokens instead of hardcoded values',
132
189
  '⚠️ Use BEM modifier pattern: .baseClass.modifier NOT .baseClass--modifier',
133
190
  '⚠️ Use descendant selectors for child element styling: .container .childClass NOT :global() selectors',
@@ -231,6 +288,20 @@ function getCSSModuleGuidelines() {
231
288
  },
232
289
  realWorldExample: {
233
290
  description: 'Complete example with state-based styling for multiple child elements',
291
+ importPattern: `// 🚨 MANDATORY: Import CSS Module as default with "css" variable name
292
+ import css from './ComponentName.module.css';
293
+
294
+ // Usage in JSX:
295
+ <div className={css.wrapper}>
296
+ <div className={css.header}>
297
+ <span className={css.title}>Title</span>
298
+ </div>
299
+ </div>
300
+
301
+ // ❌ NEVER DO THIS:
302
+ // import './ComponentName.module.css';
303
+ // <div className="wrapper">
304
+ // <div className={'wrapper'}>`,
234
305
  code: `@value (
235
306
  colorBorderPrimary,
236
307
  colorBackgroundTertiary,
@@ -295,6 +366,16 @@ function getCSSModuleGuidelines() {
295
366
  }`,
296
367
  },
297
368
  commonMistakes: [
369
+ {
370
+ mistake: '🚨 CRITICAL: Incorrect CSS Module import or usage',
371
+ wrong: `import './Component.module.css'; // Side-effect import
372
+ import styles from './Component.module.css'; // Wrong variable name
373
+ <div className="wrapper"> // String literal
374
+ <div className={'wrapper'}> // String literal in braces`,
375
+ right: `import css from './Component.module.css'; // Default import with "css" variable
376
+ <div className={css.wrapper}> // Property access with camelCase`,
377
+ explanation: 'CSS Modules MUST be imported as default with variable name "css" and used via property access, never as string literals.',
378
+ },
298
379
  {
299
380
  mistake: 'Using hardcoded pixel values',
300
381
  wrong: 'width: 58px; height: 78px; padding: 12px 16px;',
@@ -324,6 +405,346 @@ function getCSSModuleGuidelines() {
324
405
  };
325
406
  }
326
407
 
408
+ /**
409
+ * Get CSS Module import and usage patterns
410
+ */
411
+ function getCSSModuleImportPatterns() {
412
+ return {
413
+ title: '🚨 MANDATORY CSS Module Import and Usage Pattern',
414
+ critical: 'This pattern is REQUIRED but differs based on context: developing INSIDE the design system vs USING the design system in another app.',
415
+
416
+ contextWarning: {
417
+ title: '⚠️ CRITICAL: Two Different Contexts',
418
+ description: 'The patterns differ significantly based on where you are developing',
419
+ contexts: {
420
+ insideDesignSystem: 'Building components IN the ui-design-system repository',
421
+ usingDesignSystem: 'Building features in an app that USES @spaced-out/ui-design-system',
422
+ },
423
+ howToKnow: 'Check package.json: If it has "name": "@spaced-out/ui-design-system", you are INSIDE. If it has "@spaced-out/ui-design-system" as a dependency, you are USING it.',
424
+ },
425
+
426
+ insideDesignSystem: {
427
+ title: '📦 Context: Developing INSIDE the Design System Repository',
428
+ fileNaming: {
429
+ tsx: 'ComponentName.tsx (PascalCase)',
430
+ css: 'ComponentName.module.css (PascalCase + .module.css)',
431
+ examples: ['DataTable.tsx + DataTable.module.css', 'UserProfile.tsx + UserProfile.module.css'],
432
+ },
433
+ cssImport: {
434
+ pattern: "import css from './ComponentName.module.css';",
435
+ examples: [
436
+ "import css from './DataTable.module.css';",
437
+ "import css from './UserProfile.module.css';",
438
+ ],
439
+ },
440
+ tokenImports: {
441
+ pattern: "@value (tokenName) from '../../styles/variables/_category.css';",
442
+ explanation: 'Use RELATIVE paths to the styles directory',
443
+ examples: [
444
+ "@value (size480) from '../../styles/variables/_size.css';",
445
+ "@value (colorPrimary) from '../../styles/variables/_color.css';",
446
+ "@value (spaceMedium) from '../../styles/variables/_space.css';",
447
+ ],
448
+ },
449
+ componentImports: {
450
+ pattern: "from 'src/components/ComponentName';",
451
+ examples: [
452
+ "import {Button} from 'src/components/Button';",
453
+ "import {Table} from 'src/components/Table';",
454
+ ],
455
+ },
456
+ utilImports: {
457
+ pattern: "from 'src/utils/utilName';",
458
+ examples: [
459
+ "import classify from 'src/utils/classify';",
460
+ "import {generateTestId} from 'src/utils/qa';",
461
+ ],
462
+ },
463
+ },
464
+
465
+ usingDesignSystem: {
466
+ title: '🏗️ Context: Using Design System in Another Application',
467
+ fileNaming: {
468
+ tsx: 'component-name.tsx (kebab-case)',
469
+ css: 'component-name.css (kebab-case, NO .module.css suffix)',
470
+ examples: ['data-table.tsx + data-table.css', 'user-profile.tsx + user-profile.css'],
471
+ critical: '🚨 File is .css NOT .module.css',
472
+ },
473
+ cssImport: {
474
+ pattern: "import css from './component-name.css';",
475
+ examples: [
476
+ "import css from './data-table.css';",
477
+ "import css from './user-profile.css';",
478
+ ],
479
+ note: 'Notice: NO .module.css suffix in the filename',
480
+ },
481
+ tokenImports: {
482
+ pattern: "@value (tokenName) from '@spaced-out/ui-design-system/lib/styles/variables/_category.css';",
483
+ explanation: 'Use NPM PACKAGE path, not relative paths',
484
+ examples: [
485
+ "@value (size480) from '@spaced-out/ui-design-system/lib/styles/variables/_size.css';",
486
+ "@value (colorPrimary) from '@spaced-out/ui-design-system/lib/styles/variables/_color.css';",
487
+ "@value (spaceMedium) from '@spaced-out/ui-design-system/lib/styles/variables/_space.css';",
488
+ ],
489
+ critical: '🚨 Must use @spaced-out/ui-design-system/lib/styles/... NOT relative paths',
490
+ },
491
+ componentImports: {
492
+ pattern: "from '@spaced-out/ui-design-system/lib/components/ComponentName';",
493
+ examples: [
494
+ "import {Button} from '@spaced-out/ui-design-system/lib/components/Button';",
495
+ "import {Table} from '@spaced-out/ui-design-system/lib/components/Table';",
496
+ ],
497
+ },
498
+ utilImports: {
499
+ pattern: "from '@spaced-out/ui-design-system/lib/utils/utilName';",
500
+ examples: [
501
+ "import classify from '@spaced-out/ui-design-system/lib/utils/classify';",
502
+ "import {generateTestId} from '@spaced-out/ui-design-system/lib/utils/qa';",
503
+ ],
504
+ },
505
+ },
506
+
507
+ comparisonTable: {
508
+ title: 'Side-by-Side Comparison',
509
+ aspect: {
510
+ tsxFileName: {
511
+ insideDS: 'ComponentName.tsx (PascalCase)',
512
+ usingDS: 'component-name.tsx (kebab-case)',
513
+ },
514
+ cssFileName: {
515
+ insideDS: 'ComponentName.module.css',
516
+ usingDS: 'component-name.css (NO .module)',
517
+ },
518
+ cssImport: {
519
+ insideDS: "import css from './ComponentName.module.css';",
520
+ usingDS: "import css from './component-name.css';",
521
+ },
522
+ tokenImport: {
523
+ insideDS: "@value (size480) from '../../styles/variables/_size.css';",
524
+ usingDS: "@value (size480) from '@spaced-out/ui-design-system/lib/styles/variables/_size.css';",
525
+ },
526
+ componentImport: {
527
+ insideDS: "import {Button} from 'src/components/Button';",
528
+ usingDS: "import {Button} from '@spaced-out/ui-design-system/lib/components/Button';",
529
+ },
530
+ },
531
+ },
532
+
533
+ correctImport: {
534
+ pattern: 'import css from \'./ComponentName.module.css\';',
535
+ explanation: 'CSS Modules MUST be imported as a default import with the variable name "css"',
536
+ examples: [
537
+ 'import css from \'./DataTable.module.css\';',
538
+ 'import css from \'./UserProfile.module.css\';',
539
+ 'import css from \'./NavigationBar.module.css\';',
540
+ ],
541
+ },
542
+
543
+ incorrectImports: {
544
+ sideEffect: {
545
+ code: 'import \'./ComponentName.module.css\';',
546
+ error: '❌ WRONG: Side-effect imports do not provide access to class names',
547
+ why: 'This imports the CSS but you cannot access the class names in your component',
548
+ },
549
+ namespace: {
550
+ code: 'import * as css from \'./ComponentName.module.css\';',
551
+ error: '❌ WRONG: Namespace imports are not supported for CSS Modules',
552
+ why: 'CSS Modules use default exports, not named exports',
553
+ },
554
+ wrongVariableName: {
555
+ code: 'import styles from \'./ComponentName.module.css\';',
556
+ error: '❌ WRONG: Variable name must be "css" not "styles" or any other name',
557
+ why: 'Consistency across the codebase requires using "css" as the variable name',
558
+ },
559
+ },
560
+
561
+ correctUsage: {
562
+ pattern: 'className={css.className}',
563
+ explanation: 'Class names are accessed as camelCase properties of the css object',
564
+ examples: [
565
+ '<div className={css.wrapper}>',
566
+ '<div className={css.tableHeader}>',
567
+ '<button className={css.submitButton}>',
568
+ '<span className={css.errorMessage}>',
569
+ ],
570
+ withClassify: [
571
+ 'className={classify(css.wrapper, css.active)}',
572
+ 'className={classify(css.button, { [css.disabled]: isDisabled })}',
573
+ 'className={classify(css.container, classNames?.wrapper)}',
574
+ ],
575
+ },
576
+
577
+ incorrectUsage: {
578
+ stringLiteral: {
579
+ code: '<div className="wrapper">',
580
+ error: '❌ WRONG: Never use string literals for class names',
581
+ why: 'CSS Modules provide scoped class names that must be accessed via the css object',
582
+ },
583
+ stringInBraces: {
584
+ code: '<div className={\'wrapper\'}>',
585
+ error: '❌ WRONG: String literals in braces are still wrong',
586
+ why: 'You must use the css object property access: className={css.wrapper}',
587
+ },
588
+ kebabCase: {
589
+ code: '<div className={css[\'table-header\']}>',
590
+ error: '❌ WRONG: Use camelCase properties, not kebab-case strings',
591
+ why: 'CSS class names are automatically converted to camelCase properties',
592
+ },
593
+ },
594
+
595
+ cssFileNaming: {
596
+ inDesignSystem: {
597
+ pattern: 'ComponentName.module.css',
598
+ examples: [
599
+ 'DataTable.module.css',
600
+ 'UserProfile.module.css',
601
+ 'NavigationBar.module.css',
602
+ ],
603
+ },
604
+ inMainApp: {
605
+ pattern: 'component-name.module.css (kebab-case)',
606
+ examples: [
607
+ 'data-table.module.css',
608
+ 'user-profile.module.css',
609
+ 'navigation-bar.module.css',
610
+ ],
611
+ note: 'The main application uses kebab-case for file names',
612
+ },
613
+ },
614
+
615
+ cssSyntax: {
616
+ classDefinition: 'Use camelCase for class names in CSS files',
617
+ correct: [
618
+ '.wrapper { }',
619
+ '.tableHeader { }',
620
+ '.submitButton { }',
621
+ '.errorMessage { }',
622
+ ],
623
+ incorrect: [
624
+ '.table-header { } // ❌ Use .tableHeader instead',
625
+ '.submit_button { } // ❌ Use .submitButton instead',
626
+ ],
627
+ },
628
+
629
+ completeExamples: {
630
+ insideDesignSystem: {
631
+ title: 'Complete Example: Building INSIDE Design System',
632
+ tsx: `// DataTable.tsx (in ui-design-system repo)
633
+ import * as React from 'react';
634
+ import classify from 'src/utils/classify';
635
+ import {generateTestId} from 'src/utils/qa';
636
+ import {Button} from 'src/components/Button';
637
+ import {SearchInput} from 'src/components/SearchInput';
638
+
639
+ // 📦 INSIDE DESIGN SYSTEM: Import with .module.css and relative path
640
+ import css from './DataTable.module.css';
641
+
642
+ export const DataTable = () => (
643
+ <div className={css.wrapper}>
644
+ <div className={css.header}>
645
+ <SearchInput className={css.search} />
646
+ <Button>Filter</Button>
647
+ </div>
648
+ <table className={css.table}>
649
+ <thead className={css.thead}>
650
+ <tr>
651
+ <th className={css.th}>Name</th>
652
+ <th className={css.th}>Status</th>
653
+ </tr>
654
+ </thead>
655
+ </table>
656
+ </div>
657
+ );`,
658
+ css: `/* DataTable.module.css (in ui-design-system repo) */
659
+ /* 📦 INSIDE DESIGN SYSTEM: Import tokens with RELATIVE paths */
660
+ @value (
661
+ colorBorderPrimary,
662
+ colorBackgroundTertiary
663
+ ) from '../../styles/variables/_color.css';
664
+
665
+ @value (
666
+ spaceSmall,
667
+ spaceMedium
668
+ ) from '../../styles/variables/_space.css';
669
+
670
+ @value (size480) from '../../styles/variables/_size.css';
671
+
672
+ .wrapper {
673
+ display: flex;
674
+ flex-direction: column;
675
+ width: size480;
676
+ }
677
+
678
+ .header {
679
+ padding: spaceMedium;
680
+ background: colorBackgroundTertiary;
681
+ }
682
+
683
+ .table {
684
+ border: 1px solid colorBorderPrimary;
685
+ }`,
686
+ },
687
+ usingDesignSystem: {
688
+ title: 'Complete Example: USING Design System in Another App',
689
+ tsx: `// data-table.tsx (in your app repo, NOT in ui-design-system)
690
+ import * as React from 'react';
691
+ import classify from '@spaced-out/ui-design-system/lib/utils/classify';
692
+ import {generateTestId} from '@spaced-out/ui-design-system/lib/utils/qa';
693
+ import {Button} from '@spaced-out/ui-design-system/lib/components/Button';
694
+ import {SearchInput} from '@spaced-out/ui-design-system/lib/components/SearchInput';
695
+
696
+ // 🏗️ USING DESIGN SYSTEM: Import WITHOUT .module.css, kebab-case filename
697
+ import css from './data-table.css';
698
+
699
+ export const DataTable = () => (
700
+ <div className={css.wrapper}>
701
+ <div className={css.header}>
702
+ <SearchInput className={css.search} />
703
+ <Button>Filter</Button>
704
+ </div>
705
+ <table className={css.table}>
706
+ <thead className={css.thead}>
707
+ <tr>
708
+ <th className={css.th}>Name</th>
709
+ <th className={css.th}>Status</th>
710
+ </tr>
711
+ </thead>
712
+ </table>
713
+ </div>
714
+ );`,
715
+ css: `/* data-table.css (in your app repo, NOT in ui-design-system) */
716
+ /* 🏗️ USING DESIGN SYSTEM: Import tokens from NPM PACKAGE path */
717
+ @value (
718
+ colorBorderPrimary,
719
+ colorBackgroundTertiary
720
+ ) from '@spaced-out/ui-design-system/lib/styles/variables/_color.css';
721
+
722
+ @value (
723
+ spaceSmall,
724
+ spaceMedium
725
+ ) from '@spaced-out/ui-design-system/lib/styles/variables/_space.css';
726
+
727
+ @value (size480) from '@spaced-out/ui-design-system/lib/styles/variables/_size.css';
728
+
729
+ .wrapper {
730
+ display: flex;
731
+ flex-direction: column;
732
+ width: size480;
733
+ }
734
+
735
+ .header {
736
+ padding: spaceMedium;
737
+ background: colorBackgroundTertiary;
738
+ }
739
+
740
+ .table {
741
+ border: 1px solid colorBorderPrimary;
742
+ }`,
743
+ },
744
+ },
745
+ };
746
+ }
747
+
327
748
  /**
328
749
  * Get design token import guidelines
329
750
  */
@@ -483,12 +904,22 @@ function getComponentTemplate() {
483
904
  import classify from 'src/utils/classify';
484
905
  import {generateTestId} from 'src/utils/qa';
485
906
 
907
+ // 🚨 CRITICAL: CSS Modules MUST be imported as default import with variable name "css"
908
+ // ✅ Correct: import css from './ComponentName.module.css';
909
+ // ❌ WRONG: import './ComponentName.module.css';
910
+ // ❌ WRONG: import * as css from './ComponentName.module.css';
911
+ // ❌ WRONG: import styles from './ComponentName.module.css';
486
912
  import css from 'src/components/ComponentName/ComponentName.module.css';
487
913
 
488
914
  // IMPORTANT: Use pure TypeScript - NO Flow types
489
915
  // ✅ Correct: React.forwardRef<HTMLDivElement, Props>
490
916
  // ❌ Wrong: Flow.AbstractComponent<Props, HTMLDivElement>
491
917
 
918
+ // IMPORTANT: Use className with CSS Module property access
919
+ // ✅ Correct: className={css.wrapper}
920
+ // ❌ WRONG: className="wrapper"
921
+ // ❌ WRONG: className={'wrapper'}
922
+
492
923
  type ClassNames = Readonly<{
493
924
  wrapper?: string;
494
925
  }>;
@@ -669,6 +1100,8 @@ const server = new Server(
669
1100
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
670
1101
  const components = getAllComponents();
671
1102
  const hooks = getAllHooks();
1103
+ const utils = getAllUtils();
1104
+ const types = getAllTypes();
672
1105
 
673
1106
  const resources = [
674
1107
  {
@@ -689,6 +1122,18 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
689
1122
  mimeType: 'application/json',
690
1123
  description: `List of all ${hooks.length} available hooks`,
691
1124
  },
1125
+ {
1126
+ uri: 'genesis://utils',
1127
+ name: 'All Utils',
1128
+ mimeType: 'application/json',
1129
+ description: `List of all ${utils.length} available utility modules`,
1130
+ },
1131
+ {
1132
+ uri: 'genesis://types',
1133
+ name: 'All Types',
1134
+ mimeType: 'application/json',
1135
+ description: `List of all ${types.length} available type definitions`,
1136
+ },
692
1137
  {
693
1138
  uri: 'genesis://tokens',
694
1139
  name: 'Design Tokens',
@@ -717,6 +1162,26 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
717
1162
  });
718
1163
  });
719
1164
 
1165
+ // Add individual util resources
1166
+ utils.forEach(util => {
1167
+ resources.push({
1168
+ uri: `genesis://util/${util}`,
1169
+ name: `Util: ${util}`,
1170
+ mimeType: 'text/markdown',
1171
+ description: `Utility functions for ${util}`,
1172
+ });
1173
+ });
1174
+
1175
+ // Add individual type resources
1176
+ types.forEach(type => {
1177
+ resources.push({
1178
+ uri: `genesis://type/${type}`,
1179
+ name: `Type: ${type}`,
1180
+ mimeType: 'text/markdown',
1181
+ description: `Type definitions for ${type}`,
1182
+ });
1183
+ });
1184
+
720
1185
  return { resources };
721
1186
  });
722
1187
 
@@ -736,6 +1201,8 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
736
1201
 
737
1202
  - **Components:** ${Object.keys(designSystemData.components).length}
738
1203
  - **Hooks:** ${Object.keys(designSystemData.hooks).length}
1204
+ - **Utils:** ${Object.keys(designSystemData.utils || {}).length}
1205
+ - **Types:** ${Object.keys(designSystemData.types || {}).length}
739
1206
  - **Design Token Categories:** ${Object.keys(designSystemData.tokens).length}
740
1207
 
741
1208
  ## Available Components
@@ -746,6 +1213,14 @@ ${getAllComponents().map(c => `- ${c}`).join('\n')}
746
1213
 
747
1214
  ${getAllHooks().map(h => `- ${h}`).join('\n')}
748
1215
 
1216
+ ## Available Utils
1217
+
1218
+ ${getAllUtils().map(u => `- ${u}`).join('\n')}
1219
+
1220
+ ## Available Types
1221
+
1222
+ ${getAllTypes().map(t => `- ${t}`).join('\n')}
1223
+
749
1224
  ## Design Token Categories
750
1225
 
751
1226
  ${Object.keys(designSystemData.tokens).map(cat => `- **${cat}**: ${Object.keys(designSystemData.tokens[cat]).length} file(s)`).join('\n')}
@@ -788,6 +1263,32 @@ ${Object.keys(designSystemData.tokens).map(cat => `- **${cat}**: ${Object.keys(d
788
1263
  };
789
1264
  }
790
1265
 
1266
+ if (uri === 'genesis://utils') {
1267
+ const utils = getAllUtils();
1268
+ return {
1269
+ contents: [
1270
+ {
1271
+ uri,
1272
+ mimeType: 'application/json',
1273
+ text: JSON.stringify(utils, null, 2),
1274
+ },
1275
+ ],
1276
+ };
1277
+ }
1278
+
1279
+ if (uri === 'genesis://types') {
1280
+ const types = getAllTypes();
1281
+ return {
1282
+ contents: [
1283
+ {
1284
+ uri,
1285
+ mimeType: 'application/json',
1286
+ text: JSON.stringify(types, null, 2),
1287
+ },
1288
+ ],
1289
+ };
1290
+ }
1291
+
791
1292
  if (uri === 'genesis://tokens') {
792
1293
  const tokens = getAllDesignTokens();
793
1294
  return {
@@ -850,6 +1351,18 @@ ${Object.keys(designSystemData.tokens).map(cat => `- **${cat}**: ${Object.keys(d
850
1351
  markdown += '\n```\n\n';
851
1352
  }
852
1353
 
1354
+ // Display additional files (sub-components)
1355
+ if (details.files.additional && Object.keys(details.files.additional).length > 0) {
1356
+ markdown += `## Additional Files (Sub-components)\n\n`;
1357
+
1358
+ for (const [fileName, fileData] of Object.entries(details.files.additional)) {
1359
+ markdown += `### ${fileName}\n\n`;
1360
+ markdown += '```typescript\n';
1361
+ markdown += fileData.content;
1362
+ markdown += '\n```\n\n';
1363
+ }
1364
+ }
1365
+
853
1366
  return {
854
1367
  contents: [
855
1368
  {
@@ -898,6 +1411,67 @@ ${Object.keys(designSystemData.tokens).map(cat => `- **${cat}**: ${Object.keys(d
898
1411
  };
899
1412
  }
900
1413
 
1414
+ if (uri.startsWith('genesis://util/')) {
1415
+ const utilName = uri.replace('genesis://util/', '');
1416
+ const details = getUtilDetails(utilName);
1417
+
1418
+ if (!details) {
1419
+ throw new Error(`Util ${utilName} not found`);
1420
+ }
1421
+
1422
+ let markdown = `# ${utilName}\n\n`;
1423
+ markdown += `**Path:** \`${details.path}\`\n\n`;
1424
+ markdown += `**Files:** ${details.allFiles.join(', ')}\n\n`;
1425
+
1426
+ // Display all files in the util module
1427
+ if (details.files && Object.keys(details.files).length > 0) {
1428
+ markdown += `## Utility Files\n\n`;
1429
+
1430
+ for (const [fileName, fileData] of Object.entries(details.files)) {
1431
+ markdown += `### ${fileName}\n\n`;
1432
+ markdown += '```typescript\n';
1433
+ markdown += fileData.content;
1434
+ markdown += '\n```\n\n';
1435
+ }
1436
+ }
1437
+
1438
+ return {
1439
+ contents: [
1440
+ {
1441
+ uri,
1442
+ mimeType: 'text/markdown',
1443
+ text: markdown,
1444
+ },
1445
+ ],
1446
+ };
1447
+ }
1448
+
1449
+ if (uri.startsWith('genesis://type/')) {
1450
+ const typeName = uri.replace('genesis://type/', '');
1451
+ const details = getTypeDetails(typeName);
1452
+
1453
+ if (!details) {
1454
+ throw new Error(`Type ${typeName} not found`);
1455
+ }
1456
+
1457
+ let markdown = `# ${typeName}\n\n`;
1458
+ markdown += `**Path:** \`${details.path}\`\n\n`;
1459
+ markdown += `## Type Definitions\n\n`;
1460
+ markdown += '```typescript\n';
1461
+ markdown += details.content;
1462
+ markdown += '\n```\n\n';
1463
+
1464
+ return {
1465
+ contents: [
1466
+ {
1467
+ uri,
1468
+ mimeType: 'text/markdown',
1469
+ text: markdown,
1470
+ },
1471
+ ],
1472
+ };
1473
+ }
1474
+
901
1475
  throw new Error(`Unknown resource: ${uri}`);
902
1476
  });
903
1477
 
@@ -965,6 +1539,50 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
965
1539
  required: ['name'],
966
1540
  },
967
1541
  },
1542
+ {
1543
+ name: 'list_utils',
1544
+ description: 'List all available utility modules in the design system',
1545
+ inputSchema: {
1546
+ type: 'object',
1547
+ properties: {},
1548
+ },
1549
+ },
1550
+ {
1551
+ name: 'get_util',
1552
+ description: 'Get detailed information about a specific utility module including all its functions',
1553
+ inputSchema: {
1554
+ type: 'object',
1555
+ properties: {
1556
+ name: {
1557
+ type: 'string',
1558
+ description: 'Name of the utility module (e.g., "classify", "qa", "dom")',
1559
+ },
1560
+ },
1561
+ required: ['name'],
1562
+ },
1563
+ },
1564
+ {
1565
+ name: 'list_types',
1566
+ description: 'List all available type definitions in the design system',
1567
+ inputSchema: {
1568
+ type: 'object',
1569
+ properties: {},
1570
+ },
1571
+ },
1572
+ {
1573
+ name: 'get_type',
1574
+ description: 'Get detailed information about a specific type definition file',
1575
+ inputSchema: {
1576
+ type: 'object',
1577
+ properties: {
1578
+ name: {
1579
+ type: 'string',
1580
+ description: 'Name of the type file (e.g., "common", "typography", "charts")',
1581
+ },
1582
+ },
1583
+ required: ['name'],
1584
+ },
1585
+ },
968
1586
  {
969
1587
  name: 'get_design_tokens',
970
1588
  description: 'Get all design tokens including colors, spacing, typography, shadows, etc.',
@@ -986,6 +1604,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
986
1604
  properties: {},
987
1605
  },
988
1606
  },
1607
+ {
1608
+ name: 'get_css_module_import_patterns',
1609
+ description: '🚨 MANDATORY: Get the required CSS Module import and usage pattern based on context. This tool shows TWO different patterns: (1) Building INSIDE ui-design-system repo: .module.css files, PascalCase, relative imports. (2) USING design system in another app: .css files, kebab-case, @spaced-out/ui-design-system imports. MUST be called FIRST before generating any component to understand context and use correct patterns. Failure to follow context-specific patterns will cause import errors.',
1610
+ inputSchema: {
1611
+ type: 'object',
1612
+ properties: {},
1613
+ },
1614
+ },
989
1615
  {
990
1616
  name: 'get_design_token_import_guidelines',
991
1617
  description: 'Get guidelines and best practices for importing design tokens in CSS Module files. This includes the correct import paths, available token files, and examples of correct vs incorrect imports. ALWAYS call this function before creating CSS Module files to ensure correct token imports.',
@@ -996,7 +1622,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
996
1622
  },
997
1623
  {
998
1624
  name: 'get_css_module_guidelines',
999
- description: 'Get comprehensive CSS Module styling guidelines including class naming conventions, token usage, icon color patterns, and common mistakes to avoid. CRITICAL: Call this before creating or modifying any CSS Module files to ensure consistency with the design system patterns.',
1625
+ description: 'Get comprehensive CSS Module styling guidelines including MANDATORY import pattern (import css from "./file.module.css"), class naming conventions, token usage, icon color patterns, and common mistakes to avoid. 🚨 CRITICAL: Call this BEFORE creating or modifying any component files to ensure correct CSS Module usage and design system patterns. This includes the mandatory pattern: import css from "./Component.module.css" and className={css.className}.',
1000
1626
  inputSchema: {
1001
1627
  type: 'object',
1002
1628
  properties: {},
@@ -1126,6 +1752,76 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1126
1752
  };
1127
1753
  }
1128
1754
 
1755
+ case 'list_utils': {
1756
+ const utils = getAllUtils();
1757
+ return {
1758
+ content: [
1759
+ {
1760
+ type: 'text',
1761
+ text: JSON.stringify(utils, null, 2),
1762
+ },
1763
+ ],
1764
+ };
1765
+ }
1766
+
1767
+ case 'get_util': {
1768
+ const details = getUtilDetails(args.name);
1769
+ if (!details) {
1770
+ return {
1771
+ content: [
1772
+ {
1773
+ type: 'text',
1774
+ text: `Util "${args.name}" not found`,
1775
+ },
1776
+ ],
1777
+ isError: true,
1778
+ };
1779
+ }
1780
+ return {
1781
+ content: [
1782
+ {
1783
+ type: 'text',
1784
+ text: JSON.stringify(details, null, 2),
1785
+ },
1786
+ ],
1787
+ };
1788
+ }
1789
+
1790
+ case 'list_types': {
1791
+ const types = getAllTypes();
1792
+ return {
1793
+ content: [
1794
+ {
1795
+ type: 'text',
1796
+ text: JSON.stringify(types, null, 2),
1797
+ },
1798
+ ],
1799
+ };
1800
+ }
1801
+
1802
+ case 'get_type': {
1803
+ const details = getTypeDetails(args.name);
1804
+ if (!details) {
1805
+ return {
1806
+ content: [
1807
+ {
1808
+ type: 'text',
1809
+ text: `Type "${args.name}" not found`,
1810
+ },
1811
+ ],
1812
+ isError: true,
1813
+ };
1814
+ }
1815
+ return {
1816
+ content: [
1817
+ {
1818
+ type: 'text',
1819
+ text: JSON.stringify(details, null, 2),
1820
+ },
1821
+ ],
1822
+ };
1823
+ }
1824
+
1129
1825
  case 'get_design_tokens': {
1130
1826
  const allTokens = getAllDesignTokens();
1131
1827
  const tokens = args.category ? { [args.category]: allTokens[args.category] } : allTokens;
@@ -1151,6 +1847,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1151
1847
  };
1152
1848
  }
1153
1849
 
1850
+ case 'get_css_module_import_patterns': {
1851
+ const patterns = getCSSModuleImportPatterns();
1852
+ return {
1853
+ content: [
1854
+ {
1855
+ type: 'text',
1856
+ text: JSON.stringify(patterns, null, 2),
1857
+ },
1858
+ ],
1859
+ };
1860
+ }
1861
+
1154
1862
  case 'get_design_token_import_guidelines': {
1155
1863
  const guidelines = getDesignTokenImportGuidelines();
1156
1864
  return {
package/mcp/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaced-out/genesis-mcp-server",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "MCP server for Genesis UI Design System - provides AI assistants with access to components, hooks, and design tokens",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaced-out/ui-design-system",
3
- "version": "0.5.21",
3
+ "version": "0.5.22",
4
4
  "description": "Sense UI components library",
5
5
  "author": {
6
6
  "name": "Spaced Out"