diff --git a/bun.lockb b/bun.lockb index 2081ffc..ccbb9ff 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 31ccde4..4698619 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -1,16 +1,54 @@ // @ts-check +import react from '@astrojs/react' import starlight from '@astrojs/starlight' +import tailwind from '@astrojs/tailwind' import { defineConfig } from 'astro/config' import { mermaid } from './src/plugins/mermaid' export default defineConfig({ + vite: { + resolve: { + /** + * @uiw/* packages are not compatible with ESM, as they do not import with `.js` extension. + * We're using source in TypeScript instead. + */ + alias: { + '@uiw/react-codemirror': '@uiw/react-codemirror/src/index.tsx', + '@uiw/codemirror-extensions-basic-setup': + '@uiw/codemirror-extensions-basic-setup/src/index.ts', + '@uiw/codemirror-theme-abyss': '@uiw/codemirror-theme-abyss/src/index.ts', + '@uiw/codemirror-themes': '@uiw/codemirror-themes/src/index.tsx', + }, + conditions: ['bun'], + }, + optimizeDeps: { + /** + * We need to tell Vite to process @uiw/* and related packages, so we transpile them + * properly. + */ + include: [ + '@uiw/codemirror-extensions-basic-setup', + '@codemirror/state', + '@codemirror/view', + '@codemirror/language', + '@uiw/codemirror-theme-abyss', + '@uiw/codemirror-themes', + '@codemirror/lang-javascript', + ], + }, + }, integrations: [ + react(), + tailwind({ + applyBaseStyles: false, + }), starlight({ title: 'Flows AI', social: { github: 'https://github.com/callstackincubator/flows-ai', }, + customCss: ['./src/styles/base.css'], sidebar: [ { label: 'Introduction', @@ -30,6 +68,10 @@ export default defineConfig({ label: 'Guides', autogenerate: { directory: 'guides' }, }, + { + label: 'Sandbox', + slug: 'sandbox', + }, ], }), ], diff --git a/docs/package.json b/docs/package.json index 4ff1019..843fcad 100644 --- a/docs/package.json +++ b/docs/package.json @@ -2,11 +2,23 @@ "name": "docs-new", "version": "0.0.1", "dependencies": { + "@astrojs/react": "^4.1.6", "@astrojs/starlight": "^0.31.1", + "@astrojs/starlight-tailwind": "^3.0.0", + "@astrojs/tailwind": "^5.1.5", + "@codemirror/lang-javascript": "^6.2.2", "@expressive-code/plugin-collapsible-sections": "^0.40.1", + "@flows-ai/ui": "workspace:*", + "@types/react": "^19.0.8", + "@types/react-dom": "^19.0.3", + "@uiw/codemirror-theme-abyss": "^4.23.7", + "@uiw/react-codemirror": "^4.23.7", "astro": "^5.1.5", "mermaid": "^11.4.1", - "sharp": "^0.32.5" + "react": "^19.0.0", + "react-dom": "^19.0.0", + "sharp": "^0.32.5", + "tailwindcss": "^3.4.17" }, "private": true, "scripts": { diff --git a/docs/src/components/Sandbox.tsx b/docs/src/components/Sandbox.tsx new file mode 100644 index 0000000..9a03112 --- /dev/null +++ b/docs/src/components/Sandbox.tsx @@ -0,0 +1,62 @@ +import { javascript } from '@codemirror/lang-javascript' +import { Flow } from '@flows-ai/ui' +import { abyss } from '@uiw/codemirror-theme-abyss' +import ReactCodeMirror from '@uiw/react-codemirror' +import s from 'dedent' +import { useEffect, useState } from 'react' + +const defaultCode = s` + import { parallel } from 'https://esm.sh/flows-ai/flows'; + + export default parallel([ + { + agent: 'githubAgent', + input: 'Get me the latest commit message from the main branch of the flows-ai repo', + } + ]) +` + +export function Sandbox() { + const [code, setCode] = useState(defaultCode) + const [result, setResult] = useState(null) + + const evaluateCode = async () => { + try { + const blob = new Blob([code], { type: 'text/javascript' }) + const url = URL.createObjectURL(blob) + + const module = await import(/* @vite-ignore */ url) + setResult(module.default) + + URL.revokeObjectURL(url) + } catch (error) { + console.error(error) + setResult(null) + } + } + + useEffect(() => { + evaluateCode() + }, []) + + return ( +
+ setCode(value)} + onBlur={evaluateCode} + basicSetup={{ + syntaxHighlighting: true, + }} + extensions={[javascript({ jsx: true, typescript: true })]} + theme={abyss} + /> + {result && ( +
+ +
+ )} +
+ ) +} diff --git a/docs/src/content/docs/sandbox.mdx b/docs/src/content/docs/sandbox.mdx new file mode 100644 index 0000000..67ac7c9 --- /dev/null +++ b/docs/src/content/docs/sandbox.mdx @@ -0,0 +1,10 @@ +--- +title: Sandbox +tableOfContents: false +pagination: false +--- +import '@/styles/full-screen.css' +import { Sandbox } from '@/components/Sandbox' + + + diff --git a/docs/src/styles/base.css b/docs/src/styles/base.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/docs/src/styles/base.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/docs/src/styles/full-screen.css b/docs/src/styles/full-screen.css new file mode 100644 index 0000000..04f6755 --- /dev/null +++ b/docs/src/styles/full-screen.css @@ -0,0 +1,3 @@ +:root { + --sl-content-width: 100%; +} diff --git a/docs/tailwind.config.mjs b/docs/tailwind.config.mjs new file mode 100644 index 0000000..c6d8d27 --- /dev/null +++ b/docs/tailwind.config.mjs @@ -0,0 +1,16 @@ +import starlightPlugin from '@astrojs/starlight-tailwind' +import colors from 'tailwindcss/colors' + +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], + plugins: [starlightPlugin()], + theme: { + extend: { + colors: { + accent: colors.purple, + gray: colors.zinc, + }, + }, + }, +} diff --git a/docs/tsconfig.json b/docs/tsconfig.json index ef73de3..08a3012 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -1,11 +1,10 @@ { - "extends": "astro/tsconfigs/strict", - "include": [".astro/types.d.ts", "**/*"], - "exclude": ["dist"], + "extends": "../tsconfig.json", "compilerOptions": { "baseUrl": ".", "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], } } } + diff --git a/packages/builder/index.html b/packages/builder/index.html deleted file mode 100644 index 80157b3..0000000 --- a/packages/builder/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - Flows AI Builder - - - -
- - - - diff --git a/packages/builder/src/index.css b/packages/builder/src/index.css deleted file mode 100644 index 55da8c6..0000000 --- a/packages/builder/src/index.css +++ /dev/null @@ -1,30 +0,0 @@ -:root { - font-family: system-ui, sans-serif; - line-height: 1.5; - font-weight: 400; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -} - -body { - margin: 0; -} - -.react-flow__node { - box-shadow: var(--xy-node-boxshadow-default); - border-radius: var(--xy-node-border-radius-default); - background-color: var(--xy-node-background-color-default); - display: flex; - justify-content: center; - align-items: center; - text-align: center; - padding: 10px; - font-size: 12px; - flex-direction: column; - border: var(--xy-node-border-default); - color: var(--xy-node-color, var(--xy-node-color-default)); -} \ No newline at end of file diff --git a/packages/builder/src/main.tsx b/packages/builder/src/main.tsx deleted file mode 100644 index f7d2441..0000000 --- a/packages/builder/src/main.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import './index.css' - -import { ReactFlowProvider } from '@xyflow/react' -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' - -import App from './App.tsx' - -/** - * Temporarily, the application takes full screen. - */ -createRoot(document.getElementById('root')!).render( - - -
- -
-
-
-) diff --git a/packages/builder/src/vite-env.d.ts b/packages/builder/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/packages/builder/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/packages/builder/tsconfig.json b/packages/builder/tsconfig.json deleted file mode 100644 index 596e2cf..0000000 --- a/packages/builder/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src"] -} diff --git a/packages/builder/vite.config.ts b/packages/builder/vite.config.ts deleted file mode 100644 index ae74518..0000000 --- a/packages/builder/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import react from '@vitejs/plugin-react' -import { defineConfig } from 'vite' - -export default defineConfig({ - plugins: [react()], -}) diff --git a/packages/builder/package.json b/packages/ui/package.json similarity index 54% rename from packages/builder/package.json rename to packages/ui/package.json index 36910c4..3836465 100644 --- a/packages/builder/package.json +++ b/packages/ui/package.json @@ -1,17 +1,25 @@ { - "name": "@flows-ai/builder", - "private": true, + "name": "@flows-ai/ui", "version": "0.2.1", "type": "module", + "exports": { + "bun": "./src/index.ts", + "types": { + "import": "./dist/index.d.ts", + "require": "./dist/index.d.cts" + }, + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" + "prepare": "bun run build", + "build": "tsup-node" }, "dependencies": { "@dagrejs/dagre": "^1.1.4", - "@xyflow/react": "^12.4.1", + "@xyflow/react": "^12.4.1" + }, + "peerDependencies": { "react": "^19.0.0", "react-dom": "^19.0.0" }, diff --git a/packages/builder/src/App.tsx b/packages/ui/src/Flow.tsx similarity index 78% rename from packages/builder/src/App.tsx rename to packages/ui/src/Flow.tsx index 0be37e4..46ac339 100644 --- a/packages/builder/src/App.tsx +++ b/packages/ui/src/Flow.tsx @@ -1,23 +1,22 @@ import '@xyflow/react/dist/style.css' +import './flow.css' import Dagre from '@dagrejs/dagre' import { Background, - Edge, - Node, + type Edge, + type Node, ReactFlow, + ReactFlowProvider, useEdgesState, useNodesInitialized, useNodesState, useReactFlow, } from '@xyflow/react' -import { FlowDefinition } from 'flows-ai' -import { useEffect, useMemo } from 'react' +import { type FlowDefinition } from 'flows-ai' +import { useEffect } from 'react' -// tbd: let's keep it during testing phase -// going forward, we will have to do something such as drag&drop or loader -import { githubProjectHealthAnalysisFlow } from '../../../example/flows.ts' -import AgentNode from './AgentNode.tsx' +import AgentNode from './nodes/agent.tsx' const nodeTypes = { agent: AgentNode, @@ -113,21 +112,18 @@ function generateNodesAndEdges( return { nodes, edges } } -function Flow() { - const { fitView, getNodes, getEdges } = useReactFlow() +function Flow({ flow }: { flow: FlowDefinition }) { + const { fitView } = useReactFlow() const nodesInitialized = useNodesInitialized() - const { nodes: initialNodes, edges: initialEdges } = useMemo( - () => generateNodesAndEdges(githubProjectHealthAnalysisFlow), - [] - ) + const graph = generateNodesAndEdges(flow) - const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes) - const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges) + const [nodes, setNodes, onNodesChange] = useNodesState(graph.nodes) + const [edges, setEdges, onEdgesChange] = useEdgesState(graph.edges) useEffect(() => { if (nodesInitialized) { - const layouted = getLayoutedElements(getNodes(), getEdges(), 'TB') + const layouted = getLayoutedElements(nodes, edges, 'TB') setNodes([...layouted.nodes]) setEdges([...layouted.edges]) @@ -138,6 +134,11 @@ function Flow() { } }, [nodesInitialized]) + useEffect(() => { + setNodes(graph.nodes) + setEdges(graph.edges) + }, [flow]) + return ( ) => ( + + + +) diff --git a/packages/ui/src/flow.css b/packages/ui/src/flow.css new file mode 100644 index 0000000..778c76f --- /dev/null +++ b/packages/ui/src/flow.css @@ -0,0 +1,14 @@ +.react-flow__node { + box-shadow: var(--xy-node-boxshadow-default); + border-radius: var(--xy-node-border-radius-default); + background-color: white; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + padding: 10px; + font-size: 12px; + flex-direction: column; + border: var(--xy-node-border-default); + color: black; +} diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts new file mode 100644 index 0000000..4684116 --- /dev/null +++ b/packages/ui/src/index.ts @@ -0,0 +1 @@ +export { default as Flow } from './Flow' diff --git a/packages/builder/src/AgentNode.tsx b/packages/ui/src/nodes/agent.tsx similarity index 77% rename from packages/builder/src/AgentNode.tsx rename to packages/ui/src/nodes/agent.tsx index 6787baa..79abc15 100644 --- a/packages/builder/src/AgentNode.tsx +++ b/packages/ui/src/nodes/agent.tsx @@ -1,5 +1,5 @@ -import { Handle, Node, NodeProps, Position } from '@xyflow/react' -import { FlowDefinition } from 'flows-ai' +import { Handle, type Node, type NodeProps, Position } from '@xyflow/react' +import type { FlowDefinition } from 'flows-ai' /** * Custom generic node for all types of agents. diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json new file mode 100644 index 0000000..59f2bd9 --- /dev/null +++ b/packages/ui/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src"], + "compilerOptions": { + "lib": ["DOM"] + } +} diff --git a/packages/ui/tsup.config.ts b/packages/ui/tsup.config.ts new file mode 100644 index 0000000..9d64866 --- /dev/null +++ b/packages/ui/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'tsup' + +export default defineConfig({ + entry: ['./src/**/*.ts'], + format: ['cjs', 'esm'], + target: 'node20', + splitting: false, + clean: true, + dts: true, +})