Paperclip is a template language that's designed for visual development. See what you're creating in real-time, directly within VS Code.
Paperclip just covers basic HTML, CSS, and syntax for defining dumb components. Here's an example:
<!-- todo-list.pc -->
<!--
Styles are scoped to this file, so you don't have to worry about them leaking out.
-->
<style>
* {
font-family: Helvetica;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li[done] {
text-decoration: line-through;
}
</style>
<!-- Parts are building blocks that are individually used in application code (more information below). -->
<part id="TodoItem">
<!-- You can assign attribute bindings. -->
<li {done}>
<input type="checkbox" checked={done} onClick={onDoneClick}>
<!-- You can also define slots where text & elements are inserted into. -->
{label}
</li>
</part>
<part id="TodoList">
<h1>Todos:</h1>
<input type="text" onKeyPress={onNewTodoKeyPress} placeholder="Add a new todo..." >
<ul>
{todoItems}
</ul>
</part>
<!-- Preview is a special tag for development that allows you to see how all of your parts look when put together in their varying states. -->
<preview>
<TodoList todoItems={<>
<TodoItem label="Feed cat" done />
<TodoItem label="Take out trash" />
<TodoItem label="Walk dog" done />
</>} />
</preview>
Here's what you see in VS Code as you type away:
☝🏻This example uses just about all of the features that Paperclip has to offer. No logic, just syntax for describing how your UI looks.
Templates compile directly to highly optimized code. Using our list example above, here's how you might use it in a React app:
// <part /> elements are exposed as React components.
import { TodoList, TodoItem } from "./list.pc";
import React, { useState } from "react";
export default () => {
const [todos, setTodos] = useState([
{ label: "Clean car" },
{ label: "Eat food", done: true },
{ label: "Sell car" }
]);
const onNewInputKeyPress = (event) => {
if (event.key === "Enter" && value) {
setTodos([...todos, { label: event.target.value }]);
event.target.value = "";
}
};
const onDoneClick = (todo: Todo) => {
setTodos(
todos.map(oldTodo => {
return oldTodo.id === todo.id
? {
...oldTodo,
done: !oldTodo.done
}
: oldTodo;
})
);
};
// The attribute bindings & slots that were defined are
// exposed as props for each <part /> component.
return (
<TodoList
onNewTodoKeyPress={onNewInputKeyPress}
todoItems={todos.map(todo => {
return (
<TodoItem
done={todo.done}
onDoneClick={() => onDoneClick(todo)}
label={todo.label}
key={todo.id}
/>
);
})}
/>
);
};
The code for this example is also here.
More compiler targets are planned for other languages and frameworks. React is just a starting point ✌🏻.
As you can see, <part />
elements are exported as dumb components that React can use. From there we can combine all parts with logic to create a functional component. That's the gist of Paperclip!
Templates compile down to strongly typed code, so you don't have to guess about what your templates need. Here's a generated TypesScript definition of our React app above:
import {ReactNode, ReactHTML, Factory, InputHTMLAttributes, ClassAttributes} from "react";
type ElementProps = InputHTMLAttributes<HTMLInputElement> & ClassAttributes<HTMLInputElement>;
export declare const styled: (tag: keyof ReactHTML | Factory<ElementProps>, defaultProps?: ElementProps) => Factory<ElementProps>;
type TodoItemProps = {
done: String | boolean | Number | Object | ReactNode,
onDoneClick: Function,
label: String | boolean | Number | Object | ReactNode,
};
export const TodoItem: Factory<TodoItemProps>;
type TodoListProps = {
onNewTodoKeyPress: Function,
todoItems: String | boolean | Number | Object | ReactNode,
};
export const TodoList: Factory<TodoListProps>;
- Works out of the box. Just download the VS Code extension and start typing away.
- Previews are powered by a low-level runtime, so your changes appear instantly, and won't slow down as your project scales.
- Templates can be compiled to strongly typed code.
- Templates Integrate with your existing React application (more languages & frameworks soon).
- Integrates with Webpack.
This is just the beginning! Here are just a few planned features:
- Zero-setup automated visual regression testing. Just plug in your Paperclip files.
- More compiler targets: Ruby, PHP, VueJS, AngularJS, and others.
- More code editor integrations: Sublime, Atom.
- More visual tooling in the preview, so you can make visual changes directly.
- Preview against different browsers directly within your code editor.
- Animation tooling
The goal for Paperclip is to eliminate bottlenecks around HTML & CSS development, and provide tooling that helps you ship UI features quicker. More specifically:
- Eliminate the lag time between writing code & seeing UI.
- Shorten the gap between design -> code by bringing more design tooling into web development.
- Provide better safety around building UIs with easier to use cross-browser testing tools.