Compare commits

..

8 Commits

Author SHA1 Message Date
alonso.torres
0f407d5c3c Add new plugin methods 2026-01-27 17:20:20 +01:00
Andrey Antukh
3112b240a0 📎 Add missing entry on changelog 2026-01-27 09:28:41 +01:00
Andrey Antukh
56fd66b91a 🐛 Fix several issues related to path edition (#8187)
*  Improve save-path-content event consistency

Mainly removing possible race conditions from the event
implementation.

*  Ensure path content snapshot on start-path-edit event

*  Reuse already available shape-id on split-segments
2026-01-27 09:27:42 +01:00
David Barragán Merino
1ce0b60e3d 🔧 Run all the jobs if the workflow is launched manually 2026-01-26 17:13:54 +01:00
David Barragán Merino
ef80901400 🔧 Enable secret inheritance 2026-01-26 14:00:55 +01:00
David Barragán Merino
5306bed548 🔧 Define deploy plugin packages workflows 2026-01-26 13:47:57 +01:00
David Barragán Merino
92a319ddd1 🔧 Rename wrangle to wrangler 2026-01-26 13:47:57 +01:00
David Barragán Merino
68a6d4c9a8 🔧 Add deploy plugin packages workflow placeholder and wrangle config files 2026-01-26 13:47:57 +01:00
21 changed files with 207 additions and 217 deletions

View File

@@ -7,11 +7,11 @@ on:
- staging
- main
paths:
- 'plugins/libs/plugin-types/index.d.ts'
- 'plugins/libs/plugin-types/REAME.md'
- 'plugins/tools/typedoc.css'
- 'plugins/CHANGELOG.md'
- 'plugins/wrangler-penpot-plugins-api-doc.toml'
- "plugins/libs/plugin-types/index.d.ts"
- "plugins/libs/plugin-types/REAME.md"
- "plugins/tools/typedoc.css"
- "plugins/CHANGELOG.md"
- "plugins/wrangler-penpot-plugins-api-doc.toml"
workflow_dispatch:
inputs:
gh_ref:
@@ -86,28 +86,28 @@ jobs:
run: |
REF="${{ steps.vars.outputs.gh_ref }}"
case "$REF" in
main)
echo "WORKER_NAME=penpot-plugins-api-doc-pro" >> $GITHUB_ENV
echo "WORKER_URI=doc.plugins.penpot.app" >> $GITHUB_ENV ;;
staging)
echo "WORKER_NAME=penpot-plugins-api-doc-pre" >> $GITHUB_ENV
echo "WORKER_URI=doc.plugins.penpot.dev" >> $GITHUB_ENV ;;
develop)
echo "WORKER_NAME=penpot-plugins-api-doc-hourly" >> $GITHUB_ENV
echo "WORKER_URI=doc.plugins.hourly.penpot.dev" >> $GITHUB_ENV ;;
main) echo "WORKER_NAME=penpot-plugins-api-doc-pro" >> $GITHUB_ENV ;;
staging) echo "WORKER_NAME=penpot-plugins-api-doc-pre" >> $GITHUB_ENV ;;
develop) echo "WORKER_NAME=penpot-plugins-api-doc-hourly" >> $GITHUB_ENV ;;
*) echo "Unsupported branch ${REF}" && exit 1 ;;
esac
- name: Set the custom url
working-directory: plugins
shell: bash
run: |
sed -i "s/WORKER_URI/${{ env.WORKER_URI }}/g" wrangler-penpot-plugins-api-doc.toml
- name: Deploy to Cloudflare Workers
uses: cloudflare/wrangler-action@v3
with:
workingDirectory: plugins
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: deploy --config wrangle-penpot-plugins-api-doc.toml --name ${{ env.WORKER_NAME }}
command: deploy --config wrangler-penpot-plugins-api-doc.toml --name ${{ env.WORKER_NAME }}
- name: Notify Mattermost
if: failure()
uses: mattermost/action-mattermost-notify@master
with:
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK }}
MATTERMOST_CHANNEL: bot-alerts-cicd
TEXT: |
❌ 🧩📚 *[PENPOT PLUGINS] Error deploying API documentation.*
📄 Triggered from ref: `${{ inputs.gh_ref }}`
🔗 Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
@infra

