272 lines
7.6 KiB
Markdown
272 lines
7.6 KiB
Markdown
Here’s a complete README draft you can use for your project:
|
||
|
||
---
|
||
|
||
# 🖌️ tldraw Interactive UI Controllers
|
||
|
||
This project extends [tldraw](https://tldraw.dev) to support **interactive UI components** (similar to Balsamiq) that can be dropped into the canvas and interacted with directly.
|
||
|
||
We’ve built **10 controllers**:
|
||
|
||
1. ✅ **Checkbox**
|
||
2. 🔘 **Radio Group**
|
||
3. ✏️ **Text Input**
|
||
4. 📝 **Textarea**
|
||
5. ⏹ **Button**
|
||
6. 🔄 **Toggle Switch**
|
||
7. 📅 **Date Picker**
|
||
8. 🔽 **ComboBox (Select Dropdown)**
|
||
9. 📊 **Data Grid (Table)**
|
||
10. 📦 **Form Container** (groups other controls)
|
||
|
||
All controllers are **fully interactive** inside the canvas, not just static wireframes.
|
||
|
||
---
|
||
|
||
## 🚀 Features
|
||
|
||
* Drag & drop controllers into the tldraw canvas.
|
||
* Controls retain **state** (e.g., checkbox checked, input text, dropdown selection).
|
||
* Controls are **resizable & draggable** like normal shapes.
|
||
* Real **HTML elements embedded in SVG** via `foreignObject`.
|
||
* Can be extended with new components easily.
|
||
|
||
---
|
||
|
||
## 📂 Project Structure
|
||
|
||
```
|
||
src/
|
||
├─ shapes/
|
||
│ ├─ ButtonShape.tsx
|
||
│ ├─ CheckboxShape.tsx
|
||
│ ├─ ComboBoxShape.tsx
|
||
│ ├─ DataGridShape.tsx
|
||
│ ├─ DatePickerShape.tsx
|
||
│ ├─ FormShape.tsx
|
||
│ ├─ InputShape.tsx
|
||
│ ├─ RadioGroupShape.tsx
|
||
│ ├─ TextAreaShape.tsx
|
||
│ └─ ToggleShape.tsx
|
||
├─ components/
|
||
│ └─ ControlsPalette.tsx
|
||
├─ App.tsx
|
||
└─ main.tsx
|
||
```
|
||
|
||
---
|
||
|
||
## ⚡ Installation
|
||
|
||
```bash
|
||
git clone https://github.com/your-org/tldraw-ui-controllers.git
|
||
cd tldraw-ui-controllers
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
Open [http://localhost:5173](http://localhost:5173) in your browser.
|
||
|
||
---
|
||
|
||
## 🛠️ Usage
|
||
|
||
### Adding a Control
|
||
|
||
Each control is implemented as a **custom shape**.
|
||
From the **palette sidebar**, you can click any control to insert it:
|
||
|
||
```tsx
|
||
editor.createShape({
|
||
type: "checkbox",
|
||
x: 200,
|
||
y: 200,
|
||
props: { checked: false, label: "Accept Terms" },
|
||
});
|
||
```
|
||
|
||
### Example: Checkbox Implementation
|
||
|
||
```tsx
|
||
type CheckboxShape = TLBaseShape<"checkbox", { checked: boolean; label: string }>;
|
||
|
||
class CheckboxShapeUtil extends ShapeUtil<CheckboxShape> {
|
||
static override type = "checkbox";
|
||
|
||
override render(shape: CheckboxShape) {
|
||
return (
|
||
<foreignObject width={200} height={40}>
|
||
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
||
<input
|
||
type="checkbox"
|
||
checked={shape.props.checked}
|
||
onChange={(e) =>
|
||
this.editor.updateShape({
|
||
...shape,
|
||
props: { ...shape.props, checked: e.target.checked },
|
||
})
|
||
}
|
||
/>
|
||
<span>{shape.props.label}</span>
|
||
</div>
|
||
</foreignObject>
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🎛️ Controllers
|
||
|
||
| Control | Description | Example Props |
|
||
| ------------------ | -------------------------- | ---------------------------------------------- |
|
||
| **Button** | Clickable button | `{ label: "Submit" }` |
|
||
| **Checkbox** | Standard checkbox | `{ checked: false, label: "Accept Terms" }` |
|
||
| **Radio Group** | Multiple exclusive options | `{ options: ["A", "B", "C"], selected: "A" }` |
|
||
| **Text Input** | Single-line input | `{ value: "", placeholder: "Enter text" }` |
|
||
| **Textarea** | Multi-line input | `{ value: "", placeholder: "Write here..." }` |
|
||
| **Toggle Switch** | On/Off toggle | `{ on: true }` |
|
||
| **Date Picker** | Calendar input | `{ date: "2025-09-01" }` |
|
||
| **ComboBox** | Dropdown list | `{ options: ["One", "Two"], selected: "One" }` |
|
||
| **Data Grid** | Simple editable table | `{ rows: [["A1","B1"],["A2","B2"]] }` |
|
||
| **Form Container** | Holds other shapes | `{ title: "User Form" }` |
|
||
|
||
---
|
||
|
||
## 🧩 Extending with New Controls
|
||
|
||
To add a new control:
|
||
|
||
1. Create a new `ShapeUtil` subclass in `src/shapes/`.
|
||
2. Use `<foreignObject>` to render any HTML element.
|
||
3. Update `App.tsx` to register it in `shapeUtils`.
|
||
4. Add it to the **ControlsPalette**.
|
||
|
||
---
|
||
|
||
## 📸 Preview
|
||
|
||
* Palette on the left with draggable controllers.
|
||
* tldraw canvas on the right.
|
||
* Controls behave just like Balsamiq but **real & interactive**.
|
||
|
||
---
|
||
Got it ✅ I see your **Prompt-to-Wireframe (tldraw)** app running locally — it already generates wireframes on the canvas. Now you want to **integrate the interactive controllers (button, forms, data grid, date picker, etc.)** into this environment.
|
||
|
||
Here’s how you can integrate the two:
|
||
|
||
---
|
||
|
||
## 🔹 Integration Plan
|
||
|
||
1. **Extend your current tldraw setup**
|
||
|
||
* Right now your app renders `<Tldraw />` with AI-generated wireframes.
|
||
* You’ll register your **10 custom controllers (shapes)** into the same editor.
|
||
|
||
2. **Add Controllers Palette**
|
||
|
||
* Create a sidebar/panel with the controllers (like Balsamiq’s top bar).
|
||
* Each controller button inserts its shape into the tldraw canvas.
|
||
|
||
3. **Register Custom Shapes**
|
||
|
||
* In your `App.tsx` (or wherever `<Tldraw />` is rendered), pass `shapeUtils` with all the controllers you built:
|
||
|
||
```tsx
|
||
import {
|
||
ButtonShapeUtil,
|
||
CheckboxShapeUtil,
|
||
ComboBoxShapeUtil,
|
||
DataGridShapeUtil,
|
||
DatePickerShapeUtil,
|
||
FormShapeUtil,
|
||
InputShapeUtil,
|
||
RadioGroupShapeUtil,
|
||
TextAreaShapeUtil,
|
||
ToggleShapeUtil,
|
||
} from "./shapes";
|
||
|
||
<Tldraw shapeUtils={[
|
||
ButtonShapeUtil,
|
||
CheckboxShapeUtil,
|
||
ComboBoxShapeUtil,
|
||
DataGridShapeUtil,
|
||
DatePickerShapeUtil,
|
||
FormShapeUtil,
|
||
InputShapeUtil,
|
||
RadioGroupShapeUtil,
|
||
TextAreaShapeUtil,
|
||
ToggleShapeUtil,
|
||
]} />
|
||
```
|
||
|
||
4. **Connect Palette → Shape Creation**
|
||
Example for a button in your palette:
|
||
|
||
```tsx
|
||
function ControlsPalette({ editor }) {
|
||
return (
|
||
<div className="palette">
|
||
<button
|
||
onClick={() =>
|
||
editor.createShape({
|
||
type: "button",
|
||
x: 200,
|
||
y: 200,
|
||
props: { label: "Click Me" },
|
||
})
|
||
}
|
||
>
|
||
➕ Button
|
||
</button>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
Add similar buttons for checkbox, date picker, grid, etc.
|
||
|
||
5. **Combine With Prompt-to-Wireframe Flow**
|
||
|
||
* When your AI generates wireframes, they appear as usual.
|
||
* The user can then drag in **interactive controllers** to replace/augment them.
|
||
* Example: AI generates a rectangle with label "DATA TABLE" → user deletes it and inserts a real **DataGridShape**.
|
||
|
||
---
|
||
|
||
## 🔹 Updated Project Structure
|
||
|
||
```
|
||
src/
|
||
├─ shapes/ # all 10 controllers
|
||
│ ├─ ButtonShape.tsx
|
||
│ ├─ CheckboxShape.tsx
|
||
│ ├─ ...
|
||
├─ components/
|
||
│ ├─ ControlsPalette.tsx
|
||
│ └─ WireframeGenerator.tsx # your existing AI integration
|
||
├─ App.tsx
|
||
└─ main.tsx
|
||
```
|
||
|
||
---
|
||
|
||
## 🔹 User Flow After Integration
|
||
|
||
1. User enters a **prompt** → AI generates a wireframe layout (as in your screenshot).
|
||
2. User sees a **palette of interactive controllers**.
|
||
3. User drags/drops or clicks to insert **real interactive controls** (button, forms, date pickers, data grid).
|
||
4. Wireframe evolves into a **clickable mockup**, not just static boxes.
|
||
|
||
---
|
||
|
||
## 📜 License
|
||
|
||
MIT License © 2025
|
||
|
||
---
|
||
|
||
👉 Do you want me to **include example code for all 10 controllers in the README** (full implementations), or just keep this README as a **setup + usage guide** and document the shape types in a separate file?
|