{"version":3,"file":"cisstech-nge-markdown-stackblitz.mjs","sources":["../../../projects/nge/markdown/stackblitz/stackblitz.ts","../../../projects/nge/markdown/stackblitz/cisstech-nge-markdown-stackblitz.ts"],"sourcesContent":["import { DATA_STACKBLITZ, NGE_MARKDOWN_CODE_ACTIONS } from '@cisstech/nge/markdown'\nimport type { NgeMarkdownCodeActionProvider, NgeMarkdownFeature } from '@cisstech/nge/markdown'\n\nconst STACKBLITZ_SVG =\n  '<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M10.5 13.5H4.5L14 2l-.5 8.5h6L10 22z\"/></svg>'\n\n/**\n * Options for opening fenced code in [StackBlitz](https://stackblitz.com). The\n * author owns the project scaffold (files and dependencies); the fenced snippet\n * is injected at {@link file}, so the example is whatever the author configures,\n * not a fragile generated one.\n */\nexport interface NgeMarkdownStackblitzOptions {\n  /**\n   * Path the fenced snippet is written to in the project, e.g. `src/main.ts`.\n   */\n  file: string\n  /**\n   * StackBlitz template. `node` (default) runs a real npm project in\n   * WebContainers, with dependencies declared in the `package.json` file.\n   * EngineBlock templates (`angular-cli`, `typescript`...) use `dependencies`.\n   */\n  template?: 'node' | 'angular-cli' | 'typescript' | 'javascript' | 'create-react-app' | 'vue' | 'html' | 'polymer'\n  /** Project title shown in StackBlitz. */\n  title?: string\n  /** Project description. */\n  description?: string\n  /** Scaffold files (package.json, index.html, ...), by path. The snippet is added to `file`. */\n  files?: Record<string, string>\n  /** npm dependencies for EngineBlock templates; ignored for `node` (use `package.json`). */\n  dependencies?: Record<string, string>\n  /** File opened in the editor. Default: {@link file}. */\n  openFile?: string\n}\n\n/** A StackBlitz project payload plus the file to open, ready for the SDK. */\nexport interface StackblitzProject {\n  project: {\n    title: string\n    description?: string\n    template: string\n    files: Record<string, string>\n    dependencies?: Record<string, string>\n  }\n  openFile: string\n}\n\n/** Assembles the StackBlitz project from the scaffold and the snippet. Pure and testable. */\nexport function buildStackblitzProject(code: string, options: NgeMarkdownStackblitzOptions): StackblitzProject {\n  return {\n    project: {\n      title: options.title ?? 'Example',\n      ...(options.description ? { description: options.description } : {}),\n      template: options.template ?? 'node',\n      files: { ...(options.files ?? {}), [options.file]: code },\n      ...(options.dependencies ? { dependencies: options.dependencies } : {}),\n    },\n    openFile: options.openFile ?? options.file,\n  }\n}\n\n/** Opens the snippet in StackBlitz. Loads the SDK lazily, so it never ships in the initial bundle. */\nexport async function openInStackblitz(code: string, options: NgeMarkdownStackblitzOptions): Promise<void> {\n  const { project, openFile } = buildStackblitzProject(code, options)\n  const sdk = (await import('@stackblitz/sdk')).default\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  sdk.openProject(project as any, { openFile, newWindow: true })\n}\n\n/**\n * The \"Open in StackBlitz\" toolbar action, added to blocks flagged with the\n * `stackblitz` fence keyword. Contributed through the markdown code-action token\n * so the highlighter never references the StackBlitz SDK.\n */\nexport function stackblitzCodeActionProvider(options: NgeMarkdownStackblitzOptions): NgeMarkdownCodeActionProvider {\n  return ({ pre }) =>\n    pre.getAttribute(DATA_STACKBLITZ) === 'true'\n      ? { title: 'Open in StackBlitz', icon: STACKBLITZ_SVG, run: (snippet) => openInStackblitz(snippet, options) }\n      : null\n}\n\n/**\n * Add an \"Open in StackBlitz\" action to fenced blocks marked with the\n * `stackblitz` flag. The snippet is injected into the project scaffold you\n * configure here (files and dependencies), so the example runs exactly as you\n * set it up.\n *\n * Import from `@cisstech/nge/markdown/stackblitz`: the StackBlitz SDK lives\n * behind this entry point, so only apps that use this feature pull it in and\n * need the `@stackblitz/sdk` dependency.\n */\nexport function withStackblitz(options: NgeMarkdownStackblitzOptions): NgeMarkdownFeature {\n  return {\n    providers: [{ provide: NGE_MARKDOWN_CODE_ACTIONS, multi: true, useValue: stackblitzCodeActionProvider(options) }],\n  }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAGA,MAAM,cAAc,GAClB,+IAA+I;AA2CjJ;AACM,SAAU,sBAAsB,CAAC,IAAY,EAAE,OAAqC,EAAA;IACxF,OAAO;AACL,QAAA,OAAO,EAAE;AACP,YAAA,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS;AACjC,YAAA,IAAI,OAAO,CAAC,WAAW,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC;AACpE,YAAA,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,MAAM;AACpC,YAAA,KAAK,EAAE,EAAE,IAAI,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,EAAE;AACzD,YAAA,IAAI,OAAO,CAAC,YAAY,GAAG,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC;AACxE,SAAA;AACD,QAAA,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI;KAC3C;AACH;AAEA;AACO,eAAe,gBAAgB,CAAC,IAAY,EAAE,OAAqC,EAAA;AACxF,IAAA,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,sBAAsB,CAAC,IAAI,EAAE,OAAO,CAAC;IACnE,MAAM,GAAG,GAAG,CAAC,MAAM,OAAO,iBAAiB,CAAC,EAAE,OAAO;;AAErD,IAAA,GAAG,CAAC,WAAW,CAAC,OAAc,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAChE;AAEA;;;;AAIG;AACG,SAAU,4BAA4B,CAAC,OAAqC,EAAA;AAChF,IAAA,OAAO,CAAC,EAAE,GAAG,EAAE,KACb,GAAG,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK;UAClC,EAAE,KAAK,EAAE,oBAAoB,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,OAAO,KAAK,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC;UACzG,IAAI;AACZ;AAEA;;;;;;;;;AASG;AACG,SAAU,cAAc,CAAC,OAAqC,EAAA;IAClE,OAAO;AACL,QAAA,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,yBAAyB,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,4BAA4B,CAAC,OAAO,CAAC,EAAE,CAAC;KAClH;AACH;;AC/FA;;AAEG;;;;"}