@tpitre/story-ui 3.10.1 → 3.10.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../cli/update.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AA2SD;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAkItF;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CA+BpC"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../cli/update.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAgTD;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAkItF;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CA+BpC"}
@@ -12,6 +12,11 @@ const MANAGED_FILES = [
12
12
  target: 'src/stories/StoryUI/StoryUIPanel.tsx',
13
13
  description: 'Main chat panel component'
14
14
  },
15
+ {
16
+ source: 'templates/StoryUI/StoryUIPanel.css',
17
+ target: 'src/stories/StoryUI/StoryUIPanel.css',
18
+ description: 'Panel styles'
19
+ },
15
20
  {
16
21
  source: 'templates/StoryUI/StoryUIPanel.mdx',
17
22
  target: 'src/stories/StoryUI/StoryUIPanel.mdx',
@@ -1 +1 @@
1
- {"version":3,"file":"generateStory.d.ts","sourceRoot":"","sources":["../../../mcp-server/routes/generateStory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAgc5C,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,2DAkgBxE"}
1
+ {"version":3,"file":"generateStory.d.ts","sourceRoot":"","sources":["../../../mcp-server/routes/generateStory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAgc5C,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,2DAwfxE"}
@@ -605,23 +605,68 @@ export async function generateStoryFromPrompt(req, res) {
605
605
  // Fallback to cleaned prompt if Claude fails
606
606
  aiTitle = cleanPromptForTitle(prompt);
607
607
  }
608
- // Escape the title for TypeScript
608
+ // Generate unique ID and filename FIRST so we can include hash in title
609
+ // This is done early to ensure unique titles prevent Storybook duplicate ID errors
610
+ const fileExtension = frameworkAdapter?.defaultExtension || '.stories.tsx';
611
+ const timestamp = Date.now();
612
+ // Always generate a hash - either from existing IDs or new
613
+ let hash;
614
+ let finalFileName;
615
+ let storyId;
616
+ if (isActualUpdate && (fileName || providedStoryId)) {
617
+ // For updates, preserve the existing fileName and ID
618
+ if (providedStoryId) {
619
+ storyId = providedStoryId;
620
+ const hashMatch = providedStoryId.match(/^story-([a-f0-9]{8})$/);
621
+ hash = hashMatch ? hashMatch[1] : crypto.createHash('sha1').update(prompt + timestamp).digest('hex').slice(0, 8);
622
+ finalFileName = fileName || `${providedStoryId}.stories.tsx`;
623
+ logger.log('📝 Using provided storyId:', finalFileName);
624
+ }
625
+ else if (fileName) {
626
+ const hashMatch = fileName.match(/-([a-f0-9]{8})(?:\.stories\.tsx)?$/);
627
+ hash = hashMatch ? hashMatch[1] : crypto.createHash('sha1').update(prompt + timestamp).digest('hex').slice(0, 8);
628
+ storyId = `story-${hash}`;
629
+ finalFileName = fileName;
630
+ }
631
+ else {
632
+ // Fallback - should not reach here given the if condition, but satisfies TypeScript
633
+ hash = crypto.createHash('sha1').update(prompt + timestamp).digest('hex').slice(0, 8);
634
+ storyId = `story-${hash}`;
635
+ finalFileName = fileNameFromTitle(aiTitle, hash, fileExtension);
636
+ }
637
+ if (!finalFileName.endsWith('.stories.tsx')) {
638
+ finalFileName = finalFileName + '.stories.tsx';
639
+ }
640
+ logger.log('📌 Preserving story identity for update:', { storyId, fileName: finalFileName });
641
+ }
642
+ else {
643
+ // For new stories, ALWAYS generate new IDs with timestamp to ensure uniqueness
644
+ hash = crypto.createHash('sha1').update(prompt + timestamp).digest('hex').slice(0, 8);
645
+ finalFileName = fileName || fileNameFromTitle(aiTitle, hash, fileExtension);
646
+ storyId = `story-${hash}`;
647
+ logger.log('🆕 Creating new story:', { storyId, fileName: finalFileName });
648
+ }
649
+ // Escape the title for TypeScript and append hash for uniqueness
609
650
  const prettyPrompt = escapeTitleForTS(aiTitle);
610
- // Fix title with storyPrefix - handle both single-line and multi-line formats
611
- fixedFileContents = fixedFileContents.replace(/(const\s+meta\s*=\s*\{[\s\S]*?title:\s*["'])([^"']+)(["'])/, (match, p1, oldTitle, p3) => {
651
+ // Append hash to title to prevent Storybook duplicate ID errors
652
+ const uniqueTitle = `${prettyPrompt} (${hash})`;
653
+ // Fix title with storyPrefix and hash - handle both single-line and multi-line formats
654
+ // Note: (?::\s*\w+(?:<[^>]+>)?)? handles TypeScript type annotations including generics
655
+ // e.g., "const meta: Meta = {" or "const meta: Meta<typeof Button> = {"
656
+ fixedFileContents = fixedFileContents.replace(/(const\s+meta\s*(?::\s*\w+(?:<[^>]+>)?)?\s*=\s*\{[\s\S]*?title:\s*["'])([^"']+)(["'])/, (match, p1, oldTitle, p3) => {
612
657
  // Check if the title already has the prefix to avoid double prefixing
613
- const titleToUse = prettyPrompt.startsWith(config.storyPrefix)
614
- ? prettyPrompt
615
- : config.storyPrefix + prettyPrompt;
658
+ const titleToUse = uniqueTitle.startsWith(config.storyPrefix)
659
+ ? uniqueTitle
660
+ : config.storyPrefix + uniqueTitle;
616
661
  return p1 + titleToUse + p3;
617
662
  });
618
663
  // Fallback: export default { title: "..." } format
619
664
  if (!fixedFileContents.includes(config.storyPrefix)) {
620
665
  fixedFileContents = fixedFileContents.replace(/(export\s+default\s*\{[\s\S]*?title:\s*["'])([^"']+)(["'])/, (match, p1, oldTitle, p3) => {
621
666
  // Check if the title already has the prefix to avoid double prefixing
622
- const titleToUse = prettyPrompt.startsWith(config.storyPrefix)
623
- ? prettyPrompt
624
- : config.storyPrefix + prettyPrompt;
667
+ const titleToUse = uniqueTitle.startsWith(config.storyPrefix)
668
+ ? uniqueTitle
669
+ : config.storyPrefix + uniqueTitle;
625
670
  return p1 + titleToUse + p3;
626
671
  });
627
672
  }
@@ -657,60 +702,6 @@ export async function generateStoryFromPrompt(req, res) {
657
702
  else {
658
703
  logger.log('✅ Final validation passed after post-processing');
659
704
  }
660
- // Check if this is an update to an existing story
661
- // ONLY consider it an update if we're in the same conversation context
662
- let existingStory = null;
663
- if (isActualUpdate && fileName) {
664
- // When updating within a conversation, look for the story by fileName
665
- existingStory = storyTracker.findByTitle(aiTitle);
666
- if (existingStory && existingStory.fileName !== fileName) {
667
- // If found story has different fileName, it's not the same story
668
- existingStory = null;
669
- }
670
- }
671
- // Remove the automatic "find by prompt" logic that was preventing duplicates
672
- // Generate unique ID and filename
673
- let hash, finalFileName, storyId;
674
- if (isActualUpdate && (fileName || providedStoryId)) {
675
- // For updates, preserve the existing fileName and ID
676
- // Ensure the filename has the proper .stories.tsx extension
677
- // FIX: Handle case where fileName is undefined but providedStoryId exists
678
- if (fileName) {
679
- finalFileName = fileName;
680
- }
681
- else if (providedStoryId) {
682
- // Generate filename from storyId when fileName not provided
683
- finalFileName = `${providedStoryId}.stories.tsx`;
684
- logger.log('📝 Generated filename from storyId:', finalFileName);
685
- }
686
- if (finalFileName && !finalFileName.endsWith('.stories.tsx')) {
687
- finalFileName = finalFileName + '.stories.tsx';
688
- }
689
- // Use provided storyId or extract from fileName
690
- if (providedStoryId) {
691
- storyId = providedStoryId;
692
- // Extract hash from storyId
693
- const hashMatch = providedStoryId.match(/^story-([a-f0-9]{8})$/);
694
- hash = hashMatch ? hashMatch[1] : crypto.createHash('sha1').update(prompt).digest('hex').slice(0, 8);
695
- }
696
- else {
697
- // Extract hash from existing fileName if possible
698
- const hashMatch = fileName.match(/-([a-f0-9]{8})(?:\.stories\.tsx)?$/);
699
- hash = hashMatch ? hashMatch[1] : crypto.createHash('sha1').update(prompt).digest('hex').slice(0, 8);
700
- storyId = `story-${hash}`;
701
- }
702
- logger.log('📌 Preserving story identity for update:', { storyId, fileName: finalFileName });
703
- }
704
- else {
705
- // For new stories, ALWAYS generate new IDs with timestamp to ensure uniqueness
706
- const timestamp = Date.now();
707
- hash = crypto.createHash('sha1').update(prompt + timestamp).digest('hex').slice(0, 8);
708
- // Use the framework adapter's defaultExtension for the correct file extension
709
- const fileExtension = frameworkAdapter?.defaultExtension || '.stories.tsx';
710
- finalFileName = fileName || fileNameFromTitle(aiTitle, hash, fileExtension);
711
- storyId = `story-${hash}`;
712
- logger.log('🆕 Creating new story:', { storyId, fileName: finalFileName, extension: fileExtension });
713
- }
714
705
  // Write story to file system
715
706
  const outPath = generateStory({
716
707
  fileContents: fixedFileContents,
@@ -1 +1 @@
1
- {"version":3,"file":"generateStoryStream.d.ts","sourceRoot":"","sources":["../../../mcp-server/routes/generateStoryStream.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA2c5C,wBAAsB,6BAA6B,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAqhB9E"}
1
+ {"version":3,"file":"generateStoryStream.d.ts","sourceRoot":"","sources":["../../../mcp-server/routes/generateStoryStream.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA2c5C,wBAAsB,6BAA6B,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBA0hB9E"}
@@ -699,23 +699,7 @@ export async function generateStoryFromPromptStream(req, res) {
699
699
  if (!aiTitle || aiTitle.length < 2) {
700
700
  aiTitle = cleanPromptForTitle(prompt);
701
701
  }
702
- const prettyPrompt = escapeTitleForTS(aiTitle);
703
- // Fix title with storyPrefix
704
- fixedFileContents = fixedFileContents.replace(/(const\s+meta\s*=\s*\{[\s\S]*?title:\s*["'])([^"']+)(["'])/, (match, p1, oldTitle, p3) => {
705
- const titleToUse = prettyPrompt.startsWith(config.storyPrefix)
706
- ? prettyPrompt
707
- : config.storyPrefix + prettyPrompt;
708
- return p1 + titleToUse + p3;
709
- });
710
- if (!fixedFileContents.includes(config.storyPrefix)) {
711
- fixedFileContents = fixedFileContents.replace(/(export\s+default\s*\{[\s\S]*?title:\s*["'])([^"']+)(["'])/, (match, p1, oldTitle, p3) => {
712
- const titleToUse = prettyPrompt.startsWith(config.storyPrefix)
713
- ? prettyPrompt
714
- : config.storyPrefix + prettyPrompt;
715
- return p1 + titleToUse + p3;
716
- });
717
- }
718
- // Generate IDs
702
+ // Generate IDs FIRST so we can include hash in title for uniqueness
719
703
  let hash;
720
704
  let finalFileName;
721
705
  let storyId;
@@ -739,6 +723,27 @@ export async function generateStoryFromPromptStream(req, res) {
739
723
  finalFileName = fileName || fileNameFromTitle(aiTitle, hash);
740
724
  storyId = `story-${hash}`;
741
725
  }
726
+ // Now create title with hash suffix to ensure uniqueness
727
+ const prettyPrompt = escapeTitleForTS(aiTitle);
728
+ // Append hash to title to prevent Storybook duplicate ID errors
729
+ const uniqueTitle = `${prettyPrompt} (${hash})`;
730
+ // Fix title with storyPrefix and hash
731
+ // Note: (?::\s*\w+(?:<[^>]+>)?)? handles TypeScript type annotations including generics
732
+ // e.g., "const meta: Meta = {" or "const meta: Meta<typeof Button> = {"
733
+ fixedFileContents = fixedFileContents.replace(/(const\s+meta\s*(?::\s*\w+(?:<[^>]+>)?)?\s*=\s*\{[\s\S]*?title:\s*["'])([^"']+)(["'])/, (match, p1, oldTitle, p3) => {
734
+ const titleToUse = uniqueTitle.startsWith(config.storyPrefix)
735
+ ? uniqueTitle
736
+ : config.storyPrefix + uniqueTitle;
737
+ return p1 + titleToUse + p3;
738
+ });
739
+ if (!fixedFileContents.includes(config.storyPrefix)) {
740
+ fixedFileContents = fixedFileContents.replace(/(export\s+default\s*\{[\s\S]*?title:\s*["'])([^"']+)(["'])/, (match, p1, oldTitle, p3) => {
741
+ const titleToUse = uniqueTitle.startsWith(config.storyPrefix)
742
+ ? uniqueTitle
743
+ : config.storyPrefix + uniqueTitle;
744
+ return p1 + titleToUse + p3;
745
+ });
746
+ }
742
747
  // Ensure file extension is correct
743
748
  if (finalFileName && !finalFileName.endsWith('.stories.tsx')) {
744
749
  finalFileName = finalFileName + '.stories.tsx';
@@ -1 +1 @@
1
- {"version":3,"file":"angular-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/angular-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,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,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IA0HT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IA+J/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;CA2BrE;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;AAEH,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,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IA0HT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAgK/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;CA2BrE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CAErD"}
@@ -227,7 +227,6 @@ export const ProductCard: Story = {
227
227
  \`\`\`typescript
228
228
  import type { Meta, StoryObj } from '@storybook/angular';
229
229
  import { applicationConfig } from '@storybook/angular';
230
- import { action } from '@storybook/addon-actions';
231
230
  import { ButtonComponent } from 'your-library';
232
231
 
233
232
  const meta: Meta<ButtonComponent> = {
@@ -238,16 +237,18 @@ const meta: Meta<ButtonComponent> = {
238
237
  providers: [],
239
238
  }),
240
239
  ],
240
+ argTypes: {
241
+ // Use argTypes with action for event logging instead of addon-actions
242
+ onClick: { action: 'clicked' },
243
+ },
241
244
  };
242
245
 
243
246
  export default meta;
244
247
  type Story = StoryObj<ButtonComponent>;
245
248
 
246
249
  export const WithClick: Story = {
247
- render: () => ({
248
- props: {
249
- onClick: action('button-click'),
250
- },
250
+ render: (args) => ({
251
+ props: args,
251
252
  template: \`
252
253
  <app-button (click)="onClick($event)" variant="primary">
253
254
  Click me
@@ -1 +1 @@
1
- {"version":3,"file":"svelte-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/svelte-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,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,aAAc,SAAQ,oBAAoB;IACrD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAY;IACxC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAGjD;IACF,QAAQ,CAAC,gBAAgB,iBAAiB;IAE1C,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IA8GT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAuJ/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IA4CT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IAsB1D;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAiDzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAwBpE;;OAEG;IACH,eAAe,CACb,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;CAWV;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAEnD"}
1
+ {"version":3,"file":"svelte-adapter.d.ts","sourceRoot":"","sources":["../../../story-generator/framework-adapters/svelte-adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,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,aAAc,SAAQ,oBAAoB;IACrD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAY;IACxC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,wBAAwB,EAAE,cAAc,EAAE,CAGjD;IACF,QAAQ,CAAC,gBAAgB,iBAAiB;IAE1C,oBAAoB,CAClB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM;IAmGT,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAyI/C,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,MAAM;IA4CT,gBAAgB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM;IAsB1D;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAiDzC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAwBpE;;OAEG;IACH,eAAe,CACb,UAAU,EAAE,mBAAmB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,MAAM;CAWV;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAEnD"}
@@ -28,43 +28,40 @@ Use ONLY the Svelte components from the ${componentSystemName} listed below.
28
28
 
29
29
  MANDATORY IMPORTS - First lines of every story file:
30
30
  1. import type { Meta, StoryObj } from '@storybook/svelte';
31
- 2. import ComponentName from '${config.importPath || 'your-library'}/ComponentName.svelte';
31
+ 2. import { ComponentName } from '${config.importPath || 'flowbite-svelte'}';
32
32
 
33
- SVELTE STORY FORMAT:
34
- - Import .svelte files directly
33
+ SVELTE STORY FORMAT (CSF 3.0):
34
+ - Use named imports from flowbite-svelte (NOT default imports from .svelte files)
35
35
  - Props are passed via args object
36
- - Use render function for complex templates
36
+ - Use render function ONLY for multiple components or complex layouts
37
37
 
38
- STORY STRUCTURE (CSF 3.0):
38
+ STORY STRUCTURE:
39
39
  - Meta object with component, title, and parameters
40
- - Stories use args for simple prop passing
41
- - Use render for component composition
40
+ - Stories use args for prop passing
41
+ - Keep stories simple - avoid complex render functions when possible
42
42
 
43
43
  CRITICAL RULES:
44
- - Import Svelte components (default export from .svelte files)
45
- - For slots, use render with a wrapper component
46
- - Events use on: directive in Svelte templates
44
+ - Import using named exports: import { Button, Card } from 'flowbite-svelte';
45
+ - DO NOT use 'slot' property in render functions - it does NOT work
46
+ - DO NOT use 'children' in args
47
+ - For components that need text content, use the component's text/label prop if available
48
+ - For button text, most Flowbite components accept text as a prop or the component handles it
47
49
 
48
- CRITICAL - SVELTE SLOT CONTENT:
49
- - Svelte components use SLOTS for content, NOT children props
50
- - Always use render function with 'slot' property for text/content
51
- - Never use 'children' in args - it will cause runtime errors
52
-
53
- Example structure:
50
+ SIMPLE EXAMPLE (PREFERRED):
54
51
  \`\`\`typescript
55
52
  import type { Meta, StoryObj } from '@storybook/svelte';
56
- import { Button } from 'your-library';
53
+ import { Button } from 'flowbite-svelte';
57
54
 
58
55
  const meta: Meta<Button> = {
59
56
  title: 'Components/Button',
60
57
  component: Button,
61
58
  tags: ['autodocs'],
59
+ parameters: { layout: 'centered' },
62
60
  argTypes: {
63
- variant: {
61
+ color: {
64
62
  control: 'select',
65
- options: ['primary', 'secondary', 'ghost'],
63
+ options: ['primary', 'blue', 'alternative', 'dark', 'light', 'green', 'red'],
66
64
  },
67
- onclick: { action: 'clicked' },
68
65
  },
69
66
  };
70
67
 
@@ -73,201 +70,179 @@ type Story = StoryObj<typeof meta>;
73
70
 
74
71
  export const Primary: Story = {
75
72
  args: {
76
- variant: 'primary',
73
+ color: 'primary',
77
74
  },
78
- render: (args) => ({
75
+ };
76
+
77
+ export const AllColors: Story = {
78
+ render: () => ({
79
79
  Component: Button,
80
- props: args,
81
- slot: 'Click me',
80
+ props: { color: 'blue' },
82
81
  }),
83
82
  };
84
83
  \`\`\`
85
84
 
86
- For stories with slots (using wrapper component):
87
- \`\`\`svelte
88
- <!-- ButtonWithIcon.stories.svelte -->
89
- <script context="module" lang="ts">
90
- import type { Meta } from '@storybook/svelte';
91
- import Button from 'your-library/Button.svelte';
92
- import Icon from 'your-library/Icon.svelte';
93
-
94
- export const meta: Meta<Button> = {
95
- title: 'Components/Button/WithIcon',
96
- component: Button,
97
- };
98
- </script>
99
-
100
- <script lang="ts">
101
- import { Story } from '@storybook/svelte';
102
- </script>
103
-
104
- <Story name="With Icon">
105
- <Button variant="primary">
106
- <Icon slot="icon" name="star" />
107
- Starred
108
- </Button>
109
- </Story>
85
+ FOR MULTIPLE COMPONENTS (use render with template):
86
+ \`\`\`typescript
87
+ import type { Meta, StoryObj } from '@storybook/svelte';
88
+ import { ButtonGroup, Button } from 'flowbite-svelte';
89
+
90
+ const meta: Meta<ButtonGroup> = {
91
+ title: 'Components/ButtonGroup',
92
+ component: ButtonGroup,
93
+ tags: ['autodocs'],
94
+ parameters: { layout: 'centered' },
95
+ };
96
+
97
+ export default meta;
98
+ type Story = StoryObj<typeof meta>;
99
+
100
+ // For simple button groups, just show the component
101
+ export const Default: Story = {
102
+ args: {},
103
+ };
110
104
  \`\`\`
111
105
 
112
106
  SVELTE TEMPLATE SYNTAX:
113
107
  - Props: property={value}
114
- - Events: on:event={handler}
108
+ - Events: onclick={handler} (Svelte 5 syntax, NOT on:click)
115
109
  - Two-way binding: bind:value
116
110
  - Conditionals: {#if condition}...{/if}
117
111
  - Loops: {#each items as item}...{/each}
118
112
 
119
- SLOTS:
120
- - Default slot: Content between tags
121
- - Named slots: <span slot="name">content</span>
122
- - Slot props: let:prop
123
-
124
113
  ${this.getCommonRules()}`;
125
114
  }
126
115
  generateExamples(config) {
127
- const lib = config.importPath || 'your-library';
116
+ const lib = config.importPath || 'flowbite-svelte';
128
117
  return `
129
- ## Example Stories for Svelte
118
+ ## Example Stories for Svelte (CSF 3.0 Format)
130
119
 
131
- ### TypeScript Stories File
120
+ ### Simple Component Story (PREFERRED)
132
121
  \`\`\`typescript
133
122
  import type { Meta, StoryObj } from '@storybook/svelte';
134
- import { Button } from 'your-library';
123
+ import { Button } from '${lib}';
135
124
 
136
125
  const meta: Meta<Button> = {
137
126
  title: 'Components/Button',
138
127
  component: Button,
139
128
  tags: ['autodocs'],
129
+ parameters: { layout: 'centered' },
140
130
  argTypes: {
141
- variant: {
131
+ color: {
142
132
  control: 'select',
143
- options: ['primary', 'secondary', 'ghost'],
133
+ options: ['primary', 'blue', 'alternative', 'dark', 'light', 'green', 'red'],
144
134
  },
145
135
  size: {
146
136
  control: 'select',
147
- options: ['small', 'medium', 'large'],
137
+ options: ['xs', 'sm', 'md', 'lg', 'xl'],
148
138
  },
149
- onclick: { action: 'clicked' },
150
139
  },
151
140
  };
152
141
 
153
142
  export default meta;
154
143
  type Story = StoryObj<typeof meta>;
155
144
 
156
- // IMPORTANT: Use render with slot property for content
157
- export const Default: Story = {
145
+ export const Primary: Story = {
158
146
  args: {
159
- variant: 'primary',
160
- size: 'medium',
147
+ color: 'primary',
148
+ size: 'md',
161
149
  },
162
- render: (args) => ({
163
- Component: Button,
164
- props: args,
165
- slot: 'Button',
166
- }),
167
150
  };
168
151
 
169
152
  export const Disabled: Story = {
170
153
  args: {
171
- variant: 'primary',
154
+ color: 'primary',
172
155
  disabled: true,
173
156
  },
174
- render: (args) => ({
157
+ };
158
+
159
+ export const AllSizes: Story = {
160
+ render: () => ({
175
161
  Component: Button,
176
- props: args,
177
- slot: 'Disabled',
162
+ props: { color: 'blue', size: 'lg' },
178
163
  }),
179
164
  };
180
165
  \`\`\`
181
166
 
182
- ### Svelte Stories File (for complex templates)
183
- \`\`\`svelte
184
- <!-- Card.stories.svelte -->
185
- <script context="module" lang="ts">
186
- import type { Meta } from '@storybook/svelte';
187
- import Card from '${lib}/Card.svelte';
188
- import Button from 'your-library/Button.svelte';
189
- import Text from '${lib}/Text.svelte';
190
-
191
- export const meta: Meta<Card> = {
192
- title: 'Components/Card',
193
- component: Card,
194
- };
195
- </script>
196
-
197
- <script lang="ts">
198
- import { Story, Template } from '@storybook/svelte';
199
- </script>
200
-
201
- <Story name="Product Card">
202
- <Card style="width: 300px">
203
- <img
204
- slot="media"
205
- src="https://picsum.photos/300/200"
206
- alt="Product"
207
- />
208
- <Text slot="title" variant="heading">Product Name</Text>
209
- <Text>$99.00</Text>
210
- <Button slot="actions" variant="primary">Add to Cart</Button>
211
- </Card>
212
- </Story>
213
-
214
- <Story name="Simple Card">
215
- <Card>
216
- <Text>Simple card content</Text>
217
- </Card>
218
- </Story>
219
- \`\`\`
167
+ ### Card Component Story
168
+ \`\`\`typescript
169
+ import type { Meta, StoryObj } from '@storybook/svelte';
170
+ import { Card } from '${lib}';
220
171
 
221
- ### With Reactive State
222
- \`\`\`svelte
223
- <!-- Input.stories.svelte -->
224
- <script context="module" lang="ts">
225
- import type { Meta } from '@storybook/svelte';
226
- import Input from '${lib}/Input.svelte';
227
-
228
- export const meta: Meta<Input> = {
229
- title: 'Components/Input',
230
- component: Input,
231
- };
232
- </script>
233
-
234
- <script lang="ts">
235
- import { Story } from '@storybook/svelte';
236
- let value = '';
237
- </script>
238
-
239
- <Story name="Controlled">
240
- <div>
241
- <Input bind:value placeholder="Type here..." />
242
- <p>Value: {value}</p>
243
- </div>
244
- </Story>
172
+ const meta: Meta<Card> = {
173
+ title: 'Components/Card',
174
+ component: Card,
175
+ tags: ['autodocs'],
176
+ parameters: { layout: 'centered' },
177
+ };
178
+
179
+ export default meta;
180
+ type Story = StoryObj<typeof meta>;
181
+
182
+ export const Default: Story = {
183
+ args: {
184
+ class: 'max-w-sm',
185
+ },
186
+ };
187
+
188
+ export const WithImage: Story = {
189
+ args: {
190
+ img: 'https://picsum.photos/300/200',
191
+ class: 'max-w-sm',
192
+ },
193
+ };
194
+
195
+ export const Horizontal: Story = {
196
+ args: {
197
+ horizontal: true,
198
+ class: 'max-w-xl',
199
+ },
200
+ };
245
201
  \`\`\`
246
202
 
247
- ### With Event Handling
203
+ ### Alert Component Story
248
204
  \`\`\`typescript
249
205
  import type { Meta, StoryObj } from '@storybook/svelte';
250
- import { action } from '@storybook/addon-actions';
251
- import { Button } from 'your-library';
206
+ import { Alert } from '${lib}';
252
207
 
253
- const meta: Meta<Button> = {
254
- title: 'Components/Button',
255
- component: Button,
208
+ const meta: Meta<Alert> = {
209
+ title: 'Components/Alert',
210
+ component: Alert,
211
+ tags: ['autodocs'],
212
+ parameters: { layout: 'centered' },
213
+ argTypes: {
214
+ color: {
215
+ control: 'select',
216
+ options: ['primary', 'blue', 'red', 'green', 'yellow', 'dark'],
217
+ },
218
+ },
256
219
  };
257
220
 
258
221
  export default meta;
259
222
  type Story = StoryObj<typeof meta>;
260
223
 
261
- export const WithClickHandler: Story = {
224
+ export const Info: Story = {
262
225
  args: {
263
- variant: 'primary',
264
- onclick: action('button-clicked'),
226
+ color: 'blue',
227
+ },
228
+ };
229
+
230
+ export const Success: Story = {
231
+ args: {
232
+ color: 'green',
233
+ },
234
+ };
235
+
236
+ export const Warning: Story = {
237
+ args: {
238
+ color: 'yellow',
239
+ },
240
+ };
241
+
242
+ export const Error: Story = {
243
+ args: {
244
+ color: 'red',
265
245
  },
266
- render: (args) => ({
267
- Component: Button,
268
- props: args,
269
- slot: 'Click me',
270
- }),
271
246
  };
272
247
  \`\`\`
273
248
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"storyValidator.d.ts","sourceRoot":"","sources":["../../story-generator/storyValidator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,EAAE,CA2CrE"}
1
+ {"version":3,"file":"storyValidator.d.ts","sourceRoot":"","sources":["../../story-generator/storyValidator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,EAAE,CA6CrE"}
@@ -7,8 +7,10 @@ export function validateStory(storyContent) {
7
7
  { pattern: /UNSAFE_style\s*=\s*\{/i, message: 'The `UNSAFE_style` prop is strictly forbidden. Do not use it for any reason.' },
8
8
  { pattern: /UNSAFE_className\s*=\s*['"]/i, message: 'The `UNSAFE_className` prop is forbidden.' },
9
9
  { pattern: /<Text\s+as\s*=\s*["']h[1-6]["']/i, message: 'Text component does not support heading elements (h1-h6) in the "as" prop. Use Heading component instead.' },
10
- // Remove overly strict rules - divs, imgs, and inline styles are fine in moderation
11
- // Only check for actual syntax errors or patterns that would break Storybook
10
+ // Catch imports that don't exist in production environments
11
+ { pattern: /from\s+['"]@storybook\/addon-actions['"]/i, message: 'Do not import from @storybook/addon-actions. Use argTypes with action property instead: argTypes: { onClick: { action: "clicked" } }' },
12
+ // Catch Svelte slot property which doesn't work in modern Storybook
13
+ { pattern: /slot:\s*['"][^'"]+['"]/i, message: 'The slot property in render functions does not work in Svelte Storybook. Use simple args-based stories instead.' },
12
14
  ];
13
15
  lines.forEach((line, index) => {
14
16
  for (const { pattern, message } of forbiddenPatterns) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tpitre/story-ui",
3
- "version": "3.10.1",
3
+ "version": "3.10.3",
4
4
  "description": "AI-powered Storybook story generator with dynamic component discovery",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",