{"id":31038320,"url":"https://github.com/ai-shifu/remark-flow","last_synced_at":"2026-01-20T17:16:44.545Z","repository":{"id":312848359,"uuid":"1016071084","full_name":"ai-shifu/remark-flow","owner":"ai-shifu","description":"Remark plugin to parse and process MarkdownFlow syntax in React applications","archived":false,"fork":false,"pushed_at":"2026-01-12T20:20:22.000Z","size":317,"stargazers_count":1,"open_issues_count":3,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T01:24:27.262Z","etag":null,"topics":["markdown-flow","markdownflow","mdflow","react","react-markdown","remark-plugin","typescript"],"latest_commit_sha":null,"homepage":"https://markdownflow.ai","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ai-shifu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-07-08T12:53:43.000Z","updated_at":"2025-10-09T00:57:32.000Z","dependencies_parsed_at":"2025-09-27T17:18:22.055Z","dependency_job_id":null,"html_url":"https://github.com/ai-shifu/remark-flow","commit_stats":null,"previous_names":["ai-shifu/remark-flow"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ai-shifu/remark-flow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ai-shifu%2Fremark-flow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ai-shifu%2Fremark-flow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ai-shifu%2Fremark-flow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ai-shifu%2Fremark-flow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ai-shifu","download_url":"https://codeload.github.com/ai-shifu/remark-flow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ai-shifu%2Fremark-flow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28607625,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T16:10:39.856Z","status":"ssl_error","status_checked_at":"2026-01-20T16:10:39.493Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["markdown-flow","markdownflow","mdflow","react","react-markdown","remark-plugin","typescript"],"created_at":"2025-09-14T07:01:13.300Z","updated_at":"2026-01-20T17:16:44.535Z","avatar_url":"https://github.com/ai-shifu.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Remark Flow\n\n**A remark plugin library for parsing [MarkdownFlow](https://markdownflow.ai) documents**\n\n[MarkdownFlow](https://markdownflow.ai) (also known as MDFlow or markdown-flow) extends standard Markdown with AI to create personalized, interactive pages. Its tagline is **\"Write Once, Deliver Personally\"**.\n\n\u003cdiv align=\"center\"\u003e\n\n[![npm version](https://badge.fury.io/js/remark-flow.svg)](https://badge.fury.io/js/remark-flow)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)\n\nEnglish | [简体中文](README_ZH-CN.md)\n\n\u003c/div\u003e\n\n## 🚀 Quick Start\n\n### Install\n\n```bash\nnpm install remark-flow\n# or\nyarn add remark-flow\n# or\npnpm add remark-flow\n```\n\n### Basic Usage\n\n```typescript\nimport { remark } from 'remark';\nimport remarkFlow from 'remark-flow';\n\nconst processor = remark().use(remarkFlow);\n\nconst markdown = `\n# Welcome to Interactive Content!\n\nChoose one option: ?[Option A | Option B | Option C]\nChoose multiple skills: ?[%{{skills}} JavaScript||TypeScript||Python]\nEnter your name: ?[%{{username}}...Please enter your name]\n`;\n\nconst result = processor.processSync(markdown);\n// Each ?[...] becomes a structured custom-variable node in the AST\n```\n\n### Advanced Usage\n\n```typescript\nimport { unified } from 'unified';\nimport remarkParse from 'remark-parse';\nimport remarkFlow from 'remark-flow';\nimport remarkStringify from 'remark-stringify';\n\nconst processor = unified()\n  .use(remarkParse)\n  .use(remarkFlow)\n  .use(remarkStringify);\n\nconst result = processor.processSync(`\nSelect theme: ?[%{{theme}} Light//light | Dark//dark | ...custom]\nAction: ?[Save Changes//save | Cancel//cancel]\n`);\n```\n\n## 🧩 Supported Syntax Patterns\n\n### 1. Simple Buttons\n\n```markdown\n?[Submit]\n?[Continue | Cancel]\n?[Yes | No | Maybe]\n```\n\n**Output:** `{ buttonTexts: [\"Yes\", \"No\", \"Maybe\"], buttonValues: [\"Yes\", \"No\", \"Maybe\"], isMultiSelect: false }`\n\n### 2. Custom Button Values\n\n```markdown\n?[Save Changes//save-action]\n?[确定//confirm | 取消//cancel]\n```\n\n**Output:** `{ buttonTexts: [\"Save Changes\"], buttonValues: [\"save-action\"] }`\n\n### 3. Variable Text Input\n\n```markdown\n?[%{{username}}...Enter your name]\n?[%{{age}}...How old are you?]\n?[%{{comment}}...]\n```\n\n**Output:** `{ variableName: \"username\", placeholder: \"Enter your name\" }`\n\n### 4. Variable Button Selection (Single-Select)\n\n```markdown\n?[%{{theme}} Light | Dark]\n?[%{{size}} Small//S | Medium//M | Large//L]\n```\n\n**Output:** `{ variableName: \"theme\", buttonTexts: [\"Light\", \"Dark\"], buttonValues: [\"Light\", \"Dark\"], isMultiSelect: false }`\n\n### 5. Variable Button Selection (Multi-Select)\n\n```markdown\n?[%{{skills}} JavaScript||TypeScript||Python]\n?[%{{lang}} JS//JavaScript||TS//TypeScript||PY//Python]\n```\n\n**Output:** `{ variableName: \"skills\", buttonTexts: [\"JavaScript\", \"TypeScript\", \"Python\"], buttonValues: [\"JavaScript\", \"TypeScript\", \"Python\"], isMultiSelect: true }`\n\n### 6. Combined: Buttons + Text Input\n\n```markdown\n# Single-select with text input\n\n?[%{{size}} Small//S | Medium//M | Large//L | ...custom size]\n\n# Multi-select with text input\n\n?[%{{tags}} React||Vue||Angular||...Other framework]\n```\n\n**Output:**\n\n```typescript\n{\n  variableName: \"size\",\n  buttonTexts: [\"Small\", \"Medium\", \"Large\"],\n  buttonValues: [\"S\", \"M\", \"L\"],\n  placeholder: \"custom size\"\n}\n```\n\n### 7. Separator Priority Rules\n\nThe first separator type encountered determines the parsing mode:\n\n```markdown\n# Single-select mode (| appears first)\n\n?[%{{option}} A | B||C] # Results in: [\"A\", \"B||C\"]\n\n# Multi-select mode (|| appears first)\n\n?[%{{option}} A||B | C] # Results in: [\"A\", \"B | C\"]\n```\n\n**Key Points:**\n\n- `|` = Single-select mode, `||` becomes part of button values\n- `||` = Multi-select mode, `|` becomes part of button values\n- First separator type wins and determines the entire parsing behavior\n\n### 8. Unicode \u0026 International Support\n\n```markdown\n?[%{{语言}} English//en | 中文//zh | 日本語//ja]\n?[%{{用户名}}...请输入您的姓名]\n?[👍 Good | 👎 Bad | 🤔 Unsure]\n```\n\n## 📖 API Reference\n\n### Plugin Exports\n\n```typescript\n// Default export (recommended)\nimport remarkFlow from 'remark-flow';\n\n// Named exports\nimport {\n  remarkFlow, // Main plugin, functionally the same as the default export\n  remarkInteraction, // The core plugin, which is also the default export\n  remarkCustomVariable, // Variable-focused plugin\n  createInteractionParser, // Parser factory\n  InteractionType, // Type enums\n} from 'remark-flow';\n```\n\n### Output Format\n\nAll plugins transform `?[...]` syntax into `custom-variable` AST nodes:\n\n```typescript\ninterface CustomVariableNode extends Node {\n  type: 'custom-variable';\n  data: {\n    variableName?: string; // For %{{name}} syntax\n    buttonTexts?: string[]; // Button display text\n    buttonValues?: string[]; // Corresponding button values\n    placeholder?: string; // Text input placeholder\n  };\n}\n```\n\n### Parser API\n\n```typescript\nimport { createInteractionParser, InteractionType } from 'remark-flow';\n\nconst parser = createInteractionParser();\n\n// Parse content and get detailed result\nconst result = parser.parse('?[%{{theme}} Light | Dark]');\n\n// Parse and convert to remark-compatible format\nconst remarkData = parser.parseToRemarkFormat('?[%{{theme}} Light | Dark]');\n```\n\n## 🔗 Usage Examples\n\nremark-flow can be used in two main ways:\n\n1. **Standalone** - Parse and transform syntax, then render with your own UI components\n2. **With markdown-flow-ui** - Use the pre-built React components for instant interactive UI\n\n### 🎯 Standalone Usage (Custom Rendering)\n\nWhen using remark-flow standalone, you parse the syntax and create your own UI components based on the AST nodes.\n\n#### Basic AST Transformation\n\n```typescript\nimport { remark } from 'remark';\nimport { visit } from 'unist-util-visit';\nimport remarkFlow from 'remark-flow';\nimport type { Node } from 'unist';\n\nconst processor = remark().use(remarkFlow);\n\nconst markdown = `\n# Choose Your Preferences\n\nSelect language: ?[%{{language}} JavaScript | Python | TypeScript | Go]\nEnter your name: ?[%{{username}}...Your full name]\nAction: ?[Save//save | Cancel//cancel]\n`;\n\n// Parse and examine the AST\nconst ast = processor.parse(markdown);\nprocessor.runSync(ast);\n\n// Find custom-variable nodes\nvisit(ast, 'custom-variable', (node: any) =\u003e {\n  console.log('Found interaction:', node.data);\n  // Output: { variableName: 'language', buttonTexts: ['JavaScript', 'Python', 'TypeScript', 'Go'], buttonValues: [...] }\n});\n```\n\n#### Custom HTML Renderer\n\n```typescript\nimport { visit } from 'unist-util-visit';\nimport { remark } from 'remark';\nimport remarkHtml from 'remark-html';\n\nfunction createCustomRenderer() {\n  return (tree: Node) =\u003e {\n    visit(tree, 'custom-variable', (node: any) =\u003e {\n      const { variableName, buttonTexts, buttonValues, placeholder } =\n        node.data;\n\n      if (buttonTexts \u0026\u0026 buttonTexts.length \u003e 0) {\n        // Render as button group\n        const buttonsHtml = buttonTexts\n          .map((text, i) =\u003e {\n            const value = buttonValues?.[i] || text;\n            return `\u003cbutton onclick=\"selectOption('${variableName}', '${value}')\" class=\"interactive-btn\"\u003e\n              ${text}\n            \u003c/button\u003e`;\n          })\n          .join('');\n\n        node.type = 'html';\n        node.value = `\n          \u003cdiv class=\"button-group\" data-variable=\"${variableName}\"\u003e\n            ${buttonsHtml}\n          \u003c/div\u003e\n        `;\n      } else if (placeholder) {\n        // Render as text input\n        node.type = 'html';\n        node.value = `\n          \u003cdiv class=\"input-group\"\u003e\n            \u003clabel for=\"${variableName}\"\u003e${placeholder}\u003c/label\u003e\n            \u003cinput\n              id=\"${variableName}\"\n              name=\"${variableName}\"\n              placeholder=\"${placeholder}\"\n              class=\"interactive-input\"\n            /\u003e\n          \u003c/div\u003e\n        `;\n      }\n    });\n  };\n}\n\n// Use with remark processor\nconst processor = remark()\n  .use(remarkFlow)\n  .use(createCustomRenderer)\n  .use(remarkHtml);\n\nconst result = processor.processSync(markdown);\nconsole.log(result.toString()); // HTML with custom interactive elements\n```\n\n#### React Custom Components\n\n```typescript\nimport React from 'react';\nimport { remark } from 'remark';\nimport remarkReact from 'remark-react';\nimport remarkFlow from 'remark-flow';\n\n// Custom React components for interactive elements\nconst InteractiveButton = ({ variableName, buttonTexts, buttonValues, onSelect }) =\u003e (\n  \u003cdiv className=\"flex gap-2\"\u003e\n    {buttonTexts.map((text, i) =\u003e (\n      \u003cbutton\n        key={i}\n        onClick={() =\u003e onSelect(variableName, buttonValues[i])}\n        className=\"px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600\"\n      \u003e\n        {text}\n      \u003c/button\u003e\n    ))}\n  \u003c/div\u003e\n);\n\nconst InteractiveInput = ({ variableName, placeholder, onInput }) =\u003e (\n  \u003cdiv className=\"my-2\"\u003e\n    \u003cinput\n      type=\"text\"\n      placeholder={placeholder}\n      onChange={(e) =\u003e onInput(variableName, e.target.value)}\n      className=\"border border-gray-300 rounded px-3 py-2 w-full\"\n    /\u003e\n  \u003c/div\u003e\n);\n\n// Usage in React component\nfunction CustomMarkdownRenderer() {\n  const handleInteraction = (variableName, value) =\u003e {\n    console.log(`${variableName}: ${value}`);\n    // Handle user interaction\n  };\n\n  const processor = remark()\n    .use(remarkFlow)\n    .use(remarkReact, {\n      remarkReactComponents: {\n        'custom-variable': ({ node }) =\u003e {\n          const { variableName, buttonTexts, buttonValues, placeholder } = node.data;\n\n          if (buttonTexts?.length \u003e 0) {\n            return (\n              \u003cInteractiveButton\n                variableName={variableName}\n                buttonTexts={buttonTexts}\n                buttonValues={buttonValues}\n                onSelect={handleInteraction}\n              /\u003e\n            );\n          }\n\n          if (placeholder) {\n            return (\n              \u003cInteractiveInput\n                variableName={variableName}\n                placeholder={placeholder}\n                onInput={handleInteraction}\n              /\u003e\n            );\n          }\n\n          return null;\n        },\n      },\n    });\n\n  const content = `\n  # Interactive Form\n\n  Choose language: ?[%{{lang}} English | 中文 | Español]\n  Your name: ?[%{{name}}...Enter your name]\n  Action: ?[Submit//submit | Reset//reset]\n  `;\n\n  return \u003cdiv\u003e{processor.processSync(content).result}\u003c/div\u003e;\n}\n```\n\n### 🎨 With markdown-flow-ui (Pre-built Components)\n\nFor a complete React component library with ready-to-use interactive components, use [markdown-flow-ui](https://github.com/ai-shifu/markdown-flow-ui).\n\n#### Basic Integration\n\n```typescript\nimport { MarkdownFlow } from 'markdown-flow-ui';\n\nfunction InteractiveChat() {\n  const content = `\n  # Welcome! 👋\n\n  Select your preference: ?[%{{language}} JavaScript | Python | TypeScript]\n  Enter your name: ?[%{{username}}...Your full name]\n  Ready to start: ?[Let's Go!//start]\n  `;\n\n  return (\n    \u003cMarkdownFlow\n      initialContentList={[{ content }]}\n      onSend={(data) =\u003e {\n        console.log('User interaction:', data);\n        // Handle user interactions\n      }}\n      typingSpeed={30}\n    /\u003e\n  );\n}\n```\n\n**For advanced examples with streaming, multi-step forms, and more features, see:**\n\n- 📖 [markdown-flow-ui Documentation](https://github.com/ai-shifu/markdown-flow-ui#readme)\n\n### 📊 Comparison: Standalone vs markdown-flow-ui\n\n| Aspect                | Standalone Usage                   | With markdown-flow-ui                  |\n| --------------------- | ---------------------------------- | -------------------------------------- |\n| **Setup Complexity**  | Medium - Need custom rendering     | Low - Pre-built components             |\n| **Customization**     | High - Full control over UI        | Medium - Theme/style customization     |\n| **Bundle Size**       | Smaller - Only remark plugin       | Larger - Full React component library  |\n| **Framework Support** | Any (React, Vue, vanilla JS, etc.) | React only                             |\n| **Advanced Features** | Manual implementation needed       | Built-in (streaming, typewriter, etc.) |\n| **Use Case**          | Custom UI requirements, non-React  | Rapid prototyping, React projects      |\n\n## 🌐 MarkdownFlow Ecosystem\n\nremark-flow is part of the MarkdownFlow ecosystem for creating personalized, AI-driven interactive documents:\n\n- **[markdown-flow](https://github.com/ai-shifu/markdown-flow)** - The main repository containing homepage, documentation, and interactive playground\n- **[markdown-flow-agent-py](https://github.com/ai-shifu/markdown-flow-agent-py)** - Python agent for transforming MarkdownFlow documents into personalized content\n- **[remark-flow](https://github.com/ai-shifu/remark-flow)** - Remark plugin to parse and process MarkdownFlow syntax in React applications\n- **[markdown-flow-ui](https://github.com/ai-shifu/markdown-flow-ui)** - React component library for rendering interactive MarkdownFlow documents\n\n## 💖 Sponsors\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://ai-shifu.com\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/ai-shifu/ai-shifu/main/assets/logo_en.png\" alt=\"AI-Shifu\" width=\"150\" /\u003e\n  \u003c/a\u003e\n  \u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://ai-shifu.com\"\u003eAI-Shifu.com\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n  \u003cp\u003eAI-powered personalized learning platform\u003c/p\u003e\n\u003c/div\u003e\n\n## 📄 License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## 🙏 Acknowledgments\n\n- [Remark](https://remark.js.org/) for markdown processing\n- [Unified](https://unifiedjs.com/) for the plugin architecture\n- [Unist](https://github.com/syntax-tree/unist) for AST utilities\n- [TypeScript](https://www.typescriptlang.org/) for type safety\n- [Jest](https://jestjs.io/) for testing framework\n\n## 📞 Support\n\n- 📖 [Documentation](https://github.com/ai-shifu/remark-flow#readme)\n- 🐛 [Issue Tracker](https://github.com/ai-shifu/remark-flow/issues)\n- 💬 [Discussions](https://github.com/ai-shifu/remark-flow/discussions)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fai-shifu%2Fremark-flow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fai-shifu%2Fremark-flow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fai-shifu%2Fremark-flow/lists"}