Add playground file with example of how to create a component

This also fixes several internal issues related to component
creaton.
This commit is contained in:
Andrey Antukh 2025-05-19 11:13:52 +02:00
parent 778de6adaf
commit 645c4a57db
2 changed files with 126 additions and 9 deletions

View file

@ -122,7 +122,9 @@
[:component-id ::sm/uuid]
[:file-id {:optional true} ::sm/uuid]
[:name {:optional true} ::sm/text]
[:path {:optional true} ::sm/text]])
[:path {:optional true} ::sm/text]
[:frame-id {:optional true} ::sm/uuid]
[:page-id {:optional true} ::sm/uuid]])
(def ^:private check-add-component
(sm/check-fn schema:add-component
@ -134,7 +136,9 @@
(def schema:add-component-instance
[:map
[:component-id ::sm/uuid]
[:file-id {:optional true} ::sm/uuid]])
[:file-id {:optional true} ::sm/uuid]
[:frame-id {:optional true} ::sm/uuid]
[:page-id {:optional true} ::sm/uuid]])
(def ^:private check-add-component-instance
(sm/check-fn schema:add-component-instance
@ -392,15 +396,18 @@
(defn add-component
[state params]
(let [{:keys [component-id file-id name path]}
(let [{:keys [component-id file-id page-id frame-id name path]}
(-> (check-add-component params)
(update :component-id default-uuid))
frame-id
(get state ::current-frame-id)
file-id
(or file-id (::current-file-id state))
page-id
(get state ::current-page-id)
(or page-id (get state ::current-page-id))
frame-id
(or frame-id (get state ::current-frame-id))
change1
(d/without-nils
@ -414,8 +421,10 @@
change2
{:type :mod-obj
:id frame-id
:page-id page-id
:operations
[{:type :set :attr :component-root :val true}
{:type :set :attr :main-instance :val true}
{:type :set :attr :component-id :val component-id}
{:type :set :attr :component-file :val file-id}]}]
@ -423,23 +432,28 @@
(commit-change change1)
(commit-change change2))))
(defn add-component-instance
[state params]
(let [{:keys [component-id file-id]}
(let [{:keys [component-id file-id frame-id page-id]}
(check-add-component-instance params)
file-id
(or file-id (get state ::current-file-id))
frame-id
(get state ::current-frame-id)
(or frame-id (get state ::current-frame-id))
page-id
(or page-id (get state ::current-page-id))
change
{:type :mod-obj
:id frame-id
:page-id page-id
:operations
[{:type :set :attr :component-root :val false}
[{:type :set :attr :component-root :val true}
{:type :set :attr :component-id :val component-id}
{:type :set :attr :component-file :val file-id}]}]

View file

@ -0,0 +1,103 @@
import * as penpot from "#self";
import { createWriteStream } from 'fs';
import { Writable } from "stream";
// Example of creating component and instance out of order
(async function() {
const context = penpot.createBuildContext();
{
context.addFile({name: "Test File 1"});
context.addPage({name: "Foo Page"})
const mainBoardId = context.genId();
const mainRectId = context.genId();
// First create instance (just for with the purpose of teaching
// that it can be done, without putting that under obligation to
// do it in this order or the opposite)
context.addBoard({
name: "Board Instance 1",
x: 700,
y: 0,
width: 500,
height: 300,
shapeRef: mainBoardId,
touched: ["name-group"]
})
context.addRect({
name: "Rect Instance 1",
x: 800,
y: 20,
width:100,
height:200,
shapeRef: mainRectId,
touched: ["name-group"]
});
// this function call takes the current board from context, but it
// also can be passed as parameter on an explicit way if you
// prefer
context.addComponentInstance({
componentId: "00000000-0000-0000-0000-000000000001"
});
context.closeBoard();
// Then, create the main instance
context.addBoard({
id: mainBoardId,
name: "Board",
x: 0,
y: 0,
width: 500,
height: 300,
})
context.addRect({
id: mainRectId,
name: "Rect 1",
x: 20,
y: 20,
width:100,
height:200,
});
context.addComponent({
componentId: "00000000-0000-0000-0000-000000000001",
name: "Component 1",
});
context.closeBoard();
context.closeFile();
}
{
// Create a file stream to write the zip to
const output = createWriteStream('sample-with-components.zip');
// Wrap Node's stream in a WHATWG WritableStream
const writable = Writable.toWeb(output);
await penpot.exportStream(context, writable);
}
})().catch((cause) => {
console.error(cause);
const causeExplain = cause.explain;
if (causeExplain) {
console.log("EXPLAIN:")
console.error(cause.explain);
}
// const innerCause = cause.cause;
// if (innerCause) {
// console.log("INNER:");
// console.error(innerCause);
// }
process.exit(-1);
}).finally(() => {
process.exit(0);
})