diff --git a/CHANGES.md b/CHANGES.md index 7c759be733..193ca53fb2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,13 @@ The initial prototype is completly reworked for provide a more consistent API and to have proper validation and params decoding. All the details can be found on [its own changelog](library/CHANGES.md) +**Penpot migrate from Redis to Valkey** + +As [Valkey](https://valkey.io/) is an opne-souce fork of [Redis](https://redis.io/) +version 7.2.4, this version of Penpot will be compatible with Redis but may diverge +in future versions. Therefore, **migration from Redis to ValKey is recommended for all +on-premises instances** that want to keep up to date. + ### :heart: Community contributions (Thank you!) ### :sparkles: New features & Enhancements @@ -45,6 +52,7 @@ on [its own changelog](library/CHANGES.md) - Update google fonts (at 2025/05/19) [Taiga 10792](https://tree.taiga.io/project/penpot/us/10792) - Add tooltip component to DS [Taiga 9220](https://tree.taiga.io/project/penpot/us/9220) - Allow multi file token export [Taiga #10144](https://tree.taiga.io/project/penpot/us/10144) +- Add Serbian language ### :bug: Bugs fixed @@ -54,7 +62,9 @@ on [its own changelog](library/CHANGES.md) - Fix element positioning on the right side to adjust to grid [#11073](https://tree.taiga.io/project/penpot/issue/11073) - Fix palette is over sidebar [#11160](https://tree.taiga.io/project/penpot/issue/11160) - Fix font size input not displaying "mixed" when multiple texts are selected [Taiga #11177](https://tree.taiga.io/project/penpot/issue/11177) - +- Misalignments at Create account [Taiga #11315](https://tree.taiga.io/project/penpot/issue/11315) +- Fix issue with importing files where flex/grid is used [Taiga #11334](https://tree.taiga.io/project/penpot/issue/11334) +- Fix wrong color in the export progress bar [Taiga #11299](https://tree.taiga.io/project/penpot/issue/11299) ## 2.7.2 diff --git a/common/deps.edn b/common/deps.edn index bffd94a026..f6e54ae876 100644 --- a/common/deps.edn +++ b/common/deps.edn @@ -28,7 +28,7 @@ integrant/integrant {:mvn/version "0.13.1"} funcool/tubax {:mvn/version "2021.05.20-0"} - funcool/cuerdas {:mvn/version "2025.05.26-411"} + funcool/cuerdas {:mvn/version "2025.06.16-414"} funcool/promesa {:git/sha "f52f58cfacf62f59eab717e2637f37729d0cc383" :git/url "https://github.com/funcool/promesa"} diff --git a/common/src/app/common/files/shapes_helpers.cljc b/common/src/app/common/files/shapes_helpers.cljc index fa1ba12bd0..a6421f9405 100644 --- a/common/src/app/common/files/shapes_helpers.cljc +++ b/common/src/app/common/files/shapes_helpers.cljc @@ -91,10 +91,10 @@ parent-id (or parent-id (get selected-obj :parent-id)) base-parent (get objects parent-id) - layout-props + layout-attrs (when (and (= 1 (count selected)) (ctl/any-layout? base-parent)) - (select-keys selected-obj ctl/layout-item-props)) + (select-keys selected-obj ctl/layout-child-attrs)) target-cell-id (if (and (nil? target-cell-id) @@ -129,8 +129,8 @@ :parent-id parent-id :shapes (into [] selected)) - (some? layout-props) - (d/patch-object layout-props) + (some? layout-attrs) + (d/patch-object layout-attrs) ;; Frames from shapes will not be displayed in viewer and no clipped (or (not= frame-id uuid/zero) without-fill?) diff --git a/common/src/app/common/types/path.cljc b/common/src/app/common/types/path.cljc index b06c72afbe..65336fe2d5 100644 --- a/common/src/app/common/types/path.cljc +++ b/common/src/app/common/types/path.cljc @@ -104,36 +104,11 @@ (impl/path-data (reduce apply-to-index (vec content) modifiers)))) -(defn- transform-content-legacy - [content transform] - (if (some? transform) - (let [set-tr - (fn [params px py] - (let [tr-point (-> (gpt/point (get params px) (get params py)) - (gpt/transform transform))] - (assoc params - px (:x tr-point) - py (:y tr-point)))) - - transform-params - (fn [{:keys [x c1x c2x] :as params}] - (cond-> params - (some? x) (set-tr :x :y) - (some? c1x) (set-tr :c1x :c1y) - (some? c2x) (set-tr :c2x :c2y)))] - - (into [] - (map #(update % :params transform-params)) - content)) - content)) - (defn transform-content "Applies a transformation matrix over content and returns a new content as PathData instance." [content transform] - #_(segment/transform-content content transform) - (some-> (transform-content-legacy (vec content) transform) - (impl/from-plain))) + (segment/transform-content content transform)) (defn move-content [content move-vec] diff --git a/common/src/app/common/types/path/impl.cljc b/common/src/app/common/types/path/impl.cljc index cb973ca70e..bc948d9f5c 100644 --- a/common/src/app/common/types/path/impl.cljc +++ b/common/src/app/common/types/path/impl.cljc @@ -65,34 +65,34 @@ (let [t (buf/read-short buffer offset)] (case t (1 2) - (let [x (buf/read-float buffer (+ offset 20)) - y (buf/read-float buffer (+ offset 24)) - x (+ (* x a) (* y c) e) - y (+ (* x b) (* y d) f)] - (buf/write-float buffer (+ offset 20) x) - (buf/write-float buffer (+ offset 24) y)) + (let [x (buf/read-float buffer (+ offset 20)) + y (buf/read-float buffer (+ offset 24)) + x' (+ (* x a) (* y c) e) + y' (+ (* x b) (* y d) f)] + (buf/write-float buffer (+ offset 20) x') + (buf/write-float buffer (+ offset 24) y')) 3 - (let [c1x (buf/read-float buffer (+ offset 4)) - c1y (buf/read-float buffer (+ offset 8)) - c2x (buf/read-float buffer (+ offset 12)) - c2y (buf/read-float buffer (+ offset 16)) - x (buf/read-float buffer (+ offset 20)) - y (buf/read-float buffer (+ offset 24)) + (let [c1x (buf/read-float buffer (+ offset 4)) + c1y (buf/read-float buffer (+ offset 8)) + c2x (buf/read-float buffer (+ offset 12)) + c2y (buf/read-float buffer (+ offset 16)) + x (buf/read-float buffer (+ offset 20)) + y (buf/read-float buffer (+ offset 24)) - c1x (+ (* c1x a) (* c1y c) e) - c1y (+ (* c1x b) (* c1y d) f) - c2x (+ (* c2x a) (* c2y c) e) - c2y (+ (* c2x b) (* c2y d) f) - x (+ (* x a) (* y c) e) - y (+ (* x b) (* y d) f)] + c1x' (+ (* c1x a) (* c1y c) e) + c1y' (+ (* c1x b) (* c1y d) f) + c2x' (+ (* c2x a) (* c2y c) e) + c2y' (+ (* c2x b) (* c2y d) f) + x' (+ (* x a) (* y c) e) + y' (+ (* x b) (* y d) f)] - (buf/write-float buffer (+ offset 4) c1x) - (buf/write-float buffer (+ offset 8) c1y) - (buf/write-float buffer (+ offset 12) c2x) - (buf/write-float buffer (+ offset 16) c2y) - (buf/write-float buffer (+ offset 20) x) - (buf/write-float buffer (+ offset 24) y)) + (buf/write-float buffer (+ offset 4) c1x') + (buf/write-float buffer (+ offset 8) c1y') + (buf/write-float buffer (+ offset 12) c2x') + (buf/write-float buffer (+ offset 16) c2y') + (buf/write-float buffer (+ offset 20) x') + (buf/write-float buffer (+ offset 24) y')) nil))) diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index aac6b018e8..ed0ba5ae3a 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -313,7 +313,7 @@ :title "Shape"} [:group [:merge {:title "GroupShape"} - ctsl/schema:layout-attrs + ctsl/schema:layout-child-attrs schema:group-attrs schema:shape-generic-attrs schema:shape-geom-attrs @@ -321,8 +321,8 @@ [:frame [:merge {:title "FrameShape"} + ctsl/schema:layout-child-attrs ctsl/schema:layout-attrs - ::ctsl/layout-attrs schema:frame-attrs schema:shape-generic-attrs schema:shape-geom-attrs @@ -332,14 +332,14 @@ [:bool [:merge {:title "BoolShape"} - ctsl/schema:layout-attrs + ctsl/schema:layout-child-attrs schema:bool-attrs schema:shape-generic-attrs schema:shape-base-attrs]] [:rect [:merge {:title "RectShape"} - ctsl/schema:layout-attrs + ctsl/schema:layout-child-attrs schema:rect-attrs schema:shape-generic-attrs schema:shape-geom-attrs @@ -347,7 +347,7 @@ [:circle [:merge {:title "CircleShape"} - ctsl/schema:layout-attrs + ctsl/schema:layout-child-attrs schema:circle-attrs schema:shape-generic-attrs schema:shape-geom-attrs @@ -355,7 +355,7 @@ [:image [:merge {:title "ImageShape"} - ctsl/schema:layout-attrs + ctsl/schema:layout-child-attrs schema:image-attrs schema:shape-generic-attrs schema:shape-geom-attrs @@ -363,7 +363,7 @@ [:svg-raw [:merge {:title "SvgRawShape"} - ctsl/schema:layout-attrs + ctsl/schema:layout-child-attrs schema:svg-raw-attrs schema:shape-generic-attrs schema:shape-geom-attrs @@ -371,14 +371,14 @@ [:path [:merge {:title "PathShape"} - ctsl/schema:layout-attrs + ctsl/schema:layout-child-attrs schema:path-attrs schema:shape-generic-attrs schema:shape-base-attrs]] [:text [:merge {:title "TextShape"} - ctsl/schema:layout-attrs + ctsl/schema:layout-child-attrs schema:text-attrs schema:shape-generic-attrs schema:shape-geom-attrs @@ -682,23 +682,6 @@ :r3 :r4}) -(def ^:private layout-extract-props - #{:layout - :layout-flex-dir - :layout-gap-type - :layout-gap - :layout-wrap-type - :layout-align-items - :layout-align-content - :layout-justify-items - :layout-justify-content - :layout-padding-type - :layout-padding - :layout-grid-dir - :layout-grid-rows - :layout-grid-columns - :layout-grid-cells}) - (defn extract-props "Retrieves an object with the 'pasteable' properties for a shape." [shape] @@ -729,9 +712,8 @@ (assoc-props node txt/text-node-attrs))) props))) - (extract-layout-props - [props shape] - (d/patch-object props (select-keys shape layout-extract-props)))] + (extract-layout-attrs [props shape] + (d/patch-object props (select-keys shape ctsl/layout-attrs)))] (let [;; For texts we don't extract the fill extract-props @@ -739,7 +721,7 @@ (-> shape (select-keys extract-props) (cond-> (cfh/text-shape? shape) (extract-text-props shape)) - (cond-> (ctsl/any-layout? shape) (extract-layout-props shape)))))) + (cond-> (ctsl/any-layout? shape) (extract-layout-attrs shape)))))) (defn patch-props "Given the object of `extract-props` applies it to a shape. Adapt the shape if necesary" @@ -764,7 +746,7 @@ (d/patch-object (select-keys props txt/text-node-attrs)))))))))) (patch-layout-props [shape props] - (let [shape (d/patch-object shape (select-keys props layout-extract-props))] + (let [shape (d/patch-object shape (select-keys props ctsl/layout-attrs))] (cond-> shape (ctsl/grid-layout? shape) (ctsl/assign-cells objects))))] diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index e66016502f..10051ee759 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -43,7 +43,6 @@ ;; :layout-item-absolute ;; boolean ;; :layout-item-z-index ;; int - (def layout-types #{:flex :grid}) @@ -74,49 +73,6 @@ (def justify-items-types #{:start :end :center :stretch}) -(def layout-item-props - [:layout-item-margin - :layout-item-margin-type - :layout-item-h-sizing - :layout-item-v-sizing - :layout-item-max-h - :layout-item-min-h - :layout-item-max-w - :layout-item-min-w - :layout-item-absolute - :layout-item-z-index]) - -(sm/register! - ^{::sm/type ::layout-attrs} - [:map {:title "LayoutAttrs"} - [:layout {:optional true} [::sm/one-of layout-types]] - [:layout-flex-dir {:optional true} [::sm/one-of flex-direction-types]] - [:layout-gap {:optional true} - [:map - [:row-gap {:optional true} ::sm/safe-number] - [:column-gap {:optional true} ::sm/safe-number]]] - [:layout-gap-type {:optional true} [::sm/one-of gap-types]] - [:layout-wrap-type {:optional true} [::sm/one-of wrap-types]] - [:layout-padding-type {:optional true} [::sm/one-of padding-type]] - [:layout-padding {:optional true} - [:map - [:p1 ::sm/safe-number] - [:p2 ::sm/safe-number] - [:p3 ::sm/safe-number] - [:p4 ::sm/safe-number]]] - [:layout-justify-content {:optional true} [::sm/one-of justify-content-types]] - [:layout-justify-items {:optional true} [::sm/one-of justify-items-types]] - [:layout-align-content {:optional true} [::sm/one-of align-content-types]] - [:layout-align-items {:optional true} [::sm/one-of align-items-types]] - - [:layout-grid-dir {:optional true} [::sm/one-of grid-direction-types]] - [:layout-grid-rows {:optional true} - [:vector {:gen/max 2} ::grid-track]] - [:layout-grid-columns {:optional true} - [:vector {:gen/max 2} ::grid-track]] - [:layout-grid-cells {:optional true} - [:map-of {:gen/max 5} ::sm/uuid ::grid-cell]]]) - ;; Grid types (def grid-track-types #{:percent :flex :auto :fixed}) @@ -130,29 +86,59 @@ (def grid-cell-justify-self-types #{:auto :start :center :end :stretch}) -(sm/register! - ^{::sm/type ::grid-cell} - [:map {:title "GridCell"} - [:id ::sm/uuid] - [:area-name {:optional true} :string] - [:row ::sm/safe-int] - [:row-span ::sm/safe-int] - [:column ::sm/safe-int] - [:column-span ::sm/safe-int] - [:position {:optional true} [::sm/one-of grid-position-types]] - [:align-self {:optional true} [::sm/one-of grid-cell-align-self-types]] - [:justify-self {:optional true} [::sm/one-of grid-cell-justify-self-types]] - [:shapes - [:vector {:gen/max 1} ::sm/uuid]]]) +(def ^:private schema:grid-cell + [:map {:title "GridCell"} + [:id ::sm/uuid] + [:area-name {:optional true} :string] + [:row ::sm/safe-int] + [:row-span ::sm/safe-int] + [:column ::sm/safe-int] + [:column-span ::sm/safe-int] + [:position {:optional true} [::sm/one-of grid-position-types]] + [:align-self {:optional true} [::sm/one-of grid-cell-align-self-types]] + [:justify-self {:optional true} [::sm/one-of grid-cell-justify-self-types]] + [:shapes + [:vector {:gen/max 1} ::sm/uuid]]]) -(sm/register! - ^{::sm/type ::grid-track} - [:map {:title "GridTrack"} - [:type [::sm/one-of grid-track-types]] - [:value {:optional true} [:maybe ::sm/safe-number]]]) +(def ^:private schema:grid-track + [:map {:title "GridTrack"} + [:type [::sm/one-of grid-track-types]] + [:value {:optional true} [:maybe ::sm/safe-number]]]) -(def check-grid-track! - (sm/check-fn ::grid-track)) +(def schema:layout-attrs + [:map {:title "LayoutAttrs"} + [:layout {:optional true} [::sm/one-of layout-types]] + [:layout-flex-dir {:optional true} [::sm/one-of flex-direction-types]] + [:layout-gap {:optional true} + [:map + [:row-gap {:optional true} ::sm/safe-number] + [:column-gap {:optional true} ::sm/safe-number]]] + [:layout-gap-type {:optional true} [::sm/one-of gap-types]] + [:layout-wrap-type {:optional true} [::sm/one-of wrap-types]] + [:layout-padding-type {:optional true} [::sm/one-of padding-type]] + [:layout-padding {:optional true} + [:map + [:p1 ::sm/safe-number] + [:p2 ::sm/safe-number] + [:p3 ::sm/safe-number] + [:p4 ::sm/safe-number]]] + [:layout-justify-content {:optional true} [::sm/one-of justify-content-types]] + [:layout-justify-items {:optional true} [::sm/one-of justify-items-types]] + [:layout-align-content {:optional true} [::sm/one-of align-content-types]] + [:layout-align-items {:optional true} [::sm/one-of align-items-types]] + [:layout-grid-dir {:optional true} [::sm/one-of grid-direction-types]] + [:layout-grid-rows {:optional true} + [:vector {:gen/max 2} schema:grid-track]] + [:layout-grid-columns {:optional true} + [:vector {:gen/max 2} schema:grid-track]] + [:layout-grid-cells {:optional true} + [:map-of {:gen/max 5} ::sm/uuid schema:grid-cell]]]) + +(def ^:private check-grid-track + (sm/check-fn schema:grid-track)) + +(def layout-attrs + (sm/keys schema:layout-attrs)) ;; LAYOUT CHILDREN @@ -168,7 +154,7 @@ (def item-align-self-types #{:start :end :center :stretch}) -(def schema:layout-attrs +(def schema:layout-child-attrs [:map {:title "LayoutChildAttrs"} [:layout-item-margin-type {:optional true} [::sm/one-of item-margin-types]] [:layout-item-margin {:optional true} @@ -187,6 +173,9 @@ [:layout-item-absolute {:optional true} :boolean] [:layout-item-z-index {:optional true} ::sm/safe-number]]) +(def layout-child-attrs + (sm/keys schema:layout-child-attrs)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SCHEMAS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -194,8 +183,6 @@ (def valid-layouts #{:flex :grid}) -(sm/register! ::layout [::sm/one-of valid-layouts]) - (defn flex-layout? ([objects id] (flex-layout? (get objects id))) @@ -754,9 +741,7 @@ ([type parent value] (add-grid-track type parent value nil)) ([type parent value index] - (dm/assert! - "expected a valid grid definition for `value`" - (check-grid-track! value)) + (assert (check-grid-track value)) (let [[tracks-prop tracks-prop-other prop prop-other prop-span prop-span-other] (if (= type :column) diff --git a/common/test/common_tests/types/path_data_test.cljc b/common/test/common_tests/types/path_data_test.cljc index b96d0e8458..aef996608a 100644 --- a/common/test/common_tests/types/path_data_test.cljc +++ b/common/test/common_tests/types/path_data_test.cljc @@ -25,6 +25,15 @@ {:command :curve-to :params {:c1x 368.0 :c1y 737.0 :c2x 310.0 :c2y 681.0 :x 264.0 :y 634.0}} {:command :close-path :params {}}]) +(def sample-content-square + [{:command :move-to, :params {:x 0, :y 0}} + {:command :line-to, :params {:x 10, :y 0}} + {:command :line-to, :params {:x 10, :y 10}} + {:command :line-to, :params {:x 10, :y 0}} + {:command :line-to, :params {:x 0, :y 10}} + {:command :line-to, :params {:x 0, :y 0}} + {:command :close-path :params {}}]) + (def sample-content-large [{:command :move-to :params {:x 480.0 :y 839.0}} {:command :line-to :params {:x 439.0 :y 802.0}} @@ -179,6 +188,42 @@ (t/is (= (vec result1) result2)) (t/is (= result2 result3)))) +(t/deftest path-transform-3 + (let [matrix (gmt/rotate-matrix 42 (gpt/point 0 0)) + content (path/content sample-content-square) + + result1 (path/transform-content content matrix) + result2 (transform-plain-content sample-content-square matrix) + result3 (transform-plain-content content matrix)] + + (t/is (= (count result1) (count result2))) + (doseq [[seg-a seg-b] (map vector result1 result2)] + (t/is (= (:command seg-a) + (:command seg-b))) + + (let [params-a (get seg-a :params) + params-b (get seg-b :params)] + + (t/is (mth/close? (get params-a :x 0) + (get params-b :x 0))) + (t/is (mth/close? (get params-a :y 0) + (get params-b :y 0))))) + + + (doseq [[seg-a seg-b] (map vector result1 result3)] + (t/is (= (:command seg-a) + (:command seg-b))) + + (let [params-a (get seg-a :params) + params-b (get seg-b :params)] + + (t/is (mth/close? (get params-a :x 0) + (get params-b :x 0))) + (t/is (mth/close? (get params-a :y 0) + (get params-b :y 0))))))) + + + (defn- content->points "Given a content return all points. @@ -278,15 +323,6 @@ (t/is (= result2 expect)) (t/is (= result3 expect)))) -(def sample-content-square - [{:command :move-to, :params {:x 0, :y 0}} - {:command :line-to, :params {:x 10, :y 0}} - {:command :line-to, :params {:x 10, :y 10}} - {:command :line-to, :params {:x 10, :y 0}} - {:command :line-to, :params {:x 0, :y 10}} - {:command :line-to, :params {:x 0, :y 0}} - {:command :close-path :params {}}]) - (t/deftest points-to-content (let [initial [(gpt/point 0.0 0.0) (gpt/point 10.0 10.0) diff --git a/docker/devenv/files/bashrc b/docker/devenv/files/bashrc index 6dcc66f191..bb098b2f17 100644 --- a/docker/devenv/files/bashrc +++ b/docker/devenv/files/bashrc @@ -1,5 +1,7 @@ #!/usr/bin/env bash +EMSDK_QUIET=1 . /usr/local/emsdk/emsdk_env.sh; + alias l='ls --color -GFlh' alias rm='rm -r' alias ls='ls --color -F' diff --git a/docker/images/docker-compose.yaml b/docker/images/docker-compose.yaml index a5fc6b57e7..42cb16ce10 100644 --- a/docker/images/docker-compose.yaml +++ b/docker/images/docker-compose.yaml @@ -111,7 +111,7 @@ services: depends_on: penpot-postgres: condition: service_healthy - penpot-redis: + penpot-valkey: condition: service_healthy networks: @@ -148,10 +148,10 @@ services: PENPOT_DATABASE_USERNAME: penpot PENPOT_DATABASE_PASSWORD: penpot - ## Redis is used for the websockets notifications. Don't touch unless the redis - ## container has different parameters or different name. + ## Valkey (or previously redis) is used for the websockets notifications. Don't touch + ## unless the valkey container has different parameters or different name. - PENPOT_REDIS_URI: redis://penpot-redis/0 + PENPOT_REDIS_URI: redis://penpot-valkey/0 ## Default configuration for assets storage: using filesystem based with all files ## stored in a docker volume. @@ -195,7 +195,7 @@ services: restart: always depends_on: - penpot-redis: + penpot-valkey: condition: service_healthy networks: @@ -206,8 +206,8 @@ services: # communicate with the frontend. PENPOT_PUBLIC_URI: http://penpot-frontend:8080 - ## Redis is used for the websockets notifications. - PENPOT_REDIS_URI: redis://penpot-redis/0 + ## Valkey (or previowsly Redis) is used for the websockets notifications. + PENPOT_REDIS_URI: redis://penpot-valkey/0 penpot-postgres: image: "postgres:15" @@ -233,12 +233,12 @@ services: - POSTGRES_USER=penpot - POSTGRES_PASSWORD=penpot - penpot-redis: - image: redis:7.2 + penpot-valkey: + image: valkey/valkey:8.1 restart: always healthcheck: - test: ["CMD-SHELL", "redis-cli ping | grep PONG"] + test: ["CMD-SHELL", "valkey-cli ping | grep PONG"] interval: 1s timeout: 3s retries: 5 diff --git a/docs/plugins/getting-started.md b/docs/plugins/getting-started.md index b2d2e5e9f5..9765e737b0 100644 --- a/docs/plugins/getting-started.md +++ b/docs/plugins/getting-started.md @@ -140,7 +140,8 @@ The manifest.json file contains the basic infor "user:read", "comment:read", "comment:write", - "allow:downloads" + "allow:downloads", + "allow:localstorage" ] } ``` @@ -173,6 +174,9 @@ Typical use cases: adding new comments to pages; deleting existing comments; rep - allow:downloads: Allows downloading of the project file. Grants access to endpoints and operations that enable the downloading of the entire project file. Typical use cases: downloading the full project file for backup or sharing. +- allow:localstorage: Allows the access to the local storage proxy to store information. This info is only available for the plugin installation but be aware that a user can see this information in the browser. +Typical use cases: storing authentication tokens for a plugin login + _Note: Write permissions automatically includes its corresponding read permission (e.g., content:write includes content:read) because reading is required to perform write or modification actions._ ### What are plugin.ts and plugin.js files? diff --git a/docs/technical-guide/configuration.md b/docs/technical-guide/configuration.md index e4f075e094..b6e3d10071 100644 --- a/docs/technical-guide/configuration.md +++ b/docs/technical-guide/configuration.md @@ -353,9 +353,9 @@ If you are not using SMTP configuration and want to log the emails in the consol PENPOT_FLAGS: [...] enable-log-emails ``` -## Redis +## Valkey -The Redis configuration is very simple, just provide a valid redis URI. Redis is used +The Valkey configuration is very simple, just provide a valid redis URI. Valkey is used mainly for websocket notifications coordination. ```bash diff --git a/docs/technical-guide/getting-started/kubernetes.md b/docs/technical-guide/getting-started/kubernetes.md index d2e9f969d9..142f498947 100644 --- a/docs/technical-guide/getting-started/kubernetes.md +++ b/docs/technical-guide/getting-started/kubernetes.md @@ -72,7 +72,7 @@ argument to helm install. For example, ```bash helm install my-release \ --set global.postgresqlEnabled=true \ - --set global.redisEnabled=true \ + --set global.valkeyEnabled=true \ --set persistence.assets.enabled=true \ penpot/penpot ``` diff --git a/exporter/src/app/handlers/export_shapes.cljs b/exporter/src/app/handlers/export_shapes.cljs index 348a68e4a8..9327d29801 100644 --- a/exporter/src/app/handlers/export_shapes.cljs +++ b/exporter/src/app/handlers/export_shapes.cljs @@ -47,7 +47,7 @@ (s/def ::params (s/keys :req-un [::exports ::profile-id] - :opt-un [::wait ::name])) + :opt-un [::wait ::name ::skip-children])) (defn handler [{:keys [:request/auth-token] :as exchange} {:keys [exports] :as params}] @@ -60,7 +60,7 @@ (handle-multiple-export exchange (assoc params :exports exports))))) (defn- handle-single-export - [exchange {:keys [export wait profile-id name] :as params}] + [exchange {:keys [export wait profile-id name skip-children] :as params}] (let [topic (str profile-id) resource (rsc/create (:type export) (or name (:name export))) @@ -90,7 +90,7 @@ :resource-id (:id resource) :status "error" :cause (ex-message cause)}))) - + export (assoc export :skip-children skip-children) proc (-> (rd/render export on-progress) (p/then (constantly resource)) (p/catch on-error))] @@ -99,7 +99,7 @@ (assoc exchange :response/body (dissoc resource :path))))) (defn- handle-multiple-export - [exchange {:keys [exports wait profile-id name] :as params}] + [exchange {:keys [exports wait profile-id name skip-children] :as params}] (let [resource (rsc/create :zip (or name (-> exports first :name))) total (count exports) topic (str profile-id) @@ -141,7 +141,8 @@ proc (-> (p/do (p/loop [exports (seq exports)] - (when-let [export (first exports)] + (when-let [export (-> (first exports) + (assoc :skip-children skip-children))] (p/do (rd/render export append) (p/recur (rest exports))))) diff --git a/exporter/src/app/renderer/bitmap.cljs b/exporter/src/app/renderer/bitmap.cljs index e206bfe9ba..54335be501 100644 --- a/exporter/src/app/renderer/bitmap.cljs +++ b/exporter/src/app/renderer/bitmap.cljs @@ -17,7 +17,7 @@ [promesa.core :as p])) (defn render - [{:keys [file-id page-id share-id token scale type objects] :as params} on-object] + [{:keys [file-id page-id share-id token scale type objects skip-children] :as params} on-object] (letfn [(prepare-options [uri] #js {:screen #js {:width bw/default-viewport-width :height bw/default-viewport-height} @@ -56,7 +56,8 @@ :page-id page-id :share-id share-id :object-id (mapv :id objects) - :route "objects"} + :route "objects" + :skip-children skip-children} uri (-> (cf/get :public-uri) (assoc :path "/render.html") (assoc :query (u/map->query-string params)))] diff --git a/frontend/resources/plugins-runtime/index.js b/frontend/resources/plugins-runtime/index.js index 07b7a342ca..18b374e80d 100644 --- a/frontend/resources/plugins-runtime/index.js +++ b/frontend/resources/plugins-runtime/index.js @@ -3,7 +3,7 @@ var qn = (t) => { }; var Kn = (t, e, r) => e.has(t) || qn("Cannot " + r); var at = (t, e, r) => (Kn(t, e, "read from private field"), r ? r.call(t) : e.get(t)), tn = (t, e, r) => e.has(t) ? qn("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, r), fr = (t, e, r, n) => (Kn(t, e, "write to private field"), n ? n.call(t, r) : e.set(t, r), r); -const x = globalThis, { +const S = globalThis, { Array: na, ArrayBuffer: To, Date: oa, @@ -45,12 +45,12 @@ const x = globalThis, { getOwnPropertyNames: Nt, getPrototypeOf: G, is: Zr, - isFrozen: uu, - isSealed: du, - isExtensible: fu, + isFrozen: du, + isSealed: fu, + isExtensible: pu, keys: Co, prototype: zr, - seal: pu, + seal: hu, preventExtensions: da, setPrototypeOf: wr, values: Ro, @@ -74,7 +74,7 @@ const x = globalThis, { return n; }, { apply: ue, - construct: Sr, + construct: xr, get: ya, getOwnPropertyDescriptor: _a, has: Oo, @@ -82,7 +82,7 @@ const x = globalThis, { ownKeys: qe, preventExtensions: ba, set: Mo -} = la, { isArray: pt, prototype: ve } = na, { prototype: xr } = To, { prototype: jt } = $e, { prototype: Br } = RegExp, { prototype: cr } = Dt, { prototype: Ge } = _e, { prototype: Gr } = ze, { prototype: Lo } = Ut, { prototype: Vr } = Function, { prototype: Fo } = ca, { prototype: Do } = G( +} = la, { isArray: pt, prototype: ve } = na, { prototype: Sr } = To, { prototype: jt } = $e, { prototype: Br } = RegExp, { prototype: cr } = Dt, { prototype: Ge } = _e, { prototype: Gr } = ze, { prototype: Lo } = Ut, { prototype: Vr } = Function, { prototype: Fo } = ca, { prototype: Do } = G( // eslint-disable-next-line no-empty-function, func-names function* () { } @@ -95,9 +95,9 @@ const x = globalThis, { ), jo = ( /** @type {any} */ P(ve.flatMap) -), Er = P(ve.pop), ne = P(ve.push), wa = P(ve.slice), Zo = P(ve.some), zo = P(ve.sort), Sa = P(ve[De]), xa = P(xr.slice), Ea = P( +), Er = P(ve.pop), ne = P(ve.push), wa = P(ve.slice), Zo = P(ve.some), zo = P(ve.sort), xa = P(ve[De]), Sa = P(Sr.slice), Ea = P( // @ts-expect-error we know it is there on all conforming platforms - ee(xr, "byteLength").get + ee(Sr, "byteLength").get ), ka = P(Uo.set), pe = P(jt.set), Ke = P(jt.get), Wr = P(jt.has), Pa = P(jt.delete), Aa = P(jt.entries), Ta = P(jt[De]), In = P(cr.add); P(cr.delete); const Yn = P(cr.forEach), Cn = P(cr.has), Ia = P(cr[De]), Rn = P(Br.test), $n = P(Br.exec), Ca = P(Br[$o]), Bo = P(Ge.endsWith), Go = P(Ge.includes), Ra = P(Ge.indexOf); @@ -180,8 +180,8 @@ const { freeze: ut } = Object, { apply: ja } = Reflect, Ln = (t) => (e, ...r) => ut(Xo); const { getEnvironmentOption: ce, - getEnvironmentOptionsList: hu, - environmentOptionsListHas: mu + getEnvironmentOptionsList: mu, + environmentOptionsListHas: gu } = Xo(globalThis, !0), Ar = (t) => (t = `${t}`, t.length >= 1 && Go("aeiouAEIOU", t[0]) ? `an ${t}` : `a ${t}`); y(Ar); const Qo = (t, e = void 0) => { @@ -404,7 +404,7 @@ const eo = new ze(), as = (t, e = t.name) => { }); } y(t); -}, Ce = (t = re`Assert failed`, e = x.Error, { +}, Ce = (t = re`Assert failed`, e = S.Error, { errorName: r = void 0, cause: n = void 0, errors: o = void 0, @@ -448,7 +448,7 @@ const Xa = (t) => { `); return Ho(e, " ") || r === -1 ? e : Nn(e, r + 1); }, Ir = { - getStackString: x.getStackString || Xa, + getStackString: S.getStackString || Xa, tagError: (t) => as(t), resetErrorTagNum: () => { yn = 0; @@ -532,8 +532,8 @@ const Qa = (t) => ue(cs, t, []) !== void 0, ei = (t) => { }); }); }, ri = () => { - if (typeof x.harden == "function") - return x.harden; + if (typeof S.harden == "function") + return S.harden; const t = new Ut(), { harden: e } = { /** * @template T @@ -752,7 +752,7 @@ function lt(t) { cause: !1 }; } -function Se(t) { +function xe(t) { return { // Properties of the TypedArray Constructors "[[Proto]]": "%TypedArray%", @@ -760,7 +760,7 @@ function Se(t) { prototype: t }; } -function xe(t) { +function Se(t) { return { // Properties of the TypedArray Prototype Objects "[[Proto]]": "%TypedArrayPrototype%", @@ -1471,39 +1471,39 @@ const so = { with: a }, // The TypedArray Constructors - BigInt64Array: Se("%BigInt64ArrayPrototype%"), - BigUint64Array: Se("%BigUint64ArrayPrototype%"), + BigInt64Array: xe("%BigInt64ArrayPrototype%"), + BigUint64Array: xe("%BigUint64ArrayPrototype%"), // https://github.com/tc39/proposal-float16array - Float16Array: Se("%Float16ArrayPrototype%"), - Float32Array: Se("%Float32ArrayPrototype%"), - Float64Array: Se("%Float64ArrayPrototype%"), - Int16Array: Se("%Int16ArrayPrototype%"), - Int32Array: Se("%Int32ArrayPrototype%"), - Int8Array: Se("%Int8ArrayPrototype%"), - Uint16Array: Se("%Uint16ArrayPrototype%"), - Uint32Array: Se("%Uint32ArrayPrototype%"), - Uint8ClampedArray: Se("%Uint8ClampedArrayPrototype%"), + Float16Array: xe("%Float16ArrayPrototype%"), + Float32Array: xe("%Float32ArrayPrototype%"), + Float64Array: xe("%Float64ArrayPrototype%"), + Int16Array: xe("%Int16ArrayPrototype%"), + Int32Array: xe("%Int32ArrayPrototype%"), + Int8Array: xe("%Int8ArrayPrototype%"), + Uint16Array: xe("%Uint16ArrayPrototype%"), + Uint32Array: xe("%Uint32ArrayPrototype%"), + Uint8ClampedArray: xe("%Uint8ClampedArrayPrototype%"), Uint8Array: { - ...Se("%Uint8ArrayPrototype%"), + ...xe("%Uint8ArrayPrototype%"), // https://github.com/tc39/proposal-arraybuffer-base64 fromBase64: a, // https://github.com/tc39/proposal-arraybuffer-base64 fromHex: a }, - "%BigInt64ArrayPrototype%": xe("BigInt64Array"), - "%BigUint64ArrayPrototype%": xe("BigUint64Array"), + "%BigInt64ArrayPrototype%": Se("BigInt64Array"), + "%BigUint64ArrayPrototype%": Se("BigUint64Array"), // https://github.com/tc39/proposal-float16array - "%Float16ArrayPrototype%": xe("Float16Array"), - "%Float32ArrayPrototype%": xe("Float32Array"), - "%Float64ArrayPrototype%": xe("Float64Array"), - "%Int16ArrayPrototype%": xe("Int16Array"), - "%Int32ArrayPrototype%": xe("Int32Array"), - "%Int8ArrayPrototype%": xe("Int8Array"), - "%Uint16ArrayPrototype%": xe("Uint16Array"), - "%Uint32ArrayPrototype%": xe("Uint32Array"), - "%Uint8ClampedArrayPrototype%": xe("Uint8ClampedArray"), + "%Float16ArrayPrototype%": Se("Float16Array"), + "%Float32ArrayPrototype%": Se("Float32Array"), + "%Float64ArrayPrototype%": Se("Float64Array"), + "%Int16ArrayPrototype%": Se("Int16Array"), + "%Int32ArrayPrototype%": Se("Int32Array"), + "%Int8ArrayPrototype%": Se("Int8Array"), + "%Uint16ArrayPrototype%": Se("Uint16Array"), + "%Uint32ArrayPrototype%": Se("Uint32Array"), + "%Uint8ClampedArrayPrototype%": Se("Uint8ClampedArray"), "%Uint8ArrayPrototype%": { - ...xe("Uint8Array"), + ...Se("Uint8Array"), // https://github.com/tc39/proposal-arraybuffer-base64 setFromBase64: a, // https://github.com/tc39/proposal-arraybuffer-base64 @@ -2031,7 +2031,7 @@ const ms = (t) => { finalIntrinsics: s, isPseudoNative: i }; - return y(c), n(us), n(hs(x, ds)), c; + return y(c), n(us), n(hs(S, ds)), c; }, ii = (t, e) => { const { addIntrinsics: r, finalIntrinsics: n } = ms(e); return r(hs(t, fs)), n(); @@ -2123,7 +2123,7 @@ function ci(t, e, r) { const m = p["[[Proto]]"]; i(f, h, m), typeof h == "function" && e(h); for (const A of qe(h)) { - const S = s(f, A), w = `${f}.${S}`, R = u(h, p, S); + const x = s(f, A), w = `${f}.${x}`, R = u(h, p, x); (!R || !l(w, h, A, R)) && ls(h, A, R === !1, w, r); } } @@ -2190,7 +2190,7 @@ function ui(t = "safe") { }, o = ({ powers: c = "none" } = {}) => { let l; return c === "original" ? l = function(...d) { - return new.target === void 0 ? ue(e, void 0, d) : Sr(e, d, new.target); + return new.target === void 0 ? ue(e, void 0, d) : xr(e, d, new.target); } : l = function(...d) { if (new.target === void 0) throw _( @@ -2200,7 +2200,7 @@ function ui(t = "safe") { throw _( "secure mode Calling new %SharedDate%() with no arguments throws" ); - return Sr(e, d, new.target); + return xr(e, d, new.target); }, B(l, { length: { value: 7 }, prototype: { @@ -2274,7 +2274,7 @@ function fi(t = "safe") { throw _(`unrecognized regExpTaming ${t}`); const e = Xe.prototype, r = (s = {}) => { const i = function(...l) { - return new.target === void 0 ? Xe(...l) : Sr(Xe, l, new.target); + return new.target === void 0 ? Xe(...l) : xr(Xe, l, new.target); }; if (B(i, { length: { value: 2 }, @@ -2479,7 +2479,7 @@ function mi(t, e, { warn: r }, n = []) { const o = new Dt(n); function s(d, f, h, p) { if ("value" in p && p.configurable) { - const { value: m } = p, A = Cn(o, h), { get: S, set: w } = ee( + const { value: m } = p, A = Cn(o, h), { get: x, set: w } = ee( { get [h]() { return m; @@ -2501,13 +2501,13 @@ function mi(t, e, { warn: r }, n = []) { }, h ); - D(S, "originalValue", { + D(x, "originalValue", { value: m, writable: !1, enumerable: !1, configurable: !1 }), D(f, h, { - get: S, + get: x, set: w, enumerable: p.enumerable, configurable: p.configurable @@ -2527,13 +2527,13 @@ function mi(t, e, { warn: r }, n = []) { const m = ee(f, p); if (!m || m.get || m.set) continue; - const A = `${d}.${_e(p)}`, S = h[p]; - if (S === !0) + const A = `${d}.${_e(p)}`, x = h[p]; + if (x === !0) i(A, f, p); - else if (S === "*") + else if (x === "*") c(A, m.value); - else if (ke(S)) - l(A, m.value, S); + else if (ke(x)) + l(A, m.value, x); else throw _(`Unexpected override enablement plan ${A}`); } @@ -2619,7 +2619,7 @@ ${o} configurable: !1 } }), G(Ee) === Ee.prototype || ao`Function prototype is the same accross compartments`, G(e) === Ee.prototype || ao`Function constructor prototype is the same accross compartments`, e; -}, Si = (t) => { +}, xi = (t) => { D( t, fa, @@ -2701,11 +2701,11 @@ ${o} configurable: !0 }); } -}, { Fail: xi, quote: bs } = Y, ws = new Ur( +}, { Fail: Si, quote: bs } = Y, ws = new Ur( Mn, y({ get(t, e) { - xi`Please report unexpected scope handler trap: ${bs(_e(e))}`; + Si`Please report unexpected scope handler trap: ${bs(_e(e))}`; } }) ), Ei = { @@ -2715,7 +2715,7 @@ ${o} throw Wt(`${_e(e)} is not defined`); }, has(t, e) { - return e in x; + return e in S; }, // note: this is likely a bug of safari // https://bugs.webkit.org/show_bug.cgi?id=195534 @@ -2736,18 +2736,18 @@ ${o} ownKeys(t) { return []; } -}, Ss = y( +}, xs = y( H( ws, Be(Ei) ) ), ki = new Ur( Mn, - Ss -), xs = (t) => { + xs +), Ss = (t) => { const e = { // inherit scopeTerminator behavior - ...Ss, + ...xs, // Redirect set properties to the globalObject. set(o, s, i) { return Mo(t, s, i); @@ -2767,7 +2767,7 @@ ${o} r ); }; -y(xs); +y(Ss); const { Fail: Pi } = Y, Ai = () => { const t = H(null), e = y({ eval: { @@ -2978,7 +2978,7 @@ const Ni = (t) => { globalTransforms: r = [], sloppyGlobalsMode: n = !1 }) => { - const o = n ? xs(t) : ki, s = Ai(), { evalScope: i } = s, c = y({ + const o = n ? Ss(t) : ki, s = Ai(), { evalScope: i } = s, c = y({ evalScope: i, moduleLexicals: e, globalObject: t, @@ -3028,7 +3028,7 @@ function Li(t = "safe") { throw _(`unrecognized domainTaming ${t}`); if (t === "unsafe") return; - const e = x.process || void 0; + const e = S.process || void 0; if (typeof e == "object") { const r = ee(e, "domain"); if (r !== void 0 && r.get !== void 0) @@ -3044,7 +3044,7 @@ function Li(t = "safe") { } } const Fi = () => { - const t = {}, e = x.ModuleSource; + const t = {}, e = S.ModuleSource; if (e !== void 0) { let n = function() { }; @@ -3142,38 +3142,38 @@ y(dt); const zn = (t, e) => { if (!t) return; - const { getStackString: r, tagError: n, takeMessageLogArgs: o, takeNoteLogArgsArray: s } = e, i = (S, w) => de(S, (T) => Kr(T) ? (ne(w, T), `(${n(T)})`) : T), c = (S, w, R, T, j) => { + const { getStackString: r, tagError: n, takeMessageLogArgs: o, takeNoteLogArgsArray: s } = e, i = (x, w) => de(x, (T) => Kr(T) ? (ne(w, T), `(${n(T)})`) : T), c = (x, w, R, T, j) => { const I = n(w), L = R === dt.MESSAGE ? `${I}:` : `${I} ${R}`, Z = i(T, j); - t[S](L, ...Z); - }, l = (S, w, R = void 0) => { + t[x](L, ...Z); + }, l = (x, w, R = void 0) => { if (w.length === 0) return; if (w.length === 1 && R === void 0) { - f(S, w[0]); + f(x, w[0]); return; } let T; w.length === 1 ? T = "Nested error" : T = `Nested ${w.length} errors`, R !== void 0 && (T = `${T} under ${R}`), t.group(T); try { for (const j of w) - f(S, j); + f(x, j); } finally { t.groupEnd(); } - }, u = new Ut(), d = (S) => (w, R) => { + }, u = new Ut(), d = (x) => (w, R) => { const T = []; - c(S, w, dt.NOTE, R, T), l(S, T, n(w)); - }, f = (S, w) => { + c(x, w, dt.NOTE, R, T), l(x, T, n(w)); + }, f = (x, w) => { if (lr(u, w)) return; const R = n(w); qr(u, w); const T = [], j = o(w), I = s( w, - d(S) + d(x) ); - j === void 0 ? t[S](`${R}:`, w.message) : c( - S, + j === void 0 ? t[x](`${R}:`, w.message) : c( + x, w, dt.MESSAGE, j, @@ -3182,24 +3182,24 @@ const zn = (t, e) => { let L = r(w); typeof L == "string" && L.length >= 1 && !Bo(L, ` `) && (L += ` -`), t[S](L), w.cause && c(S, w, dt.CAUSE, [w.cause], T), w.errors && c(S, w, dt.ERRORS, w.errors, T); +`), t[x](L), w.cause && c(x, w, dt.CAUSE, [w.cause], T), w.errors && c(x, w, dt.ERRORS, w.errors, T); for (const Z of I) - c(S, w, dt.NOTE, Z, T); - l(S, T, R); - }, h = de(jn, ([S, w]) => { + c(x, w, dt.NOTE, Z, T); + l(x, T, R); + }, h = de(jn, ([x, w]) => { const R = (...T) => { const j = [], I = i(T, j); - t[S] && t[S](...I), l(S, j); + t[x] && t[x](...I), l(x, j); }; - return D(R, "name", { value: S }), [S, y(R)]; + return D(R, "name", { value: x }), [x, y(R)]; }), p = et( Zn, - ([S, w]) => S in t - ), m = de(p, ([S, w]) => { + ([x, w]) => x in t + ), m = de(p, ([x, w]) => { const R = (...T) => { - t[S](...T); + t[x](...T); }; - return D(R, "name", { value: S }), [S, y(R)]; + return D(R, "name", { value: x }), [x, y(R)]; }), A = bt([...h, ...m]); return ( /** @type {VirtualConsole} */ @@ -3293,13 +3293,13 @@ const fo = (t) => { const s = ( /** @type {VirtualConsole} */ // eslint-disable-next-line no-nested-ternary - typeof x.console < "u" ? x.console : typeof x.print == "function" ? ( + typeof S.console < "u" ? S.console : typeof S.print == "function" ? ( // Make a good-enough console for eshost (including only functions that // log at a specific level with no special argument interpretation). // https://console.spec.whatwg.org/#logging ((u) => y({ debug: u, log: u, info: u, warn: u, error: u }))( // eslint-disable-next-line no-undef - po(x.print) + po(S.print) ) ) : void 0 ); @@ -3311,7 +3311,7 @@ const fo = (t) => { const i = ( /** @type {VirtualConsole} */ t === "unsafe" ? s : zn(s, o) - ), c = x.process || void 0; + ), c = S.process || void 0; if (e !== "none" && typeof c == "object" && typeof c.on == "function") { let u; if (e === "platform" || e === "exit") { @@ -3328,7 +3328,7 @@ const fo = (t) => { }); d && (c.on("unhandledRejection", d.unhandledRejectionHandler), c.on("rejectionHandled", d.rejectionHandledHandler), c.on("exit", d.processTerminationHandler)); } - const l = x.window || void 0; + const l = S.window || void 0; if (e !== "none" && typeof l == "object" && typeof l.addEventListener == "function" && l.addEventListener("error", (u) => { u.preventDefault(), i.error("SES_UNCAUGHT_EXCEPTION:", u.error), (e === "exit" || e === "abort") && (l.location.href = "about:blank"); }), r !== "none" && typeof l == "object" && typeof l.addEventListener == "function") { @@ -3444,8 +3444,8 @@ const fo = (t) => { if (lr(f, p)) return p; const m = { - prepareStackTrace(A, S) { - return he(l, A, { callSites: S }), p(A, Gi(S)); + prepareStackTrace(A, x) { + return he(l, A, { callSites: x }), p(A, Gi(x)); } }; return qr(f, m.prepareStackTrace), m.prepareStackTrace; @@ -3486,7 +3486,7 @@ function nc(t = "safe", e = "concise") { const r = le.prototype, { captureStackTrace: n } = le, o = typeof n == "function" ? "v8" : "unknown", s = (l = {}) => { const u = function(...f) { let h; - return new.target === void 0 ? h = ue(le, this, f) : h = Sr(le, f, new.target), o === "v8" && ue(n, le, [h, u]), h; + return new.target === void 0 ? h = ue(le, this, f) : h = xr(le, f, new.target), o === "v8" && ue(n, le, [h, u]), h; }; return B(u, { length: { value: 1 }, @@ -3850,7 +3850,7 @@ function* lc(t, e, r, n, o, s, i) { ); return pe(f, n, w), w; } - const S = Bt( + const x = Bt( t, e, r, @@ -3860,7 +3860,7 @@ function* lc(t, e, r, n, o, s, i) { s, i ); - return pe(f, n, S), S; + return pe(f, n, x), x; } else throw Ce( re`module descriptor must be a string or object for specifier ${U( @@ -3967,7 +3967,7 @@ const It = (t, e, r, n, o, s, i) => { o )}` }); -}, { quote: xt } = Y, hc = () => { +}, { quote: St } = Y, hc = () => { let t = !1; const e = H(null, { // Make this appear like an ESM module namespace object. @@ -3987,7 +3987,7 @@ const It = (t, e, r, n, o, s, i) => { get(r, n, o) { if (!t) throw _( - `Cannot get property ${xt( + `Cannot get property ${St( n )} of module exports namespace, the module has not yet begun to execute` ); @@ -3995,13 +3995,13 @@ const It = (t, e, r, n, o, s, i) => { }, set(r, n, o) { throw _( - `Cannot set property ${xt(n)} of module exports namespace` + `Cannot set property ${St(n)} of module exports namespace` ); }, has(r, n) { if (!t) throw _( - `Cannot check property ${xt( + `Cannot check property ${St( n )}, the module has not yet begun to execute` ); @@ -4009,7 +4009,7 @@ const It = (t, e, r, n, o, s, i) => { }, deleteProperty(r, n) { throw _( - `Cannot delete property ${xt(n)}s of module exports namespace` + `Cannot delete property ${St(n)}s of module exports namespace` ); }, ownKeys(r) { @@ -4022,7 +4022,7 @@ const It = (t, e, r, n, o, s, i) => { getOwnPropertyDescriptor(r, n) { if (!t) throw _( - `Cannot get own property descriptor ${xt( + `Cannot get own property descriptor ${St( n )}, the module has not yet begun to execute` ); @@ -4050,7 +4050,7 @@ const It = (t, e, r, n, o, s, i) => { }, defineProperty(r, n, o) { throw _( - `Cannot define property ${xt(n)} of module exports namespace` + `Cannot define property ${St(n)} of module exports namespace` ); }, apply(r, n, o) { @@ -4131,15 +4131,15 @@ const It = (t, e, r, n, o, s, i) => { const p = []; D(c, f, { get: () => h, - set: (S) => { - h = S; + set: (x) => { + h = x; for (const w of p) - w(S); + w(x); }, enumerable: !0, configurable: !1 - }), u[f] = (S) => { - ne(p, S), S(h); + }), u[f] = (x) => { + ne(p, x), x(h); }; }), u["*"] = (f) => { f(c); @@ -4178,7 +4178,7 @@ const It = (t, e, r, n, o, s, i) => { __reexportMap__: h = {}, __needsImportMeta__: p = !1, __syncModuleFunctor__: m - } = i, A = z(t, o), { __shimTransforms__: S, importMetaHook: w } = A, { exportsProxy: R, exportsTarget: T, activate: j } = Bn( + } = i, A = z(t, o), { __shimTransforms__: x, importMetaHook: w } = A, { exportsProxy: R, exportsTarget: T, activate: j } = Bn( o, A, e, @@ -4231,7 +4231,7 @@ const It = (t, e, r, n, o, s, i) => { `binding ${mr(we)} not yet initialized` ); return ie; - }, St = y((Ie) => { + }, xt = y((Ie) => { ie = Ie, ge = !1; for (const en of te) en(Ie); @@ -4245,14 +4245,14 @@ const It = (t, e, r, n, o, s, i) => { ae = { get: Ae, notify: (Ie) => { - Ie !== St && (ne(te, Ie), ge || Ie(ie)); + Ie !== xt && (ne(te, Ie), ge || Ie(ie)); } }, be[W] = ae, q && D(L, W, { get: Ae, set: Te, enumerable: !0, configurable: !1 - }), se[W] = St; + }), se[W] = xt; } I[we] = { get: ae.get, @@ -4274,13 +4274,13 @@ const It = (t, e, r, n, o, s, i) => { ie.execute(); const { notifiers: ge } = ie; for (const [te, Ae] of ae) { - const St = ge[te]; - if (!St) + const xt = ge[te]; + if (!xt) throw ir( `The requested module '${q}' does not provide an export named '${te}'` ); for (const Te of Ae) - St(Te); + xt(Te); } if (Hr(l, q)) for (const [te, Ae] of me( @@ -4312,7 +4312,7 @@ const It = (t, e, r, n, o, s, i) => { let wt; m !== void 0 ? wt = m : wt = Fs(A, u, { globalObject: o.globalThis, - transforms: S, + transforms: x, __moduleShimLexicals__: L }); let Pe = !1, st; @@ -4352,7 +4352,7 @@ const It = (t, e, r, n, o, s, i) => { o )}` ); - return xc(t, e, i); + return Sc(t, e, i); }; function _c(t) { return typeof t.__syncModuleProgram__ == "string"; @@ -4374,7 +4374,7 @@ function wc(t, e) { r )}, for module ${X(e)}`; } -function Sc(t, e) { +function xc(t, e) { ke(t) || ft`Invalid module source: must be of type object, got ${X( t )}, for module ${X(e)}`; @@ -4387,11 +4387,11 @@ function Sc(t, e) { o )}, for module ${X(e)}`; } -const xc = (t, e, r) => { +const Sc = (t, e, r) => { const { compartment: n, moduleSpecifier: o, resolvedImports: s, moduleSource: i } = r, { instances: c } = z(t, n); if (Wr(c, o)) return Ke(c, o); - Sc(i, o); + xc(i, o); const l = new $e(); let u; if (_c(i)) @@ -4545,7 +4545,7 @@ const Ec = (...t) => { modules: r }; } -}, Sn = (t, e, r, n = void 0) => { +}, xn = (t, e, r, n = void 0) => { function o(...s) { if (new.target === void 0) throw _( @@ -4562,9 +4562,9 @@ const Ec = (...t) => { importNowHook: p, moduleMapHook: m, importMetaHook: A, - __noNamespaceBox__: S = !1 + __noNamespaceBox__: x = !1 } = Ec(...s), w = [...c, ...l], R = { __proto__: null, ...u }, T = { __proto__: null, ...d }, j = new $e(), I = new $e(), L = new $e(), Z = {}; - Si(Z), _s(Z); + xi(Z), _s(Z); const { safeEvaluate: se } = Un({ globalObject: Z, globalTransforms: w, @@ -4596,7 +4596,7 @@ const Ec = (...t) => { deferredExports: L, instances: I, parentCompartment: n, - noNamespaceBox: S + noNamespaceBox: x }); } return o.prototype = Vn, o; @@ -4608,10 +4608,10 @@ function kc() { return arguments; } const Pc = () => { - const t = Ee.prototype.constructor, e = ee(kc(), "callee"), r = e && e.get, n = Na(new _e()), o = G(n), s = Br[$o] && Ca(/./), i = s && G(s), c = Sa([]), l = G(c), u = G(sa), d = Ta(new $e()), f = G(d), h = Ia(new Dt()), p = G(h), m = G(l); + const t = Ee.prototype.constructor, e = ee(kc(), "callee"), r = e && e.get, n = Na(new _e()), o = G(n), s = Br[$o] && Ca(/./), i = s && G(s), c = xa([]), l = G(c), u = G(sa), d = Ta(new $e()), f = G(d), h = Ia(new Dt()), p = G(h), m = G(l); function* A() { } - const S = dn(A), w = S.prototype; + const x = dn(A), w = x.prototype; async function* R() { } const T = dn( @@ -4628,7 +4628,7 @@ const Pc = () => { "%AsyncGeneratorPrototype%": I, "%AsyncIteratorPrototype%": L, "%Generator%": w, - "%InertGeneratorFunction%": S, + "%InertGeneratorFunction%": x, "%IteratorPrototype%": m, "%MapIteratorPrototype%": f, "%RegExpStringIteratorPrototype%": i, @@ -4638,22 +4638,22 @@ const Pc = () => { "%TypedArray%": u, "%InertCompartment%": Gn }; - return x.Iterator && (J["%IteratorHelperPrototype%"] = G( + return S.Iterator && (J["%IteratorHelperPrototype%"] = G( // eslint-disable-next-line @endo/no-polymorphic-call - x.Iterator.from([]).take(0) + S.Iterator.from([]).take(0) ), J["%WrapForValidIteratorPrototype%"] = G( // eslint-disable-next-line @endo/no-polymorphic-call - x.Iterator.from({ + S.Iterator.from({ next() { return { value: void 0 }; } }) - )), x.AsyncIterator && (J["%AsyncIteratorHelperPrototype%"] = G( + )), S.AsyncIterator && (J["%AsyncIteratorHelperPrototype%"] = G( // eslint-disable-next-line @endo/no-polymorphic-call - x.AsyncIterator.from([]).take(0) + S.AsyncIterator.from([]).take(0) ), J["%WrapForValidAsyncIteratorPrototype%"] = G( // eslint-disable-next-line @endo/no-polymorphic-call - x.AsyncIterator.from({ next() { + S.AsyncIterator.from({ next() { } }) )), J; }, Us = (t, e) => { @@ -4734,10 +4734,10 @@ const Ac = () => { } }); }, Rc = () => { - if (typeof xr.transfer == "function") + if (typeof Sr.transfer == "function") return {}; - const t = x.structuredClone; - return typeof t != "function" ? {} : (D(xr, "transfer", { + const t = S.structuredClone; + return typeof t != "function" ? {} : (D(Sr, "transfer", { // @ts-expect-error value: { /** @@ -4753,7 +4753,7 @@ const Ac = () => { const o = new To(r), s = new mn(this), i = new mn(o); return ka(i, s), t(this, { transfer: [this] }), o; } else { - const o = xa(this, 0, r); + const o = Sa(this, 0, r); return t(this, { transfer: [this] }), o; } } @@ -4790,13 +4790,13 @@ const Ac = () => { return gr(vo); if (t !== "platform" && t !== "console") throw new _(`Invalid lockdown reporting option: ${t}`); - if (t === "console" || x.window === x || x.importScripts !== void 0) + if (t === "console" || S.window === S || S.importScripts !== void 0) return console; - if (x.console !== void 0) { - const e = x.console, r = Wo(e.error, e); + if (S.console !== void 0) { + const e = S.console, r = Wo(e.error, e); return gr(r); } - return x.print !== void 0 ? gr(x.print) : gr(vo); + return S.print !== void 0 ? gr(S.print) : gr(vo); }, bo = (t, e, r) => { const { warn: n, error: o, groupCollapsed: s, groupEnd: i } = e; let c = !1; @@ -4823,7 +4823,7 @@ const $c = ri(), Nc = () => { ` eval("SES_changed = true"); return SES_changed; ` - )(Ko, !1), t || delete x.SES_changed; + )(Ko, !1), t || delete S.SES_changed; } catch { t = !0; } @@ -4871,7 +4871,7 @@ const $c = ri(), Nc = () => { __hardenTaming__: m = ce("LOCKDOWN_HARDEN_TAMING", "safe"), dateTaming: A = "safe", // deprecated - mathTaming: S = "safe", + mathTaming: x = "safe", // deprecated ...w } = t; @@ -4883,20 +4883,20 @@ const $c = ri(), Nc = () => { Y.fail( wo`Already locked down at ${yr} (SES_ALREADY_LOCKED_DOWN)`, _ - ), yr = _("Prior lockdown (SES_ALREADY_LOCKED_DOWN)"), yr.stack, Nc(), x.Function.prototype.constructor !== x.Function && // @ts-ignore harden is absent on globalThis type def. - typeof x.harden == "function" && // @ts-ignore lockdown is absent on globalThis type def. - typeof x.lockdown == "function" && x.Date.prototype.constructor !== x.Date && typeof x.Date.now == "function" && // @ts-ignore does not recognize that Date constructor is a special + ), yr = _("Prior lockdown (SES_ALREADY_LOCKED_DOWN)"), yr.stack, Nc(), S.Function.prototype.constructor !== S.Function && // @ts-ignore harden is absent on globalThis type def. + typeof S.harden == "function" && // @ts-ignore lockdown is absent on globalThis type def. + typeof S.lockdown == "function" && S.Date.prototype.constructor !== S.Date && typeof S.Date.now == "function" && // @ts-ignore does not recognize that Date constructor is a special // Function. // eslint-disable-next-line @endo/no-polymorphic-call - Zr(x.Date.prototype.constructor.now(), NaN)) + Zr(S.Date.prototype.constructor.now(), NaN)) throw _( "Already locked down but not by this SES instance (SES_MULTIPLE_INSTANCES)" ); Li(d); const I = Ns(), { addIntrinsics: L, completePrototypes: Z, finalIntrinsics: se } = ms(T), J = Us($c, m); - L({ harden: J }), L(li()), L(ui(A)), L(nc(e, u)), L(di(S)), L(fi(s)), L(Ac()), L(Rc()), L(Fi()), L(Pc()), Z(); + L({ harden: J }), L(li()), L(ui(A)), L(nc(e, u)), L(di(x)), L(fi(s)), L(Ac()), L(Rc()), L(Fi()), L(Pc()), Z(); const be = se(), Me = { __proto__: null }; - typeof x.Buffer == "function" && (Me.Buffer = x.Buffer); + typeof S.Buffer == "function" && (Me.Buffer = S.Buffer); let dr; e === "safe" && (dr = be["%InitialGetStackString%"]); const zt = Zi( @@ -4905,13 +4905,13 @@ const $c = ri(), Nc = () => { o, dr ); - if (x.console = /** @type {Console} */ + if (S.console = /** @type {Console} */ zt.console, typeof /** @type {any} */ zt.console._times == "object" && (Me.SafeMap = G( // eslint-disable-next-line no-underscore-dangle /** @type {any} */ zt.console._times - )), (e === "unsafe" || e === "unsafe-debug") && x.assert === Y && (x.assert = Xr(void 0, !0)), vi(be, i), Ic(be), bo( + )), (e === "unsafe" || e === "unsafe-debug") && S.assert === Y && (S.assert = Xr(void 0, !0)), vi(be, i), Ic(be), bo( "SES Removing unpermitted intrinsics", T, (Pe) => ci( @@ -4919,21 +4919,21 @@ const $c = ri(), Nc = () => { I, Pe ) - ), _s(x), vs(x, { + ), _s(S), vs(S, { intrinsics: be, newGlobalPropertyNames: ro, - makeCompartmentConstructor: Sn, + makeCompartmentConstructor: xn, markVirtualizedNativeFunction: I }), f === "noEval") wn( - x, + S, Fa, I ); else if (f === "safeEval") { - const { safeEvaluate: Pe } = Un({ globalObject: x }); + const { safeEvaluate: Pe } = Un({ globalObject: S }); wn( - x, + S, Pe, I ); @@ -4960,43 +4960,43 @@ const $c = ri(), Nc = () => { hostIntrinsics: Me, globals: { // Harden evaluators - Function: x.Function, - eval: x.eval, + Function: S.Function, + eval: S.eval, // @ts-ignore Compartment does exist on globalThis - Compartment: x.Compartment, + Compartment: S.Compartment, // Harden Symbol - Symbol: x.Symbol + Symbol: S.Symbol } }; for (const st of Nt(ro)) - Pe.globals[st] = x[st]; + Pe.globals[st] = S[st]; return J(Pe), J; }; }; -x.lockdown = (t) => { +S.lockdown = (t) => { const e = Zs(t); - x.harden = e(); + S.harden = e(); }; -x.repairIntrinsics = (t) => { +S.repairIntrinsics = (t) => { const e = Zs(t); - x.hardenIntrinsics = () => { - x.harden = e(); + S.hardenIntrinsics = () => { + S.harden = e(); }; }; const Oc = Ns(), Mc = js("none"); -x.Compartment = Sn( - Sn, +S.Compartment = xn( + xn, // Any reporting that would need to be done should have already been done // during `lockdown()`. // See https://github.com/endojs/endo/pull/2624#discussion_r1840979770 - ii(x, Mc), + ii(S, Mc), Oc ); -x.assert = Y; +S.assert = Y; const Lc = Ms(Ir), Fc = ha( "MAKE_CAUSAL_CONSOLE_FROM_LOGGER_KEY_FOR_SES_AVA" ); -x[Fc] = Lc; +S[Fc] = Lc; const Dc = (t, e = t, r) => { let n = { x: 0, y: 0 }, o = { x: 0, y: 0 }, s = { x: 0, y: 0 }; const i = (u) => { @@ -5027,16 +5027,19 @@ function jc(t, e, r, n, o) { ), s.setAttribute("title", t), s.setAttribute("iframe-src", e), o && s.setAttribute("allow-downloads", "true"), document.body.appendChild(s), s; } function zs(t, e = 335, r = 590) { - const s = e > window.innerWidth ? window.innerWidth - 290 : e, i = parseInt( - t.style.getPropertyValue("--modal-block-start") || "40", - 10 - ), c = window.innerHeight - i; - return e = Math.min(e, s), r = Math.min(r, c), e = Math.max(e, 200), r = Math.max(r, 200), t.wrapper.style.width = `${e}px`, t.wrapper.style.minWidth = `${e}px`, t.wrapper.style.height = `${r}px`, t.wrapper.style.minHeight = `${r}px`, { width: e, height: r }; + var d; + let s = (d = t.shadowRoot) == null ? void 0 : d.querySelector(".wrapper"), i = 0, c = 0; + if (s) { + let f = s.getBoundingClientRect(); + i = f.x, c = f.y; + } + const l = window.innerWidth - i - 40, u = window.innerHeight - c - 40; + return e = Math.min(e, l), r = Math.min(r, u), e = Math.max(e, 200), r = Math.max(r, 200), t.wrapper.style.width = `${e}px`, t.wrapper.style.minWidth = `${e}px`, t.wrapper.style.height = `${r}px`, t.wrapper.style.minHeight = `${r}px`, { width: e, height: r }; } const Zc = ` -`; +`, zc = 3; var We, Rt; -class zc extends HTMLElement { +class Bc extends HTMLElement { constructor() { super(); tn(this, We); @@ -5054,7 +5057,7 @@ class zc extends HTMLElement { (r = at(this, Rt)) == null || r.call(this); } calculateZIndex() { - const r = document.querySelectorAll("plugin-modal"), n = Array.from(r).filter((s) => s !== this).map((s) => Number(s.style.zIndex)), o = Math.max(...n, 0); + const r = document.querySelectorAll("plugin-modal"), n = Array.from(r).filter((s) => s !== this).map((s) => Number(s.style.zIndex)), o = Math.max(...n, zc); this.style.zIndex = (o + 1).toString(); } connectedCallback() { @@ -5108,7 +5111,7 @@ class zc extends HTMLElement { } } We = new WeakMap(), Rt = new WeakMap(); -customElements.define("plugin-modal", zc); +customElements.define("plugin-modal", Bc); var F; (function(t) { t.assertEqual = (o) => o; @@ -5145,14 +5148,14 @@ var F; } t.joinValues = n, t.jsonStringifyReplacer = (o, s) => typeof s == "bigint" ? s.toString() : s; })(F || (F = {})); -var xn; +var Sn; (function(t) { t.mergeShapes = (e, r) => ({ ...e, ...r // second overwrites first }); -})(xn || (xn = {})); +})(Sn || (Sn = {})); const b = F.arrayToEnum([ "string", "nan", @@ -5212,7 +5215,7 @@ const b = F.arrayToEnum([ "invalid_intersection_types", "not_multiple_of", "not_finite" -]), Bc = (t) => JSON.stringify(t, null, 2).replace(/"([^"]+)":/g, "$1:"); +]), Gc = (t) => JSON.stringify(t, null, 2).replace(/"([^"]+)":/g, "$1:"); class ye extends Error { get errors() { return this.issues; @@ -5330,7 +5333,7 @@ const Mt = (t, e) => { return { message: r }; }; let Bs = Mt; -function Gc(t) { +function Vc(t) { Bs = t; } function $r() { @@ -5356,7 +5359,7 @@ const Nr = (t) => { path: s, message: c }; -}, Vc = []; +}, Hc = []; function v(t, e) { const r = $r(), n = Nr({ issueData: e, @@ -5440,7 +5443,7 @@ class je { return this._cachedPath.length || (this._key instanceof Array ? this._cachedPath.push(...this._path, ...this._key) : this._cachedPath.push(...this._path, this._key)), this._cachedPath; } } -const So = (t, e) => { +const xo = (t, e) => { if (yt(e)) return { success: !0, data: e.value }; if (!t.common.issues.length) @@ -5527,7 +5530,7 @@ class O { data: e, parsedType: He(e) }, s = this._parseSync({ data: e, path: o.path, parent: o }); - return So(o, s); + return xo(o, s); } "~validate"(e) { var r, n; @@ -5581,7 +5584,7 @@ class O { data: e, parsedType: He(e) }, o = this._parse({ data: e, path: n.path, parent: n }), s = await (qt(o) ? o : Promise.resolve(o)); - return So(n, s); + return xo(n, s); } refine(e, r) { const n = (o) => typeof r == "string" || typeof r > "u" ? { message: r } : typeof r == "function" ? r(o) : r; @@ -5687,14 +5690,14 @@ class O { return this.safeParse(null).success; } } -const Hc = /^c[^\s-]{8,}$/i, Wc = /^[0-9a-z]+$/, qc = /^[0-9A-HJKMNP-TV-Z]{26}$/i, Kc = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i, Yc = /^[a-z0-9_-]{21}$/i, Jc = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/, Xc = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/, Qc = /^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i, el = "^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$"; +const Wc = /^c[^\s-]{8,}$/i, qc = /^[0-9a-z]+$/, Kc = /^[0-9A-HJKMNP-TV-Z]{26}$/i, Yc = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i, Jc = /^[a-z0-9_-]{21}$/i, Xc = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/, Qc = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/, el = /^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i, tl = "^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$"; let hn; -const tl = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/, rl = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/, nl = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/, ol = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/, sl = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/, al = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/, Vs = "((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))", il = new RegExp(`^${Vs}$`); +const rl = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/, nl = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/, ol = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/, sl = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/, al = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/, il = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/, Vs = "((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))", cl = new RegExp(`^${Vs}$`); function Hs(t) { let e = "([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d"; return t.precision ? e = `${e}\\.\\d{${t.precision}}` : t.precision == null && (e = `${e}(\\.\\d+)?`), e; } -function cl(t) { +function ll(t) { return new RegExp(`^${Hs(t)}$`); } function Ws(t) { @@ -5702,11 +5705,11 @@ function Ws(t) { const r = []; return r.push(t.local ? "Z?" : "Z"), t.offset && r.push("([+-]\\d{2}:?\\d{2})"), e = `${e}(${r.join("|")})`, new RegExp(`^${e}$`); } -function ll(t, e) { - return !!((e === "v4" || !e) && tl.test(t) || (e === "v6" || !e) && nl.test(t)); -} function ul(t, e) { - if (!Jc.test(t)) + return !!((e === "v4" || !e) && rl.test(t) || (e === "v6" || !e) && ol.test(t)); +} +function dl(t, e) { + if (!Xc.test(t)) return !1; try { const [r] = t.split("."), n = r.replace(/-/g, "+").replace(/_/g, "/").padEnd(r.length + (4 - r.length % 4) % 4, "="), o = JSON.parse(atob(n)); @@ -5715,8 +5718,8 @@ function ul(t, e) { return !1; } } -function dl(t, e) { - return !!((e === "v4" || !e) && rl.test(t) || (e === "v6" || !e) && ol.test(t)); +function fl(t, e) { + return !!((e === "v4" || !e) && nl.test(t) || (e === "v6" || !e) && sl.test(t)); } class Re extends O { _parse(e) { @@ -5767,43 +5770,43 @@ class Re extends O { message: s.message }), n.dirty()); } else if (s.kind === "email") - Qc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + el.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "email", code: g.invalid_string, message: s.message }), n.dirty()); else if (s.kind === "emoji") - hn || (hn = new RegExp(el, "u")), hn.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + hn || (hn = new RegExp(tl, "u")), hn.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "emoji", code: g.invalid_string, message: s.message }), n.dirty()); else if (s.kind === "uuid") - Kc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + Yc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "uuid", code: g.invalid_string, message: s.message }), n.dirty()); else if (s.kind === "nanoid") - Yc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + Jc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "nanoid", code: g.invalid_string, message: s.message }), n.dirty()); else if (s.kind === "cuid") - Hc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + Wc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "cuid", code: g.invalid_string, message: s.message }), n.dirty()); else if (s.kind === "cuid2") - Wc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + qc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "cuid2", code: g.invalid_string, message: s.message }), n.dirty()); else if (s.kind === "ulid") - qc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + Kc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "ulid", code: g.invalid_string, message: s.message @@ -5838,35 +5841,35 @@ class Re extends O { code: g.invalid_string, validation: "datetime", message: s.message - }), n.dirty()) : s.kind === "date" ? il.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + }), n.dirty()) : s.kind === "date" ? cl.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { code: g.invalid_string, validation: "date", message: s.message - }), n.dirty()) : s.kind === "time" ? cl(s).test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + }), n.dirty()) : s.kind === "time" ? ll(s).test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { code: g.invalid_string, validation: "time", message: s.message - }), n.dirty()) : s.kind === "duration" ? Xc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + }), n.dirty()) : s.kind === "duration" ? Qc.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "duration", code: g.invalid_string, message: s.message - }), n.dirty()) : s.kind === "ip" ? ll(e.data, s.version) || (o = this._getOrReturnCtx(e, o), v(o, { + }), n.dirty()) : s.kind === "ip" ? ul(e.data, s.version) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "ip", code: g.invalid_string, message: s.message - }), n.dirty()) : s.kind === "jwt" ? ul(e.data, s.alg) || (o = this._getOrReturnCtx(e, o), v(o, { + }), n.dirty()) : s.kind === "jwt" ? dl(e.data, s.alg) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "jwt", code: g.invalid_string, message: s.message - }), n.dirty()) : s.kind === "cidr" ? dl(e.data, s.version) || (o = this._getOrReturnCtx(e, o), v(o, { + }), n.dirty()) : s.kind === "cidr" ? fl(e.data, s.version) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "cidr", code: g.invalid_string, message: s.message - }), n.dirty()) : s.kind === "base64" ? sl.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + }), n.dirty()) : s.kind === "base64" ? al.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "base64", code: g.invalid_string, message: s.message - }), n.dirty()) : s.kind === "base64url" ? al.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { + }), n.dirty()) : s.kind === "base64url" ? il.test(e.data) || (o = this._getOrReturnCtx(e, o), v(o, { validation: "base64url", code: g.invalid_string, message: s.message @@ -6105,7 +6108,7 @@ Re.create = (t) => { ...N(t) }); }; -function fl(t, e) { +function pl(t, e) { const r = (t.toString().split(".")[1] || "").length, n = (e.toString().split(".")[1] || "").length, o = r > n ? r : n, s = parseInt(t.toFixed(o).replace(".", "")), i = parseInt(e.toFixed(o).replace(".", "")); return s % i / Math.pow(10, o); } @@ -6144,7 +6147,7 @@ class tt extends O { inclusive: s.inclusive, exact: !1, message: s.message - }), o.dirty()) : s.kind === "multipleOf" ? fl(e.data, s.value) !== 0 && (n = this._getOrReturnCtx(e, n), v(n, { + }), o.dirty()) : s.kind === "multipleOf" ? pl(e.data, s.value) !== 0 && (n = this._getOrReturnCtx(e, n), v(n, { code: g.not_multiple_of, multipleOf: s.value, message: s.message @@ -7853,7 +7856,7 @@ Dr.create = (t) => new Dr({ typeName: C.ZodNaN, ...N(t) }); -const pl = Symbol("zod_brand"); +const hl = Symbol("zod_brand"); class Hn extends O { _parse(e) { const { ctx: r } = this._processInputParams(e), n = r.data; @@ -7930,16 +7933,16 @@ function Ks(t, e = {}, r) { } }) : Lt.create(); } -const hl = { +const ml = { object: V.lazycreate }; var C; (function(t) { t.ZodString = "ZodString", t.ZodNumber = "ZodNumber", t.ZodNaN = "ZodNaN", t.ZodBigInt = "ZodBigInt", t.ZodBoolean = "ZodBoolean", t.ZodDate = "ZodDate", t.ZodSymbol = "ZodSymbol", t.ZodUndefined = "ZodUndefined", t.ZodNull = "ZodNull", t.ZodAny = "ZodAny", t.ZodUnknown = "ZodUnknown", t.ZodNever = "ZodNever", t.ZodVoid = "ZodVoid", t.ZodArray = "ZodArray", t.ZodObject = "ZodObject", t.ZodUnion = "ZodUnion", t.ZodDiscriminatedUnion = "ZodDiscriminatedUnion", t.ZodIntersection = "ZodIntersection", t.ZodTuple = "ZodTuple", t.ZodRecord = "ZodRecord", t.ZodMap = "ZodMap", t.ZodSet = "ZodSet", t.ZodFunction = "ZodFunction", t.ZodLazy = "ZodLazy", t.ZodLiteral = "ZodLiteral", t.ZodEnum = "ZodEnum", t.ZodEffects = "ZodEffects", t.ZodNativeEnum = "ZodNativeEnum", t.ZodOptional = "ZodOptional", t.ZodNullable = "ZodNullable", t.ZodDefault = "ZodDefault", t.ZodCatch = "ZodCatch", t.ZodPromise = "ZodPromise", t.ZodBranded = "ZodBranded", t.ZodPipeline = "ZodPipeline", t.ZodReadonly = "ZodReadonly"; })(C || (C = {})); -const ml = (t, e = { +const gl = (t, e = { message: `Input not instance of ${t.name}` -}) => Ks((r) => r instanceof t, e), Ys = Re.create, Js = tt.create, gl = Dr.create, yl = rt.create, Xs = Kt.create, _l = _t.create, vl = Mr.create, bl = Yt.create, wl = Jt.create, Sl = Lt.create, xl = mt.create, El = Ye.create, kl = Lr.create, Pl = Ne.create, Al = V.create, Tl = V.strictCreate, Il = Xt.create, Cl = Qr.create, Rl = Qt.create, $l = Ze.create, Nl = er.create, Ol = Fr.create, Ml = vt.create, Ll = Ct.create, Fl = tr.create, Dl = rr.create, Ul = nt.create, jl = nr.create, Zl = Ft.create, xo = Oe.create, zl = Ue.create, Bl = ot.create, Gl = Oe.createWithPreprocess, Vl = ur.create, Hl = () => Ys().optional(), Wl = () => Js().optional(), ql = () => Xs().optional(), Kl = { +}) => Ks((r) => r instanceof t, e), Ys = Re.create, Js = tt.create, yl = Dr.create, _l = rt.create, Xs = Kt.create, vl = _t.create, bl = Mr.create, wl = Yt.create, xl = Jt.create, Sl = Lt.create, El = mt.create, kl = Ye.create, Pl = Lr.create, Al = Ne.create, Tl = V.create, Il = V.strictCreate, Cl = Xt.create, Rl = Qr.create, $l = Qt.create, Nl = Ze.create, Ol = er.create, Ml = Fr.create, Ll = vt.create, Fl = Ct.create, Dl = tr.create, Ul = rr.create, jl = nt.create, Zl = nr.create, zl = Ft.create, So = Oe.create, Bl = Ue.create, Gl = ot.create, Vl = Oe.createWithPreprocess, Hl = ur.create, Wl = () => Ys().optional(), ql = () => Js().optional(), Kl = () => Xs().optional(), Yl = { string: (t) => Re.create({ ...t, coerce: !0 }), number: (t) => tt.create({ ...t, coerce: !0 }), boolean: (t) => Kt.create({ @@ -7948,14 +7951,14 @@ const ml = (t, e = { }), bigint: (t) => rt.create({ ...t, coerce: !0 }), date: (t) => _t.create({ ...t, coerce: !0 }) -}, Yl = $; +}, Jl = $; var K = /* @__PURE__ */ Object.freeze({ __proto__: null, defaultErrorMap: Mt, - setErrorMap: Gc, + setErrorMap: Vc, getErrorMap: $r, makeIssue: Nr, - EMPTY_PATH: Vc, + EMPTY_PATH: Hc, addIssueToContext: v, ParseStatus: oe, INVALID: $, @@ -7969,7 +7972,7 @@ var K = /* @__PURE__ */ Object.freeze({ return F; }, get objectUtil() { - return xn; + return Sn; }, ZodParsedType: b, getParsedType: He, @@ -8009,63 +8012,63 @@ var K = /* @__PURE__ */ Object.freeze({ ZodDefault: or, ZodCatch: sr, ZodNaN: Dr, - BRAND: pl, + BRAND: hl, ZodBranded: Hn, ZodPipeline: ur, ZodReadonly: ar, custom: Ks, Schema: O, ZodSchema: O, - late: hl, + late: ml, get ZodFirstPartyTypeKind() { return C; }, - coerce: Kl, + coerce: Yl, any: Sl, - array: Pl, - bigint: yl, + array: Al, + bigint: _l, boolean: Xs, - date: _l, - discriminatedUnion: Cl, - effect: xo, - enum: Ul, - function: Ll, - instanceof: ml, - intersection: Rl, - lazy: Fl, - literal: Dl, - map: Ol, - nan: gl, - nativeEnum: jl, - never: El, - null: wl, - nullable: Bl, + date: vl, + discriminatedUnion: Rl, + effect: So, + enum: jl, + function: Fl, + instanceof: gl, + intersection: $l, + lazy: Dl, + literal: Ul, + map: Ml, + nan: yl, + nativeEnum: Zl, + never: kl, + null: xl, + nullable: Gl, number: Js, - object: Al, - oboolean: ql, - onumber: Wl, - optional: zl, - ostring: Hl, - pipeline: Vl, - preprocess: Gl, - promise: Zl, - record: Nl, - set: Ml, - strictObject: Tl, + object: Tl, + oboolean: Kl, + onumber: ql, + optional: Bl, + ostring: Wl, + pipeline: Hl, + preprocess: Vl, + promise: zl, + record: Ol, + set: Ll, + strictObject: Il, string: Ys, - symbol: vl, - transformer: xo, - tuple: $l, - undefined: bl, - union: Il, - unknown: xl, - void: kl, - NEVER: Yl, + symbol: bl, + transformer: So, + tuple: Nl, + undefined: wl, + union: Cl, + unknown: El, + void: Pl, + NEVER: Jl, ZodIssueCode: g, - quotelessJson: Bc, + quotelessJson: Gc, ZodError: ye }); -const Jl = K.object({ +const Xl = K.object({ pluginId: K.string(), name: K.string(), host: K.string().url(), @@ -8081,16 +8084,17 @@ const Jl = K.object({ "user:read", "comment:read", "comment:write", - "allow:downloads" + "allow:downloads", + "allow:localstorage" ]) ) }); function Qs(t, e) { return new URL(e, t).toString(); } -function Xl(t) { +function Ql(t) { return fetch(t).then((e) => e.json()).then((e) => { - if (!Jl.safeParse(e).success) + if (!Xl.safeParse(e).success) throw new Error("Invalid plugin manifest"); return e; }).catch((e) => { @@ -8107,14 +8111,14 @@ function Eo(t) { const ea = K.object({ width: K.number().positive(), height: K.number().positive() -}), Ql = K.function().args( +}), eu = K.function().args( K.string(), K.string(), K.enum(["dark", "light"]), ea.optional(), K.boolean().optional() ).implement((t, e, r, n, o) => jc(t, e, r, n, o)); -async function eu(t, e, r, n) { +async function tu(t, e, r, n) { let o = await Eo(e), s = !1, i = !1, c = null, l = []; const u = /* @__PURE__ */ new Set(), d = !!e.permissions.find( (I) => I === "allow:downloads" @@ -8130,7 +8134,7 @@ async function eu(t, e, r, n) { }), l = [], p = []; }, A = () => { m(), u.forEach(clearTimeout), u.clear(), c && (c.removeEventListener("close", A), c.remove(), c = null), i = !0, r(); - }, S = async () => { + }, x = async () => { if (!s) { s = !0; return; @@ -8138,9 +8142,9 @@ async function eu(t, e, r, n) { m(), o = await Eo(e), n(o); }, w = (I, L, Z) => { const se = t.theme, J = Qs(e.host, L); - (c == null ? void 0 : c.getAttribute("iframe-src")) !== J && (c = Ql(I, J, se, Z, d), c.setTheme(se), c.addEventListener("close", A, { + (c == null ? void 0 : c.getAttribute("iframe-src")) !== J && (c = eu(I, J, se, Z, d), c.setTheme(se), c.addEventListener("close", A, { once: !0 - }), c.addEventListener("load", S)); + }), c.addEventListener("load", x)); }, R = (I) => { l.push(I); }, T = (I, L, Z) => { @@ -8182,7 +8186,7 @@ async function eu(t, e, r, n) { } }; } -const tu = [ +const ru = [ "finish", "pagechange", "filechange", @@ -8191,7 +8195,7 @@ const tu = [ "shapechange", "contentsave" ]; -function ru(t) { +function nu(t) { const e = (n) => { if (!t.manifest.permissions.includes(n)) throw new Error(`Permission ${n} is not granted`); @@ -8258,7 +8262,7 @@ function ru(t) { t.close(); }, on(n, o, s) { - return K.enum(tu).parse(n), K.function().parse(o), e("content:read"), t.registerListener(n, o, s); + return K.enum(ru).parse(n), K.function().parse(o), e("content:read"), t.registerListener(n, o, s); }, off(n) { t.destroyListener(n); @@ -8306,6 +8310,9 @@ function ru(t) { get theme() { return t.context.theme; }, + get localStorage() { + return e("allow:localstorage"), t.context.localStorage; + }, createBoard() { return e("content:write"), t.context.createBoard(); }, @@ -8348,6 +8355,9 @@ function ru(t) { generateStyle(n, o) { return e("content:read"), t.context.generateStyle(n, o); }, + generateFontFaces(n) { + return e("content:read"), t.context.generateFontFaces(n); + }, openViewer() { e("content:read"), t.context.openViewer(); }, @@ -8386,9 +8396,9 @@ const k = { return t == null ? t : harden(t); } }; -function nu(t) { +function ou(t) { k.hardenIntrinsics(); - const e = ru(t), r = { + const e = nu(t), r = { get(c, l, u) { const d = Reflect.get(c, l, u); return typeof d == "function" ? function(...f) { @@ -8492,14 +8502,14 @@ function nu(t) { compartment: i }; } -async function ou(t, e, r) { +async function su(t, e, r) { const n = async () => { try { s.evaluate(); } catch (i) { console.error(i), o.close(); } - }, o = await eu( + }, o = await tu( t, e, function() { @@ -8508,7 +8518,7 @@ async function ou(t, e, r) { function() { n(); } - ), s = nu(o); + ), s = ou(o); return n(), { plugin: o, manifest: e, @@ -8516,7 +8526,7 @@ async function ou(t, e, r) { }; } let gt = [], An = null; -function su(t) { +function au(t) { An = t; } const Po = () => { @@ -8532,13 +8542,13 @@ window.addEventListener("message", (t) => { console.error(e); } }); -const au = async function(t, e) { +const iu = async function(t, e) { try { const r = An && An(t.pluginId); if (!r) return; Po(); - const n = await ou( + const n = await su( k.harden(r), t, () => { @@ -8550,11 +8560,11 @@ const au = async function(t, e) { Po(), console.error(r); } }, ta = async function(t, e) { - au(t, e); -}, iu = async function(t) { - const e = await Xl(t); + iu(t, e); +}, cu = async function(t) { + const e = await Ql(t); ta(e); -}, cu = function(t) { +}, lu = function(t) { const e = gt.find((r) => r.manifest.pluginId === t); e && e.plugin.close(); }; @@ -8570,7 +8580,7 @@ repairIntrinsics({ const Ao = globalThis; Ao.initPluginsRuntime = (t) => { try { - console.log("%c[PLUGINS] Initialize runtime", "color: #008d7c"), su(t), Ao.ɵcontext = t("TEST"), globalThis.ɵloadPlugin = ta, globalThis.ɵloadPluginByUrl = iu, globalThis.ɵunloadPlugin = cu; + console.log("%c[PLUGINS] Initialize runtime", "color: #008d7c"), au(t), Ao.ɵcontext = t("TEST"), globalThis.ɵloadPlugin = ta, globalThis.ɵloadPluginByUrl = cu, globalThis.ɵunloadPlugin = lu; } catch (e) { console.error(e); } diff --git a/frontend/scripts/_helpers.js b/frontend/scripts/_helpers.js index 7602b9c149..ffa74c1889 100644 --- a/frontend/scripts/_helpers.js +++ b/frontend/scripts/_helpers.js @@ -274,6 +274,7 @@ async function readTranslations() { "fa", "fr", "he", + "sr", "nb_NO", "pl", "pt_BR", diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index b916688d07..f634741270 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -444,14 +444,16 @@ (mf/defc object-svg {::mf/wrap [mf/memo]} - [{:keys [objects object-id embed] + [{:keys [objects object-id embed skip-children] :or {embed false} :as props}] (let [object (get objects object-id) object (cond-> object (:hide-fill-on-export object) - (assoc :fills [])) + (assoc :fills []) + skip-children + (assoc :shapes [])) {:keys [width height] :as bounds} (gsb/get-object-bounds objects object {:ignore-margin? false}) vbox (format-viewbox bounds) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index 8e290054f7..3cedef6c88 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -35,6 +35,7 @@ :content (tr "onboarding-v2.newsletter.updates")}])] [:div {:class (stl/css :fields-row :input-visible :newsletter-option-wrapper)} [:& fm/input {:name :accept-newsletter-updates + :class (stl/css :checkbox-newsletter-updates) :type "checkbox" :default-checked false :label updates-label}]])) @@ -53,6 +54,7 @@ [:div {:class (stl/css :fields-row :input-visible :accept-terms-and-privacy-wrapper)} [:& fm/input {:name :accept-terms-and-privacy + :show-error false :class (stl/css :checkbox-terms-and-privacy) :type "checkbox" :default-checked false diff --git a/frontend/src/app/main/ui/auth/register.scss b/frontend/src/app/main/ui/auth/register.scss index 0309cd44ac..f4fd493a1b 100644 --- a/frontend/src/app/main/ui/auth/register.scss +++ b/frontend/src/app/main/ui/auth/register.scss @@ -14,9 +14,11 @@ } } -.checkbox-terms-and-privacy { +.checkbox-terms-and-privacy, +.checkbox-newsletter-updates { align-items: flex-start; } + .register-form { gap: $s-24; } diff --git a/frontend/src/app/main/ui/components/code_block.scss b/frontend/src/app/main/ui/components/code_block.scss index 7b44c702ae..5f28cd4624 100644 --- a/frontend/src/app/main/ui/components/code_block.scss +++ b/frontend/src/app/main/ui/components/code_block.scss @@ -4,9 +4,11 @@ // // Copyright (c) KALEIDOS INC +@use "../ds/typography.scss" as t; @import "refactor/common-refactor.scss"; .code-display { + @include t.use-typography("code-font"); user-select: text; border-radius: $br-8; margin-top: $s-8; diff --git a/frontend/src/app/main/ui/dashboard/import.cljs b/frontend/src/app/main/ui/dashboard/import.cljs index afe962f7d2..30f94ffb9f 100644 --- a/frontend/src/app/main/ui/dashboard/import.cljs +++ b/frontend/src/app/main/ui/dashboard/import.cljs @@ -170,6 +170,9 @@ (rx/filter some?) (rx/subs! (fn [message] + (when (some? (:error message)) + (st/emit! (ptk/data-event ::ev/event {::ev/name "import-files-error" + :error (:error message)}))) (swap! state update-with-analyze-result message)))))) (defn- import-files @@ -467,6 +470,7 @@ (when (and (= :analyze status) errors?) [:& context-notification {:level :warning + :class (stl/css :context-notification-error) :content (tr "dashboard.import.import-warning")}]) (when (= :import-success status) @@ -480,12 +484,12 @@ :class (stl/css :context-notification-error) :content (tr "dashboard.import.import-error.disclaimer")}]) - (if (= :import-error status) + (if (or (= :import-error status) (and (= :analyze status) errors?)) [:div {:class (stl/css :import-error-disclaimer)} [:div (tr "dashboard.import.import-error.message1")] [:ul {:class (stl/css :import-error-list)} (for [entry entries] - (when (= :import-error (:status entry)) + (when (contains? #{:import-error :analyze-error} (:status entry)) [:li {:class (stl/css :import-error-list-enry)} (:name entry)]))] [:div (tr "dashboard.import.import-error.message2")]] diff --git a/frontend/src/app/main/ui/ds/buttons/button.cljs b/frontend/src/app/main/ui/ds/buttons/button.cljs index 37adcd41da..376d063fc7 100644 --- a/frontend/src/app/main/ui/ds/buttons/button.cljs +++ b/frontend/src/app/main/ui/ds/buttons/button.cljs @@ -36,4 +36,4 @@ (on-ref node)))})] [:> "button" props (when icon [:> icon* {:icon-id icon :size "m"}]) - [:span {:class (stl/css :label-wrapper)} children]])) \ No newline at end of file + [:span {:class (stl/css :label-wrapper)} children]])) diff --git a/frontend/src/app/main/ui/ds/buttons/icon_button.cljs b/frontend/src/app/main/ui/ds/buttons/icon_button.cljs index 33ee369523..1d2995ea8e 100644 --- a/frontend/src/app/main/ui/ds/buttons/icon_button.cljs +++ b/frontend/src/app/main/ui/ds/buttons/icon_button.cljs @@ -6,11 +6,11 @@ (ns app.main.ui.ds.buttons.icon-button (:require-macros - [app.common.data.macros :as dm] [app.main.style :as stl]) (:require + [app.common.data :as d] [app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]] - [app.main.ui.ds.tooltip.tooltip :refer [tooltip*]] + [app.main.ui.ds.tooltip :refer [tooltip*]] [rumext.v2 :as mf])) (def ^:private schema:icon-button @@ -24,18 +24,30 @@ [:maybe [:enum "primary" "secondary" "ghost" "destructive" "action"]]]]) (mf/defc icon-button* - {::mf/schema schema:icon-button} + {::mf/schema schema:icon-button + ::mf/memo true} [{:keys [class icon icon-class variant aria-label children] :rest props}] - (let [variant (or variant "primary") - tooltip-id (mf/use-id) - class (dm/str class " " (stl/css-case :icon-button true - :icon-button-primary (= variant "primary") - :icon-button-secondary (= variant "secondary") - :icon-button-ghost (= variant "ghost") - :icon-button-action (= variant "action") - :icon-button-destructive (= variant "destructive"))) - props (mf/spread-props props {:class class - :aria-labelledby tooltip-id})] - [:> tooltip* {:tooltip-content aria-label + (let [variant + (d/nilv variant "primary") + + tooltip-id + (mf/use-id) + + button-class + (stl/css-case :icon-button true + :icon-button-primary (identical? variant "primary") + :icon-button-secondary (identical? variant "secondary") + :icon-button-ghost (identical? variant "ghost") + :icon-button-action (identical? variant "action") + :icon-button-destructive (identical? variant "destructive")) + + props + (mf/spread-props props + {:class [class button-class] + :aria-labelledby tooltip-id})] + + [:> tooltip* {:content aria-label :id tooltip-id} - [:> "button" props [:> icon* {:icon-id icon :aria-hidden true :class icon-class}] children]])) \ No newline at end of file + [:> :button props + [:> icon* {:icon-id icon :aria-hidden true :class icon-class}] + children]])) diff --git a/frontend/src/app/main/ui/ds/tooltip.cljs b/frontend/src/app/main/ui/ds/tooltip.cljs new file mode 100644 index 0000000000..2cd68ec5d6 --- /dev/null +++ b/frontend/src/app/main/ui/ds/tooltip.cljs @@ -0,0 +1,12 @@ +;; 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.main.ui.ds.tooltip + (:require + [app.common.data.macros :as dm] + [app.main.ui.ds.tooltip.tooltip :as impl])) + +(dm/export impl/tooltip*) diff --git a/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs b/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs index c69c2609e5..92d3b7901e 100644 --- a/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs +++ b/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs @@ -15,21 +15,49 @@ [app.util.timers :as ts] [rumext.v2 :as mf])) -(defn- calculate-tooltip-rect [tooltip trigger-rect placement offset] +(def ^:private ^:const arrow-height 12) +(def ^:private ^:const half-arrow-height (/ arrow-height 2)) +(def ^:private ^:const overlay-offset 32) + +(defn- clear-schedule + [ref] + (when-let [schedule (mf/ref-val ref)] + (ts/dispose! schedule) + (mf/set-ref-val! ref nil))) + +(defn- add-schedule + [ref delay f] + (mf/set-ref-val! ref (ts/schedule delay f))) + +(defn- show-popover + [node] + (when (.-isConnected ^js node) + (.showPopover ^js node))) + +(defn- hide-popover + [node] + (dom/unset-css-property! node "block-size") + (dom/unset-css-property! node "display") + (.hidePopover ^js node)) + +(defn- calculate-placement-bounding-rect + "Given a placement, calcultates the bounding rect for it taking in + account provided tooltip bounding rect and the origin bounding + rect." + [placement tooltip-brect origin-brect offset] (let [{trigger-top :top trigger-left :left trigger-right :right trigger-bottom :bottom trigger-width :width - trigger-height :height} trigger-rect + trigger-height :height} + origin-brect {tooltip-width :width - tooltip-height :height} (dom/get-bounding-rect tooltip) + tooltip-height :height} + tooltip-brect - offset (d/nilv offset 2) - arrow-height 12 - half-arrow-height (/ arrow-height 2) - overlay-offset 32] + offset (d/nilv offset 2)] (case placement "bottom" @@ -95,7 +123,10 @@ :width tooltip-width :height tooltip-height}))) -(defn- get-fallback-order [placement] +(defn- get-fallback-order + "Get a vector of placement followed with ordered fallback pacements + for the specified placement" + [placement] (case placement "top" ["top" "right" "bottom" "left" "top-right" "bottom-right" "bottom-left" "top-left"] "bottom" ["bottom" "left" "top" "right" "bottom-right" "bottom-left" "top-left" "top-right"] @@ -106,65 +137,93 @@ "bottom-left" ["bottom-left" "left" "top" "right" "bottom" "top-left" "top-right" "bottom-right"] "top-left" ["top-left" "top" "right" "bottom" "left" "bottom-left" "top-right" "bottom-right"])) +(defn- find-matching-placement + "Algorithm for find a correct placement and placement-brect for the + provided placement, if the current placement does not matches, it + uses the predefined fallbacks. Returns an array of matched placement + and its bounding rect." + [placement tooltip-brect origin-brect window-size offset] + (loop [placements (seq (get-fallback-order placement))] + (when-let [placement (first placements)] + (let [placement-brect (calculate-placement-bounding-rect placement tooltip-brect origin-brect offset)] + (if (dom/is-bounding-rect-outside? placement-brect window-size) + (recur (rest placements)) + #js [placement placement-brect]))))) + +(defn- update-tooltip-position + "Update the tooltip position having in account the current window + size, placement. It calculates the appropriate placement and updates + the dom with the result." + [tooltip placement origin-brect offset] + (show-popover tooltip) + (let [tooltip-brect (dom/get-bounding-rect tooltip) + window-size (dom/get-window-size)] + (when-let [[placement placement-rect] (find-matching-placement placement tooltip-brect origin-brect window-size offset)] + + (let [height (if (or (= placement "right") (= placement "left")) + (- (:height placement-rect) arrow-height) + (:height placement-rect))] + (dom/set-css-property! tooltip "display" "grid") + (dom/set-css-property! tooltip "block-size" (dm/str height "px")) + (dom/set-css-property! tooltip "inset-block-start" (dm/str (:top placement-rect) "px")) + (dom/set-css-property! tooltip "inset-inline-start" (dm/str (:left placement-rect) "px"))) + placement))) + (def ^:private schema:tooltip [:map [:class {:optional true} :string] [:id {:optional true} :string] [:offset {:optional true} :int] [:delay {:optional true} :int] + [:content [:or fn? :string [:fn mf/element?]]] [:placement {:optional true} [:maybe [:enum "top" "bottom" "left" "right" "top-right" "bottom-right" "bottom-left" "top-left"]]]]) (mf/defc tooltip* {::mf/schema schema:tooltip} - [{:keys [class id children tooltip-content placement offset delay] :rest props}] - (let [id (or id (mf/use-id)) - placement* (mf/use-state #(d/nilv placement "top")) - placement (deref placement*) - delay (d/nilv delay 300) + [{:keys [class id children content placement offset delay] :rest props}] + (let [internal-id + (mf/use-id) - schedule-ref (mf/use-ref nil) + id + (d/nilv id internal-id) - position-tooltip - (fn [^js tooltip trigger-rect] - (let [all-placements (get-fallback-order placement)] - (when (.-isConnected tooltip) - (.showPopover ^js tooltip)) - (loop [[current-placement & remaining-placements] all-placements] - (when current-placement - (reset! placement* current-placement) - (let [tooltip-rect (calculate-tooltip-rect tooltip trigger-rect current-placement offset)] - (if (dom/is-bounding-rect-outside? tooltip-rect) - (recur remaining-placements) - (do (dom/set-css-property! tooltip "display" "grid") - (dom/set-css-property! tooltip "inset-block-start" (dm/str (:top tooltip-rect) "px")) - (dom/set-css-property! tooltip "inset-inline-start" (dm/str (:left tooltip-rect) "px"))))))))) + placement* + (mf/use-state #(d/nilv placement "top")) + + placement + (deref placement*) + + delay + (d/nilv delay 300) + + schedule-ref + (mf/use-ref nil) on-show (mf/use-fn - (mf/deps id placement) + (mf/deps id placement offset) (fn [event] - (when-let [schedule (mf/ref-val schedule-ref)] - (ts/dispose! schedule) - (mf/set-ref-val! schedule-ref nil)) + (clear-schedule schedule-ref) (when-let [tooltip (dom/get-element id)] - (let [trigger-rect (->> (dom/get-target event) - (dom/get-bounding-rect))] - (mf/set-ref-val! - schedule-ref - (ts/schedule - delay - #(position-tooltip tooltip trigger-rect))))))) + (let [origin-brect + (->> (dom/get-target event) + (dom/get-bounding-rect)) + + update-position + (fn [] + (let [placement (update-tooltip-position tooltip placement origin-brect offset)] + (reset! placement* placement)))] + + (add-schedule schedule-ref delay update-position))))) on-hide (mf/use-fn (mf/deps id) - (fn [] (when-let [tooltip (dom/get-element id)] - (when-let [schedule (mf/ref-val schedule-ref)] - (ts/dispose! schedule) - (mf/set-ref-val! schedule-ref nil)) - (dom/unset-css-property! tooltip "display") - (.hidePopover ^js tooltip)))) + (fn [] + (when-let [tooltip (dom/get-element id)] + (clear-schedule schedule-ref) + (hide-popover tooltip)))) handle-key-down (mf/use-fn @@ -173,33 +232,38 @@ (when (kbd/esc? event) (on-hide)))) - class (d/append-class class (stl/css-case - :tooltip true - :tooltip-top (= placement "top") - :tooltip-bottom (= placement "bottom") - :tooltip-left (= placement "left") - :tooltip-right (= placement "right") - :tooltip-top-right (= placement "top-right") - :tooltip-bottom-right (= placement "bottom-right") - :tooltip-bottom-left (= placement "bottom-left") - :tooltip-top-left (= placement "top-left"))) + tooltip-class + (stl/css-case + :tooltip true + :tooltip-top (identical? placement "top") + :tooltip-bottom (identical? placement "bottom") + :tooltip-left (identical? placement "left") + :tooltip-right (identical? placement "right") + :tooltip-top-right (identical? placement "top-right") + :tooltip-bottom-right (identical? placement "bottom-right") + :tooltip-bottom-left (identical? placement "bottom-left") + :tooltip-top-left (identical? placement "top-left")) + + props + (mf/spread-props props + {:on-mouse-enter on-show + :on-mouse-leave on-hide + :on-focus on-show + :on-blur on-hide + :on-key-down handle-key-down + :class (stl/css :tooltip-trigger) + :aria-describedby id}) + content + (if (fn? content) + (content) + content)] - props (mf/spread-props props {:on-mouse-enter on-show - :on-mouse-leave on-hide - :on-focus on-show - :on-blur on-hide - :on-key-down handle-key-down - :class (stl/css :tooltip-trigger) - :aria-describedby id})] [:> :div props children - [:div {:class class + [:div {:class [class tooltip-class] :id id :popover "auto" :role "tooltip"} - [:div {:class (stl/css :tooltip-content)} - (if (fn? tooltip-content) - (tooltip-content) - tooltip-content)] + [:div {:class (stl/css :tooltip-content)} content] [:div {:class (stl/css :tooltip-arrow) - :id "tooltip-arrow"}]]])) \ No newline at end of file + :id "tooltip-arrow"}]]])) diff --git a/frontend/src/app/main/ui/ds/tooltip/tooltip.mdx b/frontend/src/app/main/ui/ds/tooltip/tooltip.mdx index 1dfb2945f0..dfae36dba7 100644 --- a/frontend/src/app/main/ui/ds/tooltip/tooltip.mdx +++ b/frontend/src/app/main/ui/ds/tooltip/tooltip.mdx @@ -32,7 +32,7 @@ If `placement` is not provided, the tooltip will default to "top". [:> tlp/tooltip* {:id "test-tooltip" :placement "bottom" - :tooltip-content "Tooltip content"} + :content "Tooltip content"} [:div "Trigger component"]]) ``` @@ -44,8 +44,7 @@ Tooltip content can include HTML elements: [:> tlp/tooltip* {:id "test-tooltip" :placement "bottom" - :tooltip-content (mf/html - [:span "Tooltip content"])} + :content (mf/html [:span "Tooltip content"])} [:div "Trigger component"]]) ``` diff --git a/frontend/src/app/main/ui/ds/tooltip/tooltip.scss b/frontend/src/app/main/ui/ds/tooltip/tooltip.scss index cb2ce09c2b..ae97c8b17b 100644 --- a/frontend/src/app/main/ui/ds/tooltip/tooltip.scss +++ b/frontend/src/app/main/ui/ds/tooltip/tooltip.scss @@ -16,6 +16,7 @@ $arrow-side: 12px; background-color: transparent; overflow: hidden; inline-size: fit-content; + block-size: fit-content; } .tooltip-arrow { @@ -145,6 +146,7 @@ $arrow-side: 12px; border: $b-1 solid var(--color-accent-primary-muted); padding: var(--sp-s) var(--sp-m); grid-area: content; + block-size: fit-content; } .tooltip-trigger { diff --git a/frontend/src/app/main/ui/ds/tooltip/tooltip.stories.jsx b/frontend/src/app/main/ui/ds/tooltip/tooltip.stories.jsx index 985ad19895..0f2398edc0 100644 --- a/frontend/src/app/main/ui/ds/tooltip/tooltip.stories.jsx +++ b/frontend/src/app/main/ui/ds/tooltip/tooltip.stories.jsx @@ -37,10 +37,10 @@ export default { }, args: { children: ( - + ), id: "popover-example", - tooltipContent: "This is the tooltip content", + content: "This is the tooltip content", delay: 300, }, render: ({ children, ...args }) => ( @@ -74,18 +74,18 @@ export const Corners = { > - + + - + - + - + - + - + - + ), diff --git a/frontend/src/app/main/ui/exports/assets.cljs b/frontend/src/app/main/ui/exports/assets.cljs index 633bceed7d..4544fc171a 100644 --- a/frontend/src/app/main/ui/exports/assets.cljs +++ b/frontend/src/app/main/ui/exports/assets.cljs @@ -21,6 +21,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr c]] [app.util.strings :as ust] + [app.util.theme :as theme] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -208,8 +209,8 @@ [] (let [state (mf/deref refs/export) profile (mf/deref refs/profile) - theme (or (:theme profile) "default") - is-default-theme? (= "default" theme) + theme (or (:theme profile) theme/default) + is-default-theme? (= theme/default theme) error? (:error state) healthy? (:healthy? state) detail-visible? (:detail-visible state) diff --git a/frontend/src/app/main/ui/workspace/plugins.cljs b/frontend/src/app/main/ui/workspace/plugins.cljs index 8179af0cef..8ea1e76496 100644 --- a/frontend/src/app/main/ui/workspace/plugins.cljs +++ b/frontend/src/app/main/ui/workspace/plugins.cljs @@ -275,7 +275,14 @@ [:div {:class (stl/css :permissions-list-entry)} i/oauth-1 [:p {:class (stl/css :permissions-list-text)} - (tr "workspace.plugins.permissions.allow-download")]])]) + (tr "workspace.plugins.permissions.allow-download")]]) + + (cond + (contains? permissions "allow:localstorage") + [:div {:class (stl/css :permissions-list-entry)} + i/oauth-1 + [:p {:class (stl/css :permissions-list-text)} + (tr "workspace.plugins.permissions.allow-localstorage")]])]) (mf/defc plugins-permissions-dialog {::mf/register modal/components diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/export.cljs b/frontend/src/app/main/ui/workspace/tokens/modals/export.cljs index f925ea6a95..8c2377689d 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/export.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/modals/export.cljs @@ -9,8 +9,10 @@ (:require [app.common.json :as json] [app.common.types.tokens-lib :as ctob] + [app.main.data.event :as ev] [app.main.data.modal :as modal] [app.main.refs :as refs] + [app.main.store :as st] [app.main.ui.components.code-block :refer [code-block]] [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] @@ -22,6 +24,7 @@ [app.util.i18n :refer [tr]] [app.util.webapi :as wapi] [app.util.zip :as zip] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc export-tab* @@ -59,6 +62,7 @@ (mf/deps tokens-json) (fn [] (when tokens-json + (st/emit! (ptk/data-event ::ev/event {::ev/name "export-tokens" :type "single"})) (->> (wapi/create-blob (or tokens-json "{}") "application/json") (dom/trigger-download "tokens.json")))))] [:> export-tab* {:is-disabled is-disabled @@ -85,6 +89,7 @@ (mf/use-fn (mf/deps files) (fn [] + (st/emit! (ptk/data-event ::ev/event {::ev/name "export-tokens" :type "multiple"})) (download-tokens-zip! files)))] [:> export-tab* {:on-export on-export :is-disabled is-disabled} diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/export.scss b/frontend/src/app/main/ui/workspace/tokens/modals/export.scss index f38db8616a..922e8c403d 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/export.scss +++ b/frontend/src/app/main/ui/workspace/tokens/modals/export.scss @@ -38,6 +38,7 @@ flex-direction: column; gap: var(--sp-m); padding-top: var(--sp-m); + max-width: calc(var(--modal-width) - var(--modal-padding) * 2); } .preview-label { @@ -79,8 +80,10 @@ flex-grow: 1; overflow: hidden; text-overflow: ellipsis; + padding: var(--sp-xs); + overflow: hidden; + text-overflow: ellipsis; white-space: nowrap; - padding: var(--sp-s); } .export-actions { @@ -108,7 +111,6 @@ overflow-x: auto; word-wrap: normal; white-space: pre; - max-width: calc(var(--modal-width) - var(--modal-padding) * 2); } .disabled-message { diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 223e5e2279..92022e2172 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -10,7 +10,6 @@ [app.common.data :as d] [app.common.types.tokens-lib :as ctob] [app.config :as cf] - [app.main.data.event :as ev] [app.main.data.modal :as modal] [app.main.data.style-dictionary :as sd] [app.main.data.workspace.tokens.application :as dwta] @@ -37,7 +36,6 @@ [app.util.dom :as dom] [app.util.i18n :refer [tr]] [okulary.core :as l] - [potok.v2.core :as ptk] [rumext.v2 :as mf] [shadow.resource])) @@ -384,7 +382,6 @@ on-export (mf/use-fn (fn [] - (st/emit! (ptk/data-event ::ev/event {::ev/name "export-tokens"})) (modal/show! :tokens/export {}))) on-modal-show diff --git a/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs b/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs index bf6120ec52..f18e442c12 100644 --- a/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs @@ -47,29 +47,32 @@ :class (stl/css-case :check-icon true :check-icon-visible selected?)}]])])) +(defn- open-tokens-theme-modal + [] + (modal/show! :tokens/themes {})) + (mf/defc theme-options [{:keys [active-theme-paths themes on-close]}] - (let [on-edit-click #(modal/show! :tokens/themes {})] - [:ul {:class (stl/css :theme-options :custom-select-dropdown) - :role "listbox"} - (for [[group themes] themes] - [:li {:key group - :aria-labelledby (dm/str group "-label") - :role "group"} - (when (seq group) - [:> text* {:as "span" :typography "headline-small" :class (stl/css :group) :id (dm/str (str/kebab group) "-label") :title group} group]) - [:& themes-list {:themes themes - :active-theme-paths active-theme-paths - :on-close on-close - :grouped? true}]]) - [:li {:class (stl/css :separator) - :aria-hidden true}] - [:li {:class (stl/css-case :checked-element true - :checked-element-button true) - :role "option" - :on-click on-edit-click} - [:> text* {:as "span" :typography "body-small"} (tr "workspace.tokens.edit-themes")] - [:> icon* {:icon-id i/arrow-right :aria-hidden true}]]])) + [:ul {:class (stl/css :theme-options :custom-select-dropdown) + :role "listbox"} + (for [[group themes] themes] + [:li {:key group + :aria-labelledby (dm/str group "-label") + :role "group"} + (when (seq group) + [:> text* {:as "span" :typography "headline-small" :class (stl/css :group) :id (dm/str (str/kebab group) "-label") :title group} group]) + [:& themes-list {:themes themes + :active-theme-paths active-theme-paths + :on-close on-close + :grouped? true}]]) + [:li {:class (stl/css :separator) + :aria-hidden true}] + [:li {:class (stl/css-case :checked-element true + :checked-element-button true) + :role "option" + :on-click open-tokens-theme-modal} + [:> text* {:as "span" :typography "body-small"} (tr "workspace.tokens.edit-themes")] + [:> icon* {:icon-id i/arrow-right :aria-hidden true}]]]) (mf/defc theme-select [{:keys []}] diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index 5845994aff..8c6c80bc90 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -25,14 +25,17 @@ [app.main.data.workspace.groups :as dwg] [app.main.data.workspace.media :as dwm] [app.main.data.workspace.selection :as dws] + [app.main.fonts :refer [fetch-font-css]] [app.main.router :as rt] [app.main.store :as st] + [app.main.ui.shapes.text.fontfaces :refer [shapes->fonts]] [app.plugins.events :as events] [app.plugins.file :as file] [app.plugins.fonts :as fonts] [app.plugins.format :as format] [app.plugins.history :as history] [app.plugins.library :as library] + [app.plugins.local-storage :as local-storage] [app.plugins.page :as page] [app.plugins.parser :as parser] [app.plugins.shape :as shape] @@ -41,7 +44,8 @@ [app.plugins.viewport :as viewport] [app.util.code-gen :as cg] [app.util.object :as obj] - [beicon.v2.core :as rx])) + [beicon.v2.core :as rx] + [cuerdas.core :as str])) ;; ;; PLUGINS PUBLIC API - The plugins will able to access this functions @@ -85,6 +89,11 @@ {:this true :get #(.getTheme ^js %)} + :localStorage + {:this true + :get + (fn [_] (local-storage/local-storage-proxy plugin-id))} + :selection {:this true :get #(.getSelectedShapes ^js %) @@ -428,6 +437,24 @@ (cg/generate-style-code objects type shapes shapes-with-children {:with-prelude? prelude?}))))) + :generateFontFaces + (fn [shapes] + (js/Promise. + (fn [resolve reject] + (let [objects (u/locate-objects) + all-children + (->> shapes + (map #(obj/get % "$id")) + (cfh/selected-with-children objects) + (map (d/getf objects))) + fonts (shapes->fonts all-children)] + (->> (rx/from fonts) + (rx/merge-map fetch-font-css) + (rx/reduce conj []) + (rx/map #(str/join "\n" %)) + (rx/first) + (rx/subs! #(resolve %) reject)))))) + :openViewer (fn [] (let [params {:page-id (:current-page-id @st/state) diff --git a/frontend/src/app/plugins/local_storage.cljs b/frontend/src/app/plugins/local_storage.cljs new file mode 100644 index 0000000000..cac6529be1 --- /dev/null +++ b/frontend/src/app/plugins/local_storage.cljs @@ -0,0 +1,71 @@ +;; 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.local-storage + (:require + [app.common.data.macros :as dm] + [app.common.exceptions :as ex] + [app.plugins.register :as r] + [app.plugins.utils :as u] + [app.util.globals :as g] + [app.util.object :as obj] + [cuerdas.core :as str])) + +(defonce ^:private local-storage + (ex/ignoring (unchecked-get g/global "localStorage"))) + +(defn prefix-key + [plugin-id key] + (dm/str "penpot-plugins:" plugin-id "/" key)) + +(defn local-storage-proxy + [plugin-id] + (obj/reify {:name "LocalStorageProxy"} + :$plugin {:enumerable false :get (fn [] plugin-id)} + + :getItem + (fn [key] + (cond + (not (r/check-permission plugin-id "allow:localstorage")) + (u/display-not-valid :getItem "Plugin doesn't have 'allow:localstorage' permission") + + (not (string? key)) + (u/display-not-valid :getItem "The key must be a string") + + :else + (.getItem ^js local-storage (prefix-key plugin-id key)))) + + :setItem + (fn [key value] + (cond + (not (r/check-permission plugin-id "allow:localstorage")) + (u/display-not-valid :setItem "Plugin doesn't have 'allow:localstorage' permission") + + (not (string? key)) + (u/display-not-valid :setItem "The key must be a string") + + :else + (.setItem ^js local-storage (prefix-key plugin-id key) value))) + + :removeItem + (fn [key] + (cond + (not (r/check-permission plugin-id "allow:localstorage")) + (u/display-not-valid :removeItem "Plugin doesn't have 'allow:localstorage' permission") + + (not (string? key)) + (u/display-not-valid :removeItem "The key must be a string") + + :else + (.getItem ^js local-storage (prefix-key plugin-id key)))) + + :getKeys + (fn [] + (->> (.keys js/Object local-storage) + (filter #(str/starts-with? % (prefix-key plugin-id ""))) + (map #(str/replace % (prefix-key plugin-id "") "")) + (apply array))))) + diff --git a/frontend/src/app/plugins/parser.cljs b/frontend/src/app/plugins/parser.cljs index caaa697f74..0033246e49 100644 --- a/frontend/src/app/plugins/parser.cljs +++ b/frontend/src/app/plugins/parser.cljs @@ -253,7 +253,8 @@ (d/without-nils {:type (-> (obj/get export "type") parse-keyword) :scale (obj/get export "scale" 1) - :suffix (obj/get export "suffix" "")}))) + :suffix (obj/get export "suffix" "") + :skip-children (obj/get export "skipChildren" false)}))) (defn parse-exports [^js exports] diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index c1dc10c8f7..2af5681994 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -1138,6 +1138,7 @@ {:cmd :export-shapes :profile-id (:profile-id @st/state) :wait true + :skip-children (:skip-children value false) :exports [{:file-id file-id :page-id page-id :object-id id @@ -1230,6 +1231,39 @@ (cond-> (cfh/frame-shape? data) (-> (crc/add-properties! + {:name "clipContent" + :get + (fn [self] + (-> self u/proxy->shape :show-content not)) + + :set + (fn [_ value] + (cond + (not (boolean? value)) + (u/display-not-valid :clipContent value) + + (not (r/check-permission plugin-id "content:write")) + (u/display-not-valid :clipContent "Plugin doesn't have 'content:write' permission") + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :show-content (not value))))))} + + {:name "showInViewMode" + :get + (fn [self] + (-> self u/proxy->shape :hide-in-viewer not)) + :set + (fn [_ value] + (cond + (not (boolean? value)) + (u/display-not-valid :showInViewMode value) + + (not (r/check-permission plugin-id "content:write")) + (u/display-not-valid :showInViewMode "Plugin doesn't have 'content:write' permission") + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :hide-in-viewer (not value))))))} + {:name "grid" :get (fn [self] diff --git a/frontend/src/app/render.cljs b/frontend/src/app/render.cljs index 90d7f1a0a4..56509025eb 100644 --- a/frontend/src/app/render.cljs +++ b/frontend/src/app/render.cljs @@ -62,7 +62,7 @@ (mf/defc object-svg {::mf/wrap-props false} - [{:keys [object-id embed]}] + [{:keys [object-id embed skip-children]}] (let [objects (mf/deref ref:objects)] ;; Set the globa CSS to assign the page size, needed for PDF @@ -79,11 +79,12 @@ [:& render/object-svg {:objects objects :object-id object-id - :embed embed}]))) + :embed embed + :skip-children skip-children}]))) (mf/defc objects-svg {::mf/wrap-props false} - [{:keys [object-ids embed]}] + [{:keys [object-ids embed skip-children]}] (when-let [objects (mf/deref ref:objects)] (for [object-id object-ids] (let [objects (render/adapt-objects-for-shape objects object-id)] @@ -91,7 +92,8 @@ {:objects objects :key (str object-id) :object-id object-id - :embed embed}])))) + :embed embed + :skip-children skip-children}])))) (defn- fetch-objects-bundle [& {:keys [file-id page-id share-id object-id] :as options}] @@ -121,6 +123,7 @@ [:file-id ::sm/uuid] [:share-id {:optional true} ::sm/uuid] [:embed {:optional true} :boolean] + [:skip-children {:optional true} :boolean] [:object-id [:or ::sm/uuid @@ -135,7 +138,7 @@ (defn- render-objects [params] - (let [{:keys [file-id page-id embed share-id object-id] :as params} (render-objects-decoder params)] + (let [{:keys [file-id page-id embed share-id object-id skip-children] :as params} (render-objects-decoder params)] (if-not (render-objects-validator params) (do (js/console.error "invalid arguments") @@ -152,7 +155,8 @@ :page-id page-id :share-id share-id :object-id object-id - :embed embed}]) + :embed embed + :skip-children skip-children}]) (mf/html [:& objects-svg @@ -160,7 +164,8 @@ :page-id page-id :share-id share-id :object-ids (into #{} object-id) - :embed embed}])))))) + :embed embed + :skip-children skip-children}])))))) ;; ---- COMPONENTS SPRITE diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index b629631de1..c674698a83 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -421,17 +421,16 @@ :height (.-height ^js rect)})) (defn is-bounding-rect-outside? - [rect] - (let [{:keys [left top right bottom]} rect - {:keys [width height]} (get-window-size)] - (or (< left 0) - (< top 0) - (> right width) - (> bottom height)))) + [{:keys [left top right bottom]} {:keys [width height]}] + (or (< left 0) + (< top 0) + (> right width) + (> bottom height))) (defn is-element-outside? [element] - (is-bounding-rect-outside? (get-bounding-rect element))) + (is-bounding-rect-outside? (get-bounding-rect element) + (get-window-size))) (defn bounding-rect->rect [rect] diff --git a/frontend/src/app/util/extends.cljs b/frontend/src/app/util/extends.cljs index 4cec0733f3..aff5220d6b 100644 --- a/frontend/src/app/util/extends.cljs +++ b/frontend/src/app/util/extends.cljs @@ -9,6 +9,7 @@ extensions" (:require [promesa.impl :as pi]) - (:import goog.async.Deferred)) + (:import + goog.async.Deferred)) (pi/extend-promise! Deferred) diff --git a/frontend/src/app/util/i18n.cljs b/frontend/src/app/util/i18n.cljs index 06aecacc84..66f262f0e9 100644 --- a/frontend/src/app/util/i18n.cljs +++ b/frontend/src/app/util/i18n.cljs @@ -43,6 +43,7 @@ {:label "Украї́нська мо́ва (community)" :value "uk"} {:label "Český jazyk (community)" :value "cs"} {:label "Latviešu valoda (community)" :value "lv"} + {:label "Српски (community)" :value "sr"} {:label "Føroyskt mál (community)" :value "fo"} {:label "Korean (community)" :value "ko"} {:label "עִבְרִית (community)" :value "he"} diff --git a/frontend/test/frontend_tests/plugins/context_shapes_test.cljs b/frontend/test/frontend_tests/plugins/context_shapes_test.cljs index 590162203f..501a602c75 100644 --- a/frontend/test/frontend_tests/plugins/context_shapes_test.cljs +++ b/frontend/test/frontend_tests/plugins/context_shapes_test.cljs @@ -176,10 +176,10 @@ (t/is (= (-> (. shape -exports) (aget 0) (aget "type")) "pdf")) (t/is (= (-> (. shape -exports) (aget 0) (aget "scale")) 2)) (t/is (= (-> (. shape -exports) (aget 0) (aget "suffix")) "test")) - (t/is (= (get-in @store (get-shape-path :exports)) [{:type :pdf :scale 2 :suffix "test"}])) + (t/is (= (get-in @store (get-shape-path :exports)) [{:type :pdf :scale 2 :suffix "test" :skip-children false}])) (set! (.-exports shape) #js [#js {:type 10 :scale 2 :suffix "test"}]) - (t/is (= (get-in @store (get-shape-path :exports)) [{:type :pdf :scale 2 :suffix "test"}]))) + (t/is (= (get-in @store (get-shape-path :exports)) [{:type :pdf :scale 2 :suffix "test" :skip-children false}]))) (t/testing " - flipX" (set! (.-flipX shape) true) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index c2149468fc..884b530044 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -6670,6 +6670,9 @@ msgstr "" msgid "workspace.plugins.permissions.allow-download" msgstr "Start file downloads." +msgid "workspace.plugins.permissions.allow-localstorage" +msgstr "Store data in the browser." + #: src/app/main/ui/workspace/plugins.cljs:271 msgid "workspace.plugins.permissions.comment-read" msgstr "Read your comments and replies." diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 06a5b77d18..fbe76c8a42 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -6696,6 +6696,9 @@ msgstr "" msgid "workspace.plugins.permissions.allow-download" msgstr "Comenzar descargas de ficheros." +msgid "workspace.plugins.permissions.allow-localstorage" +msgstr "Guardar datos en el navegador." + #: src/app/main/ui/workspace/plugins.cljs:271 msgid "workspace.plugins.permissions.comment-read" msgstr "Leer tus comentarios y respuestas."