View File

@@ -1,123 +0,0 @@
name: Plugins/styles-doc deployer
on:
push:
branches:
- develop
- staging
- main
paths:
- 'plugins/apps/example-styles/**'
- 'plugins/libs/plugins-styles/**'
- 'plugins/wrangler-penpot-plugins-styles-doc.toml'
workflow_dispatch:
inputs:
gh_ref:
description: 'Name of the branch'
type: choice
required: true
default: 'develop'
options:
- develop
- staging
- main
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Extract some useful variables
id: vars
run: |
echo "gh_ref=${{ inputs.gh_ref || github.ref_name }}" >> $GITHUB_OUTPUT
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ steps.vars.outputs.gh_ref }}
# START: Setup Node and PNPM enabling cache
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
- name: Enable PNPM
working-directory: ./plugins
shell: bash
run: |
corepack enable;
corepack install;
- name: Get pnpm store path
id: pnpm-store
working-directory: ./plugins
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-store.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-${{ hashFiles('plugins/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
# END: Setup Node and PNPM enabling cache
- name: Install deps
working-directory: ./plugins
shell: bash
run: |
pnpm install --no-frozen-lockfile;
pnpm add -D -w wrangler@latest;
- name: Build styles
working-directory: plugins
shell: bash
run: npx nx run example-styles:build
- name: Select Worker name
run: |
REF="${{ steps.vars.outputs.gh_ref }}"
case "$REF" in
main)
echo "WORKER_NAME=penpot-plugins-styles-doc-pro" >> $GITHUB_ENV
echo "WORKER_URI=styles-doc.plugins.penpot.app" >> $GITHUB_ENV ;;
staging)
echo "WORKER_NAME=penpot-plugins-styles-doc-pre" >> $GITHUB_ENV
echo "WORKER_URI=styles-doc.plugins.penpot.dev" >> $GITHUB_ENV ;;
develop)
echo "WORKER_NAME=penpot-plugins-styles-doc-hourly" >> $GITHUB_ENV
echo "WORKER_URI=styles-doc.plugins.hourly.penpot.dev" >> $GITHUB_ENV ;;
*) echo "Unsupported branch ${REF}" && exit 1 ;;
esac
- name: Set the custom url
working-directory: plugins
shell: bash
run: |
sed -i "s/WORKER_URI/${{ env.WORKER_URI }}/g" wrangler-penpot-plugins-styles-doc.toml
- name: Deploy to Cloudflare Workers
uses: cloudflare/wrangler-action@v3
with:
workingDirectory: plugins
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: deploy --config wrangler-penpot-plugins-styles-doc.toml --name ${{ env.WORKER_NAME }}
- name: Notify Mattermost
if: failure()
uses: mattermost/action-mattermost-notify@master
with:
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK }}
MATTERMOST_CHANNEL: bot-alerts-cicd
TEXT: |
❌ 🧩💅 *[PENPOT PLUGINS] Error deploying Styles documentation.*
📄 Triggered from ref: `${{ inputs.gh_ref }}`
🔗 Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
@infra

View File

