@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.
Files changed (31) hide show
  1. package/dist/cli/index.js +50 -9
  2. package/dist/mcp-server/index.js +2 -2
  3. package/dist/mcp-server/mcp-stdio-server.js +15 -2
  4. package/dist/mcp-server/routes/components.d.ts.map +1 -1
  5. package/dist/mcp-server/routes/components.js +30 -12
  6. package/dist/mcp-server/routes/generateStory.d.ts.map +1 -1
  7. package/dist/mcp-server/routes/generateStory.js +7 -1
  8. package/dist/story-generator/componentDiscovery.d.ts +14 -0
  9. package/dist/story-generator/componentDiscovery.d.ts.map +1 -1
  10. package/dist/story-generator/enhancedComponentDiscovery.d.ts +34 -0
  11. package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -1
  12. package/dist/story-generator/enhancedComponentDiscovery.js +461 -1
  13. package/dist/story-generator/framework-adapters/angular-adapter.d.ts +0 -4
  14. package/dist/story-generator/framework-adapters/angular-adapter.d.ts.map +1 -1
  15. package/dist/story-generator/framework-adapters/angular-adapter.js +1 -9
  16. package/dist/story-generator/framework-adapters/base-adapter.d.ts +8 -0
  17. package/dist/story-generator/framework-adapters/base-adapter.d.ts.map +1 -1
  18. package/dist/story-generator/framework-adapters/base-adapter.js +89 -2
  19. package/dist/story-generator/framework-adapters/react-adapter.d.ts.map +1 -1
  20. package/dist/story-generator/framework-adapters/react-adapter.js +68 -10
  21. package/dist/story-generator/framework-adapters/web-components-adapter.d.ts +0 -4
  22. package/dist/story-generator/framework-adapters/web-components-adapter.d.ts.map +1 -1
  23. package/dist/story-generator/framework-adapters/web-components-adapter.js +1 -9
  24. package/dist/story-generator/postProcessStory.d.ts +23 -0
  25. package/dist/story-generator/postProcessStory.d.ts.map +1 -1
  26. package/dist/story-generator/postProcessStory.js +134 -0
  27. package/dist/story-generator/promptGenerator.d.ts.map +1 -1
  28. package/dist/story-generator/promptGenerator.js +165 -11
  29. package/dist/story-ui.config.d.ts +16 -0
  30. package/dist/story-ui.config.d.ts.map +1 -1
  31. 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
- const props = this.extractPropsFromFile(content);
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;IA4B1D;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;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"}
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;IAUT;;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"}
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
- // Fall back to import path from config
56
- return config.importPath || 'unknown';
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;IA+GT;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAkE/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IA4CT,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"}
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"}