@tpitre/story-ui 4.7.0 → 4.8.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/dist/cli/index.js +50 -9
- package/dist/mcp-server/index.js +2 -2
- package/dist/mcp-server/mcp-stdio-server.js +15 -2
- package/dist/mcp-server/routes/components.d.ts.map +1 -1
- package/dist/mcp-server/routes/components.js +30 -12
- package/dist/mcp-server/routes/generateStory.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStory.js +7 -1
- package/dist/story-generator/componentDiscovery.d.ts +14 -0
- package/dist/story-generator/componentDiscovery.d.ts.map +1 -1
- package/dist/story-generator/enhancedComponentDiscovery.d.ts +34 -0
- package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -1
- package/dist/story-generator/enhancedComponentDiscovery.js +461 -1
- package/dist/story-generator/framework-adapters/angular-adapter.d.ts +0 -4
- package/dist/story-generator/framework-adapters/angular-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/angular-adapter.js +1 -9
- package/dist/story-generator/framework-adapters/base-adapter.d.ts +8 -0
- package/dist/story-generator/framework-adapters/base-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/base-adapter.js +89 -2
- package/dist/story-generator/framework-adapters/react-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/react-adapter.js +68 -10
- package/dist/story-generator/framework-adapters/web-components-adapter.d.ts +0 -4
- package/dist/story-generator/framework-adapters/web-components-adapter.d.ts.map +1 -1
- package/dist/story-generator/framework-adapters/web-components-adapter.js +1 -9
- package/dist/story-generator/postProcessStory.d.ts +23 -0
- package/dist/story-generator/postProcessStory.d.ts.map +1 -1
- package/dist/story-generator/postProcessStory.js +134 -0
- package/dist/story-generator/promptGenerator.d.ts.map +1 -1
- package/dist/story-generator/promptGenerator.js +165 -11
- package/dist/story-ui.config.d.ts +16 -0
- package/dist/story-ui.config.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -654,11 +654,22 @@ export class EnhancedComponentDiscovery {
|
|
|
654
654
|
if (this.shouldSkipComponent(componentName, content)) {
|
|
655
655
|
continue;
|
|
656
656
|
}
|
|
657
|
-
|
|
657
|
+
let props = this.extractPropsFromFile(content);
|
|
658
|
+
// Always check co-located story file for additional props (argTypes, args)
|
|
659
|
+
// Story files often define props that aren't in the component source (e.g., disabled, children)
|
|
660
|
+
const storyProps = this.extractPropsFromStoryFile(file);
|
|
661
|
+
for (const prop of storyProps) {
|
|
662
|
+
if (!props.includes(prop)) {
|
|
663
|
+
props.push(prop);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
// Extract rich prop type information from story file argTypes
|
|
667
|
+
const propTypes = this.extractRichPropsFromStoryFile(file);
|
|
658
668
|
this.discoveredComponents.set(componentName, {
|
|
659
669
|
name: componentName,
|
|
660
670
|
filePath: file,
|
|
661
671
|
props,
|
|
672
|
+
propTypes: propTypes.length > 0 ? propTypes : undefined,
|
|
662
673
|
source,
|
|
663
674
|
description: `${componentName} component`,
|
|
664
675
|
category: this.categorizeComponent(componentName, content),
|
|
@@ -765,6 +776,11 @@ export class EnhancedComponentDiscovery {
|
|
|
765
776
|
}
|
|
766
777
|
/**
|
|
767
778
|
* Extract props from file content
|
|
779
|
+
* Supports multiple patterns:
|
|
780
|
+
* - TypeScript interfaces (interface ButtonProps { variant: ... })
|
|
781
|
+
* - PropTypes (Component.propTypes = { variant: ... })
|
|
782
|
+
* - Function parameter destructuring ({ className, variant, ...props }: Props)
|
|
783
|
+
* - VariantProps from class-variance-authority
|
|
768
784
|
*/
|
|
769
785
|
extractPropsFromFile(content) {
|
|
770
786
|
const props = [];
|
|
@@ -786,8 +802,452 @@ export class EnhancedComponentDiscovery {
|
|
|
786
802
|
props.push(match[1]);
|
|
787
803
|
}
|
|
788
804
|
}
|
|
805
|
+
// Extract from function parameter destructuring
|
|
806
|
+
// Matches patterns like:
|
|
807
|
+
// function Component({ prop1, prop2, ...rest }: Props)
|
|
808
|
+
// const Component = ({ prop1, prop2 }: Props) =>
|
|
809
|
+
// export function Component({ prop1, prop2 }: React.ComponentProps<"div">)
|
|
810
|
+
const destructuringProps = this.extractDestructuredProps(content);
|
|
811
|
+
for (const prop of destructuringProps) {
|
|
812
|
+
if (!props.includes(prop)) {
|
|
813
|
+
props.push(prop);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
// Extract from VariantProps (class-variance-authority pattern)
|
|
817
|
+
// Matches: VariantProps<typeof buttonVariants>
|
|
818
|
+
const variantPropsMatch = content.match(/VariantProps<typeof\s+(\w+)>/);
|
|
819
|
+
if (variantPropsMatch) {
|
|
820
|
+
const variantsName = variantPropsMatch[1];
|
|
821
|
+
// Look for the cva definition to extract variant names
|
|
822
|
+
const cvaMatch = content.match(new RegExp(`${variantsName}\\s*=\\s*cva\\([^,]+,\\s*{\\s*variants:\\s*{([^}]+(?:{[^}]*}[^}]*)*)}`));
|
|
823
|
+
if (cvaMatch) {
|
|
824
|
+
const variantsContent = cvaMatch[1];
|
|
825
|
+
// Extract variant property names (e.g., variant, size)
|
|
826
|
+
const variantMatches = variantsContent.matchAll(/^\s*(\w+)\s*:\s*{/gm);
|
|
827
|
+
for (const match of variantMatches) {
|
|
828
|
+
if (!props.includes(match[1])) {
|
|
829
|
+
props.push(match[1]);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return props;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Extract props from function parameter destructuring patterns
|
|
838
|
+
* Works with React, Vue <script setup>, and other frameworks
|
|
839
|
+
*/
|
|
840
|
+
extractDestructuredProps(content) {
|
|
841
|
+
const props = [];
|
|
842
|
+
// Pattern 1: function Component({ prop1, prop2, ...rest }: Type)
|
|
843
|
+
// Pattern 2: const Component = ({ prop1, prop2 }: Type) =>
|
|
844
|
+
// Pattern 3: export function Component({ prop1, prop2 }: Type)
|
|
845
|
+
const functionPatterns = [
|
|
846
|
+
// function Name({ destructured }: Type)
|
|
847
|
+
/(?:export\s+)?(?:default\s+)?function\s+[A-Z]\w*\s*\(\s*\{\s*([^}]+)\s*\}\s*:/g,
|
|
848
|
+
// const Name = ({ destructured }: Type) =>
|
|
849
|
+
/(?:export\s+)?const\s+[A-Z]\w*\s*=\s*\(\s*\{\s*([^}]+)\s*\}\s*:/g,
|
|
850
|
+
// const Name: FC<Props> = ({ destructured }) =>
|
|
851
|
+
/(?:export\s+)?const\s+[A-Z]\w*\s*:\s*\w+(?:<[^>]+>)?\s*=\s*\(\s*\{\s*([^}]+)\s*\}\s*\)/g,
|
|
852
|
+
];
|
|
853
|
+
for (const pattern of functionPatterns) {
|
|
854
|
+
let match;
|
|
855
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
856
|
+
const destructuredContent = match[1];
|
|
857
|
+
// Extract individual prop names, ignoring spread operator (...rest)
|
|
858
|
+
const propMatches = destructuredContent.matchAll(/(?:^|,)\s*(?!\.\.\.)([\w]+)(?:\s*=\s*[^,}]+)?(?=\s*[,}]|$)/g);
|
|
859
|
+
for (const propMatch of propMatches) {
|
|
860
|
+
const propName = propMatch[1].trim();
|
|
861
|
+
// Skip common internal props and rest patterns
|
|
862
|
+
if (propName && !['ref', 'props', 'rest'].includes(propName) && !props.includes(propName)) {
|
|
863
|
+
props.push(propName);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
789
868
|
return props;
|
|
790
869
|
}
|
|
870
|
+
/**
|
|
871
|
+
* Extract props from co-located story file (e.g., Button.stories.tsx)
|
|
872
|
+
* This is a fallback for components like shadcn/ui that don't use interface Props patterns
|
|
873
|
+
*/
|
|
874
|
+
extractPropsFromStoryFile(componentPath) {
|
|
875
|
+
const props = [];
|
|
876
|
+
// Construct story file path: button.tsx -> button.stories.tsx
|
|
877
|
+
const dir = path.dirname(componentPath);
|
|
878
|
+
const ext = path.extname(componentPath);
|
|
879
|
+
const name = path.basename(componentPath, ext);
|
|
880
|
+
// Try different story file naming conventions
|
|
881
|
+
const storyPaths = [
|
|
882
|
+
path.join(dir, `${name}.stories.tsx`),
|
|
883
|
+
path.join(dir, `${name}.stories.ts`),
|
|
884
|
+
path.join(dir, `${name}.story.tsx`),
|
|
885
|
+
path.join(dir, `${name}.story.ts`),
|
|
886
|
+
];
|
|
887
|
+
let storyContent = '';
|
|
888
|
+
for (const storyPath of storyPaths) {
|
|
889
|
+
if (fs.existsSync(storyPath)) {
|
|
890
|
+
try {
|
|
891
|
+
storyContent = fs.readFileSync(storyPath, 'utf-8');
|
|
892
|
+
break;
|
|
893
|
+
}
|
|
894
|
+
catch {
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
if (!storyContent) {
|
|
900
|
+
return props;
|
|
901
|
+
}
|
|
902
|
+
// Extract from argTypes: { propName: { control: ..., options: ... } }
|
|
903
|
+
// Only match prop names followed by `: {` to avoid picking up nested properties like control, options
|
|
904
|
+
const argTypesMatch = storyContent.match(/argTypes\s*:\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/);
|
|
905
|
+
if (argTypesMatch) {
|
|
906
|
+
// Match prop names followed by `: {` which indicates argType config object
|
|
907
|
+
const propMatches = argTypesMatch[1].matchAll(/(\w+)\s*:\s*\{/g);
|
|
908
|
+
for (const match of propMatches) {
|
|
909
|
+
// Skip common argTypes meta-properties that shouldn't be props
|
|
910
|
+
const metaProps = ['control', 'options', 'description', 'table', 'type', 'defaultValue', 'if', 'mapping'];
|
|
911
|
+
if (!metaProps.includes(match[1]) && !props.includes(match[1])) {
|
|
912
|
+
props.push(match[1]);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
// Extract from args: { propName: value }
|
|
917
|
+
const argsMatches = storyContent.matchAll(/args\s*:\s*\{([^}]+)\}/g);
|
|
918
|
+
for (const argsMatch of argsMatches) {
|
|
919
|
+
const argContent = argsMatch[1];
|
|
920
|
+
const propMatches = argContent.matchAll(/^\s*(\w+)\s*:/gm);
|
|
921
|
+
for (const match of propMatches) {
|
|
922
|
+
if (!props.includes(match[1])) {
|
|
923
|
+
props.push(match[1]);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
// Extract from render function parameters if they use destructuring
|
|
928
|
+
// e.g., render: ({ variant, size }) => ...
|
|
929
|
+
const renderMatches = storyContent.matchAll(/render\s*:\s*\(\s*\{\s*([^}]+)\s*\}\s*\)/g);
|
|
930
|
+
for (const renderMatch of renderMatches) {
|
|
931
|
+
const paramContent = renderMatch[1];
|
|
932
|
+
const propMatches = paramContent.matchAll(/(\w+)(?:\s*,|\s*$)/g);
|
|
933
|
+
for (const match of propMatches) {
|
|
934
|
+
if (!props.includes(match[1])) {
|
|
935
|
+
props.push(match[1]);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
return props;
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* Extract rich prop type information from story file argTypes
|
|
943
|
+
* Framework-agnostic: works with any Storybook project (React, Vue, Angular, Svelte, etc.)
|
|
944
|
+
*/
|
|
945
|
+
extractRichPropsFromStoryFile(componentPath) {
|
|
946
|
+
const propTypes = [];
|
|
947
|
+
// Construct story file path: button.tsx -> button.stories.tsx
|
|
948
|
+
const dir = path.dirname(componentPath);
|
|
949
|
+
const ext = path.extname(componentPath);
|
|
950
|
+
const name = path.basename(componentPath, ext);
|
|
951
|
+
// Try different story file naming conventions
|
|
952
|
+
const storyPaths = [
|
|
953
|
+
path.join(dir, `${name}.stories.tsx`),
|
|
954
|
+
path.join(dir, `${name}.stories.ts`),
|
|
955
|
+
path.join(dir, `${name}.story.tsx`),
|
|
956
|
+
path.join(dir, `${name}.story.ts`),
|
|
957
|
+
];
|
|
958
|
+
let storyContent = '';
|
|
959
|
+
for (const storyPath of storyPaths) {
|
|
960
|
+
if (fs.existsSync(storyPath)) {
|
|
961
|
+
try {
|
|
962
|
+
storyContent = fs.readFileSync(storyPath, 'utf-8');
|
|
963
|
+
break;
|
|
964
|
+
}
|
|
965
|
+
catch {
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
if (!storyContent) {
|
|
971
|
+
return propTypes;
|
|
972
|
+
}
|
|
973
|
+
// Parse argTypes block using brace counting for reliable extraction
|
|
974
|
+
// This handles nested objects properly (e.g., control: { type: 'select' })
|
|
975
|
+
const argTypesContent = this.extractArgTypesBlock(storyContent);
|
|
976
|
+
if (argTypesContent) {
|
|
977
|
+
// Match each prop definition: propName: { ... }
|
|
978
|
+
// This regex handles nested objects properly
|
|
979
|
+
const propPattern = /(\w+)\s*:\s*\{([^{}]*(?:\{[^{}]*\}[^{}]*)*)\}/g;
|
|
980
|
+
let propMatch;
|
|
981
|
+
while ((propMatch = propPattern.exec(argTypesContent)) !== null) {
|
|
982
|
+
const propName = propMatch[1];
|
|
983
|
+
const propConfig = propMatch[2];
|
|
984
|
+
// Skip meta-properties that aren't actual props
|
|
985
|
+
const metaProps = ['control', 'options', 'description', 'table', 'type', 'defaultValue', 'if', 'mapping'];
|
|
986
|
+
if (metaProps.includes(propName)) {
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
989
|
+
// Extract control type
|
|
990
|
+
let controlType = 'unknown';
|
|
991
|
+
const controlMatch = propConfig.match(/control\s*:\s*['"]?([\w-]+)['"]?/);
|
|
992
|
+
const controlObjMatch = propConfig.match(/control\s*:\s*\{\s*type\s*:\s*['"]?([\w-]+)['"]?/);
|
|
993
|
+
if (controlObjMatch) {
|
|
994
|
+
controlType = controlObjMatch[1];
|
|
995
|
+
}
|
|
996
|
+
else if (controlMatch) {
|
|
997
|
+
controlType = controlMatch[1];
|
|
998
|
+
}
|
|
999
|
+
// Map control types to our type system
|
|
1000
|
+
const typeMapping = {
|
|
1001
|
+
'select': 'select',
|
|
1002
|
+
'radio': 'radio',
|
|
1003
|
+
'inline-radio': 'radio',
|
|
1004
|
+
'boolean': 'boolean',
|
|
1005
|
+
'number': 'number',
|
|
1006
|
+
'range': 'number',
|
|
1007
|
+
'text': 'string',
|
|
1008
|
+
'color': 'string',
|
|
1009
|
+
'date': 'string',
|
|
1010
|
+
'object': 'object',
|
|
1011
|
+
'array': 'array',
|
|
1012
|
+
'file': 'object',
|
|
1013
|
+
};
|
|
1014
|
+
const type = typeMapping[controlType] || 'unknown';
|
|
1015
|
+
// Extract options array
|
|
1016
|
+
let options;
|
|
1017
|
+
const optionsMatch = propConfig.match(/options\s*:\s*\[([\s\S]*?)\]/);
|
|
1018
|
+
if (optionsMatch) {
|
|
1019
|
+
// Parse the options array, handling both quoted and unquoted values
|
|
1020
|
+
const optionsContent = optionsMatch[1];
|
|
1021
|
+
options = optionsContent
|
|
1022
|
+
.split(',')
|
|
1023
|
+
.map(opt => opt.trim().replace(/^['"]|['"]$/g, ''))
|
|
1024
|
+
.filter(opt => opt.length > 0);
|
|
1025
|
+
}
|
|
1026
|
+
// Extract description
|
|
1027
|
+
let description;
|
|
1028
|
+
const descMatch = propConfig.match(/description\s*:\s*['"`]([\s\S]*?)['"`]/);
|
|
1029
|
+
if (descMatch) {
|
|
1030
|
+
description = descMatch[1];
|
|
1031
|
+
}
|
|
1032
|
+
// Extract defaultValue
|
|
1033
|
+
let defaultValue;
|
|
1034
|
+
const defaultMatch = propConfig.match(/defaultValue\s*:\s*(['"][\s\S]*?['"]|[\w]+)/);
|
|
1035
|
+
if (defaultMatch) {
|
|
1036
|
+
const rawValue = defaultMatch[1].replace(/^['"]|['"]$/g, '');
|
|
1037
|
+
if (rawValue === 'true')
|
|
1038
|
+
defaultValue = true;
|
|
1039
|
+
else if (rawValue === 'false')
|
|
1040
|
+
defaultValue = false;
|
|
1041
|
+
else if (!isNaN(Number(rawValue)))
|
|
1042
|
+
defaultValue = Number(rawValue);
|
|
1043
|
+
else
|
|
1044
|
+
defaultValue = rawValue;
|
|
1045
|
+
}
|
|
1046
|
+
propTypes.push({
|
|
1047
|
+
name: propName,
|
|
1048
|
+
type,
|
|
1049
|
+
options,
|
|
1050
|
+
description,
|
|
1051
|
+
defaultValue,
|
|
1052
|
+
control: controlType,
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
// Also check for props in args that might not be in argTypes
|
|
1057
|
+
// Use smarter type inference based on value and prop name patterns
|
|
1058
|
+
const argsMatches = storyContent.matchAll(/args\s*:\s*\{([^}]+)\}/g);
|
|
1059
|
+
for (const argsMatch of argsMatches) {
|
|
1060
|
+
const argsContent = argsMatch[1];
|
|
1061
|
+
// Match prop: value pairs
|
|
1062
|
+
const propValueMatches = argsContent.matchAll(/(\w+)\s*:\s*([^,\n]+)/g);
|
|
1063
|
+
for (const match of propValueMatches) {
|
|
1064
|
+
const propName = match[1];
|
|
1065
|
+
const rawValue = match[2].trim();
|
|
1066
|
+
// Only add if not already in propTypes
|
|
1067
|
+
if (!propTypes.find(p => p.name === propName)) {
|
|
1068
|
+
// Infer type from value
|
|
1069
|
+
let inferredType = 'unknown';
|
|
1070
|
+
let description;
|
|
1071
|
+
// Check value-based inference
|
|
1072
|
+
if (rawValue === 'true' || rawValue === 'false') {
|
|
1073
|
+
inferredType = 'boolean';
|
|
1074
|
+
}
|
|
1075
|
+
else if (/^['"`]/.test(rawValue)) {
|
|
1076
|
+
inferredType = 'string';
|
|
1077
|
+
}
|
|
1078
|
+
else if (!isNaN(Number(rawValue)) && rawValue !== '') {
|
|
1079
|
+
inferredType = 'number';
|
|
1080
|
+
}
|
|
1081
|
+
else if (rawValue.startsWith('[')) {
|
|
1082
|
+
inferredType = 'array';
|
|
1083
|
+
}
|
|
1084
|
+
else if (rawValue.startsWith('{')) {
|
|
1085
|
+
inferredType = 'object';
|
|
1086
|
+
}
|
|
1087
|
+
// Check name-based inference for common patterns
|
|
1088
|
+
const booleanPatterns = ['disabled', 'checked', 'defaultChecked', 'open', 'defaultOpen',
|
|
1089
|
+
'selected', 'expanded', 'collapsed', 'visible', 'hidden', 'loading', 'error',
|
|
1090
|
+
'required', 'readonly', 'readOnly', 'active', 'pressed', 'indeterminate',
|
|
1091
|
+
'asChild', 'modal', 'loop', 'autoFocus', 'closeOnEscape', 'closeOnOutsideClick'];
|
|
1092
|
+
if (booleanPatterns.some(p => propName.toLowerCase().includes(p.toLowerCase()))) {
|
|
1093
|
+
inferredType = 'boolean';
|
|
1094
|
+
description = `Whether the component is ${propName.replace(/^(default|is|has)/, '').toLowerCase()}`;
|
|
1095
|
+
}
|
|
1096
|
+
// Name patterns for strings
|
|
1097
|
+
const stringPatterns = ['placeholder', 'label', 'title', 'description', 'name', 'id',
|
|
1098
|
+
'className', 'style', 'href', 'src', 'alt', 'value', 'defaultValue'];
|
|
1099
|
+
if (stringPatterns.some(p => propName.toLowerCase() === p.toLowerCase())) {
|
|
1100
|
+
if (inferredType === 'unknown')
|
|
1101
|
+
inferredType = 'string';
|
|
1102
|
+
}
|
|
1103
|
+
propTypes.push({
|
|
1104
|
+
name: propName,
|
|
1105
|
+
type: inferredType,
|
|
1106
|
+
description,
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
// Phase 3: Scan story code for prop values to infer select types
|
|
1112
|
+
// This catches variants used in JSX/render functions even without argTypes
|
|
1113
|
+
this.inferSelectTypesFromStoryCode(storyContent, propTypes);
|
|
1114
|
+
// Phase 4: Generate better descriptions for common props
|
|
1115
|
+
this.enhancePropDescriptions(propTypes);
|
|
1116
|
+
return propTypes;
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Scan story code for prop usage patterns to infer select types
|
|
1120
|
+
* Looks for patterns like: variant="destructive", size='lg', type={value}
|
|
1121
|
+
*/
|
|
1122
|
+
inferSelectTypesFromStoryCode(storyContent, propTypes) {
|
|
1123
|
+
// Common props that are typically selects with limited options
|
|
1124
|
+
const selectCandidates = ['variant', 'size', 'type', 'color', 'align', 'position',
|
|
1125
|
+
'orientation', 'side', 'status', 'state', 'mode', 'theme', 'intent', 'severity'];
|
|
1126
|
+
for (const propName of selectCandidates) {
|
|
1127
|
+
const existingProp = propTypes.find(p => p.name === propName);
|
|
1128
|
+
// Skip if already typed as select with options
|
|
1129
|
+
if (existingProp?.type === 'select' && existingProp.options?.length) {
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1132
|
+
// Find all values used for this prop in JSX and args
|
|
1133
|
+
const values = new Set();
|
|
1134
|
+
// Pattern 1: JSX attribute - propName="value" or propName='value'
|
|
1135
|
+
const jsxPattern = new RegExp(`${propName}=["']([^"']+)["']`, 'g');
|
|
1136
|
+
let match;
|
|
1137
|
+
while ((match = jsxPattern.exec(storyContent)) !== null) {
|
|
1138
|
+
values.add(match[1]);
|
|
1139
|
+
}
|
|
1140
|
+
// Pattern 2: args object - propName: 'value' or propName: "value"
|
|
1141
|
+
const argsPattern = new RegExp(`${propName}\\s*:\\s*["']([^"']+)["']`, 'g');
|
|
1142
|
+
while ((match = argsPattern.exec(storyContent)) !== null) {
|
|
1143
|
+
values.add(match[1]);
|
|
1144
|
+
}
|
|
1145
|
+
// If we found multiple unique values, it's definitely a select
|
|
1146
|
+
if (values.size >= 2) {
|
|
1147
|
+
const options = Array.from(values).sort();
|
|
1148
|
+
if (existingProp) {
|
|
1149
|
+
// Upgrade existing prop to select
|
|
1150
|
+
existingProp.type = 'select';
|
|
1151
|
+
existingProp.options = options;
|
|
1152
|
+
}
|
|
1153
|
+
else {
|
|
1154
|
+
// Add new prop as select
|
|
1155
|
+
propTypes.push({
|
|
1156
|
+
name: propName,
|
|
1157
|
+
type: 'select',
|
|
1158
|
+
options,
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
else if (values.size === 1) {
|
|
1163
|
+
// Single non-default value found - likely a select with default + this value
|
|
1164
|
+
const foundValue = Array.from(values)[0];
|
|
1165
|
+
if (foundValue !== 'default') {
|
|
1166
|
+
const options = ['default', foundValue];
|
|
1167
|
+
if (existingProp) {
|
|
1168
|
+
// Upgrade existing prop to select
|
|
1169
|
+
existingProp.type = 'select';
|
|
1170
|
+
existingProp.options = options;
|
|
1171
|
+
}
|
|
1172
|
+
else {
|
|
1173
|
+
propTypes.push({
|
|
1174
|
+
name: propName,
|
|
1175
|
+
type: 'select',
|
|
1176
|
+
options,
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Generate better descriptions for common props when not provided
|
|
1185
|
+
*/
|
|
1186
|
+
enhancePropDescriptions(propTypes) {
|
|
1187
|
+
const descriptionTemplates = {
|
|
1188
|
+
variant: 'Visual style variant of the component',
|
|
1189
|
+
size: 'Size of the component',
|
|
1190
|
+
disabled: 'Whether the component is disabled',
|
|
1191
|
+
checked: 'Whether the component is checked',
|
|
1192
|
+
defaultChecked: 'Default checked state',
|
|
1193
|
+
open: 'Whether the component is open',
|
|
1194
|
+
defaultOpen: 'Default open state',
|
|
1195
|
+
selected: 'Whether the item is selected',
|
|
1196
|
+
expanded: 'Whether the component is expanded',
|
|
1197
|
+
loading: 'Whether the component is in loading state',
|
|
1198
|
+
error: 'Whether the component is in error state',
|
|
1199
|
+
required: 'Whether the field is required',
|
|
1200
|
+
readOnly: 'Whether the component is read-only',
|
|
1201
|
+
placeholder: 'Placeholder text when empty',
|
|
1202
|
+
label: 'Label text for the component',
|
|
1203
|
+
title: 'Title of the component',
|
|
1204
|
+
description: 'Description text',
|
|
1205
|
+
children: 'Content to render inside the component',
|
|
1206
|
+
className: 'Additional CSS classes',
|
|
1207
|
+
asChild: 'Render as child element for composition',
|
|
1208
|
+
orientation: 'Layout orientation (horizontal/vertical)',
|
|
1209
|
+
align: 'Content alignment',
|
|
1210
|
+
side: 'Side where the component appears',
|
|
1211
|
+
position: 'Position of the component',
|
|
1212
|
+
type: 'Type of the component',
|
|
1213
|
+
color: 'Color variant',
|
|
1214
|
+
intent: 'Intent/purpose variant (info, success, warning, error)',
|
|
1215
|
+
severity: 'Severity level',
|
|
1216
|
+
status: 'Current status',
|
|
1217
|
+
state: 'Current state',
|
|
1218
|
+
mode: 'Operating mode',
|
|
1219
|
+
theme: 'Theme variant',
|
|
1220
|
+
};
|
|
1221
|
+
for (const prop of propTypes) {
|
|
1222
|
+
// Only enhance if description is missing or generic
|
|
1223
|
+
if (!prop.description || prop.description.endsWith(' property')) {
|
|
1224
|
+
const template = descriptionTemplates[prop.name];
|
|
1225
|
+
if (template) {
|
|
1226
|
+
prop.description = template;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Extract the content of the argTypes block using brace counting
|
|
1233
|
+
* This handles nested objects more reliably than regex
|
|
1234
|
+
*/
|
|
1235
|
+
extractArgTypesBlock(content) {
|
|
1236
|
+
const startMatch = content.match(/argTypes\s*:\s*\{/);
|
|
1237
|
+
if (!startMatch || startMatch.index === undefined)
|
|
1238
|
+
return null;
|
|
1239
|
+
const startIndex = startMatch.index + startMatch[0].length;
|
|
1240
|
+
let braceCount = 1;
|
|
1241
|
+
let endIndex = startIndex;
|
|
1242
|
+
for (let i = startIndex; i < content.length && braceCount > 0; i++) {
|
|
1243
|
+
if (content[i] === '{')
|
|
1244
|
+
braceCount++;
|
|
1245
|
+
if (content[i] === '}')
|
|
1246
|
+
braceCount--;
|
|
1247
|
+
endIndex = i;
|
|
1248
|
+
}
|
|
1249
|
+
return content.substring(startIndex, endIndex);
|
|
1250
|
+
}
|
|
791
1251
|
/**
|
|
792
1252
|
* Extract slots from content
|
|
793
1253
|
*/
|
|
@@ -26,10 +26,6 @@ export declare class AngularAdapter extends BaseFrameworkAdapter {
|
|
|
26
26
|
generateExamples(config: StoryUIConfig): string;
|
|
27
27
|
generateSampleStory(config: StoryUIConfig, components: DiscoveredComponent[]): string;
|
|
28
28
|
getStoryTemplate(options?: StoryGenerationOptions): string;
|
|
29
|
-
/**
|
|
30
|
-
* Convert PascalCase to kebab-case for selectors
|
|
31
|
-
*/
|
|
32
|
-
private toKebabCase;
|
|
33
29
|
/**
|
|
34
30
|
* Post-process Angular stories
|
|
35
31
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/angular-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,cAAe,SAAQ,oBAAoB;IACtD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAa;IACzC,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAGjD;IACF,QAAQ,CAAC,gBAAgB,iBAAiB;IAE1C;;OAEG;IACH,wBAAwB,IAAI,MAAM,EAAE;IAIpC;;;OAGG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAmD1E,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAuJT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAsL/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IAqDT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"angular-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/angular-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,cAAe,SAAQ,oBAAoB;IACtD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAa;IACzC,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAGjD;IACF,QAAQ,CAAC,gBAAgB,iBAAiB;IAE1C;;OAEG;IACH,wBAAwB,IAAI,MAAM,EAAE;IAIpC;;;OAGG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAmD1E,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAuJT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAsL/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IAqDT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IA8B1D;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAkBzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;CA+CrE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CAErD"}
|
|
@@ -474,15 +474,7 @@ export const Default: Story = {
|
|
|
474
474
|
};
|
|
475
475
|
`;
|
|
476
476
|
}
|
|
477
|
-
|
|
478
|
-
* Convert PascalCase to kebab-case for selectors
|
|
479
|
-
*/
|
|
480
|
-
toKebabCase(str) {
|
|
481
|
-
return str
|
|
482
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
483
|
-
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
|
|
484
|
-
.toLowerCase();
|
|
485
|
-
}
|
|
477
|
+
// toKebabCase inherited from BaseFrameworkAdapter
|
|
486
478
|
/**
|
|
487
479
|
* Post-process Angular stories
|
|
488
480
|
*/
|
|
@@ -42,6 +42,14 @@ export declare abstract class BaseFrameworkAdapter implements FrameworkAdapter {
|
|
|
42
42
|
* Get the import path for a component
|
|
43
43
|
*/
|
|
44
44
|
protected getImportPath(component: DiscoveredComponent, config: StoryUIConfig): string;
|
|
45
|
+
/**
|
|
46
|
+
* Convert PascalCase to kebab-case
|
|
47
|
+
*/
|
|
48
|
+
protected toKebabCase(str: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Get the base component name (for sub-components like CardHeader, returns 'Card')
|
|
51
|
+
*/
|
|
52
|
+
protected getBaseComponentName(componentName: string): string;
|
|
45
53
|
/**
|
|
46
54
|
* Group components by their category
|
|
47
55
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/base-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAG/D;;GAEG;AACH,8BAAsB,oBAAqB,YAAW,gBAAgB;IACpE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAAC;IAC7D,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAE3C;;;OAGG;IACH,QAAQ,CAAC,wBAAwB,IAAI,MAAM,EAAE;IAE7C;;;OAGG;IACH,QAAQ,CAAC,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAEnF;;OAEG;IACH,QAAQ,CAAC,oBAAoB,CAC3B,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAET;;OAEG;IACH,0BAA0B,CACxB,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;IAmBT;;OAEG;IACH,SAAS,CAAC,oBAAoB,CAC5B,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,aAAa,GACpB,MAAM;IAkBT;;OAEG;IACH,SAAS,CAAC,aAAa,CACrB,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,aAAa,GACpB,MAAM;
|
|
1
|
+
{"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/base-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAG/D;;GAEG;AACH,8BAAsB,oBAAqB,YAAW,gBAAgB;IACpE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAAC;IAC7D,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAE3C;;;OAGG;IACH,QAAQ,CAAC,wBAAwB,IAAI,MAAM,EAAE;IAE7C;;;OAGG;IACH,QAAQ,CAAC,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAEnF;;OAEG;IACH,QAAQ,CAAC,oBAAoB,CAC3B,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAET;;OAEG;IACH,0BAA0B,CACxB,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;IAmBT;;OAEG;IACH,SAAS,CAAC,oBAAoB,CAC5B,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,aAAa,GACpB,MAAM;IAkBT;;OAEG;IACH,SAAS,CAAC,aAAa,CACrB,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,aAAa,GACpB,MAAM;IAuBT;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAI1C;;OAEG;IACH,SAAS,CAAC,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAsE7D;;OAEG;IACH,SAAS,CAAC,wBAAwB,CAChC,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM,CAAC,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAcxC;;OAEG;IACH,QAAQ,CAAC,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAExD;;OAEG;IACH,QAAQ,CAAC,mBAAmB,CAC1B,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IAET;;OAEG;IACH,eAAe,CACb,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;IAoBT;;;OAGG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAmBzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAkBpE;;OAEG;IACH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IAEnE;;OAEG;IACH,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIpE;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,MAAM;CA2DnC"}
|
|
@@ -52,8 +52,95 @@ export class BaseFrameworkAdapter {
|
|
|
52
52
|
if (component.__componentPath) {
|
|
53
53
|
return component.__componentPath;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
const basePath = config.importPath || 'unknown';
|
|
56
|
+
// If using individual imports, convert component name to kebab-case file path
|
|
57
|
+
if (config.importStyle === 'individual') {
|
|
58
|
+
// Find the base component name (for sub-components like CardHeader, use Card)
|
|
59
|
+
const baseComponentName = this.getBaseComponentName(component.name);
|
|
60
|
+
const kebabName = this.toKebabCase(baseComponentName);
|
|
61
|
+
const result = `${basePath}/${kebabName}`;
|
|
62
|
+
console.log(`[DEBUG] getImportPath: ${component.name} -> ${result} (importStyle=${config.importStyle})`);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
console.log(`[DEBUG] getImportPath: ${component.name} -> ${basePath} (importStyle=${config.importStyle})`);
|
|
66
|
+
// Fall back to import path from config (barrel import)
|
|
67
|
+
return basePath;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Convert PascalCase to kebab-case
|
|
71
|
+
*/
|
|
72
|
+
toKebabCase(str) {
|
|
73
|
+
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get the base component name (for sub-components like CardHeader, returns 'Card')
|
|
77
|
+
*/
|
|
78
|
+
getBaseComponentName(componentName) {
|
|
79
|
+
// Common sub-component patterns in shadcn/ui and other design systems
|
|
80
|
+
const subComponentPatterns = [
|
|
81
|
+
// Card sub-components
|
|
82
|
+
/^(Card)(Header|Footer|Title|Action|Description|Content)$/,
|
|
83
|
+
// Dialog sub-components
|
|
84
|
+
/^(Dialog)(Close|Content|Description|Footer|Header|Overlay|Portal|Title|Trigger)$/,
|
|
85
|
+
// Alert Dialog sub-components
|
|
86
|
+
/^(AlertDialog)(Portal|Overlay|Trigger|Content|Header|Footer|Title|Description|Action|Cancel)$/,
|
|
87
|
+
// Dropdown Menu sub-components
|
|
88
|
+
/^(DropdownMenu)(Portal|Trigger|Content|Group|Label|Item|CheckboxItem|RadioGroup|RadioItem|Separator|Shortcut|Sub|SubTrigger|SubContent)$/,
|
|
89
|
+
// Context Menu sub-components
|
|
90
|
+
/^(ContextMenu)(Trigger|Content|Item|CheckboxItem|RadioItem|Label|Separator|Shortcut|Group|Portal|Sub|SubContent|SubTrigger|RadioGroup)$/,
|
|
91
|
+
// Navigation Menu sub-components
|
|
92
|
+
/^(NavigationMenu)(List|Item|Content|Trigger|Link|Indicator|Viewport)$/,
|
|
93
|
+
// Select sub-components
|
|
94
|
+
/^(Select)(Content|Group|Item|Label|ScrollDownButton|ScrollUpButton|Separator|Trigger|Value)$/,
|
|
95
|
+
// Menubar sub-components
|
|
96
|
+
/^(Menubar)(Portal|Menu|Trigger|Content|Group|Separator|Label|Item|Shortcut|CheckboxItem|RadioGroup|RadioItem|Sub|SubTrigger|SubContent)$/,
|
|
97
|
+
// Accordion sub-components
|
|
98
|
+
/^(Accordion)(Item|Trigger|Content)$/,
|
|
99
|
+
// Tabs sub-components
|
|
100
|
+
/^(Tabs)(List|Trigger|Content)$/,
|
|
101
|
+
// Sheet sub-components
|
|
102
|
+
/^(Sheet)(Trigger|Close|Content|Header|Footer|Title|Description)$/,
|
|
103
|
+
// Avatar sub-components
|
|
104
|
+
/^(Avatar)(Image|Fallback)$/,
|
|
105
|
+
// Breadcrumb sub-components
|
|
106
|
+
/^(Breadcrumb)(List|Item|Link|Page|Separator|Ellipsis)$/,
|
|
107
|
+
// Command sub-components
|
|
108
|
+
/^(Command)(Dialog|Input|List|Empty|Group|Item|Shortcut|Separator)$/,
|
|
109
|
+
// Hover Card sub-components
|
|
110
|
+
/^(HoverCard)(Trigger|Content)$/,
|
|
111
|
+
// Popover sub-components
|
|
112
|
+
/^(Popover)(Trigger|Content|Anchor)$/,
|
|
113
|
+
// Collapsible sub-components
|
|
114
|
+
/^(Collapsible)(Trigger|Content)$/,
|
|
115
|
+
// Drawer sub-components
|
|
116
|
+
/^(Drawer)(Portal|Overlay|Trigger|Close|Content|Header|Footer|Title|Description)$/,
|
|
117
|
+
// Radio Group sub-components
|
|
118
|
+
/^(RadioGroup)(Item)$/,
|
|
119
|
+
// Toggle Group sub-components
|
|
120
|
+
/^(ToggleGroup)(Item)$/,
|
|
121
|
+
// Tooltip sub-components
|
|
122
|
+
/^(Tooltip)(Trigger|Content|Provider)$/,
|
|
123
|
+
// Table sub-components
|
|
124
|
+
/^(Table)(Header|Body|Footer|Head|Row|Cell|Caption)$/,
|
|
125
|
+
// Input OTP sub-components
|
|
126
|
+
/^(InputOTP)(Group|Slot|Separator)$/,
|
|
127
|
+
// Resizable sub-components
|
|
128
|
+
/^(Resizable)(PanelGroup|Panel|Handle)$/,
|
|
129
|
+
// Scroll Area sub-components
|
|
130
|
+
/^(ScrollArea|ScrollBar)$/,
|
|
131
|
+
// Pagination sub-components
|
|
132
|
+
/^(Pagination)(Content|Link|Item|Previous|Next|Ellipsis)$/,
|
|
133
|
+
// Alert sub-components
|
|
134
|
+
/^(Alert)(Title|Description)$/,
|
|
135
|
+
];
|
|
136
|
+
for (const pattern of subComponentPatterns) {
|
|
137
|
+
const match = componentName.match(pattern);
|
|
138
|
+
if (match) {
|
|
139
|
+
return match[1]; // Return the base component name
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// No match found, return original name
|
|
143
|
+
return componentName;
|
|
57
144
|
}
|
|
58
145
|
/**
|
|
59
146
|
* Group components by their category
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/react-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,YAAa,SAAQ,oBAAoB;IACpD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAW;IACvC,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAIjD;IACF,QAAQ,CAAC,gBAAgB,kBAAkB;IAE3C;;OAEG;IACH,wBAAwB,IAAI,MAAM,EAAE;IAIpC;;;OAGG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAyC1E,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;
|
|
1
|
+
{"version":3,"file":"react-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/react-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,YAAa,SAAQ,oBAAoB;IACpD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAW;IACvC,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAIjD;IACF,QAAQ,CAAC,gBAAgB,kBAAkB;IAE3C;;OAEG;IACH,wBAAwB,IAAI,MAAM,EAAE;IAIpC;;;OAGG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAyC1E,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAuJT;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAgF/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IAsDT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IA0B1D;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IA4BzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;CA2BrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD"}
|