@@ -36,6 +36,7 @@
- Fix exception on uploading large fonts [Github #8135](https://github.com/penpot/penpot/pull/8135)
- Fix unhandled exception on open-new-window helper [Github #7787](https://github.com/penpot/penpot/issues/7787)
- Fix incorrect handling of input values on layout gap and padding inputs [Github #8113](https://github.com/penpot/penpot/issues/8113)
- Fix several race conditions on path editor [Github #8187](https://github.com/penpot/penpot/pull/8187)
## 2.12.1

View File

@@ -6,4 +6,4 @@ desc: Create, deploy, and use the Penpot plugin API with our comprehensive docum
# Penpot plugins API
We've got all the documentation you need for the API right <a target="_blank" href="https://doc.plugins.penpot.app/">here</a>.
We've got all the documentation you need for the API right <a target="_blank" href="https://penpot-plugins-api-doc.pages.dev/">here</a>.

View File

@@ -9,13 +9,13 @@ desc: See the Penpot plugin API changelog for version 1.0! Find breaking changes
### <g-emoji class="g-emoji" alias="boom" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f680.png"><img class="emoji" alt="boom" height="20" width="20" src="https://github.githubassets.com/images/icons/emoji/unicode/1f680.png"></g-emoji> Epics and highlights</code>
- This marks the release of version 1.0, and from this point forward, well do our best to avoid making any more breaking changes (or make deprecations backward compatible).
- Weve redone the documentation. You can check the API here:
[https://doc.plugins.penpot.app/](https://doc.plugins.penpot.app/)
[https://penpot-plugins-api-doc.pages.dev/](https://penpot-plugins-api-doc.pages.dev/)
- New samples repository with lots of samples to use the API:
[https://github.com/penpot/penpot-plugins-samples](https://github.com/penpot/penpot-plugins-samples)
### <g-emoji class="g-emoji" alias="boom" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f4a5.png"><img class="emoji" alt="boom" height="20" width="20" src="https://github.githubassets.com/images/icons/emoji/unicode/1f4a5.png"></g-emoji> Breaking changes & Deprecations
- Changed types names to remove the Penpot prefix. So for example: <code class="language-js">PenpotShape</code> becomes <code class="language-js">Shape</code>; <code class="language-js">PenpotFile</code> becomes <code class="language-js">File</code>, and so on. Check the [API documentation](https://doc.plugins.penpot.app/) for more details.
- Changed types names to remove the Penpot prefix. So for example: <code class="language-js">PenpotShape</code> becomes <code class="language-js">Shape</code>; <code class="language-js">PenpotFile</code> becomes <code class="language-js">File</code>, and so on. Check the [API documentation](https://penpot-plugins-api-doc.pages.dev/) for more details.
- Changes on the <code class="language-js">penpot.on</code> and <code class="language-js">penpot.off</code> methods.
Previously you had to send the original callback to the off method in order to remove an event listener. Now, <code class="language-js">penpot.on</code> will return an *id* that you can pass to the <code class="language-js">penpot.off</code> method in order to remove the listener.

View File

@@ -49,7 +49,7 @@ There are two libraries that can help you with your plugin's development. They a
### Plugin styles
<code class="language-js">@penpot/plugin-styles</code> contains styles to help build the UI for Penpot plugins. To check the styles go to <a target="_blank" href="https://styles-doc.plugins.penpot.app/">Plugin styles</a>.
<code class="language-js">@penpot/plugin-styles</code> contains styles to help build the UI for Penpot plugins. To check the styles go to <a target="_blank" href="https://penpot-plugins-styles.pages.dev/">Plugin styles</a>.
```bash
npm install @penpot/plugin-styles
@@ -139,7 +139,7 @@ parent.postMessage(responseMessage, targetOrigin);
By using these message-based events, any data retrieved through the Penpot API can be communicated to and from your plugin interface seamlessly.
For more detailed information, refer to the [Penpot Plugins API Documentation](https://doc.plugins.penpot.app/).
For more detailed information, refer to the [Penpot Plugins API Documentation](https://penpot-plugins-api-doc.pages.dev/).
## 2.5. Step 5. Build the plugin file

View File

@@ -86,7 +86,7 @@ penpot.library.local.createTypography();
Penpot has dark and light modes, and you can easily add this to your plugin so your interface adapts to both themes. When you add theme support, your plugin will automatically sync with Penpot's interface settings, so the user experience is consistent no matter which mode is selected. This makes your plugin look better and also ensures it stays in line with Penpot's overall design.
Just a heads-up: if you use the <a target="_blank" href="https://styles-doc.plugins.penpot.app/">plugin-styles library</a>, many elements will automatically adapt to dark or light mode without any extra effort from you. However, if you need to customize specific elements, be sure to use the selectors provided in the <code class="language-bash">styles.css</code> of the example.
Just a heads-up: if you use the <a target="_blank" href="https://penpot-plugins-styles.pages.dev/">plugin-styles library</a>, many elements will automatically adapt to dark or light mode without any extra effort from you. However, if you need to customize specific elements, be sure to use the selectors provided in the <code class="language-bash">styles.css</code> of the example.
<a target="_blank" href="https://github.com/penpot/penpot-plugins-samples/tree/main/theme">Theme example</a>

View File

@@ -40,7 +40,7 @@ The plugin <a target="_blank" href="https://www.npmjs.com/package/@penpot/plugin
### Is the API ready to use the prototyping features?
Absolutely! You can definitely create flows and interactions in the same elements as in the interface, like frames, shapes, and groups. Just check out the API documentation for the methods: createFlow, addInteraction, or removeInteraction. And if you need more help, you can always check out the <a target="_blank" href="https://doc.plugins.penpot.app/interfaces/Flow">Flow</a> or <a target="_blank" href="https://doc.plugins.penpot.app/interfaces/Interaction">Interaction</a> interfaces.
Absolutely! You can definitely create flows and interactions in the same elements as in the interface, like frames, shapes, and groups. Just check out the API documentation for the methods: createFlow, addInteraction, or removeInteraction. And if you need more help, you can always check out the <a target="_blank" href="https://penpot-plugins-api-doc.pages.dev/interfaces/PenpotFlow">PenpotFlow</a> or <a target="_blank" href="https://penpot-plugins-api-doc.pages.dev/interfaces/PenpotInteraction">PenpotInteraction</a> interfaces.
### Are there any security or quality criteria I should be aware of?
@@ -48,8 +48,7 @@ There are no set requirements. However, we can recommend the use of <a target="_
### Is it necessary to create plugins with a UI?
No, its completely optional, in fact, we have an example of a plugin without UI. Try the plugin using this url to install it: <code class="language-js">https:\/\/create-palette.plugins.penpot.app/assets/manifest.json</code> or check the code <a target="_blank" href="https://github.com/penpot/penpot/tree/main/plugins/apps/create-palette-plugin">here</a>
No, its completely optional, in fact, we have an example of a plugin without UI. Try the plugin using this url to install it: <code class="language-js">https:\/\/create-palette-penpot-plugin.pages.dev/assets/manifest.json</code> or check the code <a target="_blank" href="https://github.com/penpot/penpot-plugins/tree/main/apps/create-palette-plugin">here</a>
### Can I create components?
@@ -59,7 +58,7 @@ Yes, it is possible to create components using:
createComponent(shapes: Shape[]): LibraryComponent;
```
Take a look at the Penpot Library methods in the <a target="_blank" href="https://doc.plugins.penpot.app/interfaces/Library">API documentation</a> or this <a target="_blank" href="https://github.com/penpot/penpot-plugins-samples/tree/main/components-library">simple example</a>.
Take a look at the Penpot Library methods in the <a target="_blank" href="https://penpot-plugins-api-doc.pages.dev/interfaces/Library">API documentation</a> or this <a target="_blank" href="https://github.com/penpot/penpot-plugins-samples/tree/main/components-library">simple example</a>.
### Is there a place where I can share my plugin?

View File

@@ -69,13 +69,12 @@ You need to provide the plugin's manifest URL for the installation. If there are
| Name | URL |
| ------------- | ------------------------------------------------------------------- |
| Color palette | https://create-palette.plugins.penpot.app/assets/manifest.json |
| Contrast | https://contrast.plugins.penpot.app/assets/manifest.json |
| Feather icons | https://icons.plugins.penpot.app/assets/manifest.json |
| Lorem ipsum | https://lorem-ipsum.plugins.penpot.app/assets/manifest.json |
| Rename layers | https://rename-layers.plugins.penpot.app/assets/manifest.json |
| Tables | https://table.plugins.penpot.app/assets/manifest.json |
| Lorem Ipsum | https://lorem-ipsum-penpot-plugin.pages.dev/assets/manifest.json |
| Contrast | https://contrast-penpot-plugin.pages.dev/assets/manifest.json |
| Feather icons | https://icons-penpot-plugin.pages.dev/assets/manifest.json |
| Tables | https://table-penpot-plugin.pages.dev/assets/manifest.json |
| Color palette | https://create-palette-penpot-plugin.pages.dev/assets/manifest.json |
| Rename layers | https://rename-layers-penpot-plugin.pages.dev/assets/manifest.json |
## 1.4. Plugin's basics

View File

@@ -70,20 +70,22 @@
(= (-> content last :command) :move-to))
(into [] (take (dec (count content)) content))
content)]
(-> state
(st/set-content content))))
(st/set-content state content)))
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (dsh/lookup-page-objects state page-id)
id (dm/get-in state [:workspace-local :edition])
old-content (dm/get-in state [:workspace-local :edit-path id :old-content])
shape (st/get-path state)]
local (get state :workspace-local)
id (get local :edition)
objects (dsh/lookup-page-objects state page-id)]
(if (and (some? old-content) (some? (:id shape)))
(let [changes (generate-path-changes it objects page-id shape old-content (:content shape))]
(rx/of (dch/commit-changes changes)))
(rx/empty)))))))
;; NOTE: we proceed only if the shape is present on the
;; objects, if shape is a ephimeral drawing shape, we should
;; do nothing
(when-let [shape (get objects id)]
(when-let [old-content (dm/get-in local [:edit-path id :old-content])]
(let [new-content (get shape :content)
changes (generate-path-changes it objects page-id shape old-content new-content)]
(rx/of (dch/commit-changes changes))))))))))

