mirror of
https://github.com/penpot/penpot.git
synced 2026-09-19 02:16:14 +00:00
✨ Add naturalChildOrdering flag to Plugin's API
This commit is contained in:
parent
717a048b73
commit
512a31d375
@ -44,6 +44,20 @@
|
|||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update-in state [:workspace-local :open-plugins] (fnil conj #{}) id))))
|
(update-in state [:workspace-local :open-plugins] (fnil conj #{}) id))))
|
||||||
|
|
||||||
|
(defn reset-plugin-flags
|
||||||
|
[id]
|
||||||
|
(ptk/reify ::reset-plugin-flags
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(update-in state [:workspace-local :plugin-flags] assoc id {}))))
|
||||||
|
|
||||||
|
(defn set-plugin-flag
|
||||||
|
[id key value]
|
||||||
|
(ptk/reify ::reset-plugin-flags
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(update-in state [:workspace-local :plugin-flags id] assoc key value))))
|
||||||
|
|
||||||
(defn remove-current-plugin
|
(defn remove-current-plugin
|
||||||
[id]
|
[id]
|
||||||
(ptk/reify ::remove-current-plugin
|
(ptk/reify ::remove-current-plugin
|
||||||
@ -54,7 +68,9 @@
|
|||||||
(defn- load-plugin!
|
(defn- load-plugin!
|
||||||
[{:keys [plugin-id name description host code icon permissions]}]
|
[{:keys [plugin-id name description host code icon permissions]}]
|
||||||
(try
|
(try
|
||||||
(st/emit! (save-current-plugin plugin-id))
|
(st/emit! (save-current-plugin plugin-id)
|
||||||
|
(reset-plugin-flags plugin-id))
|
||||||
|
|
||||||
(.ɵloadPlugin
|
(.ɵloadPlugin
|
||||||
^js ug/global
|
^js ug/global
|
||||||
#js {:pluginId plugin-id
|
#js {:pluginId plugin-id
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
[app.main.ui.shapes.text.fontfaces :refer [shapes->fonts]]
|
[app.main.ui.shapes.text.fontfaces :refer [shapes->fonts]]
|
||||||
[app.plugins.events :as events]
|
[app.plugins.events :as events]
|
||||||
[app.plugins.file :as file]
|
[app.plugins.file :as file]
|
||||||
|
[app.plugins.flags :as flags]
|
||||||
[app.plugins.fonts :as fonts]
|
[app.plugins.fonts :as fonts]
|
||||||
[app.plugins.format :as format]
|
[app.plugins.format :as format]
|
||||||
[app.plugins.history :as history]
|
[app.plugins.history :as history]
|
||||||
@ -124,6 +125,9 @@
|
|||||||
:fonts
|
:fonts
|
||||||
{:get (fn [] (fonts/fonts-subcontext plugin-id))}
|
{:get (fn [] (fonts/fonts-subcontext plugin-id))}
|
||||||
|
|
||||||
|
:flags
|
||||||
|
{:get (fn [] (flags/flags-proxy plugin-id))}
|
||||||
|
|
||||||
:library
|
:library
|
||||||
{:get (fn [] (library/library-subcontext plugin-id))}
|
{:get (fn [] (library/library-subcontext plugin-id))}
|
||||||
|
|
||||||
|
|||||||
33
frontend/src/app/plugins/flags.cljs
Normal file
33
frontend/src/app/plugins/flags.cljs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.plugins.flags
|
||||||
|
(:require
|
||||||
|
[app.main.data.plugins :as dp]
|
||||||
|
[app.main.store :as st]
|
||||||
|
[app.plugins.utils :as u]
|
||||||
|
[app.util.object :as obj]))
|
||||||
|
|
||||||
|
(defn flags-proxy
|
||||||
|
[plugin-id]
|
||||||
|
(obj/reify {:name "FlagProxy"}
|
||||||
|
:naturalChildOrdering
|
||||||
|
{:this false
|
||||||
|
:get
|
||||||
|
(fn []
|
||||||
|
(boolean
|
||||||
|
(get-in
|
||||||
|
@st/state
|
||||||
|
[:workspace-local :plugin-flags plugin-id :natural-child-ordering])))
|
||||||
|
|
||||||
|
:set
|
||||||
|
(fn [value]
|
||||||
|
(cond
|
||||||
|
(not (boolean? value))
|
||||||
|
(u/display-not-valid :naturalChildOrdering value)
|
||||||
|
|
||||||
|
:else
|
||||||
|
(st/emit! (dp/set-plugin-flag plugin-id :natural-child-ordering value))))}))
|
||||||
@ -52,6 +52,7 @@
|
|||||||
[app.plugins.parser :as parser]
|
[app.plugins.parser :as parser]
|
||||||
[app.plugins.register :as r]
|
[app.plugins.register :as r]
|
||||||
[app.plugins.ruler-guides :as rg]
|
[app.plugins.ruler-guides :as rg]
|
||||||
|
[app.plugins.state :refer [natural-child-ordering?]]
|
||||||
[app.plugins.text :as text]
|
[app.plugins.text :as text]
|
||||||
[app.plugins.utils :as u]
|
[app.plugins.utils :as u]
|
||||||
[app.util.http :as http]
|
[app.util.http :as http]
|
||||||
@ -921,7 +922,6 @@
|
|||||||
(fn []
|
(fn []
|
||||||
(let [shape (u/locate-shape file-id page-id id)]
|
(let [shape (u/locate-shape file-id page-id id)]
|
||||||
(cond
|
(cond
|
||||||
|
|
||||||
(and (not (cfh/frame-shape? shape))
|
(and (not (cfh/frame-shape? shape))
|
||||||
(not (cfh/group-shape? shape))
|
(not (cfh/group-shape? shape))
|
||||||
(not (cfh/svg-raw-shape? shape))
|
(not (cfh/svg-raw-shape? shape))
|
||||||
@ -929,9 +929,14 @@
|
|||||||
(u/display-not-valid :getChildren (:type shape))
|
(u/display-not-valid :getChildren (:type shape))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(->> (u/locate-shape file-id page-id id)
|
(let [is-reversed? (ctl/flex-layout? shape)
|
||||||
(:shapes)
|
reverse-fn
|
||||||
(format/format-array #(shape-proxy plugin-id file-id page-id %))))))
|
(if (and (natural-child-ordering? plugin-id) is-reversed?)
|
||||||
|
reverse identity)]
|
||||||
|
(->> (u/locate-shape file-id page-id id)
|
||||||
|
(:shapes)
|
||||||
|
(reverse-fn)
|
||||||
|
(format/format-array #(shape-proxy plugin-id file-id page-id %)))))))
|
||||||
|
|
||||||
:appendChild
|
:appendChild
|
||||||
(fn [child]
|
(fn [child]
|
||||||
@ -950,8 +955,10 @@
|
|||||||
(u/display-not-valid :appendChild "Plugin doesn't have 'content:write' permission")
|
(u/display-not-valid :appendChild "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(let [child-id (obj/get child "$id")]
|
(let [child-id (obj/get child "$id")
|
||||||
(st/emit! (dwsh/relocate-shapes #{child-id} id 0))))))
|
is-reversed? (ctl/flex-layout? shape)
|
||||||
|
index (if (and (natural-child-ordering? plugin-id) is-reversed?) 0 (count (:shapes shape)))]
|
||||||
|
(st/emit! (dwsh/relocate-shapes #{child-id} id index))))))
|
||||||
|
|
||||||
:insertChild
|
:insertChild
|
||||||
(fn [index child]
|
(fn [index child]
|
||||||
@ -970,7 +977,12 @@
|
|||||||
(u/display-not-valid :insertChild "Plugin doesn't have 'content:write' permission")
|
(u/display-not-valid :insertChild "Plugin doesn't have 'content:write' permission")
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(let [child-id (obj/get child "$id")]
|
(let [child-id (obj/get child "$id")
|
||||||
|
is-reversed? (ctl/flex-layout? shape)
|
||||||
|
index
|
||||||
|
(if (and (natural-child-ordering? plugin-id) is-reversed?)
|
||||||
|
(- (count (:shapes shape)) index)
|
||||||
|
index)]
|
||||||
(st/emit! (dwsh/relocate-shapes #{child-id} id index))))))
|
(st/emit! (dwsh/relocate-shapes #{child-id} id index))))))
|
||||||
|
|
||||||
;; Only for frames
|
;; Only for frames
|
||||||
@ -1360,7 +1372,8 @@
|
|||||||
(let [shape (u/proxy->shape self)
|
(let [shape (u/proxy->shape self)
|
||||||
file-id (obj/get self "$file")
|
file-id (obj/get self "$file")
|
||||||
page-id (obj/get self "$page")
|
page-id (obj/get self "$page")
|
||||||
ids (->> children (map #(obj/get % "$id")))]
|
reverse-fn (if (natural-child-ordering? plugin-id) reverse identity)
|
||||||
|
ids (->> children reverse-fn (map #(obj/get % "$id")))]
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
(not= (set ids) (set (:shapes shape)))
|
(not= (set ids) (set (:shapes shape)))
|
||||||
|
|||||||
16
frontend/src/app/plugins/state.cljs
Normal file
16
frontend/src/app/plugins/state.cljs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.plugins.state
|
||||||
|
(:require
|
||||||
|
[app.main.store :as st]))
|
||||||
|
|
||||||
|
(defn natural-child-ordering?
|
||||||
|
[plugin-id]
|
||||||
|
(boolean
|
||||||
|
(get-in
|
||||||
|
@st/state
|
||||||
|
[:workspace-local :plugin-flags plugin-id :natural-child-ordering])))
|
||||||
@ -1,6 +1,10 @@
|
|||||||
|
## 1.5.0 (Unreleased)
|
||||||
|
|
||||||
|
- **plugin-types**: Added a flags subcontexts with the flag `naturalChildrenOrdering`
|
||||||
|
|
||||||
## 1.4.2 (2026-01-21)
|
## 1.4.2 (2026-01-21)
|
||||||
|
|
||||||
- **plugin-types:** fix atob/btoa functions
|
- **plugin-runtime:** fix atob/btoa functions
|
||||||
|
|
||||||
## 1.4.0 (2026-01-21)
|
## 1.4.0 (2026-01-21)
|
||||||
|
|
||||||
|
|||||||
18
plugins/libs/plugin-types/index.d.ts
vendored
18
plugins/libs/plugin-types/index.d.ts
vendored
@ -804,6 +804,11 @@ export interface Context {
|
|||||||
*/
|
*/
|
||||||
readonly viewport: Viewport;
|
readonly viewport: Viewport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides flags to customize the API behavior.
|
||||||
|
*/
|
||||||
|
readonly flags: Flags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context encapsulating the history operations
|
* Context encapsulating the history operations
|
||||||
*
|
*
|
||||||
@ -1679,6 +1684,19 @@ export interface Fill {
|
|||||||
fillImage?: ImageData;
|
fillImage?: ImageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This subcontext allows the API o change certain defaults
|
||||||
|
*/
|
||||||
|
export interface Flags {
|
||||||
|
/**
|
||||||
|
* If `true` the .children property will be always sorted in the z-index ordering.
|
||||||
|
* Also, appendChild method will be append the children in the top-most position.
|
||||||
|
* The insertchild method is changed acordingly to respect this ordering.
|
||||||
|
* Defaults to false
|
||||||
|
*/
|
||||||
|
naturalChildOrdering: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a flexible layout configuration in Penpot.
|
* Represents a flexible layout configuration in Penpot.
|
||||||
* This interface extends `CommonLayout` and includes properties for defining the direction,
|
* This interface extends `CommonLayout` and includes properties for defining the direction,
|
||||||
|
|||||||
@ -1,31 +1,32 @@
|
|||||||
import type {
|
import type {
|
||||||
Penpot,
|
|
||||||
EventsMap,
|
|
||||||
Page,
|
|
||||||
Shape,
|
|
||||||
Rectangle,
|
|
||||||
Board,
|
|
||||||
Group,
|
|
||||||
Viewport,
|
|
||||||
Text,
|
|
||||||
File,
|
|
||||||
Theme,
|
|
||||||
LibraryContext,
|
|
||||||
Ellipse,
|
|
||||||
Path,
|
|
||||||
BooleanType,
|
|
||||||
Boolean,
|
|
||||||
User,
|
|
||||||
ActiveUser,
|
ActiveUser,
|
||||||
FontsContext,
|
Board,
|
||||||
SvgRaw,
|
Boolean,
|
||||||
|
BooleanType,
|
||||||
Color,
|
Color,
|
||||||
ColorShapeInfo,
|
ColorShapeInfo,
|
||||||
|
Ellipse,
|
||||||
|
EventsMap,
|
||||||
|
File,
|
||||||
|
Flags,
|
||||||
|
FontsContext,
|
||||||
|
Group,
|
||||||
HistoryContext,
|
HistoryContext,
|
||||||
LocalStorage,
|
|
||||||
VariantContainer,
|
|
||||||
LibraryComponent,
|
LibraryComponent,
|
||||||
|
LibraryContext,
|
||||||
LibraryVariantComponent,
|
LibraryVariantComponent,
|
||||||
|
LocalStorage,
|
||||||
|
Page,
|
||||||
|
Path,
|
||||||
|
Penpot,
|
||||||
|
Rectangle,
|
||||||
|
Shape,
|
||||||
|
SvgRaw,
|
||||||
|
Text,
|
||||||
|
Theme,
|
||||||
|
User,
|
||||||
|
VariantContainer,
|
||||||
|
Viewport,
|
||||||
} from '@penpot/plugin-types';
|
} from '@penpot/plugin-types';
|
||||||
|
|
||||||
import { Permissions } from '../models/manifest.model.js';
|
import { Permissions } from '../models/manifest.model.js';
|
||||||
@ -193,6 +194,10 @@ export function createApi(
|
|||||||
return plugin.context.fonts;
|
return plugin.context.fonts;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get flags(): Flags {
|
||||||
|
return plugin.context.flags;
|
||||||
|
},
|
||||||
|
|
||||||
get currentUser(): User {
|
get currentUser(): User {
|
||||||
checkPermission('user:read');
|
checkPermission('user:read');
|
||||||
return plugin.context.currentUser;
|
return plugin.context.currentUser;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user