diff --git a/common/src/app/common/files/builder.cljc b/common/src/app/common/files/builder.cljc index 210051262..19e668193 100644 --- a/common/src/app/common/files/builder.cljc +++ b/common/src/app/common/files/builder.cljc @@ -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}]}] diff --git a/library/playground/components.js b/library/playground/components.js new file mode 100644 index 000000000..8b400b761 --- /dev/null +++ b/library/playground/components.js @@ -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); +})