View File

@@ -8,7 +8,6 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.geom.point :as gpt]
[app.common.types.path :as path]
[app.common.types.path.helpers :as path.helpers]
@@ -289,34 +288,34 @@
(declare stop-path-edit)
(defn start-path-edit
[id]
(ptk/reify ::start-path-edit
ptk/UpdateEvent
(update [_ state]
(let [objects (dsh/lookup-page-objects state)
edit-path (dm/get-in state [:workspace-local :edit-path id])
content (st/get-path state :content)
state (cond-> state
(cfh/path-shape? objects id)
(st/set-content (path/close-subpaths content)))]
shape (get objects id)]
(cond-> state
(or (not edit-path)
(= :draw (:edit-mode edit-path)))
(assoc-in [:workspace-local :edit-path id] {:edit-mode :move
:selected #{}
:snap-toggled false})
(and (some? edit-path)
(= :move (:edit-mode edit-path)))
(assoc-in [:workspace-local :edit-path id :edit-mode] :draw))))
(-> state
(st/set-content (path/close-subpaths (:content shape)))
(update-in [:workspace-local :edit-path id]
(fn [state]
(let [state (if state
(if (= :move (:edit-mode state))
(assoc state :edit-mode :draw)
state)
{:edit-mode :move
:selected #{}
:snap-toggled false})]
(assoc state :old-content (:content shape))))))))
ptk/WatchEvent
(watch [_ _ stream]
(let [stopper (->> stream
(rx/filter #(let [type (ptk/type %)]
(= type ::dwe/clear-edition-mode)
(= type ::start-path-edit))))]
(let [stopper (rx/filter #(let [type (ptk/type %)]
(= type ::dwe/clear-edition-mode)
(= type ::start-path-edit))
stream)]
(rx/concat
(rx/of (undo/start-path-undo))
(->> stream
@@ -325,7 +324,8 @@
(rx/map #(stop-path-edit id))
(rx/take-until stopper)))))))
(defn stop-path-edit [id]
(defn stop-path-edit
[id]
(ptk/reify ::stop-path-edit
ptk/UpdateEvent
(update [_ state]
@@ -335,13 +335,12 @@
(watch [_ _ _]
(rx/of (ptk/data-event :layout/update {:ids [id]})))))
(defn split-segments
[{:keys [from-p to-p t]}]
(defn- split-segments
[id {:keys [from-p to-p t]}]
(ptk/reify ::split-segments
ptk/UpdateEvent
(update [_ state]
(let [id (st/get-path-id state)
content (st/get-path state :content)]
(let [content (st/get-path state :content)]
(-> state
(assoc-in [:workspace-local :edit-path id :old-content] content)
(st/set-content (-> content
@@ -353,10 +352,10 @@
(rx/of (changes/save-path-content {:preserve-move-to true})))))
(defn create-node-at-position
[event]
[params]
(ptk/reify ::create-node-at-position
ptk/WatchEvent
(watch [_ state _]
(let [id (st/get-path-id state)]
(rx/of (dwsh/update-shapes [id] path/convert-to-path)
(split-segments event))))))
(split-segments id params))))))

View File

@@ -261,6 +261,33 @@
:else
(let [child-id (obj/get child "$id")]
(st/emit! (dwt/move-shapes-to-frame #{child-id} id nil nil)
(ptk/data-event :layout/update {:ids [id]})))))
:appendChildStart
(fn [child]
(cond
(not (shape-proxy? child))
(u/display-not-valid :appendChildStart child)
:else
(let [child-id (obj/get child "$id")
shape (u/locate-shape file-id page-id id)
index (if (ctl/reverse? shape) 0 (count (:shapes shape)))]
(st/emit! (dwt/move-shapes-to-frame #{child-id} id index nil)
(ptk/data-event :layout/update {:ids [id]})))))
:appendChildEnd
(fn [child]
(cond
(not (shape-proxy? child))
(u/display-not-valid :appendChildEnd child)
:else
(let [child-id (obj/get child "$id")
shape (u/locate-shape file-id page-id id)
index (if-not (ctl/reverse? shape) 0 (count (:shapes shape)))]
(st/emit! (dwt/move-shapes-to-frame #{child-id} id index nil)
(ptk/data-event :layout/update {:ids [id]})))))))

View File

@@ -953,6 +953,46 @@
(let [child-id (obj/get child "$id")]
(st/emit! (dwsh/relocate-shapes #{child-id} id 0))))))
:appendChildBack
(fn [child]
(let [shape (u/locate-shape file-id page-id id)]
(cond
(and (not (cfh/frame-shape? shape))
(not (cfh/group-shape? shape))
(not (cfh/svg-raw-shape? shape))
(not (cfh/bool-shape? shape)))
(u/display-not-valid :appendChildBack (:type shape))
(not (shape-proxy? child))
(u/display-not-valid :appendChildBack-child child)
(not (r/check-permission plugin-id "content:write"))
(u/display-not-valid :appendChildBack "Plugin doesn't have 'content:write' permission")
:else
(let [child-id (obj/get child "$id")]
(st/emit! (dwsh/relocate-shapes #{child-id} id 0))))))
:appendChildFront
(fn [child]
(let [shape (u/locate-shape file-id page-id id)]
(cond
(and (not (cfh/frame-shape? shape))
(not (cfh/group-shape? shape))
(not (cfh/svg-raw-shape? shape))
(not (cfh/bool-shape? shape)))
(u/display-not-valid :appendChildFront (:type shape))
(not (shape-proxy? child))
(u/display-not-valid :appendChildFront-child child)
(not (r/check-permission plugin-id "content:write"))
(u/display-not-valid :appendChildFront "Plugin doesn't have 'content:write' permission")
:else
(let [child-id (obj/get child "$id")]
(st/emit! (dwsh/relocate-shapes #{child-id} id (count (:shapes shape))))))))
:insertChild
(fn [index child]
(let [shape (u/locate-shape file-id page-id id)]

View File

@@ -1,6 +1,17 @@
## 1.5.0 (Unreleased)
- **plugin-types**: New methods:
Board
-- appendChildTop
-- appendChildBottom
FlexLayout
-- appendChildStart
-- appendChildEnd
## 1.4.2 (2026-01-21)
- **plugin-types:** fix atob/btoa functions
- **plugin-runtime:** fix atob/btoa functions
## 1.4.0 (2026-01-21)

View File

@@ -7,7 +7,7 @@ different parts of the platform, please refer to `docs/` directory.
## Reporting Bugs
We are using [GitHub Issues](https://github.com/penpot/penpot/issues)
We are using [GitHub Issues](https://github.com/penpot/penpot-plugins/issues)
for our public bugs. We keep a close eye on this and try to make it
clear when we have an internal fix in progress. Before filing a new
task, try to make sure your problem doesn't already exist.

View File

@@ -19,7 +19,7 @@ the latest changes from the `main` branch. This will trigger the
deployment at Cloudfare if the `libs/plugin-types/index.d.ts` or the
`tools/typedoc.css` files have been updated.
Take a look at the [Penpot plugins API](https://doc.plugins.penpot.app/) to see what's new.
Take a look at the [Penpot plugins API](https://penpot-plugins-api-doc.pages.dev/) to see what's new.
#### Styles

View File

@@ -281,6 +281,32 @@ export interface Board extends ShapeBase {
*/
appendChild(child: Shape): void;
/**
* Appends a child shape to the board. The new children
* will be positioned at the **top** relative to the other
* children stacking order.
* @param child The child shape to append.
*
* @example
* ```js
* board.appendChildTop(childShape);
* ```
*/
appendChildTop(child: Shape): void;
/**
* Appends a child shape to the board. The new children
* will be positioned at the **back** relative to the other
* children stacking order.
* @param child The child shape to append.
*
* @example
* ```js
* board.appendChildBack(childShape);
* ```
*/
appendChildBack(child: Shape): void;
/**
* Inserts a child shape at the specified index within the board.
* @param index The index at which to insert the child shape.
@@ -1699,6 +1725,7 @@ export interface FlexLayout extends CommonLayout {
* - 'nowrap': Child elements will not wrap.
*/
wrap?: 'wrap' | 'nowrap';
/**
* Appends a child element to the flex layout.
* @param child The child element to be appended, of type `Shape`.
@@ -1709,6 +1736,30 @@ export interface FlexLayout extends CommonLayout {
* ```
*/
appendChild(child: Shape): void;
/**
* Appends a child element to the flex layout. The element will be
* visually positioned at the start (left / top)
* @param child The child element to be appended, of type `Shape`.
*
* @example
* ```js
* flexLayout.appendChildStart(childShape);
* ```
*/
appendChildStart(child: Shape): void;
/**
* Appends a child element to the flex layout. The element will be
* visually positioned at the end (right / bottom)
* @param child The child element to be appended, of type `Shape`.
*
* @example
* ```js
* flexLayout.appendChildEnd(childShape);
* ```
*/
appendChildEnd(child: Shape): void;
}
/**

View File

@@ -20,7 +20,7 @@ Import the CSS file into your project:
For detailed examples and to see how to use the styles and components, visit the documentation at:
[Penpot Plugin Styles Documentation](https://styles-doc.plugins.penpot.app)
[Penpot Plugin Styles Documentation](https://penpot-plugins-styles.pages.dev)
#### Icons

View File

@@ -1,4 +0,0 @@
name = "penpot-plugins-api-doc"
compatibility_date = "2025-01-01"
assets = { directory = "dist/doc" }

View File

@@ -2,7 +2,3 @@ name = "penpot-plugins-api-doc"
compatibility_date = "2025-01-01"
assets = { directory = "dist/doc" }
[[routes]]
pattern = "WORKER_URI"
custom_domain = true

View File

@@ -1,8 +0,0 @@
name = "penpot-plugins-style-doc"
compatibility_date = "2025-01-01"
assets = { directory = "dist/apps/example-styles" }
[[routes]]
pattern = "WORKER_URI"
custom_domain = true