markdown-flow-ui
Complete React UI components for MarkdownFlow with built-in functionality and beautiful styling.
Installation
Quick Start
import { MarkdownFlow } from "markdown-flow-ui";
import "markdown-flow-ui/dist/styles.css";
function App() {
const template = `
# Welcome {{user_name}}!
What would you like to learn today?
?[%{{choice}}React|Vue|Angular]
`;
return (
<MarkdownFlow
template={template}
variables={{ user_name: "Alice" }}
onVariableChange={(vars) => console.log("Variables:", vars)}
apiEndpoint="https://your-api.com/process"
/>
);
}
Components
<MarkdownFlow />
The main component that renders MarkdownFlow templates.
Props
Prop | Type | Default | Description |
---|---|---|---|
template |
string |
Required | MarkdownFlow template string |
variables |
object |
{} |
Initial variables |
apiEndpoint |
string |
- | Backend API endpoint for AI processing |
onVariableChange |
function |
- | Callback when variables change |
onUserInput |
function |
- | Callback when user makes a selection |
theme |
'light' \| 'dark' \| 'auto' |
'auto' |
Color theme |
className |
string |
- | Additional CSS classes |
style |
object |
- | Inline styles |
Example with All Props
<MarkdownFlow
template={markdownTemplate}
variables={{
user_name: "Bob",
skill_level: "intermediate",
}}
apiEndpoint="https://api.example.com/markdownflow"
onVariableChange={(variables) => {
console.log("Updated variables:", variables);
}}
onUserInput={(inputData) => {
console.log("User selected:", inputData);
}}
theme="dark"
className="my-custom-class"
style={{ maxWidth: "800px", margin: "0 auto" }}
/>
<MarkdownFlowProvider />
Context provider for managing MarkdownFlow state across components.
import { MarkdownFlowProvider, useMarkdownFlow } from "markdown-flow-ui";
function App() {
return (
<MarkdownFlowProvider>
<YourComponents />
</MarkdownFlowProvider>
);
}
function YourComponent() {
const { variables, setVariable, processTemplate } = useMarkdownFlow();
// Use the context methods
}
<UserInput />
Standalone component for rendering user input elements.
import { UserInput } from "markdown-flow-ui";
<UserInput
variable="choice"
options={["Option 1", "Option 2", "Option 3"]}
onSelect={(value) => console.log("Selected:", value)}
style="buttons" // or 'dropdown', 'radio'
/>;
Hooks
useMarkdownFlow()
Access MarkdownFlow context and state.
const {
variables,
setVariable,
template,
setTemplate,
processTemplate,
isProcessing,
error,
} = useMarkdownFlow();
useVariable(name, defaultValue)
Manage a single variable.
useAIProcess()
Handle AI processing.
const { process, isLoading, result, error } = useAIProcess({
endpoint: "https://api.example.com/process",
});
// Usage
await process(template, variables);
Styling
Default Themes
Import the default stylesheet:
Custom Themes
Override CSS variables for custom theming:
:root {
--mf-primary-color: #0066cc;
--mf-background: #ffffff;
--mf-text-color: #333333;
--mf-border-color: #e0e0e0;
--mf-input-background: #f5f5f5;
--mf-input-hover: #eeeeee;
--mf-input-selected: #0066cc;
--mf-code-background: #2d3748;
--mf-code-color: #e2e8f0;
}
[data-theme="dark"] {
--mf-background: #1a1a1a;
--mf-text-color: #ffffff;
/* ... other dark theme variables */
}
Component-Specific Styling
<MarkdownFlow
classNames={{
container: "custom-container",
content: "custom-content",
userInput: "custom-input",
variable: "custom-variable",
}}
/>
Advanced Usage
Server-Side Rendering (SSR)
// pages/index.js (Next.js example)
import dynamic from "next/dynamic";
const MarkdownFlow = dynamic(
() => import("markdown-flow-ui").then((mod) => mod.MarkdownFlow),
{ ssr: false },
);
export default function Page() {
return <MarkdownFlow template={template} />;
}
Custom Renderers
Override default rendering for specific elements:
<MarkdownFlow
template={template}
renderers={{
variable: ({ name, value }) => (
<span className="custom-variable">{value || name}</span>
),
userInput: ({ variable, options, onSelect }) => (
<CustomSelect options={options} onChange={(value) => onSelect(value)} />
),
code: ({ language, value }) => (
<SyntaxHighlighter language={language}>{value}</SyntaxHighlighter>
),
}}
/>
AI Processing Integration
function App() {
const [variables, setVariables] = useState({});
const handleProcess = async (template, vars) => {
const response = await fetch("https://api.example.com/process", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ template, variables: vars }),
});
const result = await response.json();
return result.content;
};
return (
<MarkdownFlow
template={template}
variables={variables}
onVariableChange={setVariables}
processFunction={handleProcess}
/>
);
}
Real-time Collaboration
import { MarkdownFlow } from "markdown-flow-ui";
import { useWebSocket } from "your-websocket-lib";
function CollaborativeDoc() {
const { variables, sendUpdate } = useWebSocket("wss://collab.example.com");
return (
<MarkdownFlow
template={template}
variables={variables}
onVariableChange={(vars) => {
sendUpdate({ type: "variables", data: vars });
}}
/>
);
}
API Reference
MarkdownFlow Class Methods
import { MarkdownFlowProcessor } from "markdown-flow-ui";
const processor = new MarkdownFlowProcessor();
// Parse template
const parsed = processor.parse(template);
// Process with variables
const result = processor.process(template, variables);
// Validate template
const errors = processor.validate(template);
Utility Functions
import {
parseVariables,
parseUserInputs,
interpolateVariables,
validateTemplate,
} from "markdown-flow-ui/utils";
// Extract variables from template
const variables = parseVariables(template);
// Returns: ['user_name', 'skill_level', ...]
// Extract user inputs
const inputs = parseUserInputs(template);
// Returns: [{ variable: 'choice', options: [...] }, ...]
// Replace variables with values
const content = interpolateVariables(template, { user_name: "Alice" });
// Validate template syntax
const { valid, errors } = validateTemplate(template);
TypeScript Support
Full TypeScript support with type definitions included:
import { MarkdownFlow, MarkdownFlowProps, Variable } from "markdown-flow-ui";
const props: MarkdownFlowProps = {
template: "# Hello {{name}}",
variables: { name: "World" },
onVariableChange: (vars: Record<string, Variable>) => {
console.log(vars);
},
};
Examples
Interactive Tutorial
const tutorialTemplate = `
# Programming Tutorial
Welcome {{student_name}}!
Choose your path:
?[%{{path}}Frontend Development|Backend Development|Full Stack]
Based on your choice of {{path}}, we'll customize your learning experience.
`;
function Tutorial() {
const [studentName, setStudentName] = useState("");
return (
<div>
<input
placeholder="Enter your name"
onChange={(e) => setStudentName(e.target.value)}
/>
<MarkdownFlow
template={tutorialTemplate}
variables={{ student_name: studentName }}
/>
</div>
);
}
Dynamic Form
const formTemplate = `
## User Registration
?[%{{account_type}}Personal|Business|Enterprise]
{{#if account_type === 'Business'}}
Company Name: {{company_name}}
?[%{{employees}}1-10|11-50|51-200|200+]
{{/if}}
?[%{{newsletter}}Subscribe to newsletter|No thanks]
`;
function DynamicForm() {
return (
<MarkdownFlow
template={formTemplate}
onSubmit={(data) => {
console.log("Form data:", data);
}}
/>
);
}
Performance Optimization
Memoization
import { memo } from "react";
import { MarkdownFlow } from "markdown-flow-ui";
const MemoizedMarkdownFlow = memo(MarkdownFlow);
// Use when template doesn't change frequently
<MemoizedMarkdownFlow template={staticTemplate} />;
Lazy Loading
import { lazy, Suspense } from "react";
const MarkdownFlow = lazy(() => import("markdown-flow-ui"));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<MarkdownFlow template={template} />
</Suspense>
);
}
Testing
import { render, fireEvent } from "@testing-library/react";
import { MarkdownFlow } from "markdown-flow-ui";
test("renders template and handles input", () => {
const { getByText } = render(
<MarkdownFlow
template="Hello {{name}}! ?[%{{choice}}Yes|No]"
variables={{ name: "Test" }}
/>,
);
expect(getByText("Hello Test!")).toBeInTheDocument();
const yesButton = getByText("Yes");
fireEvent.click(yesButton);
// Assert behavior
});
Troubleshooting
Common Issues
- Styles not loading: Make sure to import the CSS file
- SSR errors: Use dynamic imports for Next.js
- Variables not updating: Check that variable names match exactly
- API calls failing: Verify CORS settings on your backend