diff --git a/.opencode/skills/update-changelog/SKILL.md b/.opencode/skills/update-changelog/SKILL.md index 5752b65aa3..5d89393c91 100644 --- a/.opencode/skills/update-changelog/SKILL.md +++ b/.opencode/skills/update-changelog/SKILL.md @@ -86,13 +86,32 @@ batches of 50 via GraphQL to stay within API limits. ### 5. Categorize entries -Check the labels on each issue to determine which section it belongs to: +Use the **Issue Type** field (GitHub's native issue type, accessible via GraphQL +`issueType { name }`) to determine which section an entry belongs to. +**Do not** use labels or title emoji prefixes as the source of truth — they are +often inaccurate or missing. -| Label / Title prefix | Changelog section | -|----------------------|-------------------| -| `bug` label or `:bug:` title prefix | `### :bug: Bugs fixed` | -| `enhancement` label or `:sparkles:` prefix | `### :sparkles: New features & Enhancements` | -| No label | Infer from title convention, default to bug fix | +| Issue Type (`issueType.name`) | Changelog section | +|------------------------------|-------------------| +| `Bug` | `### :bug: Bugs fixed` | +| `Feature` or `Enhancement` | `### :sparkles: New features & Enhancements` | +| No type set | Fetch the issue and check its labels as a fallback: `bug` label → bugs section, otherwise default to enhancements | + +To fetch Issue Types for all issues in a milestone efficiently, use a single +GraphQL query with aliases rather than N+1 REST calls: + +```graphql +query { + repository(owner: "penpot", name: "penpot") { + i123: issue(number: 123) { + number state milestone { number } issueType { name } + } + i456: issue(number: 456) { + number state milestone { number } issueType { name } + } + } +} +``` **Community contribution attribution:** If the issue or its fix PR has the `community contribution` label, add an attribution `(by @)` @@ -205,6 +224,7 @@ Read the top of `CHANGES.md` and confirm: can find the code changes. - **Latest version first.** New sections are inserted at the top of the changelog, below the `# CHANGELOG` header. +- **Issue Type determines section.** Use GitHub's `issueType` field (Bug → `:bug:`, Feature/Enhancement → `:sparkles:`) to categorize entries. Ignore labels and title emoji prefixes — they are unreliable for categorization. - **User-facing descriptions.** Write from the user's perspective — describe what broke and what was fixed, not internal implementation details. - **Community attribution.** When the issue or fix PR has the diff --git a/CHANGES.md b/CHANGES.md index 05346225e9..8352b7b363 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -32,6 +32,8 @@ ### :boom: Breaking changes & Deprecations ### :rocket: Epics and highlights +- WebGL rendering (beta) user preference [#9683](https://github.com/penpot/penpot/issues/9683) (PR:[9113](https://github.com/penpot/penpot/pull/9113)) +- Design Tokens at the design tab: numeric fields with token selection in place [#9358](https://github.com/penpot/penpot/issues/9358) ### :sparkles: New features & Enhancements @@ -49,11 +51,8 @@ - Rename token group [#9637](https://github.com/penpot/penpot/issues/9637) (PR: [#8275](https://github.com/penpot/penpot/pull/8275)) - Duplicate token group [#9638](https://github.com/penpot/penpot/issues/9638) (PR: [#8886](https://github.com/penpot/penpot/pull/8886)) - Copy token name from contextual menu [#9639](https://github.com/penpot/penpot/issues/9639) (PR: [#8566](https://github.com/penpot/penpot/pull/8566)) -- Add natural sorting on token names [#8635](https://github.com/penpot/penpot/issues/8635) (PR: [#8672](https://github.com/penpot/penpot/pull/8672)) - Add drag-to-change for numeric inputs in workspace sidebar (by @RenzoMXD) [#2466](https://github.com/penpot/penpot/issues/2466) (PR: [#8536](https://github.com/penpot/penpot/pull/8536)) - Add CSS linter [#9636](https://github.com/penpot/penpot/issues/9636) (PR: [#8592](https://github.com/penpot/penpot/pull/8592)) -- Save and restore selection state in undo/redo (by @eureka0928) [#6007](https://github.com/penpot/penpot/issues/6007) (PR: [#8652](https://github.com/penpot/penpot/pull/8652)) -- Fix warnings for unsupported token $type (by @Dexterity104) [#8790](https://github.com/penpot/penpot/issues/8790) (PR: [#8873](https://github.com/penpot/penpot/pull/8873)) - Add per-group add button for typographies (by @eureka0928) [#5275](https://github.com/penpot/penpot/issues/5275) (PR: [#8895](https://github.com/penpot/penpot/pull/8895)) - Add Find & Replace for text content and layer names (by @statxc) [#7108](https://github.com/penpot/penpot/issues/7108) (PR: [#8899](https://github.com/penpot/penpot/pull/8899)) - Use page name for multi-export ZIP/PDF downloads (by @Dexterity104) [#8773](https://github.com/penpot/penpot/issues/8773) (PR: [#8874](https://github.com/penpot/penpot/pull/8874)) @@ -62,8 +61,6 @@ - Sort asset library subfolders alphabetically at every nesting level (by @eureka0928) [#2572](https://github.com/penpot/penpot/issues/2572) (PR: [#8952](https://github.com/penpot/penpot/pull/8952)) - Add Paste to replace (Cmd+Shift+V) for selected shapes (by @eureka0928) [#4240](https://github.com/penpot/penpot/issues/4240) (PR: [#9033](https://github.com/penpot/penpot/pull/9033)) - Differentiate incoming and outgoing interaction link colors (by @claytonlin1110) [#7794](https://github.com/penpot/penpot/issues/7794) (PR: [#8923](https://github.com/penpot/penpot/pull/8923)) -- Add guide locking and fix locked element selection in viewer (by @Dexterity104) [#8358](https://github.com/penpot/penpot/issues/8358) (PR: [#8949](https://github.com/penpot/penpot/pull/8949)) -- Apply styles to selection (by @AzazelN28) [#9661](https://github.com/penpot/penpot/issues/9661) (PR: [#8625](https://github.com/penpot/penpot/pull/8625)) - Reorder prototyping overlay options to show Position before Relative to (by @rockchris099) [#2910](https://github.com/penpot/penpot/issues/2910) - Add customizable colors for ruler guides (by @Dexterity104) [#5199](https://github.com/penpot/penpot/issues/5199) (PR: [#8986](https://github.com/penpot/penpot/pull/8986)) - Persist asset search and section filter across sidebar tabs (by @eureka0928) [#2913](https://github.com/penpot/penpot/issues/2913) (PR: [#8985](https://github.com/penpot/penpot/pull/8985)) @@ -74,7 +71,6 @@ - Allow customising the OIDC login button label (by @wdeveloper16) [#7027](https://github.com/penpot/penpot/issues/7027) (PR: [#9026](https://github.com/penpot/penpot/pull/9026)) - Add page separators in Workspace [#9180](https://github.com/penpot/penpot/issues/9180) (PR: [#8561](https://github.com/penpot/penpot/pull/8561)) - Preserve vector content when pasting SVG from external tools (by @RenzoMXD) [#546](https://github.com/penpot/penpot/issues/546) (PR: [#9182](https://github.com/penpot/penpot/pull/9182)) -- Add Shift+Numpad aliases for zoom shortcuts (by @RenzoMXD) [#2457](https://github.com/penpot/penpot/issues/2457) (PR: [#9063](https://github.com/penpot/penpot/pull/9063)) - Add pixel grid color picker in viewport settings (by @jack-stormentswe) [#7750](https://github.com/penpot/penpot/issues/7750) (PR: [#9155](https://github.com/penpot/penpot/pull/9155)) - Add HEX/HSB/HSL support to color picker with persistent model switcher (by @edwin-rivera-dev) [#9133](https://github.com/penpot/penpot/issues/9133) (PR: [#9134](https://github.com/penpot/penpot/pull/9134)) - Show specific invitation-link error messages (by @niwinz) [#9220](https://github.com/penpot/penpot/issues/9220) (PR: [#9223](https://github.com/penpot/penpot/pull/9223)) @@ -83,15 +79,21 @@ - Add clipboard read/write permissions to the plugin system (by @wdeveloper16) [#6980](https://github.com/penpot/penpot/issues/6980) (PR: [#9053](https://github.com/penpot/penpot/pull/9053)) - Update auth hero illustration on login screen [#9532](https://github.com/penpot/penpot/issues/9532) (PR: [#9552](https://github.com/penpot/penpot/pull/9552)) - Update Open Graph link preview metadata [#9555](https://github.com/penpot/penpot/issues/9555) (PR: [#9557](https://github.com/penpot/penpot/pull/9557)) -- Fix library update button freezing [#9330](https://github.com/penpot/penpot/issues/9330) (PR: [#9513](https://github.com/penpot/penpot/pull/9513)) -- Add new numeric inputs for token management on the right sidebar [#9358](https://github.com/penpot/penpot/issues/9358) - Restore deleted team files in bulk instead of per file (by @Dexterity104) [#9246](https://github.com/penpot/penpot/issues/9246) (PR: [#9248](https://github.com/penpot/penpot/pull/9248)) - Preserve Inkscape labels when pasting SVGs (by @jeffrey701) [#7869](https://github.com/penpot/penpot/issues/7869) (PR: [#9252](https://github.com/penpot/penpot/pull/9252)) - Add Alt+click to expand layer subtree (by @MilosM348) [#7736](https://github.com/penpot/penpot/issues/7736) (PR: [#9179](https://github.com/penpot/penpot/pull/9179)) -- Fix typo in subscription settings success key (by @jack-stormentswe) [#9203](https://github.com/penpot/penpot/issues/9203) (PR: [#9204](https://github.com/penpot/penpot/pull/9204)) -### :bug: Bugs fixed +### :bug: Bugs fixed +- Add Shift+Numpad aliases for zoom shortcuts (by @RenzoMXD) [#2457](https://github.com/penpot/penpot/issues/2457) (PR: [#9063](https://github.com/penpot/penpot/pull/9063)) +- Save and restore selection state in undo/redo (by @eureka0928) [#6007](https://github.com/penpot/penpot/issues/6007) (PR: [#8652](https://github.com/penpot/penpot/pull/8652)) +- Add guide locking and fix locked element selection in viewer (by @Dexterity104) [#8358](https://github.com/penpot/penpot/issues/8358) (PR: [#8949](https://github.com/penpot/penpot/pull/8949)) +- Add natural sorting on token names [#8635](https://github.com/penpot/penpot/issues/8635) (PR: [#8672](https://github.com/penpot/penpot/pull/8672)) +- Fix warnings for unsupported token $type (by @Dexterity104) [#8790](https://github.com/penpot/penpot/issues/8790) (PR: [#8873](https://github.com/penpot/penpot/pull/8873)) +- Allow deleting the profile avatar after uploading (by @moorsecopers99) [#9067](https://github.com/penpot/penpot/issues/9067) (PR: [#9068](https://github.com/penpot/penpot/pull/9068)) +- Apply styles to selection (by @AzazelN28) [#9661](https://github.com/penpot/penpot/issues/9661) (PR: [#8625](https://github.com/penpot/penpot/pull/8625)) - Fix Alt/Option to draw shapes from center point (by @offreal) [#8360](https://github.com/penpot/penpot/issues/8360) (PR: [#8361](https://github.com/penpot/penpot/pull/8361)) +- Fix library update button freezing [#9330](https://github.com/penpot/penpot/issues/9330) (PR: [#9513](https://github.com/penpot/penpot/pull/9513)) +- Fix typo in subscription settings success key (by @jack-stormentswe) [#9203](https://github.com/penpot/penpot/issues/9203) (PR: [#9204](https://github.com/penpot/penpot/pull/9204)) - Add token name on broken token pill on sidebar [#9534](https://github.com/penpot/penpot/issues/9534) (PR: [#8527](https://github.com/penpot/penpot/pull/8527)) - Fix tooltip activated when tab change [#9539](https://github.com/penpot/penpot/issues/9539) (PR: [#8719](https://github.com/penpot/penpot/pull/8719)) - Fix title on shared button [#9541](https://github.com/penpot/penpot/issues/9541) (PR: [#8696](https://github.com/penpot/penpot/pull/8696)) @@ -127,7 +129,6 @@ - Fix app crash on multiselection with hidden shapes and opacity mixed value [#9666](https://github.com/penpot/penpot/issues/9666) (PR: [#8932](https://github.com/penpot/penpot/pull/8932)) - Fix gap input throwing an error [#9667](https://github.com/penpot/penpot/issues/9667) (PR: [#8984](https://github.com/penpot/penpot/pull/8984)) - Fix copy to be more specific [#9668](https://github.com/penpot/penpot/issues/9668) (PR: [#9028](https://github.com/penpot/penpot/pull/9028)) -- Allow deleting the profile avatar after uploading (by @moorsecopers99) [#9067](https://github.com/penpot/penpot/issues/9067) (PR: [#9068](https://github.com/penpot/penpot/pull/9068)) - Fix incorrect rendering when exporting text as SVG, PNG and JPG (by @edwin-rivera-dev) [#8516](https://github.com/penpot/penpot/issues/8516) (PR: [#9094](https://github.com/penpot/penpot/pull/9094)) - Fix typography style creation with tokenized line-height (by @juan-flores077) [#8479](https://github.com/penpot/penpot/issues/8479) (PR: [#9121](https://github.com/penpot/penpot/pull/9121)) - Fix colorpicker layout hiding eyedropper button [#9669](https://github.com/penpot/penpot/issues/9669) (PR: [#9125](https://github.com/penpot/penpot/pull/9125)) @@ -149,6 +150,10 @@ - Fix several color picker issues [#9556](https://github.com/penpot/penpot/issues/9556) (PR: [#9558](https://github.com/penpot/penpot/pull/9558)) - Fix asset icon broken on Asset tab [#9587](https://github.com/penpot/penpot/issues/9587) (PR: [#9612](https://github.com/penpot/penpot/pull/9612)) - Fix text fill color stops updating in multiselect with texts [#9608](https://github.com/penpot/penpot/issues/9608) (PR: [#9549](https://github.com/penpot/penpot/pull/9549)) +- Fix editing a legacy text element silently detaches its color token [#9255](https://github.com/penpot/penpot/issues/9255) +- Fix token application to grid paddings [#9494](https://github.com/penpot/penpot/issues/9494) +- Fix file crashing when switching a variant [#9259](https://github.com/penpot/penpot/issues/9259) + ## 2.15.4 (Unreleased) diff --git a/backend/src/app/http/assets.clj b/backend/src/app/http/assets.clj index d07090e074..430ee2bbc3 100644 --- a/backend/src/app/http/assets.clj +++ b/backend/src/app/http/assets.clj @@ -12,6 +12,7 @@ [app.common.time :as ct] [app.common.uri :as u] [app.db :as db] + [app.http.access-token :as actoken] [app.http.session :as session] [app.storage :as sto] [integrant.core :as ig] @@ -79,9 +80,17 @@ (let [bucket (-> obj meta :bucket)] (not (contains? public-buckets bucket)))) +(defn- authenticated? + "Check if the request has an authenticated profile, either via session + or access token." + [request] + (or (some? (::session/profile-id request)) + (some? (::actoken/profile-id request)))) + (defn objects-handler "Handler that serves storage objects by id. - For non-public buckets (e.g. profile), requires an authenticated session." + For non-public buckets (e.g. profile), requires authentication + via session cookie or access token." [{:keys [::sto/storage] :as cfg} request] (let [id (get-id request) obj (sto/get-object storage id)] @@ -90,7 +99,7 @@ {::yres/status 404} (and (requires-auth? obj) - (nil? (::session/profile-id request))) + (not (authenticated? request))) {::yres/status 401} :else @@ -128,7 +137,8 @@ (defmethod ig/init-key ::routes [_ cfg] - ["/assets" {:middleware [[session/authz cfg]]} + ["/assets" {:middleware [[session/authz cfg] + [actoken/authz cfg]]} ["/by-id/:id" {:handler (partial objects-handler cfg)}] ["/by-file-media-id/:id" {:handler (partial file-objects-handler cfg)}] ["/by-file-media-id/:id/thumbnail" {:handler (partial file-thumbnails-handler cfg)}]]) diff --git a/backend/src/app/main.clj b/backend/src/app/main.clj index 018e6e301d..940775bdf0 100644 --- a/backend/src/app/main.clj +++ b/backend/src/app/main.clj @@ -302,7 +302,9 @@ ::http.assets/cache-max-age (ct/duration {:hours 24}) ::http.assets/signature-max-age (ct/duration {:hours 24 :minutes 15}) ::sto/storage (ig/ref ::sto/storage) - ::session/manager (ig/ref ::session/manager)} + ::session/manager (ig/ref ::session/manager) + ::setup/props (ig/ref ::setup/props) + ::db/pool (ig/ref ::db/pool)} ::rpc/climit {::mtx/metrics (ig/ref ::mtx/metrics) diff --git a/backend/src/app/rpc/doc.clj b/backend/src/app/rpc/doc.clj index 611be93b15..62dffae23f 100644 --- a/backend/src/app/rpc/doc.clj +++ b/backend/src/app/rpc/doc.clj @@ -96,6 +96,7 @@ context (assoc @context :param-style pstyle)] {::yres/status 200 + ::yres/headers {"content-type" "text/html; charset=utf-8"} ::yres/body (-> (io/resource template) (tmpl/render context))}))) (fn [_] diff --git a/backend/test/backend_tests/http_assets_test.clj b/backend/test/backend_tests/http_assets_test.clj new file mode 100644 index 0000000000..df93d0b019 --- /dev/null +++ b/backend/test/backend_tests/http_assets_test.clj @@ -0,0 +1,461 @@ +;; 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 backend-tests.http-assets-test + (:require + [app.common.time :as ct] + [app.common.uuid :as uuid] + [app.db :as db] + [app.http :as-alias http] + [app.http.access-token :as actoken] + [app.http.assets :as assets] + [app.http.session :as session] + [app.rpc.commands.access-token :as access-token] + [app.storage :as sto] + [backend-tests.helpers :as th] + [clojure.test :as t] + [datoteka.fs :as fs] + [yetti.response :as-alias yres])) + +(t/use-fixtures :once th/state-init) +(t/use-fixtures :each (th/serial + th/database-reset + th/clean-storage)) + +;; ---------------------------------------------------------------- +;; Helpers +;; ---------------------------------------------------------------- + +(defn- configure-storage-backend + "Given storage map, returns a storage configured with the + appropriate backend for assets." + [storage] + (assoc storage ::sto/backend :fs)) + +(defn- create-storage-object! + "Create a storage object with the given bucket and content." + [storage bucket content] + (sto/put-object! storage {::sto/content (sto/content content) + :bucket bucket + :content-type "text/plain"})) + +(defn- make-handler-cfg + "Build a minimal cfg map for the assets handlers." + [storage] + {::sto/storage storage + ::assets/path "/assets"}) + +;; ---------------------------------------------------------------- +;; Tests: get-id +;; ---------------------------------------------------------------- + +(t/deftest get-id-with-valid-uuid + (let [id (uuid/next) + request {:path-params {:id (str id)}} + result (assets/get-id request)] + (t/is (= id result)))) + +(t/deftest get-id-with-invalid-uuid + (let [request {:path-params {:id "not-a-uuid"}}] + (try + (assets/get-id request) + (t/is false "should have thrown") + (catch Exception e + (t/is (= :not-found (:type (ex-data e)))))))) + +(t/deftest get-id-with-missing-id + (let [request {:path-params {}}] + (try + (assets/get-id request) + (t/is false "should have thrown") + (catch Exception e + (t/is (= :not-found (:type (ex-data e)))))))) + +;; ---------------------------------------------------------------- +;; Tests: objects-handler — non-existent objects +;; ---------------------------------------------------------------- + +(t/deftest objects-handler-non-existent-object + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + request {:path-params {:id (str (uuid/next))}} + response (assets/objects-handler cfg request)] + (t/is (= 404 (::yres/status response))))) + +(t/deftest objects-handler-invalid-uuid + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + request {:path-params {:id "not-a-uuid"}}] + (try + (assets/objects-handler cfg request) + (t/is false "should have thrown") + (catch Exception e + (t/is (= :not-found (:type (ex-data e)))))))) + +;; ---------------------------------------------------------------- +;; Tests: objects-handler — public buckets (no auth required) +;; ---------------------------------------------------------------- + +(t/deftest objects-handler-public-bucket-no-auth + ;; Objects in public buckets should be accessible without authentication. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage)] + + (doseq [bucket ["file-media-object" + "file-object-thumbnail" + "team-font-variant" + "file-data-fragment"]] + (t/testing (str "bucket: " bucket) + (let [object (create-storage-object! storage bucket "public data") + request {:path-params {:id (str (:id object))}} + response (assets/objects-handler cfg request)] + (t/is (not= 401 (::yres/status response)) + (str "bucket " bucket " should not require auth")) + (t/is (not= 404 (::yres/status response)) + (str "bucket " bucket " object should exist"))))))) + +(t/deftest objects-handler-public-bucket-with-auth + ;; Objects in public buckets should also be accessible WITH authentication. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + profile (th/create-profile* 1) + object (create-storage-object! storage "file-media-object" "public data") + request {:path-params {:id (str (:id object))} + ::session/profile-id (:id profile)} + response (assets/objects-handler cfg request)] + (t/is (not= 401 (::yres/status response))) + (t/is (not= 404 (::yres/status response))))) + +;; ---------------------------------------------------------------- +;; Tests: objects-handler — non-public buckets (auth required) +;; ---------------------------------------------------------------- + +(t/deftest objects-handler-non-public-bucket-no-auth + ;; Objects in non-public buckets should return 401 without authentication. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + object (create-storage-object! storage "profile" "profile photo") + request {:path-params {:id (str (:id object))}} + response (assets/objects-handler cfg request)] + (t/is (= 401 (::yres/status response))))) + +(t/deftest objects-handler-non-public-bucket-with-session-auth + ;; Objects in non-public buckets should be accessible with session auth. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + profile (th/create-profile* 1) + object (create-storage-object! storage "profile" "profile photo") + request {:path-params {:id (str (:id object))} + ::session/profile-id (:id profile)} + response (assets/objects-handler cfg request)] + (t/is (not= 401 (::yres/status response))) + (t/is (not= 404 (::yres/status response))))) + +(t/deftest objects-handler-non-public-bucket-with-access-token-auth + ;; Objects in non-public buckets should be accessible with access token auth. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + profile (th/create-profile* 1) + object (create-storage-object! storage "profile" "profile photo") + request {:path-params {:id (str (:id object))} + ::actoken/profile-id (:id profile)} + response (assets/objects-handler cfg request)] + (t/is (not= 401 (::yres/status response))) + (t/is (not= 404 (::yres/status response))))) + +(t/deftest objects-handler-non-public-bucket-with-both-auth + ;; Objects should be accessible when both session and access token auth are present. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + profile (th/create-profile* 1) + object (create-storage-object! storage "profile" "profile photo") + request {:path-params {:id (str (:id object))} + ::session/profile-id (:id profile) + ::actoken/profile-id (:id profile)} + response (assets/objects-handler cfg request)] + (t/is (not= 401 (::yres/status response))) + (t/is (not= 404 (::yres/status response))))) + +;; ---------------------------------------------------------------- +;; Tests: objects-handler — all non-public buckets +;; ---------------------------------------------------------------- + +(t/deftest objects-handler-all-non-public-buckets-require-auth + ;; Verify that all buckets NOT in the public set require authentication. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + profile (th/create-profile* 1)] + + (doseq [bucket ["profile" + "tempfile" + "file-data" + "file-thumbnail" + "file-change"]] + (t/testing (str "bucket: " bucket) + (let [object (create-storage-object! storage bucket "some data") + request {:path-params {:id (str (:id object))}}] + + ;; Without auth → 401 + (let [response (assets/objects-handler cfg request)] + (t/is (= 401 (::yres/status response)) + (str "bucket " bucket " should require auth"))) + + ;; With session auth → not 401 + (let [response (assets/objects-handler cfg (assoc request ::session/profile-id (:id profile)))] + (t/is (not= 401 (::yres/status response)) + (str "bucket " bucket " should be accessible with session auth"))) + + ;; With access token auth → not 401 + (let [response (assets/objects-handler cfg (assoc request ::actoken/profile-id (:id profile)))] + (t/is (not= 401 (::yres/status response)) + (str "bucket " bucket " should be accessible with access token auth")))))))) + +;; ---------------------------------------------------------------- +;; Tests: objects-handler — serve-object response (FS backend) +;; ---------------------------------------------------------------- + +(t/deftest objects-handler-fs-backend-serves-object + ;; Verify that the FS backend returns the correct response structure. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + profile (th/create-profile* 1) + object (create-storage-object! storage "file-media-object" "file content") + request {:path-params {:id (str (:id object))} + ::session/profile-id (:id profile)} + response (assets/objects-handler cfg request)] + ;; FS backend returns 204 with x-accel-redirect header + (t/is (= 204 (::yres/status response))) + (t/is (some? (get (::yres/headers response) "x-accel-redirect"))) + (t/is (= "text/plain" (get (::yres/headers response) "content-type"))) + (t/is (some? (get (::yres/headers response) "cache-control"))))) + +(t/deftest objects-handler-fs-backend-accel-redirect-path + ;; Verify that x-accel-redirect contains the object's relative path. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + object (create-storage-object! storage "file-media-object" "file content") + request {:path-params {:id (str (:id object))}} + response (assets/objects-handler cfg request) + redirect (get (::yres/headers response) "x-accel-redirect")] + ;; The redirect path should contain the object's relative path + (t/is (string? redirect)) + (t/is (clojure.string/includes? redirect (sto/object->relative-path object))))) + +;; ---------------------------------------------------------------- +;; Tests: objects-handler — cache headers +;; ---------------------------------------------------------------- + +(t/deftest objects-handler-cache-control-header + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + object (create-storage-object! storage "file-media-object" "content") + request {:path-params {:id (str (:id object))}} + response (assets/objects-handler cfg request) + cc (get (::yres/headers response) "cache-control")] + (t/is (string? cc)) + (t/is (clojure.string/starts-with? cc "max-age=")))) + +;; ---------------------------------------------------------------- +;; Tests: middleware integration — session auth end-to-end +;; ---------------------------------------------------------------- + +(t/deftest session-auth-integration + ;; Test the full session auth flow: create session → assign token → + ;; authenticate request → access protected asset. + (let [cfg th/*system* + manager (session/inmemory-manager) + profile (th/create-profile* 1) + + ;; Create a session and generate a token + session (->> (session/create-session manager {:profile-id (:id profile) + :user-agent "test-agent"}) + (#'session/assign-token cfg)) + + ;; Create a storage object in a non-public bucket + storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + object (create-storage-object! storage "profile" "profile data") + + ;; Simulate what the middleware chain does: + ;; 1. mw/auth extracts token from cookie and sets ::http/auth-data + ;; 2. session/authz reads ::http/auth-data and sets ::session/profile-id + request {::http/auth-data {:type :cookie + :token (:token session) + :claims {:sid (:id session) + :uid (:id profile)} + :metadata {:ver 1}} + :path-params {:id (str (:id object))}} + + ;; Apply session/authz middleware + handler (#'session/wrap-authz + (fn [req] + ;; This is where the actual handler would be called + ;; We verify that ::session/profile-id is set + req) + {::session/manager manager}) + result (handler request)] + + ;; Verify the session auth set the profile-id + (t/is (= (:id profile) (::session/profile-id result))) + (t/is (some? (::session/session result))))) + +;; ---------------------------------------------------------------- +;; Tests: middleware integration — access token auth end-to-end +;; ---------------------------------------------------------------- + +(t/deftest access-token-auth-integration + ;; Test the full access token flow: create token → authenticate + ;; request → access protected asset. + (let [profile (th/create-profile* 1) + + ;; Create an access token in the database + atoken (db/tx-run! th/*system* + access-token/create-access-token + (:id profile) "test-token" nil nil) + + ;; Create a storage object in a non-public bucket + storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + object (create-storage-object! storage "profile" "profile data") + + ;; Simulate what the middleware chain does: + ;; 1. mw/auth extracts token from Authorization header and sets ::http/auth-data + ;; 2. actoken/authz reads ::http/auth-data and sets ::actoken/profile-id + request {::http/auth-data {:type :token + :token (:token atoken) + :claims {:tid (:id atoken)}} + :path-params {:id (str (:id object))}} + + ;; Apply actoken/authz middleware + handler (#'actoken/wrap-authz + (fn [req] + ;; Verify that ::actoken/profile-id is set + req) + th/*system*) + result (handler request)] + + ;; Verify the access token auth set the profile-id + (t/is (= (:id profile) (::actoken/profile-id result))))) + +;; ---------------------------------------------------------------- +;; Tests: middleware chain — combined session + access token +;; ---------------------------------------------------------------- + +(t/deftest combined-middleware-chain + ;; Test that both session/authz and actoken/authz work together + ;; in the middleware chain, matching the assets route configuration. + (let [cfg th/*system* + manager (session/inmemory-manager) + profile (th/create-profile* 1) + + ;; Create a session + session (->> (session/create-session manager {:profile-id (:id profile) + :user-agent "test-agent"}) + (#'session/assign-token cfg)) + + ;; Create an access token + atoken (db/tx-run! th/*system* + access-token/create-access-token + (:id profile) "test-token" nil nil) + + ;; Build the middleware chain like assets routes do: + ;; session/authz → actoken/authz → handler + inner-handler (fn [request] request) + with-actoken (#'actoken/wrap-authz inner-handler th/*system*) + with-session (#'session/wrap-authz with-actoken {::session/manager manager})] + + (t/testing "session cookie auth sets ::session/profile-id" + (let [request {::http/auth-data {:type :cookie + :token (:token session) + :claims {:sid (:id session) + :uid (:id profile)} + :metadata {:ver 1}}} + result (with-session request)] + (t/is (= (:id profile) (::session/profile-id result))))) + + (t/testing "access token auth sets ::actoken/profile-id" + (let [request {::http/auth-data {:type :token + :token (:token atoken) + :claims {:tid (:id atoken)}}} + result (with-session request)] + (t/is (= (:id profile) (::actoken/profile-id result))))) + + (t/testing "no auth sets neither profile-id" + (let [request {} + result (with-session request)] + (t/is (nil? (::session/profile-id result))) + (t/is (nil? (::actoken/profile-id result))))))) + +;; ---------------------------------------------------------------- +;; Tests: objects-handler — edge cases +;; ---------------------------------------------------------------- + +(t/deftest objects-handler-nil-profile-id-in-session + ;; When session auth is present but profile-id is nil (e.g. invalid session), + ;; non-public objects should still be denied. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + object (create-storage-object! storage "profile" "data") + request {:path-params {:id (str (:id object))} + ::session/profile-id nil} + response (assets/objects-handler cfg request)] + (t/is (= 401 (::yres/status response))))) + +(t/deftest objects-handler-nil-profile-id-in-access-token + ;; When access token auth is present but profile-id is nil, + ;; non-public objects should still be denied. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + object (create-storage-object! storage "profile" "data") + request {:path-params {:id (str (:id object))} + ::actoken/profile-id nil} + response (assets/objects-handler cfg request)] + (t/is (= 401 (::yres/status response))))) + +(t/deftest objects-handler-empty-request + ;; A request with no path-params should raise a not-found error. + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + request {}] + (try + (assets/objects-handler cfg request) + (t/is false "should have thrown") + (catch Exception e + (t/is (= :not-found (:type (ex-data e)))))))) + +;; ---------------------------------------------------------------- +;; Tests: objects-handler — expired objects +;; ---------------------------------------------------------------- + +(t/deftest objects-handler-expired-object + ;; Expired objects should return 404 (get-object filters them out). + (let [storage (-> (:app.storage/storage th/*system*) + (configure-storage-backend)) + cfg (make-handler-cfg storage) + profile (th/create-profile* 1) + object (sto/put-object! storage {::sto/content (sto/content "expired") + ::sto/expired-at (ct/now) + :bucket "profile" + :content-type "text/plain"}) + request {:path-params {:id (str (:id object))} + ::session/profile-id (:id profile)} + response (assets/objects-handler cfg request)] + (t/is (= 404 (::yres/status response))))) diff --git a/backend/test/backend_tests/rpc_doc_test.clj b/backend/test/backend_tests/rpc_doc_test.clj index 964ed57b6a..82c0dc28ff 100644 --- a/backend/test/backend_tests/rpc_doc_test.clj +++ b/backend/test/backend_tests/rpc_doc_test.clj @@ -12,10 +12,12 @@ [app.common.schema :as sm] [app.common.schema.generators :as sg] [app.common.schema.test :as smt] + [app.config :as cf] [app.rpc :as-alias rpc] [app.rpc.doc :as rpc.doc] [backend-tests.helpers :as th] - [clojure.test :as t])) + [clojure.test :as t] + [yetti.response :as-alias yres])) (t/use-fixtures :once th/state-init) @@ -31,6 +33,17 @@ false))) {:num 15})) - - +(t/deftest doc-handler-returns-html-content-type + (with-redefs [cf/flags #{:backend-api-doc}] + (let [methods (::rpc/methods th/*system*) + handler (#'rpc.doc/handler :methods methods + :label "main" + :entrypoint "http://localhost/api/main/methods" + :openapi "http://localhost/api/main/doc/openapi" + :template "app/templates/main-api-doc.tmpl") + request {} + response (handler request)] + (t/is (= 200 (::yres/status response))) + (t/is (= "text/html; charset=utf-8" + (get-in response [::yres/headers "content-type"])))))) diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index e0ad3cab15..a97acd0f8a 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -177,7 +177,9 @@ (defn not-empty? [coll] - (boolean (seq coll))) + (if (coll? coll) + (boolean (seq coll)) + (not (nil? coll)))) (defn editable-collection? [m] diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index 5a3838c8c1..49a78726f5 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -46,8 +46,8 @@ (with-meta changes {::page-id page-id}))) ([] - {:redo-changes [] - :undo-changes '()}) + {:redo-changes [] ;; redo-changes is a vector so that conj adds things at the end, in order of execution + :undo-changes '()}) ;; undo-changes is a list to conj things at the beginning, so they execute in the reverse order when undoing several changes ([origin] {:redo-changes [] :undo-changes '() diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index d9d1a68d8b..ea274a0b32 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -2129,8 +2129,8 @@ (contains? #{:auto-height :auto-width} (:grow-type current-shape)))] (loop [attrs updatable-attrs - roperations [{:type :set-touched :touched (:touched previous-shape)}] - uoperations (list {:type :set-touched :touched (:touched current-shape)})] + roperations [] + uoperations '()] (if-let [attr (first attrs)] (let [sync-group (ctk/resolve-sync-group (:type previous-shape) attr) @@ -2272,7 +2272,13 @@ (let [updated-attrs (into #{} (comp (filter #(= :set (:type %))) (map :attr)) - roperations)] + roperations) + updated-sync-groups (into #{} + (keep #(ctk/resolve-sync-group (:type previous-shape) %)) + updated-attrs) + new-touched (set/union (or (:touched current-shape) #{}) updated-sync-groups) + roperations (into [{:type :set-touched :touched new-touched}] roperations) + uoperations (into (list {:type :set-touched :touched (:touched current-shape)}) uoperations)] (cond-> changes (> (count roperations) 1) (-> (add-update-attr-changes current-shape container roperations uoperations) diff --git a/common/src/app/common/types/text.cljc b/common/src/app/common/types/text.cljc index cde27c19c4..05516a7295 100644 --- a/common/src/app/common/types/text.cljc +++ b/common/src/app/common/types/text.cljc @@ -242,8 +242,11 @@ acc) :else - ;; If the key is not :text, and they are different, it is an attribute differece - (if (not= v1 v2) + ;; If the key is not :text, and they are different, it is an attribute difference. + ;; Take into account that some processes remove empty attributes, so in some + ;; cases we will compare [] with nil, and this is not a difference. + (if (and (not= v1 v2) + (or (d/not-empty? v1) (d/not-empty? v2))) (attribute-cb acc k) acc)))) #{} diff --git a/common/test/common_tests/logic/variants_switch_test.cljc b/common/test/common_tests/logic/variants_switch_test.cljc index 81769b976f..abb53fef70 100644 --- a/common/test/common_tests/logic/variants_switch_test.cljc +++ b/common/test/common_tests/logic/variants_switch_test.cljc @@ -17,6 +17,7 @@ [app.common.test-helpers.ids-map :as thi] [app.common.test-helpers.shapes :as ths] [app.common.test-helpers.variants :as thv] + [app.common.types.component :as ctk] [clojure.test :as t])) (t/use-fixtures :each thi/test-fixture) @@ -38,13 +39,13 @@ copy01 (ths/get-shape file :copy01) ;; ==== Action - file' (tho/swap-component-in-shape file :copy01 :c02 {:new-shape-label :copy02 :keep-touched? true}) + file' (tho/swap-component-in-shape file :copy01 :c02 {:keep-touched? true}) - copy01' (ths/get-shape file' :copy02)] + copy01' (ths/get-shape file' :copy01)] (thf/dump-file file :keys [:width]) ;; The copy had width 5 before the switch (t/is (= (:width copy01) 5)) - ;; The rect has width 15 after the switch + ;; The copy has width 15 after the switch (t/is (= (:width copy01') 15)))) (t/deftest test-simple-switch @@ -64,15 +65,15 @@ rect01 (get-in page [:objects (-> copy01 :shapes first)]) ;; ==== Action - file' (tho/swap-component-in-shape file :copy01 :c02 {:new-shape-label :copy02 :keep-touched? true}) + file' (tho/swap-component-in-shape file :copy01 :c02 {:keep-touched? true}) page' (thf/current-page file') - copy02' (ths/get-shape file' :copy02) - rect02' (get-in page' [:objects (-> copy02' :shapes first)])] + copy01' (ths/get-shape file' :copy01) + rect01' (get-in page' [:objects (-> copy01' :shapes first)])] ;; The rect had width 5 before the switch (t/is (= (:width rect01) 5)) ;; The rect has width 15 after the switch - (t/is (= (:width rect02') 15)))) + (t/is (= (:width rect01') 15)))) ;; ============================================================ ;; SIMPLE ATTRIBUTE OVERRIDES (identical variants) @@ -103,9 +104,9 @@ copy01 (ths/get-shape file :copy01) ;; ==== Action - file' (tho/swap-component-in-shape file :copy01 :c02 {:new-shape-label :copy02 :keep-touched? true}) + file' (tho/swap-component-in-shape file :copy01 :c02 {:keep-touched? true}) - copy01' (ths/get-shape file' :copy02)] + copy01' (ths/get-shape file' :copy01)] (thf/dump-file file :keys [:width]) ;; The copy had width 25 before the switch (t/is (= (:width copy01) 25)) @@ -140,16 +141,16 @@ rect01 (get-in page [:objects (:id rect01)]) ;; ==== Action - file' (tho/swap-component-in-shape file :copy01 :c02 {:new-shape-label :copy02 :keep-touched? true}) + file' (tho/swap-component-in-shape file :copy01 :c02 {:keep-touched? true}) page' (thf/current-page file') - copy02' (ths/get-shape file' :copy02) - rect02' (get-in page' [:objects (-> copy02' :shapes first)])] + copy01' (ths/get-shape file' :copy01) + rect01' (get-in page' [:objects (-> copy01' :shapes first)])] ;; The rect had width 25 before the switch (t/is (= (:width rect01) 25)) ;; The override is keept: The rect still has width 25 after the switch - (t/is (= (:width rect02') 25)))) + (t/is (= (:width rect01') 25)))) ;; ============================================================ ;; SIMPLE ATTRIBUTE OVERRIDES (different variants) @@ -183,17 +184,193 @@ rect01 (get-in page [:objects (:id rect01)]) ;; ==== Action - file' (tho/swap-component-in-shape file :copy01 :c02 {:new-shape-label :copy02 :keep-touched? true}) + file' (tho/swap-component-in-shape file :copy01 :c02 {:keep-touched? true}) page' (thf/current-page file') - copy02' (ths/get-shape file' :copy02) - rect02' (get-in page' [:objects (-> copy02' :shapes first)])] + copy01' (ths/get-shape file' :copy01) + rect01' (get-in page' [:objects (-> copy01' :shapes first)])] ;; The rect had width 25 before the switch (t/is (= (:width rect01) 25)) ;; The override isn't keept, because the property is different in the mains ;; The rect has width 15 after the switch - (t/is (= (:width rect02') 15)))) + (t/is (= (:width rect01') 15)))) + +;; ============================================================ +;; NESTED COPY SWITCH (no overrides) +;; ============================================================ + +(t/deftest test-nested-switch-in-main + (let [;; ==== Setup + file (-> (thf/sample-file :file1) + (thv/add-variant + :v01 :c01 :m01 :c02 :m02 + {:variant1-params {:width 5} + :variant2-params {:width 15}}) + + (tho/add-frame :m03) + (thc/instantiate-component :c01 + :copy01 + :parent-label :m03) + (thc/make-component :c03 :m03)) + + copy01 (ths/get-shape file :copy01) + + ;; ==== Action + file' (tho/swap-component-in-shape file :copy01 :c02 {:keep-touched? true}) + + copy01' (ths/get-shape file' :copy01)] + + (thf/dump-file file :keys [:width]) + + ;; The copy had width 5 before the switch + (t/is (= (:width copy01) 5)) + ;; The copy has width 15 after the switch + (t/is (= (:width copy01') 15)) + ;; The copy is not touched but has swap slot + (t/is (= (count (:touched copy01')) 1)) + (t/is (= (ctk/get-swap-slot copy01') (thi/id :copy01))))) + +(t/deftest test-nested-switch-in-copy + (let [;; ==== Setup + file (-> (thf/sample-file :file1) + (thv/add-variant + :v01 :c01 :m01 :c02 :m02 + {:variant1-params {:width 5} + :variant2-params {:width 15}}) + + (tho/add-frame :m03) + (thc/instantiate-component :c01 + :nested01 + :parent-label :m03) + (thc/make-component :c03 :m03) + + (thc/instantiate-component :c03 + :nested02 + :children-labels [:child01])) + + child01 (ths/get-shape file :child01) + + ;; ==== Action + file' (tho/swap-component-in-shape file :child01 :c02 {:keep-touched? true}) + + child01' (ths/get-shape file' :child01)] + + (thf/dump-file file :keys [:width]) + + ;; The copy had width 5 before the switch + (t/is (= (:width child01) 5)) + ;; The copy has width 15 after the switch + (t/is (= (:width child01') 15)) + ;; The copy is not touched but has swap slot + (t/is (= (count (:touched child01')) 1)) + (t/is (= (ctk/get-swap-slot child01') (thi/id :nested01))))) + +;; ============================================================ +;; NESTED COPY SWITCH (with overrides) +;; ============================================================ + +(t/deftest test-nested-switch-in-main-with-override + (let [;; ==== Setup + file (-> (thf/sample-file :file1) + (thv/add-variant + :v01 :c01 :m01 :c02 :m02 + {:variant1-params {:width 5} + :variant2-params {:width 15}}) + + (tho/add-frame :m03) + (thc/instantiate-component :c01 + :copy01 + :parent-label :m03) + (thc/make-component :c03 :m03)) + + page (thf/current-page file) + fills (ths/sample-fills-color :fill-color "#fabada") + changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page)) + #{(thi/id :copy01)} + (fn [shape] + (assoc shape + :width 25 + :fills fills)) + (:objects page) + {}) + + file (thf/apply-changes file changes) + + copy01 (ths/get-shape file :copy01) + + ;; ==== Action + file' (tho/swap-component-in-shape file :copy01 :c02 {:keep-touched? true}) + + copy01' (ths/get-shape file' :copy01)] + + (thf/dump-file file :keys [:width :touched]) + + ;; The copy had fill color before the switch + (t/is (= (:fills copy01) fills)) + ;; The copy still has fill color after the switch + (t/is (= (:fills copy01') fills)) + ;; The copy had width 25 before the switch + (t/is (= (:width copy01) 25)) + ;; The copy gets the switched variant width 15, because this is the value changed in the variant + (t/is (= (:width copy01') 15)) + ;; The copy is fills touched and has swap slot + (t/is (= (count (:touched copy01')) 2)) + (t/is (= (ctk/get-swap-slot copy01') (thi/id :copy01))) + (t/is (contains? (:touched copy01') :fill-group)))) + +(t/deftest test-nested-switch-in-copy-with-override + (let [;; ==== Setup + file (-> (thf/sample-file :file1) + (thv/add-variant + :v01 :c01 :m01 :c02 :m02 + {:variant1-params {:width 5} + :variant2-params {:width 15}}) + + (tho/add-frame :m03) + (thc/instantiate-component :c01 + :nested01 + :parent-label :m03) + (thc/make-component :c03 :m03) + + (thc/instantiate-component :c03 + :copy02 + :children-labels [:nested02])) + + page (thf/current-page file) + fills (ths/sample-fills-color :fill-color "#fabada") + changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page)) + #{(thi/id :nested02)} + (fn [shape] + (assoc shape + :width 25 + :fills fills)) + (:objects page) + {}) + + file (thf/apply-changes file changes) + + nested02 (ths/get-shape file :nested02) + + ;; ==== Action + file' (tho/swap-component-in-shape file :nested02 :c02 {:keep-touched? true}) + + nested02' (ths/get-shape file' :nested02)] + + (thf/dump-file file :keys [:width]) + + ;; The copy had fill color before the switch + (t/is (= (:fills nested02) fills)) + ;; The copy still has fill color after the switch + (t/is (= (:fills nested02') fills)) + ;; The copy had width 5 before the switch + (t/is (not= (:width nested02) 5)) + ;; The copy gets the switched variant width 15, because this is the value changed in the variant + (t/is (= (:width nested02') 15)) + ;; The copy is fills touched and has swap slot + (t/is (= (count (:touched nested02')) 2)) + (t/is (= (ctk/get-swap-slot nested02') (thi/id :nested01))) + (t/is (contains? (:touched nested02') :fill-group)))) ;; ============================================================ ;; TEXT OVERRIDES (identical variants) diff --git a/exporter/package.json b/exporter/package.json index ee92e952f7..48ef7f9aa0 100644 --- a/exporter/package.json +++ b/exporter/package.json @@ -11,7 +11,7 @@ }, "type": "module", "dependencies": { - "archiver": "^8.0.0", + "archiver": "7.0.1", "cookies": "^0.9.1", "date-fns": "^4.1.0", "generic-pool": "^3.9.0", diff --git a/exporter/pnpm-lock.yaml b/exporter/pnpm-lock.yaml index 7acfafe825..16082370ea 100644 --- a/exporter/pnpm-lock.yaml +++ b/exporter/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: archiver: - specifier: ^8.0.0 - version: 8.0.0 + specifier: 7.0.1 + version: 7.0.1 cookies: specifier: ^0.9.1 version: 0.9.1 @@ -61,6 +61,14 @@ packages: '@ioredis/commands@1.5.1': resolution: {integrity: sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==} + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -69,9 +77,29 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} - archiver@8.0.0: - resolution: {integrity: sha512-fV1orZfsnPn9BaSByR/qE67rJCLJEy2Ox5bq7nJh+jquWaNh6Sfec75kJ2T6PtdGUbPQlrVoSVCEOa5SdiTQ1g==} - engines: {node: '>=18'} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} @@ -84,9 +112,8 @@ packages: react-native-b4a: optional: true - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} bare-events@2.8.2: resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} @@ -135,9 +162,8 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} buffer-crc32@1.0.0: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} @@ -157,9 +183,16 @@ packages: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} - compress-commons@7.0.1: - resolution: {integrity: sha512-g0S8KAD8qf4+V//pr3BfB1aBnARLXNz2Gx+jmHU0LEriUuoQUOPOulVquHKTJ8+EAIIO7fhseNDr9wK5Q9FKBQ==} - engines: {node: '>=18'} + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} cookies@0.9.1: resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} @@ -176,9 +209,13 @@ packages: engines: {node: '>=0.8'} hasBin: true - crc32-stream@7.0.1: - resolution: {integrity: sha512-IBWsY8xznyQrcHn8h4bC8/4ErNke5elzgG8GcqF4RFPw6aHkWWRc7Tgw6upjaTX/CT/yQgqYENkxYsTYN+hW2g==} - engines: {node: '>=18'} + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -232,6 +269,15 @@ packages: domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -250,6 +296,10 @@ packages: fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -259,6 +309,14 @@ packages: resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} engines: {node: '>= 4'} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -281,13 +339,23 @@ packages: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} - is-stream@4.0.1: - resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} - engines: {node: '>=18'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + keygrip@1.1.0: resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} engines: {node: '>= 0.6'} @@ -306,15 +374,26 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + mdn-data@2.0.28: resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} mdn-data@2.12.2: resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} - engines: {node: 18 || 20 || >=22} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -326,6 +405,17 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + playwright-core@1.60.0: resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==} engines: {node: '>=18'} @@ -354,9 +444,8 @@ packages: resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - readdir-glob@3.0.0: - resolution: {integrity: sha512-AhNB2KgKeVJr16nK9LLZbJNWnYoT23ZrumNKFDebHBdkC8KHSqWo871JAUhoWC/RtjEVdqNMFpM6qrwRbaUqpw==} - engines: {node: '>=18'} + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} @@ -381,6 +470,18 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -402,12 +503,28 @@ packages: streamx@2.25.0: resolution: {integrity: sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + svgo@https://codeload.github.com/penpot/svgo/tar.gz/a46262c12c0d967708395972c374eb2adead4180: resolution: {tarball: https://codeload.github.com/penpot/svgo/tar.gz/a46262c12c0d967708395972c374eb2adead4180} version: 4.0.0 @@ -441,6 +558,19 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + ws@8.20.1: resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} engines: {node: '>=10.0.0'} @@ -460,9 +590,9 @@ packages: xregexp@5.1.2: resolution: {integrity: sha512-6hGgEMCGhqCTFEJbqmWrNIPqfpdirdGWkqshu7fFZddmTSfgv5Sn9D2SaKloR79s5VUiUlpwzg3CM3G6D3VIlw==} - zip-stream@7.0.5: - resolution: {integrity: sha512-dSvYKdvLsAHCDqPOhIwk/q5CvuWtTB3Dgpoe0uVEFjTzIOAmsQpprX25InCvrvJsirEbu1OHyy67n/kAj1Sw/w==} - engines: {node: '>=18'} + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} snapshots: @@ -472,23 +602,53 @@ snapshots: '@ioredis/commands@1.5.1': {} + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@pkgjs/parseargs@0.11.0': + optional: true + '@trysound/sax@0.2.0': {} abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 - archiver@8.0.0: + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: dependencies: - async: 3.2.6 - buffer-crc32: 1.0.0 - is-stream: 4.0.1 + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + archiver-utils@5.0.2: + dependencies: + glob: 10.5.0 + graceful-fs: 4.2.11 + is-stream: 2.0.1 lazystream: 1.0.1 + lodash: 4.17.21 normalize-path: 3.0.0 readable-stream: 4.7.0 - readdir-glob: 3.0.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.7.0 + readdir-glob: 1.1.3 tar-stream: 3.2.0 - zip-stream: 7.0.5 + zip-stream: 6.0.1 transitivePeerDependencies: - bare-abort-controller - bare-buffer @@ -498,7 +658,7 @@ snapshots: b4a@1.8.1: {} - balanced-match@4.0.4: {} + balanced-match@1.0.2: {} bare-events@2.8.2: {} @@ -536,9 +696,9 @@ snapshots: boolbase@1.0.0: {} - brace-expansion@5.0.6: + brace-expansion@2.1.0: dependencies: - balanced-match: 4.0.4 + balanced-match: 1.0.2 buffer-crc32@1.0.0: {} @@ -553,11 +713,17 @@ snapshots: cluster-key-slot@1.1.2: {} - compress-commons@7.0.1: + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + compress-commons@6.0.2: dependencies: crc-32: 1.2.2 - crc32-stream: 7.0.1 - is-stream: 4.0.1 + crc32-stream: 6.0.0 + is-stream: 2.0.1 normalize-path: 3.0.0 readable-stream: 4.7.0 @@ -572,11 +738,17 @@ snapshots: crc-32@1.2.2: {} - crc32-stream@7.0.1: + crc32-stream@6.0.0: dependencies: crc-32: 1.2.2 readable-stream: 4.7.0 + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -629,6 +801,12 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 + eastasianwidth@0.2.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + entities@4.5.0: {} event-target-shim@5.0.1: {} @@ -643,11 +821,27 @@ snapshots: fast-fifo@1.3.2: {} + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + fsevents@2.3.2: optional: true generic-pool@3.9.0: {} + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + graceful-fs@4.2.11: {} + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -680,10 +874,20 @@ snapshots: transitivePeerDependencies: - supports-color - is-stream@4.0.1: {} + is-fullwidth-code-point@3.0.0: {} + + is-stream@2.0.1: {} isarray@1.0.0: {} + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + keygrip@1.1.0: dependencies: tsscmp: 1.0.6 @@ -698,13 +902,21 @@ snapshots: lodash@4.17.21: {} + lru-cache@10.4.3: {} + mdn-data@2.0.28: {} mdn-data@2.12.2: {} - minimatch@10.2.5: + minimatch@5.1.9: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 2.1.0 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.0 + + minipass@7.1.3: {} ms@2.1.3: {} @@ -714,6 +926,15 @@ snapshots: dependencies: boolbase: 1.0.0 + package-json-from-dist@1.0.1: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + playwright-core@1.60.0: {} playwright@1.60.0: @@ -751,9 +972,9 @@ snapshots: process: 0.11.10 string_decoder: 1.3.0 - readdir-glob@3.0.0: + readdir-glob@1.1.3: dependencies: - minimatch: 10.2.5 + minimatch: 5.1.9 redis-errors@1.2.0: {} @@ -771,6 +992,14 @@ snapshots: setprototypeof@1.2.0: {} + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -793,6 +1022,18 @@ snapshots: - bare-abort-controller - react-native-b4a + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -801,6 +1042,14 @@ snapshots: dependencies: safe-buffer: 5.2.1 + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + svgo@https://codeload.github.com/penpot/svgo/tar.gz/a46262c12c0d967708395972c374eb2adead4180: dependencies: '@trysound/sax': 0.2.0 @@ -843,6 +1092,22 @@ snapshots: util-deprecate@1.0.2: {} + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + ws@8.20.1: {} xml-js@1.6.11: @@ -853,8 +1118,8 @@ snapshots: dependencies: '@babel/runtime-corejs3': 7.28.4 - zip-stream@7.0.5: + zip-stream@6.0.1: dependencies: - compress-commons: 7.0.1 - normalize-path: 3.0.0 + archiver-utils: 5.0.2 + compress-commons: 6.0.2 readable-stream: 4.7.0 diff --git a/frontend/playwright/data/workspace/get-file-13958.json b/frontend/playwright/data/workspace/get-file-13958.json new file mode 100644 index 0000000000..77b9815d1a --- /dev/null +++ b/frontend/playwright/data/workspace/get-file-13958.json @@ -0,0 +1,4321 @@ +{ + "~:features": { + "~#set": [ + "fdata/path-data", + "design-tokens/v1", + "variants/v1", + "layout/grid", + "fdata/objects-map", + "components/v2", + "fdata/shape-data-type" + ] + }, + "~:team-id": "~uc6b102e2-5aaa-809c-8007-dcd1eab2135d", + "~:permissions": { + "~:type": "~:membership", + "~:is-owner": true, + "~:is-admin": true, + "~:can-edit": true, + "~:can-read": true, + "~:is-logged": true + }, + "~:has-media-trimmed": false, + "~:comment-thread-seqn": 0, + "~:name": "color tokens detach (copy)", + "~:revn": 11, + "~:modified-at": "~m1778577544627", + "~:vern": 151920609, + "~:id": "~u1bac06a1-a942-80a6-8008-0222e1ec38d5", + "~:is-shared": false, + "~:migrations": { + "~#ordered-set": [ + "legacy-2", + "legacy-3", + "legacy-5", + "legacy-6", + "legacy-7", + "legacy-8", + "legacy-9", + "legacy-10", + "legacy-11", + "legacy-12", + "legacy-13", + "legacy-14", + "legacy-16", + "legacy-17", + "legacy-18", + "legacy-19", + "legacy-25", + "legacy-26", + "legacy-27", + "legacy-28", + "legacy-29", + "legacy-31", + "legacy-32", + "legacy-33", + "legacy-34", + "legacy-36", + "legacy-37", + "legacy-38", + "legacy-39", + "legacy-40", + "legacy-41", + "legacy-42", + "legacy-43", + "legacy-44", + "legacy-45", + "legacy-46", + "legacy-47", + "legacy-48", + "legacy-49", + "legacy-50", + "legacy-51", + "legacy-52", + "legacy-53", + "legacy-54", + "legacy-55", + "legacy-56", + "legacy-57", + "legacy-59", + "legacy-62", + "legacy-65", + "legacy-66", + "legacy-67", + "0001-remove-tokens-from-groups", + "0002-normalize-bool-content-v2", + "0002-clean-shape-interactions", + "0003-fix-root-shape", + "0003-convert-path-content-v2", + "0005-deprecate-image-type", + "0006-fix-old-texts-fills", + "0008-fix-library-colors-v4", + "0009-clean-library-colors", + "0009-add-partial-text-touched-flags", + "0010-fix-swap-slots-pointing-non-existent-shapes", + "0011-fix-invalid-text-touched-flags", + "0012-fix-position-data", + "0013-fix-component-path", + "0013-clear-invalid-strokes-and-fills", + "0014-fix-tokens-lib-duplicate-ids", + "0014-clear-components-nil-objects", + "0015-fix-text-attrs-blank-strings", + "0015-clean-shadow-color", + "0016-copy-fills-from-position-data-to-text-node", + "0017-fix-layout-flex-dir", + "0018-remove-unneeded-objects-from-components", + "0019-fix-missing-swap-slots", + "0020-sync-component-id-with-near-main", + "0021-repair-bad-tokens" + ] + }, + "~:version": 67, + "~:project-id": "~u4cdd76d8-0e6d-8168-8008-0118118e1a1a", + "~:created-at": "~m1778507716647", + "~:backend": "legacy-db", + "~:data": { + "~:pages": [ + "~u1919607f-7059-80e9-8007-d7b6ba437f17" + ], + "~:pages-index": { + "~u1919607f-7059-80e9-8007-d7b6ba437f17": { + "~:id": "~u1919607f-7059-80e9-8007-d7b6ba437f17", + "~:name": "Page 1", + "~:objects": { + "~#penpot/objects-map/v2": { + "~ufb6e1db9-e999-8049-8007-d7b7ac11fbac": "[\"~#shape\",[\"^ \",\"~:y\",603,\"~:layout-item-hsizing\",\"fill\",\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:grow-type\",\"~:auto-height\",\"~:content\",[\"^ \",\"~:type\",\"root\",\"~:children\",[[\"^ \",\"^8\",\"paragraph-set\",\"^9\",[[\"^ \",\"~:line-height\",\"1.5\",\"~:path\",\"font-screen-lg / body\",\"~:font-style\",\"normal\",\"^9\",[[\"^ \",\"^:\",\"1.5\",\"^;\",\"font-screen-lg / body\",\"^<\",\"normal\",\"~:text-transform\",\"none\",\"~:text-align\",\"left\",\"~:font-id\",\"gfont-dm-sans\",\"~:text-style-id\",\"S:61089755d06cc251915221fee7a45ae2841996c6,\",\"~:font-size\",\"16\",\"~:font-weight\",\"400\",\"~:modified-at\",\"2025-01-24T18:57:32.766Z\",\"~:font-variant-id\",\"regular\",\"~:text-decoration\",\"none\",\"~:letter-spacing\",\"0\",\"~:fills\",[[\"^ \",\"~:fill-color\",\"#2f2c35\",\"~:fill-opacity\",1]],\"~:font-family\",\"DM Sans\",\"~:text\",\"Design tokens are a set of codified design decisions that store raw design values as named entities, making them core pieces of a design system. \\n\"],[\"^ \",\"^:\",\"1\",\"^<\",\"normal\",\"^?\",\"sourcesanspro\",\"^A\",\"16\",\"^B\",\"400\",\"^D\",\"regular\",\"^F\",\"0\",\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^K\",\"\\n\"],[\"^ \",\"^:\",\"1.5\",\"^;\",\"font-screen-lg / body\",\"^<\",\"normal\",\"^=\",\"none\",\"^>\",\"left\",\"^?\",\"gfont-dm-sans\",\"^@\",\"S:61089755d06cc251915221fee7a45ae2841996c6,\",\"^A\",\"16\",\"^B\",\"400\",\"^C\",\"2025-01-24T18:57:32.766Z\",\"^D\",\"regular\",\"^E\",\"none\",\"^F\",\"0\",\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^J\",\"DM Sans\",\"^K\",\"\\n\"],[\"^ \",\"^:\",\"1\",\"^<\",\"normal\",\"^?\",\"sourcesanspro\",\"^A\",\"16\",\"^B\",\"400\",\"^D\",\"regular\",\"^F\",\"0\",\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^K\",\"\\n\"],[\"^ \",\"^:\",\"1.5\",\"^;\",\"font-screen-lg / body\",\"^<\",\"normal\",\"^=\",\"none\",\"^>\",\"left\",\"^?\",\"gfont-dm-sans\",\"^@\",\"S:61089755d06cc251915221fee7a45ae2841996c6,\",\"^A\",\"16\",\"^B\",\"400\",\"^C\",\"2025-01-24T18:57:32.766Z\",\"^D\",\"regular\",\"^E\",\"none\",\"^F\",\"0\",\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^J\",\"DM Sans\",\"^K\",\"They are adaptable to any platform and are used to replace hard-coded variables.\"]],\"^=\",\"none\",\"^>\",\"left\",\"^?\",\"gfont-dm-sans\",\"~:key\",\"6m627\",\"^@\",\"S:61089755d06cc251915221fee7a45ae2841996c6,\",\"^A\",\"16\",\"^B\",\"400\",\"^8\",\"paragraph\",\"^C\",\"2025-01-24T18:57:32.766Z\",\"^D\",\"regular\",\"^E\",\"none\",\"^F\",\"0\",\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^J\",\"DM Sans\"]]]],\"~:vertical-align\",\"top\",\"^G\",[]],\"~:blend-mode\",\"~:normal\",\"~:name\",\"Design tokens are a set\",\"~:width\",704,\"^8\",\"^K\",\"~:svg-attrs\",[\"^ \"],\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",727,\"~:y\",603]],[\"^T\",[\"^ \",\"~:x\",1431,\"~:y\",603]],[\"^T\",[\"^ \",\"~:x\",1431,\"~:y\",747]],[\"^T\",[\"^ \",\"~:x\",727,\"~:y\",747]]],\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^3\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~u1919607f-7059-80e9-8007-d7b6ba437f17\",\"~:hidden\",false,\"~:opacity\",1,\"~:id\",\"~ufb6e1db9-e999-8049-8007-d7b7ac11fbac\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:applied-tokens\",[\"^ \",\"~:fill\",\"xx.alias.color.text.default\"],\"~:layout-item-vsizing\",\"auto\",\"~:position-data\",[[\"^ \",\"~:y\",625.4199829101562,\"^:\",\"1.2\",\"^<\",\"normal\",\"~:typography-ref-id\",null,\"^=\",\"none\",\"^>\",\"left\",\"^?\",\"gfont-dm-sans\",\"^A\",\"16px\",\"^B\",\"400\",\"~:typography-ref-file\",null,\"~:text-direction\",\"ltr\",\"^Q\",676.6099853515625,\"^D\",\"regular\",\"^E\",\"none\",\"^F\",\"0px\",\"~:x\",727,\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"~:direction\",\"ltr\",\"^J\",\"DM Sans\",\"~:height\",20.8399658203125,\"^K\",\"Design tokens are a set of codified design decisions that store raw design values as named \"],[\"^ \",\"~:y\",649.4199829101562,\"^:\",\"1.2\",\"^<\",\"normal\",\"^14\",null,\"^=\",\"none\",\"^>\",\"left\",\"^?\",\"gfont-dm-sans\",\"^A\",\"16px\",\"^B\",\"400\",\"^15\",null,\"^16\",\"ltr\",\"^Q\",400.2900390625,\"^D\",\"regular\",\"^E\",\"none\",\"^F\",\"0px\",\"~:x\",727,\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^17\",\"ltr\",\"^J\",\"DM Sans\",\"^18\",20.8399658203125,\"^K\",\"entities, making them core pieces of a design system. \"],[\"^ \",\"~:y\",673.3599853515625,\"^:\",\"1.2\",\"^<\",\"normal\",\"^14\",null,\"^=\",\"none\",\"^>\",\"left\",\"^?\",\"sourcesanspro\",\"^A\",\"16px\",\"^B\",\"400\",\"^15\",null,\"^16\",\"ltr\",\"^Q\",0,\"^D\",\"regular\",\"^E\",\"none\",\"^F\",\"0px\",\"~:x\",727,\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^17\",\"ltr\",\"^J\",\"sourcesanspro\",\"^18\",20.719970703125,\"^K\",\"\"],[\"^ \",\"~:y\",697.4199829101562,\"^:\",\"1.2\",\"^<\",\"normal\",\"^14\",null,\"^=\",\"none\",\"^>\",\"left\",\"^?\",\"gfont-dm-sans\",\"^A\",\"16px\",\"^B\",\"400\",\"^15\",null,\"^16\",\"ltr\",\"^Q\",0,\"^D\",\"regular\",\"^E\",\"none\",\"^F\",\"0px\",\"~:x\",727,\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^17\",\"ltr\",\"^J\",\"DM Sans\",\"^18\",20.8399658203125,\"^K\",\"\"],[\"^ \",\"~:y\",721.3599853515625,\"^:\",\"1.2\",\"^<\",\"normal\",\"^14\",null,\"^=\",\"none\",\"^>\",\"left\",\"^?\",\"sourcesanspro\",\"^A\",\"16px\",\"^B\",\"400\",\"^15\",null,\"^16\",\"ltr\",\"^Q\",0,\"^D\",\"regular\",\"^E\",\"none\",\"^F\",\"0px\",\"~:x\",727,\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^17\",\"ltr\",\"^J\",\"sourcesanspro\",\"^18\",20.719970703125,\"^K\",\"\"],[\"^ \",\"~:y\",745.4199829101562,\"^:\",\"1.2\",\"^<\",\"normal\",\"^14\",null,\"^=\",\"none\",\"^>\",\"left\",\"^?\",\"gfont-dm-sans\",\"^A\",\"16px\",\"^B\",\"400\",\"^15\",null,\"^16\",\"ltr\",\"^Q\",607.7900390625,\"^D\",\"regular\",\"^E\",\"none\",\"^F\",\"0px\",\"~:x\",727,\"^G\",[[\"^ \",\"^H\",\"#2f2c35\",\"^I\",1]],\"^17\",\"ltr\",\"^J\",\"DM Sans\",\"^18\",20.8399658203125,\"^K\",\"They are adaptable to any platform and are used to replace hard-coded variables.\"]],\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",727,\"~:blocked\",false,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",727,\"~:y\",603,\"^Q\",704,\"^18\",144,\"~:x1\",727,\"~:y1\",603,\"~:x2\",1431,\"~:y2\",747]],\"^G\",[],\"~:flip-x\",null,\"^18\",144,\"~:flip-y\",null]]", + "~u00000000-0000-0000-0000-000000000000": "[\"~#shape\",[\"^ \",\"~:y\",0,\"~:hide-fill-on-export\",false,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:name\",\"Root Frame\",\"~:width\",0.01,\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",0.0,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.01]],[\"^:\",[\"^ \",\"~:x\",0.0,\"~:y\",0.01]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^3\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~u1919607f-7059-80e9-8007-d7b6ba437f17\",\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",0,\"~:proportion\",1.0,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",0,\"~:y\",0,\"^6\",0.01,\"~:height\",0.01,\"~:x1\",0,\"~:y1\",0,\"~:x2\",0.01,\"~:y2\",0.01]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^I\",0.01,\"~:flip-y\",null,\"~:shapes\",[\"~ufb6e1db9-e999-8049-8007-d7b7ac11fbac\"]]]" + } + } + } + }, + "~:tokens-lib": { + "~#penpot/tokens-lib": { + "~:sets": { + "~#ordered-map": [ + [ + "G-global", + { + "~#ordered-map": [ + [ + "S-color", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0cf6d3", + "~:name": "global/color", + "~:description": "", + "~:modified-at": "~m1778507716659", + "~:tokens": { + "~#ordered-map": [ + [ + "xx.global.color.mint.500", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dcb", + "~:name": "xx.global.color.mint.500", + "~:type": "~:color", + "~:value": "#188675", + "~:description": "global color mint of weight 500", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.violet.200", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca44a", + "~:name": "xx.global.color.violet.200", + "~:type": "~:color", + "~:value": "#D0D2F3", + "~:description": "global color violet of weight 200", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.neutral.300", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dba", + "~:name": "xx.global.color.neutral.300", + "~:type": "~:color", + "~:value": "#DCDCDD", + "~:description": "global color neutral of weight 300", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.mint.600", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc5", + "~:name": "xx.global.color.mint.600", + "~:type": "~:color", + "~:value": "#1A6A5D", + "~:description": "global color mint of weight 600", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.neutral.50", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db8", + "~:name": "xx.global.color.neutral.50", + "~:type": "~:color", + "~:value": "#FCFCFC", + "~:description": "global color neutral of weight 50", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.orange.500", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dd5", + "~:name": "xx.global.color.orange.500", + "~:type": "~:color", + "~:value": "#C07B4B", + "~:description": "global color orange of weight 500", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.neutral.600", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db9", + "~:name": "xx.global.color.neutral.600", + "~:type": "~:color", + "~:value": "#747279", + "~:description": "global color neutral of weight 600", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.blue.200", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db4", + "~:name": "xx.global.color.blue.200", + "~:type": "~:color", + "~:value": "#B1DBEF", + "~:description": "global color blue of weight 200", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.red.400", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca466", + "~:name": "xx.global.color.red.400", + "~:type": "~:color", + "~:value": "#F37A73", + "~:description": "global color red of weight 400", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.blue.50", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dae", + "~:name": "xx.global.color.blue.50", + "~:type": "~:color", + "~:value": "#F6FBFD", + "~:description": "global color blue of weight 50", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.violet.800", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca44d", + "~:name": "xx.global.color.violet.800", + "~:type": "~:color", + "~:value": "#39345A", + "~:description": "global color violet of weight 800", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.green.200", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca45e", + "~:name": "xx.global.color.green.200", + "~:type": "~:color", + "~:value": "#B0E1AA", + "~:description": "global color green of weight 200", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.orange.800", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dd7", + "~:name": "xx.global.color.orange.800", + "~:type": "~:color", + "~:value": "#6B432B", + "~:description": "global color orange of weight 800", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.violet.500", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca44b", + "~:name": "xx.global.color.violet.500", + "~:type": "~:color", + "~:value": "#686FC8", + "~:description": "global color violet of weight 500", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.blue.700", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db1", + "~:name": "xx.global.color.blue.700", + "~:type": "~:color", + "~:value": "#006596", + "~:description": "global color blue of weight 700", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.blue.900", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db6", + "~:name": "xx.global.color.blue.900", + "~:type": "~:color", + "~:value": "#003C5A", + "~:description": "global color blue of weight 900", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.green.50", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca458", + "~:name": "xx.global.color.green.50", + "~:type": "~:color", + "~:value": "#f7fbeb", + "~:description": "global color green of weight 50", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.red.600", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca463", + "~:name": "xx.global.color.red.600", + "~:type": "~:color", + "~:value": "#934846", + "~:description": "global color red of weight 600", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.yellow.300", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca450", + "~:name": "xx.global.color.yellow.300", + "~:type": "~:color", + "~:value": "#D4BB5F", + "~:description": "global color yellow of weight 300", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.orange.200", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dd4", + "~:name": "xx.global.color.orange.200", + "~:type": "~:color", + "~:value": "#F9CCA9", + "~:description": "global color orange of weight 200", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.violet.700", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca447", + "~:name": "xx.global.color.violet.700", + "~:type": "~:color", + "~:value": "#49457A", + "~:description": "global color violet of weight 700", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.violet.50", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca444", + "~:name": "xx.global.color.violet.50", + "~:type": "~:color", + "~:value": "#FCFCFE", + "~:description": "global color violet of weight 50", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.yellow.500", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca455", + "~:name": "xx.global.color.yellow.500", + "~:type": "~:color", + "~:value": "#84773F", + "~:description": "global color yellow of weight 500", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.yellow.50", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca44e", + "~:name": "xx.global.color.yellow.50", + "~:type": "~:color", + "~:value": "#FFFCF5", + "~:description": "global color yellow of weight 50", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.violet.400", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca448", + "~:name": "xx.global.color.violet.400", + "~:type": "~:color", + "~:value": "#9598E0", + "~:description": "global color violet of weight 400", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.red.300", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca464", + "~:name": "xx.global.color.red.300", + "~:type": "~:color", + "~:value": "#FCA69C", + "~:description": "global color red of weight 300", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.orange.700", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dd1", + "~:name": "xx.global.color.orange.700", + "~:type": "~:color", + "~:value": "#855435", + "~:description": "global color orange of weight 700", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.green.400", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca45c", + "~:name": "xx.global.color.green.400", + "~:type": "~:color", + "~:value": "#69AD65", + "~:description": "global color green of weight 400", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.blue.300", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db0", + "~:name": "xx.global.color.blue.300", + "~:type": "~:color", + "~:value": "#84C5E6", + "~:description": "global color blue of weight 300", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.blue.100", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db3", + "~:name": "xx.global.color.blue.100", + "~:type": "~:color", + "~:value": "#E0F0F9", + "~:description": "global color blue of weight 100", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.orange.600", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dcf", + "~:name": "xx.global.color.orange.600", + "~:type": "~:color", + "~:value": "#9D633E", + "~:description": "global color orange of weight 600", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.yellow.200", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca454", + "~:name": "xx.global.color.yellow.200", + "~:type": "~:color", + "~:value": "#F0D36B", + "~:description": "global color yellow of weight 200", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.red.50", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca462", + "~:name": "xx.global.color.red.50", + "~:type": "~:color", + "~:value": "#FFFBFB", + "~:description": "global color red of weight 50", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.neutral.500", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dbf", + "~:name": "xx.global.color.neutral.500", + "~:type": "~:color", + "~:value": "#8B898F", + "~:description": "global color neutral of weight 500", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.green.300", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca45a", + "~:name": "xx.global.color.green.300", + "~:type": "~:color", + "~:value": "#7FCE7A", + "~:description": "global color green of weight 300", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.green.500", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca45f", + "~:name": "xx.global.color.green.500", + "~:type": "~:color", + "~:value": "#51834E", + "~:description": "global color green of weight 500", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.red.200", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca468", + "~:name": "xx.global.color.red.200", + "~:type": "~:color", + "~:value": "#FFC7BF", + "~:description": "global color red of weight 200", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.yellow.700", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca451", + "~:name": "xx.global.color.yellow.700", + "~:type": "~:color", + "~:value": "#534B2B", + "~:description": "global color yellow of weight 700", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.blue.800", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db7", + "~:name": "xx.global.color.blue.800", + "~:type": "~:color", + "~:value": "#005179", + "~:description": "global color blue of weight 800", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.red.500", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca469", + "~:name": "xx.global.color.red.500", + "~:type": "~:color", + "~:value": "#BA5A56", + "~:description": "global color red of weight 500", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.blue.600", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4daf", + "~:name": "xx.global.color.blue.600", + "~:type": "~:color", + "~:value": "#0077B2", + "~:description": "global color blue of weight 600", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.yellow.600", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca44f", + "~:name": "xx.global.color.yellow.600", + "~:type": "~:color", + "~:value": "#685E34", + "~:description": "global color yellow of weight 600", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.yellow.100", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca453", + "~:name": "xx.global.color.yellow.100", + "~:type": "~:color", + "~:value": "#FDECC3", + "~:description": "global color yellow of weight 100", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.red.700", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca465", + "~:name": "xx.global.color.red.700", + "~:type": "~:color", + "~:value": "#743A3A", + "~:description": "global color red of weight 700", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.violet.300", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca446", + "~:name": "xx.global.color.violet.300", + "~:type": "~:color", + "~:value": "#B6B8EB", + "~:description": "global color violet of weight 300", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.orange.900", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dd6", + "~:name": "xx.global.color.orange.900", + "~:type": "~:color", + "~:value": "#4F3120", + "~:description": "global color orange of weight 900", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.mint.50", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc4", + "~:name": "xx.global.color.mint.50", + "~:type": "~:color", + "~:value": "#F6FEFB", + "~:description": "global color mint of weight 50", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.yellow.800", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca457", + "~:name": "xx.global.color.yellow.800", + "~:type": "~:color", + "~:value": "#3E3922", + "~:description": "global color yellow of weight 800", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.black", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca46c", + "~:name": "xx.global.color.black", + "~:type": "~:color", + "~:value": "#000000", + "~:description": "", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.blue.500", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db5", + "~:name": "xx.global.color.blue.500", + "~:type": "~:color", + "~:value": "#1993D0", + "~:description": "global color blue of weight 500", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.mint.800", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dcd", + "~:name": "xx.global.color.mint.800", + "~:type": "~:color", + "~:value": "#174039", + "~:description": "global color mint of weight 800", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.neutral.950", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc2", + "~:name": "xx.global.color.neutral.950", + "~:type": "~:color", + "~:value": "#1C1C1E", + "~:description": "global color neutral of weight 950", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.violet.600", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca445", + "~:name": "xx.global.color.violet.600", + "~:type": "~:color", + "~:value": "#57579C", + "~:description": "global color violet of weight 600", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.neutral.200", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dbe", + "~:name": "xx.global.color.neutral.200", + "~:type": "~:color", + "~:value": "#F3F3F4", + "~:description": "global color neutral of weight 200", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.neutral.800", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc1", + "~:name": "xx.global.color.neutral.800", + "~:type": "~:color", + "~:value": "#3B3741", + "~:description": "global color neutral of weight 800", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.red.900", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca46a", + "~:name": "xx.global.color.red.900", + "~:type": "~:color", + "~:value": "#3B2020", + "~:description": "global color red of weight 900", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.yellow.900", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca456", + "~:name": "xx.global.color.yellow.900", + "~:type": "~:color", + "~:value": "#2B2819", + "~:description": "global color yellow of weight 900", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.orange.100", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dd3", + "~:name": "xx.global.color.orange.100", + "~:type": "~:color", + "~:value": "#FCEBDC", + "~:description": "global color orange of weight 100", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.red.100", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca467", + "~:name": "xx.global.color.red.100", + "~:type": "~:color", + "~:value": "#FFE9E5", + "~:description": "global color red of weight 100", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.neutral.400", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dbc", + "~:name": "xx.global.color.neutral.400", + "~:type": "~:color", + "~:value": "#AEADB1", + "~:description": "global color neutral of weight 400", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.red.800", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca46b", + "~:name": "xx.global.color.red.800", + "~:type": "~:color", + "~:value": "#572D2D", + "~:description": "global color red of weight 800", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.orange.50", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dce", + "~:name": "xx.global.color.orange.50", + "~:type": "~:color", + "~:value": "#FEF9F5", + "~:description": "global color orange of weight 50", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.mint.200", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dca", + "~:name": "xx.global.color.mint.200", + "~:type": "~:color", + "~:value": "#55EBCE", + "~:description": "global color mint of weight 200", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.mint.900", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dcc", + "~:name": "xx.global.color.mint.900", + "~:type": "~:color", + "~:value": "#142C28", + "~:description": "global color mint of weight 900", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.mint.300", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc6", + "~:name": "xx.global.color.mint.300", + "~:type": "~:color", + "~:value": "#00D4B6", + "~:description": "global color mint of weight 300", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.green.800", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca461", + "~:name": "xx.global.color.green.800", + "~:type": "~:color", + "~:value": "#2A3E28", + "~:description": "global color green of weight 800", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.green.600", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca459", + "~:name": "xx.global.color.green.600", + "~:type": "~:color", + "~:value": "#42673F", + "~:description": "global color green of weight 600", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.green.700", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca45b", + "~:name": "xx.global.color.green.700", + "~:type": "~:color", + "~:value": "#365233", + "~:description": "global color green of weight 700", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.green.100", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca45d", + "~:name": "xx.global.color.green.100", + "~:type": "~:color", + "~:value": "#DFF3DC", + "~:description": "global color green of weight 100", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.neutral.900", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc0", + "~:name": "xx.global.color.neutral.900", + "~:type": "~:color", + "~:value": "#2F2C35", + "~:description": "global color neutral of weight 900", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.neutral.700", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dbb", + "~:name": "xx.global.color.neutral.700", + "~:type": "~:color", + "~:value": "#49454E", + "~:description": "global color neutral of weight 700", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.orange.400", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dd2", + "~:name": "xx.global.color.orange.400", + "~:type": "~:color", + "~:value": "#E39258", + "~:description": "global color orange of weight 400", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.mint.400", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc8", + "~:name": "xx.global.color.mint.400", + "~:type": "~:color", + "~:value": "#0AB29A", + "~:description": "global color mint of weight 400", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.mint.700", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc7", + "~:name": "xx.global.color.mint.700", + "~:type": "~:color", + "~:value": "#19544B", + "~:description": "global color mint of weight 700", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.yellow.400", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca452", + "~:name": "xx.global.color.yellow.400", + "~:type": "~:color", + "~:value": "#B19D51", + "~:description": "global color yellow of weight 400", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.neutral.100", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dbd", + "~:name": "xx.global.color.neutral.100", + "~:type": "~:color", + "~:value": "#FAFAFB", + "~:description": "global color neutral of weight 100", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.violet.100", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca449", + "~:name": "xx.global.color.violet.100", + "~:type": "~:color", + "~:value": "#ECEDFA", + "~:description": "global color violet of weight 100", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.orange.300", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dd0", + "~:name": "xx.global.color.orange.300", + "~:type": "~:color", + "~:value": "#F6AD76", + "~:description": "global color orange of weight 300", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.white", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc3", + "~:name": "xx.global.color.white", + "~:type": "~:color", + "~:value": "#ffffff", + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.mint.100", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dc9", + "~:name": "xx.global.color.mint.100", + "~:type": "~:color", + "~:value": "#C5F8EA", + "~:description": "global color mint of weight 100", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.blue.400", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4db2", + "~:name": "xx.global.color.blue.400", + "~:type": "~:color", + "~:value": "#53AFDC", + "~:description": "global color blue of weight 400", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.color.violet.900", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca44c", + "~:name": "xx.global.color.violet.900", + "~:type": "~:color", + "~:value": "#29253C", + "~:description": "global color violet of weight 900", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.global.color.green.900", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca460", + "~:name": "xx.global.color.green.900", + "~:type": "~:color", + "~:value": "#1E2B1D", + "~:description": "global color green of weight 900", + "~:modified-at": "~m1778507716658" + } + } + ] + ] + } + } + } + ], + [ + "S-dimension", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0e2151", + "~:name": "global/dimension", + "~:description": "", + "~:modified-at": "~m1778507716664", + "~:tokens": { + "~#ordered-map": [ + [ + "xx.global.dimensions.13", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da8", + "~:name": "xx.global.dimensions.13", + "~:type": "~:dimensions", + "~:value": "64px", + "~:description": "13th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.11", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dab", + "~:name": "xx.global.dimensions.11", + "~:type": "~:dimensions", + "~:value": "52px", + "~:description": "11th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.14", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da3", + "~:name": "xx.global.dimensions.14", + "~:type": "~:dimensions", + "~:value": "72px", + "~:description": "14th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.10", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dad", + "~:name": "xx.global.dimensions.10", + "~:type": "~:dimensions", + "~:value": "48px", + "~:description": "10th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.6", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da9", + "~:name": "xx.global.dimensions.6", + "~:type": "~:dimensions", + "~:value": "20px", + "~:description": "6th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.3", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da0", + "~:name": "xx.global.dimensions.3", + "~:type": "~:dimensions", + "~:value": "8px", + "~:description": "3rd step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.2", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4dac", + "~:name": "xx.global.dimensions.2", + "~:type": "~:dimensions", + "~:value": "4px", + "~:description": "2nd step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.12", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da7", + "~:name": "xx.global.dimensions.12", + "~:type": "~:dimensions", + "~:value": "60px", + "~:description": "12th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.8", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da2", + "~:name": "xx.global.dimensions.8", + "~:type": "~:dimensions", + "~:value": "32px", + "~:description": "8th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.7", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da5", + "~:name": "xx.global.dimensions.7", + "~:type": "~:dimensions", + "~:value": "24px", + "~:description": "7th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.15", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da4", + "~:name": "xx.global.dimensions.15", + "~:type": "~:dimensions", + "~:value": "80px", + "~:description": "15th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.4", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da1", + "~:name": "xx.global.dimensions.4", + "~:type": "~:dimensions", + "~:value": "12px", + "~:description": "4th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.9", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d9f", + "~:name": "xx.global.dimensions.9", + "~:type": "~:dimensions", + "~:value": "44px", + "~:description": "9th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.1", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4daa", + "~:name": "xx.global.dimensions.1", + "~:type": "~:dimensions", + "~:value": "2px", + "~:description": "1st step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.global.dimensions.5", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4da6", + "~:name": "xx.global.dimensions.5", + "~:type": "~:dimensions", + "~:value": "16px", + "~:description": "5th step of global dimensions sequence", + "~:modified-at": "~m1778507716657" + } + } + ] + ] + } + } + } + ], + [ + "S-Opacity", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0e7da8", + "~:name": "global/Opacity", + "~:description": "", + "~:modified-at": "~m1778507716665", + "~:tokens": { + "~#ordered-map": [ + [ + "opacity.0", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca494", + "~:name": "opacity.0", + "~:type": "~:opacity", + "~:value": "0", + "~:description": "", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "opacity.10", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca495", + "~:name": "opacity.10", + "~:type": "~:opacity", + "~:value": "0.1", + "~:description": "", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "opacity.50", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca496", + "~:name": "opacity.50", + "~:type": "~:opacity", + "~:value": "0.5", + "~:description": "", + "~:modified-at": "~m1778507716658" + } + } + ] + ] + } + } + } + ] + ] + } + ], + [ + "G-alias", + { + "~#ordered-map": [ + [ + "S-border", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ece1d", + "~:name": "alias/border", + "~:description": "", + "~:modified-at": "~m1778507716667", + "~:tokens": { + "~#ordered-map": [ + [ + "xx.alias.border.radius.sm", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b0", + "~:name": "xx.alias.border.radius.sm", + "~:type": "~:border-radius", + "~:value": "{xx.global.dimensions.2}", + "~:description": "small border radius", + "~:modified-at": "~m1778507716656" + } + } + ], + [ + "xx.alias.border.radius.md", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b1", + "~:name": "xx.alias.border.radius.md", + "~:type": "~:border-radius", + "~:value": "{xx.global.dimensions.3}", + "~:description": "medium border radius", + "~:modified-at": "~m1778507716656" + } + } + ], + [ + "xx.alias.border.radius.lg", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b2", + "~:name": "xx.alias.border.radius.lg", + "~:type": "~:border-radius", + "~:value": "{xx.global.dimensions.5}", + "~:description": "large border radius", + "~:modified-at": "~m1778507716656" + } + } + ], + [ + "xx.alias.border.radius.round", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b3", + "~:name": "xx.alias.border.radius.round", + "~:type": "~:border-radius", + "~:value": "100%", + "~:description": "", + "~:modified-at": "~m1778507716656" + } + } + ], + [ + "stroke.outline", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b4", + "~:name": "stroke.outline", + "~:type": "~:stroke-width", + "~:value": "{xx.global.dimensions.1}", + "~:description": "", + "~:modified-at": "~m1778507716656" + } + } + ], + [ + "stroke.medium", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b5", + "~:name": "stroke.medium", + "~:type": "~:stroke-width", + "~:value": "3", + "~:description": "", + "~:modified-at": "~m1778507716656" + } + } + ], + [ + "stroke.small", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b6", + "~:name": "stroke.small", + "~:type": "~:stroke-width", + "~:value": "1", + "~:description": "", + "~:modified-at": "~m1778507716656" + } + } + ], + [ + "stroke.large-test", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b7", + "~:name": "stroke.large-test", + "~:type": "~:stroke-width", + "~:value": "25", + "~:description": "", + "~:modified-at": "~m1778507716656" + } + } + ] + ] + } + } + } + ], + [ + "S-dimension", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f101a3f", + "~:name": "alias/dimension", + "~:description": "", + "~:modified-at": "~m1778507716672", + "~:tokens": { + "~#ordered-map": [ + [ + "xx.alias.size.xs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca499", + "~:name": "xx.alias.size.xs", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.6}", + "~:description": "extra small size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "rotation.45", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0cf6d1", + "~:name": "rotation.45", + "~:type": "~:rotation", + "~:value": "45", + "~:description": "", + "~:modified-at": "~m1778507716659" + } + } + ], + [ + "xx.alias.spacing.lg", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a7", + "~:name": "xx.alias.spacing.lg", + "~:type": "~:spacing", + "~:value": "{xx.global.dimensions.7}", + "~:description": "large spacing unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "dimension.top.position", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0cf6d2", + "~:name": "dimension.top.position", + "~:type": "~:dimensions", + "~:value": "{xx.global.dimensions.7}", + "~:description": "", + "~:modified-at": "~m1778507716659" + } + } + ], + [ + "xx.alias.icon.size.m", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0cf6ce", + "~:name": "xx.alias.icon.size.m", + "~:type": "~:sizing", + "~:value": "24", + "~:description": "", + "~:modified-at": "~m1778507716659" + } + } + ], + [ + "xx.alias.spacing.xxxl", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4ab", + "~:name": "xx.alias.spacing.xxxl", + "~:type": "~:spacing", + "~:value": "{xx.global.dimensions.13}", + "~:description": "extra extra extra small spacing unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.size.lg", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca49d", + "~:name": "xx.alias.size.lg", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.10}", + "~:description": "large size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.spacing.xxxs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a9", + "~:name": "xx.alias.spacing.xxxs", + "~:type": "~:spacing", + "~:value": "{xx.global.dimensions.1}", + "~:description": "extra extra extra small spacing unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.size.xxl", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a3", + "~:name": "xx.alias.size.xxl", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.13}", + "~:description": "extra extra large size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.size.xxxxl", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca49c", + "~:name": "xx.alias.size.xxxxl", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.15}", + "~:description": "extra extra extra large size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.spacing.xxs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a8", + "~:name": "xx.alias.spacing.xxs", + "~:type": "~:spacing", + "~:value": "{xx.global.dimensions.2}", + "~:description": "extra extra small spacing unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.icon.size.xs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0cf6cf", + "~:name": "xx.alias.icon.size.xs", + "~:type": "~:sizing", + "~:value": "12", + "~:description": "", + "~:modified-at": "~m1778507716659" + } + } + ], + [ + "xx.alias.size.xxs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca49e", + "~:name": "xx.alias.size.xxs", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.5}", + "~:description": "extra extra small size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.spacing.sm", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4ad", + "~:name": "xx.alias.spacing.sm", + "~:type": "~:spacing", + "~:value": "{xx.global.dimensions.4}", + "~:description": "small spacing unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.size.sm", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a4", + "~:name": "xx.alias.size.sm", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.7}", + "~:description": "small size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.icon.size.s", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0cf6d0", + "~:name": "xx.alias.icon.size.s", + "~:type": "~:sizing", + "~:value": "16", + "~:description": "", + "~:modified-at": "~m1778507716659" + } + } + ], + [ + "xx.alias.size.xl", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a1", + "~:name": "xx.alias.size.xl", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.11}", + "~:description": "extra large size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.spacing.xxl", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4ac", + "~:name": "xx.alias.spacing.xxl", + "~:type": "~:spacing", + "~:value": "{xx.global.dimensions.10}", + "~:description": "extra extra small spacing unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.size.xxxxs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a0", + "~:name": "xx.alias.size.xxxxs", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.3}", + "~:description": "extra extra extra small size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.size.xxxs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca49f", + "~:name": "xx.alias.size.xxxs", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.4}", + "~:description": "extra extra extra small size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.spacing.xl", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4aa", + "~:name": "xx.alias.spacing.xl", + "~:type": "~:spacing", + "~:value": "{xx.global.dimensions.8}", + "~:description": "extra large spacing unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.size.md", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca49a", + "~:name": "xx.alias.size.md", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.8}", + "~:description": "medium size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.spacing.md", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a6", + "~:name": "xx.alias.spacing.md", + "~:type": "~:spacing", + "~:value": "{xx.global.dimensions.5}", + "~:description": "medium spacing unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.size.xxxxxs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca49b", + "~:name": "xx.alias.size.xxxxxs", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.2}", + "~:description": "extra extra extra small size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.size.xxxl", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a2", + "~:name": "xx.alias.size.xxxl", + "~:type": "~:sizing", + "~:value": "{xx.global.dimensions.14}", + "~:description": "extra extra extra large size unit", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.spacing.xs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca4a5", + "~:name": "xx.alias.spacing.xs", + "~:type": "~:spacing", + "~:value": "{xx.global.dimensions.3}", + "~:description": "extra small spacing unit", + "~:modified-at": "~m1778507716658" + } + } + ] + ] + } + } + } + ], + [ + "S-color-dark", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f12beff", + "~:name": "alias/color-dark", + "~:description": "", + "~:modified-at": "~m1778507716682", + "~:tokens": { + "~#ordered-map": [ + [ + "xx.alias.color.purpose.onInfo", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d7e", + "~:name": "xx.alias.color.purpose.onInfo", + "~:type": "~:color", + "~:value": "{xx.global.color.blue.800}", + "~:description": "color for elements placed on informational purpose background", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.border.heavy", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d85", + "~:name": "xx.alias.color.border.heavy", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.200}", + "~:description": "heavy border color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.select", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d8d", + "~:name": "xx.alias.color.state.select", + "~:type": "~:color", + "~:value": "{xx.global.color.mint.100}", + "~:description": "background color for selected elements", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.primary.onBrand", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d92", + "~:name": "xx.alias.color.primary.onBrand", + "~:type": "~:color", + "~:value": "{xx.global.color.violet.800}", + "~:description": "color for elements that are placed on brand background color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.focus", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d8a", + "~:name": "xx.alias.color.state.focus", + "~:type": "~:color", + "~:value": "rgba({xx.global.color.neutral.100},0.16)", + "~:description": "Background color for state overlay of a focused element", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.press", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d8c", + "~:name": "xx.alias.color.state.press", + "~:type": "~:color", + "~:value": "rgba({xx.global.color.neutral.100},0.8)", + "~:description": "Background color for state overlay of a pressed element", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.warningHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d83", + "~:name": "xx.alias.color.purpose.warningHighEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.yellow.100}", + "~:description": "color for elements with warning purpose of high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.onSelect", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d91", + "~:name": "xx.alias.color.state.onSelect", + "~:type": "~:color", + "~:value": "{xx.global.color.mint.600}", + "~:description": "Foreground color for selected elements", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.primary.interaction", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d93", + "~:name": "xx.alias.color.primary.interaction", + "~:type": "~:color", + "~:value": "{xx.global.color.violet.600}", + "~:description": "Color that indicates interactions", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.border.focusOutline", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d86", + "~:name": "xx.alias.color.border.focusOutline", + "~:type": "~:color", + "~:value": "rgba({xx.global.color.blue.400},0.5)", + "~:description": "color for default focus outline", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.disable", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d8e", + "~:name": "xx.alias.color.state.disable", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.300}", + "~:description": "background color for disabled elements", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.infoHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d84", + "~:name": "xx.alias.color.purpose.infoHighEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.blue.200}", + "~:description": "color for elements with informational purpose of high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.infoLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d79", + "~:name": "xx.alias.color.purpose.infoLowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.blue.400}", + "~:description": "color for elements with informational purpose of low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.primary.brand", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d94", + "~:name": "xx.alias.color.primary.brand", + "~:type": "~:color", + "~:value": "{xx.global.color.violet.400}", + "~:description": "background color for primary brand elements ", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.text.default", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d96", + "~:name": "xx.alias.color.text.default", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.50}", + "~:description": "Default text color ", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.text.inverted", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d97", + "~:name": "xx.alias.color.text.inverted", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.900}", + "~:description": "Inverted text color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.onSuccess", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d81", + "~:name": "xx.alias.color.purpose.onSuccess", + "~:type": "~:color", + "~:value": "{xx.global.color.green.800}", + "~:description": "color for elements placed on success purpose background", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.criticalLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d7f", + "~:name": "xx.alias.color.purpose.criticalLowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.red.400}", + "~:description": "color for elements with critical purpose of low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.background.mediumEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d9b", + "~:name": "xx.alias.color.background.mediumEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.800}", + "~:description": "Background Color for components with medium emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.text.emphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d98", + "~:name": "xx.alias.color.text.emphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.white}", + "~:description": "Default text color ", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.background.highEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d9c", + "~:name": "xx.alias.color.background.highEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.700}", + "~:description": "Background Color for components with high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.hover", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d90", + "~:name": "xx.alias.color.state.hover", + "~:type": "~:color", + "~:value": "rgba({xx.global.color.neutral.100},0.16)", + "~:description": "Background color for state overlay of a hovered element", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.background.body", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d9d", + "~:name": "xx.alias.color.background.body", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.950}", + "~:description": "Body background color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.successLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d7d", + "~:name": "xx.alias.color.purpose.successLowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.green.400}", + "~:description": "color for elements with success purpose of low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.primary.onInteraction", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d95", + "~:name": "xx.alias.color.primary.onInteraction", + "~:type": "~:color", + "~:value": "{xx.global.color.violet.900}", + "~:description": "color for elements that are placed on interactive background colors", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.onCritical", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d7a", + "~:name": "xx.alias.color.purpose.onCritical", + "~:type": "~:color", + "~:value": "{xx.global.color.red.900}", + "~:description": "color for elements placed on critical purpose background", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.text.medium", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d99", + "~:name": "xx.alias.color.text.medium", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.600}", + "~:description": "Text color in subtle weight", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.criticalHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d7b", + "~:name": "xx.alias.color.purpose.criticalHighEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.red.200}", + "~:description": "color for elements with critical purpose of high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.border.medium", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d87", + "~:name": "xx.alias.color.border.medium", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.500}", + "~:description": "medium border color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.border.subtle", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d88", + "~:name": "xx.alias.color.border.subtle", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.700}", + "~:description": "subtle border color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.background.lowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d9e", + "~:name": "xx.alias.color.background.lowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.900}", + "~:description": "background color for elements with a low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.onWarning", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d80", + "~:name": "xx.alias.color.purpose.onWarning", + "~:type": "~:color", + "~:value": "{xx.global.color.yellow.800}", + "~:description": "color for elements placed on warning purpose background", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.text.subtle", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d9a", + "~:name": "xx.alias.color.text.subtle", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.400}", + "~:description": "Text color in subtle weight", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.successHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d7c", + "~:name": "xx.alias.color.purpose.successHighEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.green.100}", + "~:description": "color for elements with success purpose of high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.onDisable", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d8b", + "~:name": "xx.alias.color.state.onDisable", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.700}", + "~:description": "color for elements that are palced on disabled background color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.selectInverted", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d8f", + "~:name": "xx.alias.color.state.selectInverted", + "~:type": "~:color", + "~:value": "{xx.global.color.mint.600}", + "~:description": "Inverted background color for selected elements", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.warningLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d82", + "~:name": "xx.alias.color.purpose.warningLowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.yellow.400}", + "~:description": "color for elements with warning purpose of low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.onSelectInverted", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d89", + "~:name": "xx.alias.color.state.onSelectInverted", + "~:type": "~:color", + "~:value": "{xx.global.color.mint.100}", + "~:description": "inverted color for elements on selected backgrounds", + "~:modified-at": "~m1778507716657" + } + } + ] + ] + } + } + } + ], + [ + "S-color-light", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f161e35", + "~:name": "alias/color-light", + "~:description": "", + "~:modified-at": "~m1778507716696", + "~:tokens": { + "~#ordered-map": [ + [ + "xx.alias.color.purpose.onInfo", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca472", + "~:name": "xx.alias.color.purpose.onInfo", + "~:type": "~:color", + "~:value": "{xx.global.color.blue.100}", + "~:description": "color for elements placed on informational purpose background", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.border.heavy", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca479", + "~:name": "xx.alias.color.border.heavy", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.700}", + "~:description": "heavy border color", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.state.select", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca481", + "~:name": "xx.alias.color.state.select", + "~:type": "~:color", + "~:value": "{xx.global.color.mint.100}", + "~:description": "background color for selected elements", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.primary.onBrand", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca486", + "~:name": "xx.alias.color.primary.onBrand", + "~:type": "~:color", + "~:value": "{xx.global.color.violet.200}", + "~:description": "color for elements that are placed on brand background color", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.state.focus", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca47e", + "~:name": "xx.alias.color.state.focus", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.100}", + "~:description": "Background color for state overlay of a focused element", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.state.press", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca480", + "~:name": "xx.alias.color.state.press", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.100}", + "~:description": "Background color for state overlay of a pressed element", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.warningHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca477", + "~:name": "xx.alias.color.purpose.warningHighEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.yellow.500}", + "~:description": "color for elements with warning purpose of high emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.state.onSelect", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca485", + "~:name": "xx.alias.color.state.onSelect", + "~:type": "~:color", + "~:value": "{xx.global.color.mint.600}", + "~:description": "Foreground color for selected elements", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.primary.interaction", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca487", + "~:name": "xx.alias.color.primary.interaction", + "~:type": "~:color", + "~:value": "{xx.global.color.violet.600}", + "~:description": "Color that indicates interactions", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.border.focusOutline", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca47a", + "~:name": "xx.alias.color.border.focusOutline", + "~:type": "~:color", + "~:value": "rgba({xx.global.color.blue.500},0.8)", + "~:description": "color for default focus outline", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.state.disable", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca482", + "~:name": "xx.alias.color.state.disable", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.300}", + "~:description": "background color for disabled elements", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.infoHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca478", + "~:name": "xx.alias.color.purpose.infoHighEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.blue.500}", + "~:description": "color for elements with informational purpose of high emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.infoLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca46d", + "~:name": "xx.alias.color.purpose.infoLowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.blue.400}", + "~:description": "color for elements with informational purpose of low emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.primary.brand", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca488", + "~:name": "xx.alias.color.primary.brand", + "~:type": "~:color", + "~:value": "{xx.global.color.violet.500}", + "~:description": "background color for primary brand elements ", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.text.default", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca48b", + "~:name": "xx.alias.color.text.default", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.900}", + "~:description": "Default text color ", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.text.inverted", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca48c", + "~:name": "xx.alias.color.text.inverted", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.50}", + "~:description": "Inverted text color", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.onSuccess", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca475", + "~:name": "xx.alias.color.purpose.onSuccess", + "~:type": "~:color", + "~:value": "{xx.global.color.green.100}", + "~:description": "color for elements placed on success purpose background", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.criticalLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca473", + "~:name": "xx.alias.color.purpose.criticalLowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.red.500}", + "~:description": "color for elements with critical purpose of low emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.background.mediumEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca490", + "~:name": "xx.alias.color.background.mediumEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.100}", + "~:description": "background Color for components with medium emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.text.emphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca48d", + "~:name": "xx.alias.color.text.emphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.black}", + "~:description": "Default text color ", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.background.highEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca491", + "~:name": "xx.alias.color.background.highEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.50}", + "~:description": "background Color for components with high emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.state.hover", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca484", + "~:name": "xx.alias.color.state.hover", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.100}", + "~:description": "Background color for state overlay of a hovered element", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.background.body", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca492", + "~:name": "xx.alias.color.background.body", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.200}", + "~:description": "body background color", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.successLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca471", + "~:name": "xx.alias.color.purpose.successLowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.green.400}", + "~:description": "color for elements with success purpose of low emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.primary.onInteraction", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca489", + "~:name": "xx.alias.color.primary.onInteraction", + "~:type": "~:color", + "~:value": "{xx.global.color.violet.300}", + "~:description": "color for elements that are placed on interactive background colors", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.onCritical", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca46e", + "~:name": "xx.alias.color.purpose.onCritical", + "~:type": "~:color", + "~:value": "{xx.global.color.red.200}", + "~:description": "color for elements placed on critical purpose background", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.text.medium", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca48e", + "~:name": "xx.alias.color.text.medium", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.400}", + "~:description": "Text color in subtle weight", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.criticalHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca46f", + "~:name": "xx.alias.color.purpose.criticalHighEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.red.600}", + "~:description": "color for elements with critical purpose of high emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.border.medium", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca47b", + "~:name": "xx.alias.color.border.medium", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.500}", + "~:description": "medium border color", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.border.subtle", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca47c", + "~:name": "xx.alias.color.border.subtle", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.300}", + "~:description": "subtle border color", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.background.lowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca493", + "~:name": "xx.alias.color.background.lowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.300}", + "~:description": "background color for elements with a low emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.onWarning", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca474", + "~:name": "xx.alias.color.purpose.onWarning", + "~:type": "~:color", + "~:value": "{xx.global.color.yellow.100}", + "~:description": "color for elements placed on warning purpose background", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.text.subtle", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca48f", + "~:name": "xx.alias.color.text.subtle", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.600}", + "~:description": "Text color in subtle weight", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.successHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca470", + "~:name": "xx.alias.color.purpose.successHighEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.green.500}", + "~:description": "color for elements with success purpose of high emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.state.onDisable", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca47f", + "~:name": "xx.alias.color.state.onDisable", + "~:type": "~:color", + "~:value": "{xx.global.color.neutral.700}", + "~:description": "color for elements that are palced on disabled background color", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.state.selectInverted", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca483", + "~:name": "xx.alias.color.state.selectInverted", + "~:type": "~:color", + "~:value": "{xx.global.color.mint.600}", + "~:description": "Inverted background color for selected elements", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.purpose.warningLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca476", + "~:name": "xx.alias.color.purpose.warningLowEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.yellow.400}", + "~:description": "color for elements with warning purpose of low emphasis", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.state.onSelectInverted", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca47d", + "~:name": "xx.alias.color.state.onSelectInverted", + "~:type": "~:color", + "~:value": "{xx.global.color.mint.100}", + "~:description": "inverted color for elements on selected backgrounds", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "xx.alias.color.primary.highEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca48a", + "~:name": "xx.alias.color.primary.highEmphasis", + "~:type": "~:color", + "~:value": "{xx.global.color.violet.200}", + "~:description": "background color for primary brand elements ", + "~:modified-at": "~m1778507716658" + } + } + ] + ] + } + } + } + ], + [ + "S-media-queries", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f16cbda", + "~:name": "alias/media-queries", + "~:description": "", + "~:modified-at": "~m1778507716699", + "~:tokens": { + "~#ordered-map": [ + [ + "xx.media.xs", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d3a", + "~:name": "xx.media.xs", + "~:type": "~:dimensions", + "~:value": "576px", + "~:description": "(min-width: 576px)", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.media.sm", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d3b", + "~:name": "xx.media.sm", + "~:type": "~:dimensions", + "~:value": "768px", + "~:description": "(min-width: 768px)", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.media.md", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d3c", + "~:name": "xx.media.md", + "~:type": "~:dimensions", + "~:value": "992px", + "~:description": "min-width: 992px - Tablet portrait", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.media.lg", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d3d", + "~:name": "xx.media.lg", + "~:type": "~:dimensions", + "~:value": "1200px", + "~:description": " (min-width: 1200px) - Tablet landscape", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.media.xl", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d3e", + "~:name": "xx.media.xl", + "~:type": "~:dimensions", + "~:value": "1440px", + "~:description": " (min-width: 1440px) - Desktop small", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.media.2xl", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d3f", + "~:name": "xx.media.2xl", + "~:type": "~:dimensions", + "~:value": "1680px", + "~:description": " (min-width: 1680px) - Desktop Large", + "~:modified-at": "~m1778507716657" + } + } + ] + ] + } + } + } + ], + [ + "S-web-typography", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f171543", + "~:name": "alias/web-typography", + "~:description": "", + "~:modified-at": "~m1778507716700", + "~:tokens": { + "~#ordered-map": [ + [ + "lineHeight.paragraph", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca497", + "~:name": "lineHeight.paragraph", + "~:type": "~:number", + "~:value": "1.5", + "~:description": "", + "~:modified-at": "~m1778507716658" + } + } + ], + [ + "lineHeight.inline", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0ca498", + "~:name": "lineHeight.inline", + "~:type": "~:number", + "~:value": "1.2", + "~:description": "", + "~:modified-at": "~m1778507716658" + } + } + ] + ] + } + } + } + ], + [ + "S-app-typography", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f17704b", + "~:name": "alias/app-typography", + "~:description": "", + "~:modified-at": "~m1778507716701", + "~:tokens": { + "~#ordered-map": [ + [ + "lineHeight.paragraph", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b8", + "~:name": "lineHeight.paragraph", + "~:type": "~:number", + "~:value": "1.4", + "~:description": "", + "~:modified-at": "~m1778507716656" + } + } + ], + [ + "lineHeight.inline", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c38b9", + "~:name": "lineHeight.inline", + "~:type": "~:number", + "~:value": "1.2", + "~:description": "", + "~:modified-at": "~m1778507716656" + } + } + ] + ] + } + } + } + ], + [ + "S-shadows", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f18b19c", + "~:name": "alias/shadows", + "~:description": "", + "~:modified-at": "~m1778507716706", + "~:tokens": { + "~#ordered-map": [ + [ + "color.shadow.strong", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d63", + "~:name": "color.shadow.strong", + "~:type": "~:color", + "~:value": "rgba(\t24,20,31, 0.30)", + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "shadow.lower.hover", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d68", + "~:name": "shadow.lower.hover", + "~:type": "~:shadow", + "~:value": [ + { + "~:offset-x": "0", + "~:offset-y": "1", + "~:blur": "2", + "~:spread": "0", + "~:color": "{color.shadow.strong}", + "~:inset": false + }, + { + "~:offset-x": "0", + "~:offset-y": "0", + "~:blur": "2", + "~:spread": "0", + "~:color": "{color.shadow.base}", + "~:inset": false + } + ], + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "shadow.lower.default", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d69", + "~:name": "shadow.lower.default", + "~:type": "~:shadow", + "~:value": [ + { + "~:offset-x": "0", + "~:offset-y": "1", + "~:blur": "2", + "~:spread": "0", + "~:color": "{color.shadow.low}", + "~:inset": false + }, + { + "~:offset-x": "0", + "~:offset-y": "0", + "~:blur": "2", + "~:spread": "0", + "~:color": "{color.shadow.base}", + "~:inset": false + } + ], + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "shadow.low.hover", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d6a", + "~:name": "shadow.low.hover", + "~:type": "~:shadow", + "~:value": [ + { + "~:offset-x": "0", + "~:offset-y": "2", + "~:blur": "8", + "~:spread": "0", + "~:color": "{color.shadow.strong}", + "~:inset": false + }, + { + "~:offset-x": "0", + "~:offset-y": "0", + "~:blur": "2", + "~:spread": "0", + "~:color": "{color.shadow.base}", + "~:inset": false + } + ], + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "color.shadow.base", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d64", + "~:name": "color.shadow.base", + "~:type": "~:color", + "~:value": "rgba(\t24,20,31, 0.06)", + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "lower", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d6c", + "~:name": "lower", + "~:type": "~:shadow", + "~:value": [ + { + "~:offset-x": "0", + "~:offset-y": "1", + "~:blur": "2", + "~:spread": "0", + "~:color": "{color.shadow.low}", + "~:inset": false + } + ], + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "color.shadow.stronger", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d65", + "~:name": "color.shadow.stronger", + "~:type": "~:color", + "~:value": "rgba(\t24,20,31, 0.35)", + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "color.shadow.medium", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d66", + "~:name": "color.shadow.medium", + "~:type": "~:color", + "~:value": "rgba(\t24,20,31, 0.25)", + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "shadow.low.default", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d6b", + "~:name": "shadow.low.default", + "~:type": "~:shadow", + "~:value": [ + { + "~:offset-x": "0", + "~:offset-y": "2", + "~:blur": "8", + "~:spread": "0", + "~:color": "{color.shadow.low}", + "~:inset": false + }, + { + "~:offset-x": "0", + "~:offset-y": "0", + "~:blur": "2", + "~:spread": "0", + "~:color": "{color.shadow.base}", + "~:inset": false + } + ], + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "color.shadow.low", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d67", + "~:name": "color.shadow.low", + "~:type": "~:color", + "~:value": "rgba(\t24,20,31, 0.20)", + "~:description": "", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "base.shadow", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d6d", + "~:name": "base.shadow", + "~:type": "~:shadow", + "~:value": [ + { + "~:offset-x": "0", + "~:offset-y": "0", + "~:blur": "2", + "~:spread": "0", + "~:color": "{color.shadow.base}", + "~:inset": false + } + ], + "~:description": "sombra común", + "~:modified-at": "~m1778507716657" + } + } + ] + ] + } + } + } + ] + ] + } + ], + [ + "G-components", + { + "~#ordered-map": [ + [ + "S-section-message", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f1a31f0", + "~:name": "components/section-message", + "~:description": "", + "~:modified-at": "~m1778507716712", + "~:tokens": { + "~#ordered-map": [ + [ + "xx.component.sectionMessage.warning.icon", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d6e", + "~:name": "xx.component.sectionMessage.warning.icon", + "~:type": "~:color", + "~:value": "{xx.alias.color.purpose.onWarning}", + "~:description": "icon color for warning section messages", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.warning.background", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d6f", + "~:name": "xx.component.sectionMessage.warning.background", + "~:type": "~:color", + "~:value": "{xx.alias.color.purpose.warningHighEmphasis}", + "~:description": "background color for warning section messages", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.borderRadius", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d71", + "~:name": "xx.component.sectionMessage.borderRadius", + "~:type": "~:border-radius", + "~:value": "{xx.alias.border.radius.md}", + "~:description": "border radius for section messages", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.spacing.innerY", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d72", + "~:name": "xx.component.sectionMessage.spacing.innerY", + "~:type": "~:spacing", + "~:value": "{xx.alias.spacing.md}", + "~:description": "top and bottom inner spacing for section messages", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.height.min", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d75", + "~:name": "xx.component.sectionMessage.height.min", + "~:type": "~:sizing", + "~:value": "{xx.alias.size.md}", + "~:description": "min height of section messages", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.success.background", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d76", + "~:name": "xx.component.sectionMessage.success.background", + "~:type": "~:color", + "~:value": "{xx.alias.color.purpose.successHighEmphasis}", + "~:description": "background color for success section messages ", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.spacing.innerX", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d73", + "~:name": "xx.component.sectionMessage.spacing.innerX", + "~:type": "~:spacing", + "~:value": "{xx.alias.spacing.sm}", + "~:description": "left and right inner spacing for section messages", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.warning.text", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d70", + "~:name": "xx.component.sectionMessage.warning.text", + "~:type": "~:color", + "~:value": "{xx.alias.color.purpose.onWarning}", + "~:description": "text color for warning section messages", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.spacing.gap", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d74", + "~:name": "xx.component.sectionMessage.spacing.gap", + "~:type": "~:spacing", + "~:value": "{xx.alias.spacing.xs}", + "~:description": "gap for separating elements in section message", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.success.icon", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d77", + "~:name": "xx.component.sectionMessage.success.icon", + "~:type": "~:color", + "~:value": "{xx.alias.color.purpose.onSuccess}", + "~:description": "icon color for success section messages", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.component.sectionMessage.success.text", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d78", + "~:name": "xx.component.sectionMessage.success.text", + "~:type": "~:color", + "~:value": "{xx.alias.color.purpose.onSuccess}", + "~:description": "text color for success section messages", + "~:modified-at": "~m1778507716657" + } + } + ] + ] + } + } + } + ] + ] + } + ], + [ + "G-wl-themes", + { + "~#ordered-map": [ + [ + "S-client_theme_template", + { + "~#penpot/token-set": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f1eae34", + "~:name": "wl-themes/client_theme_template", + "~:description": "", + "~:modified-at": "~m1778507716730", + "~:tokens": { + "~#ordered-map": [ + [ + "xx.alias.color.purpose.onInfo", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d45", + "~:name": "xx.alias.color.purpose.onInfo", + "~:type": "~:color", + "~:value": "#ffffff", + "~:description": "color for elements placed on informational purpose background", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.border.heavy", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d4c", + "~:name": "xx.alias.color.border.heavy", + "~:type": "~:color", + "~:value": "#728090", + "~:description": "heavy border color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.select", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d50", + "~:name": "xx.alias.color.state.select", + "~:type": "~:color", + "~:value": "#B4B4F2", + "~:description": "background color for selected elements", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.primary.onBrand", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d56", + "~:name": "xx.alias.color.primary.onBrand", + "~:type": "~:color", + "~:value": "#f5f5fa", + "~:description": "color for elements that are placed on brand background color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.warningHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d4a", + "~:name": "xx.alias.color.purpose.warningHighEmphasis", + "~:type": "~:color", + "~:value": "#f1c40f", + "~:description": "color for elements with warning purpose of high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.onSelect", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d51", + "~:name": "xx.alias.color.state.onSelect", + "~:type": "~:color", + "~:value": "#0707D3", + "~:description": "Foreground color for selected elements", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.primary.interaction", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d57", + "~:name": "xx.alias.color.primary.interaction", + "~:type": "~:color", + "~:value": "#DC7258", + "~:description": "Color that indicates interactions", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.border.focusOutline", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d4d", + "~:name": "xx.alias.color.border.focusOutline", + "~:type": "~:color", + "~:value": "#0505A3", + "~:description": "color for default focus outline", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.disable", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d52", + "~:name": "xx.alias.color.state.disable", + "~:type": "~:color", + "~:value": "#bdc3c7", + "~:description": "background color for disabled elements", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.infoHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d4b", + "~:name": "xx.alias.color.purpose.infoHighEmphasis", + "~:type": "~:color", + "~:value": "#2980b9", + "~:description": "color for elements with informational purpose of high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.infoLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d40", + "~:name": "xx.alias.color.purpose.infoLowEmphasis", + "~:type": "~:color", + "~:value": "#2980b9", + "~:description": "color for elements with informational purpose of low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.primary.brand", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d58", + "~:name": "xx.alias.color.primary.brand", + "~:type": "~:color", + "~:value": "#3333C2", + "~:description": "background color for primary brand elements ", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.text.default", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d5a", + "~:name": "xx.alias.color.text.default", + "~:type": "~:color", + "~:value": "#353535", + "~:description": "Default text color ", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.text.inverted", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d5b", + "~:name": "xx.alias.color.text.inverted", + "~:type": "~:color", + "~:value": "#f5f5fa", + "~:description": "Inverted text color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.onSuccess", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d48", + "~:name": "xx.alias.color.purpose.onSuccess", + "~:type": "~:color", + "~:value": "#ffffff", + "~:description": "color for elements placed on success purpose background", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.criticalLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d46", + "~:name": "xx.alias.color.purpose.criticalLowEmphasis", + "~:type": "~:color", + "~:value": "#e74c3c", + "~:description": "color for elements with critical purpose of low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.background.highEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d5d", + "~:name": "xx.alias.color.background.highEmphasis", + "~:type": "~:color", + "~:value": "#ffffff", + "~:description": "background Color for components with high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.border.radius.md", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d60", + "~:name": "xx.alias.border.radius.md", + "~:type": "~:border-radius", + "~:value": "4px", + "~:description": "medium border radius", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.background.body", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d5e", + "~:name": "xx.alias.color.background.body", + "~:type": "~:color", + "~:value": "#E3E6E9", + "~:description": "body background color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.successLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d44", + "~:name": "xx.alias.color.purpose.successLowEmphasis", + "~:type": "~:color", + "~:value": "#2ecc71", + "~:description": "color for elements with success purpose of low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.primary.onInteraction", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d59", + "~:name": "xx.alias.color.primary.onInteraction", + "~:type": "~:color", + "~:value": "#f5f5fa", + "~:description": "color for elements that are placed on interactive background colors", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.onCritical", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d41", + "~:name": "xx.alias.color.purpose.onCritical", + "~:type": "~:color", + "~:value": "#ffffff", + "~:description": "color for elements placed on critical purpose background", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.criticalHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d42", + "~:name": "xx.alias.color.purpose.criticalHighEmphasis", + "~:type": "~:color", + "~:value": "#e74c3c", + "~:description": "color for elements with critical purpose of high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.border.radius.lg", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d61", + "~:name": "xx.alias.border.radius.lg", + "~:type": "~:border-radius", + "~:value": "8px", + "~:description": "large border radius", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.border.medium", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d4e", + "~:name": "xx.alias.color.border.medium", + "~:type": "~:color", + "~:value": "#9AA5B1", + "~:description": "medium border color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.border.subtle", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d4f", + "~:name": "xx.alias.color.border.subtle", + "~:type": "~:color", + "~:value": "#C3C9D0", + "~:description": "subtle border color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.background.lowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d5f", + "~:name": "xx.alias.color.background.lowEmphasis", + "~:type": "~:color", + "~:value": "#F6F7F8", + "~:description": "background color for elements with a low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.onWarning", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d47", + "~:name": "xx.alias.color.purpose.onWarning", + "~:type": "~:color", + "~:value": "#ffffff", + "~:description": "color for elements placed on warning purpose background", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.text.subtle", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d5c", + "~:name": "xx.alias.color.text.subtle", + "~:type": "~:color", + "~:value": "#9E9E9E", + "~:description": "Text color in subtle weight", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.successHighEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d43", + "~:name": "xx.alias.color.purpose.successHighEmphasis", + "~:type": "~:color", + "~:value": "#2ecc71", + "~:description": "color for elements with success purpose of high emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.onDisable", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d53", + "~:name": "xx.alias.color.state.onDisable", + "~:type": "~:color", + "~:value": "#7f8c8d", + "~:description": "color for elements that are palced on disabled background color", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.border.radius.sm", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d62", + "~:name": "xx.alias.border.radius.sm", + "~:type": "~:border-radius", + "~:value": "0", + "~:description": "small border radius", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.selectInverted", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d54", + "~:name": "xx.alias.color.state.selectInverted", + "~:type": "~:color", + "~:value": "#0707D3", + "~:description": "Inverted background color for selected elements", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.purpose.warningLowEmphasis", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d49", + "~:name": "xx.alias.color.purpose.warningLowEmphasis", + "~:type": "~:color", + "~:value": "#f1c40f", + "~:description": "color for elements with warning purpose of low emphasis", + "~:modified-at": "~m1778507716657" + } + } + ], + [ + "xx.alias.color.state.onSelectInverted", + { + "~#penpot/token": { + "~:id": "~u4cdd76d8-0e6d-8168-8008-01189f0c4d55", + "~:name": "xx.alias.color.state.onSelectInverted", + "~:type": "~:color", + "~:value": "#B4B4F2", + "~:description": "inverted color for elements on selected backgrounds", + "~:modified-at": "~m1778507716657" + } + } + ] + ] + } + } + } + ] + ] + } + ] + ] + }, + "~:themes": { + "~#ordered-map": [ + [ + "", + { + "~#ordered-map": [ + [ + "__PENPOT__HIDDEN__TOKEN__THEME__", + { + "~#penpot/token-theme": { + "~:id": "~u00000000-0000-0000-0000-000000000000", + "~:name": "__PENPOT__HIDDEN__TOKEN__THEME__", + "~:group": "", + "~:description": "", + "~:is-source": false, + "~:external-id": "", + "~:modified-at": "~m1778507716730", + "~:sets": { + "~#set": [ + "alias/border", + "global/dimension", + "global/color", + "alias/color-light", + "global/Opacity", + "alias/dimension" + ] + } + } + } + ] + ] + } + ], + [ + "Global", + { + "~#ordered-map": [ + [ + "Brand", + { + "~#penpot/token-theme": { + "~:id": "~uc00d9d2e-76f9-815b-8005-e1260332abac", + "~:name": "Brand", + "~:group": "Global", + "~:description": "", + "~:is-source": true, + "~:external-id": "c00d9d2e-76f9-815b-8005-e1260332abac", + "~:modified-at": "~m1778507716656", + "~:sets": { + "~#set": [ + "global/dimension", + "global/color", + "global/Opacity" + ] + } + } + } + ] + ] + } + ], + [ + "Alias", + { + "~#ordered-map": [ + [ + "Light Mode", + { + "~#penpot/token-theme": { + "~:id": "~uc00d9d2e-76f9-815b-8005-e1260332abb0", + "~:name": "Light Mode", + "~:group": "Alias", + "~:description": "", + "~:is-source": true, + "~:external-id": "c00d9d2e-76f9-815b-8005-e1260332abb0", + "~:modified-at": "~m1778507716656", + "~:sets": { + "~#set": [ + "alias/border", + "alias/color-light", + "alias/dimension" + ] + } + } + } + ], + [ + "Dark Mode", + { + "~#penpot/token-theme": { + "~:id": "~uc00d9d2e-76f9-815b-8005-e1260332abb2", + "~:name": "Dark Mode", + "~:group": "Alias", + "~:description": "", + "~:is-source": true, + "~:external-id": "c00d9d2e-76f9-815b-8005-e1260332abb2", + "~:modified-at": "~m1778507716656", + "~:sets": { + "~#set": [ + "alias/border", + "alias/color-dark", + "alias/dimension" + ] + } + } + } + ] + ] + } + ], + [ + "Components", + { + "~#ordered-map": [ + [ + "Section Message", + { + "~#penpot/token-theme": { + "~:id": "~uc00d9d2e-76f9-815b-8005-e1260332abb4", + "~:name": "Section Message", + "~:group": "Components", + "~:description": "", + "~:is-source": true, + "~:external-id": "c00d9d2e-76f9-815b-8005-e1260332abb4", + "~:modified-at": "~m1778507716656", + "~:sets": { + "~#set": [ + "components/section-message" + ] + } + } + } + ] + ] + } + ], + [ + "White Label", + { + "~#ordered-map": [ + [ + "Client Theme Template", + { + "~#penpot/token-theme": { + "~:id": "~uc00d9d2e-76f9-815b-8005-e1260332abb6", + "~:name": "Client Theme Template", + "~:group": "White Label", + "~:description": "", + "~:is-source": true, + "~:external-id": "c00d9d2e-76f9-815b-8005-e1260332abb6", + "~:modified-at": "~m1778507716656", + "~:sets": { + "~#set": [ + "wl-themes/client_theme_template" + ] + } + } + } + ] + ] + } + ], + [ + "patata", + { + "~#ordered-map": [ + [ + "patatilla", + { + "~#penpot/token-theme": { + "~:id": "~uc00d9d2e-76f9-815b-8005-e1260332abb8", + "~:name": "patatilla", + "~:group": "patata", + "~:description": "", + "~:is-source": false, + "~:external-id": "c00d9d2e-76f9-815b-8005-e1260332abb8", + "~:modified-at": "~m1778507716656", + "~:sets": { + "~#set": [] + } + } + } + ] + ] + } + ], + [ + "typography", + { + "~#ordered-map": [ + [ + "web", + { + "~#penpot/token-theme": { + "~:id": "~u312c1822-c99f-807a-8006-62605689cee0", + "~:name": "web", + "~:group": "typography", + "~:description": "", + "~:is-source": false, + "~:external-id": "312c1822-c99f-807a-8006-62605689cee0", + "~:modified-at": "~m1778507716656", + "~:sets": { + "~#set": [ + "alias/web-typography" + ] + } + } + } + ], + [ + "app", + { + "~#penpot/token-theme": { + "~:id": "~u312c1822-c99f-807a-8006-626064817196", + "~:name": "app", + "~:group": "typography", + "~:description": "", + "~:is-source": false, + "~:external-id": "312c1822-c99f-807a-8006-626064817196", + "~:modified-at": "~m1778507716656", + "~:sets": { + "~#set": [ + "alias/app-typography" + ] + } + } + } + ] + ] + } + ] + ] + }, + "~:active-themes": { + "~#set": [ + "Global/Brand", + "Alias/Light Mode", + "/__PENPOT__HIDDEN__TOKEN__THEME__" + ] + } + } + }, + "~:id": "~u1bac06a1-a942-80a6-8008-0222e1ec38d5", + "~:options": { + "~:components-v2": true, + "~:base-font-size": "16px" + } + } +} \ No newline at end of file diff --git a/frontend/playwright/ui/pages/WorkspacePage.js b/frontend/playwright/ui/pages/WorkspacePage.js index ec963f718a..e8e3a062b6 100644 --- a/frontend/playwright/ui/pages/WorkspacePage.js +++ b/frontend/playwright/ui/pages/WorkspacePage.js @@ -172,6 +172,7 @@ export class WorkspacePage extends BaseWebSocketPage { this.toolbarOptions = page.getByTestId("toolbar-options"); this.rectShapeButton = page.getByRole("button", { name: "Rectangle (R)" }); this.ellipseShapeButton = page.getByRole("button", { name: "Ellipse (E)" }); + this.textShapeButton = page.getByRole("button", { name: "Text (T)" }); this.moveButton = page.getByRole("button", { name: "Move (V)" }); this.boardButton = page.getByRole("button", { name: "Board (B)" }); this.toggleToolbarButton = page.getByRole("button", { diff --git a/frontend/playwright/ui/specs/multiseleccion.spec.js b/frontend/playwright/ui/specs/multiseleccion.spec.js index 5d7ee1c92c..c81e4ef5f2 100644 --- a/frontend/playwright/ui/specs/multiseleccion.spec.js +++ b/frontend/playwright/ui/specs/multiseleccion.spec.js @@ -214,6 +214,11 @@ test("Multiselection of text and typographies", async ({ page }) => { pageId: "1062e0a0-8fe0-80ae-8007-e70b4993f5f0", }); + await workspacePage.mockRPC( + "update-file?id=*", + "workspace/update-file-empty.json", + ); + const plainTextLayer = workspacePage.layers.getByTestId("layer-row").nth(5); const plainTextLayerTwo = workspacePage.layers .getByTestId("layer-row") diff --git a/frontend/playwright/ui/specs/text-editor-v2.spec.js b/frontend/playwright/ui/specs/text-editor-v2.spec.js index c12fef1bba..25676c45e1 100644 --- a/frontend/playwright/ui/specs/text-editor-v2.spec.js +++ b/frontend/playwright/ui/specs/text-editor-v2.spec.js @@ -315,3 +315,19 @@ test("BUG 11552 - Apply styles to the current caret", async ({ page }) => { await expect(fontSizeInput).toHaveValue(""); await expect(fontSizeInput).toHaveAttribute("placeholder", "Mixed"); }); + +// This is to prevent QA tests from failing due to playwright +// considering 0-width text boxes as invisible +test("BUG 14098 - Fix text editor having 0 width or height", async ({ page }) => { + const workspace = new WasmWorkspacePage(page); + + await workspace.setupEmptyFile(); + await workspace.mockRPC("update-file?id=*", "text-editor/update-file.json"); + await workspace.goToWorkspace(); + + await workspace.textShapeButton.click(); + await workspace.clickAt(200, 200); + + const textEditor = workspace.page.locator(`div[class*="viewport"]`).first().getByRole('textbox').first(); + await expect(textEditor).toBeVisible(); +}); diff --git a/frontend/playwright/ui/specs/tokens/apply.spec.js b/frontend/playwright/ui/specs/tokens/apply.spec.js index 8b09827d0f..6272eb7585 100644 --- a/frontend/playwright/ui/specs/tokens/apply.spec.js +++ b/frontend/playwright/ui/specs/tokens/apply.spec.js @@ -1030,6 +1030,56 @@ test("BUG: 13930, Token colors are shown on selected colors section", async ({ ).toBeVisible(); }); +test("BUG: 14136 Apply grid layout padding token to a shape from the sidebar does not change values", async ({ + page, +}) => { + // Setup the workspace with token features enabled + const { workspacePage, tokensSidebar, tokenContextMenuForToken } = + await setupTokensFileRender(page, { + flags: ["enable-token-combobox", "enable-feature-token-input"], + }); + + // Transform a rectangle into a grid container to expose gap properties + await page.getByRole("tab", { name: "Layers" }).click(); + + await workspacePage.layers.getByTestId("layer-row").nth(1).click(); + + const layoutSection = page.getByTestId("inspect-layout"); + await expect(layoutSection).toBeVisible(); + + const addLayoutButton = layoutSection + .getByRole("button", { name: "Add layout" }) + .first(); + await addLayoutButton.click(); + await page.getByText("Grid layout").click(); + + // Apply a dimension token to the vertical padding property + await layoutSection.getByLabel("Open token list").nth(2).click(); + const tokenDimensionMd = layoutSection.getByRole("option", { + name: "dimension.md", + }); + await expect(tokenDimensionMd).toBeVisible(); + await tokenDimensionMd.click(); + + // Expand padding to all sides + await layoutSection.getByRole('button', { name: 'Show 4 sided padding options' }).click(); + const topPaddingSection = layoutSection.getByLabel("Top padding"); + const bottomPaddingSection = layoutSection.getByLabel("Bottom padding"); + await expect(topPaddingSection).toBeVisible(); + + // Check if token is still applied to top and bottom padding + await expect(topPaddingSection.getByLabel("Detach token")).toBeVisible(); + await expect(bottomPaddingSection.getByLabel("Detach token")).toBeVisible(); + + // Check if the value of the attribute is still correct + await expect( + await topPaddingSection.getByRole("button", { name: "dimension.md" }).textContent() + ).toBe("16"); + await expect( + await bottomPaddingSection.getByRole("button", { name: "dimension.md" }).textContent() + ).toBe("16"); +}); + test.describe("Numeric Input and Token Integration Tests", () => { test("Token pill persists after blur in gap inputs", async ({ page }) => { // Setup the workspace with token features enabled diff --git a/frontend/playwright/ui/specs/tokens/text.spec.js b/frontend/playwright/ui/specs/tokens/text.spec.js new file mode 100644 index 0000000000..3c34376934 --- /dev/null +++ b/frontend/playwright/ui/specs/tokens/text.spec.js @@ -0,0 +1,29 @@ +import { test, expect } from "@playwright/test"; +import { WasmWorkspacePage } from "../../pages/WasmWorkspacePage"; + +test.beforeEach(async ({ page }) => { + await WasmWorkspacePage.init(page); +}); + +test("BUG 13958 - Fill token gets detached when editing text shape", async ({ page }) => { + const workspacePage = new WasmWorkspacePage(page); + await workspacePage.setupEmptyFile(); + // Load a file that has a text shape, whose content contains a `:fills []` in the root node. + // This attribute is removed when editing the text, causing the old code to detect that the + // fills had changed and detaching the token. + await workspacePage.mockGetFile("workspace/get-file-13958.json"); + await workspacePage.goToWorkspace(); + + // Check token is attached to the shape + await workspacePage.clickLeafLayer("Design tokens are a set"); + await expect(workspacePage.rightSidebar.getByLabel("xx.alias.color.text.default", { exact: true })).toBeVisible(); + + // Enter and exit the text editor + await workspacePage.page.keyboard.press("Enter"); + await expect(workspacePage.page.getByTestId("text-editor")).toBeVisible(); + await workspacePage.page.keyboard.press("Escape"); + await expect(workspacePage.page.getByTestId("text-editor")).not.toBeAttached(); + + // Assert token is still attached to the shape + await expect(workspacePage.rightSidebar.getByLabel("xx.alias.color.text.default", { exact: true })).toBeVisible(); +}); diff --git a/frontend/playwright/ui/specs/versions.spec.js b/frontend/playwright/ui/specs/versions.spec.js index 2c5fa018f2..98bb92acb0 100644 --- a/frontend/playwright/ui/specs/versions.spec.js +++ b/frontend/playwright/ui/specs/versions.spec.js @@ -121,6 +121,11 @@ test("BUG 13385 - Fix viewport not updating when restoring version", async ({ pa await workspacePage.mockGetFile("workspace/get-file-13385.json"); await workspacePage.mockRPC("get-profiles-for-file-comments?file-id=*", "workspace/get-profiles-for-file-comments-13385.json"); + await workspacePage.mockRPC( + "update-file?id=*", + "workspace/update-file-empty.json", + ); + // navigate to workspace and check that the circle shape is not there await workspacePage.goToWorkspace(); await expect(workspacePage.layers.getByText("Ellipse")).not.toBeVisible(); @@ -141,4 +146,4 @@ test("BUG 13385 - Fix viewport not updating when restoring version", async ({ pa // assert that the circle shape exists await expect(workspacePage.layers.getByText("Ellipse")).toBeVisible(); -}); \ No newline at end of file +}); diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index c627ac673c..e5a8160398 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -203,6 +203,38 @@ (rx/of (ptk/data-event ::all-libraries-resolved {:file-id file-id}))) (rx/take-until stopper-s)))))) + +(defn check-file-position-data + [file-id] + (ptk/reify ::fix-position-data + ptk/WatchEvent + (watch [it state _] + (let [file (dsh/lookup-file state file-id) + changes + (->> file :data :pages + (mapcat + (fn [page-id] + (->> (dsh/lookup-page-objects state file-id page-id) + (vals) + (filter cfh/text-shape?) + (filter #(nil? (:position-data %))) + (map (fn [shape] + {:type :mod-obj + :id (:id shape) + :page-id page-id + :operations + [{:type :set + :attr :position-data + :val (wasm.api/calculate-position-data shape) + :ignore-touched true + :ignore-geometry true}]}))))) + (into []))] + (rx/of (dch/commit-changes + {:redo-changes changes :undo-changes [] + :save-undo? false + :origin it + :tags #{:position-data}})))))) + (defn- workspace-initialized [file-id] (ptk/reify ::workspace-initialized diff --git a/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs b/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs index 779e7097aa..a92b0bf07b 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs @@ -423,8 +423,8 @@ (obj/merge! #js {"--editor-container-width" "auto" "--editor-container-height" "auto" - "--editor-container-min-width" (dm/str selrect-width "px") - "--editor-container-min-height" (dm/str selrect-height "px") + "--editor-container-min-width" (dm/str (max 1 selrect-width) "px") + "--editor-container-min-height" (dm/str (max 1 selrect-height) "px") "--fallback-families" (if (seq fallback-families) (dm/str (str/join ", " fallback-families)) "sourcesanspro") :display "flex"}) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index dd992ce08b..08e1774904 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -1377,6 +1377,7 @@ [:div {:class (stl/css :padding-row)} [:> padding-section* {:value (:layout-padding values) :type (:layout-padding-type values) + :ids ids :applied-tokens applied-tokens :on-type-change on-padding-type-change :on-change on-padding-change}]]] diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs index 5d3a1b95dd..88d9332ef1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs @@ -220,10 +220,11 @@ name] [:div {:class (stl/css :page-actions)} (when (and deletable? (not read-only?)) - [:> icon-button* {:variant "ghost" + [:> icon-button* {:variant "action" :aria-label (tr "modals.delete-page.title") :on-click on-delete :icon-size "s" + :icon-class (stl/css :page-delete-button-icon) :icon i/delete}])]])])]]))) ;; --- Page Item Wrapper diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss b/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss index 72f028d09c..b642d89450 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss @@ -55,6 +55,10 @@ margin-bottom: deprecated.$s-12; } +.page-delete-button-icon { + color: transparent; +} + .page-element { @include deprecated.body-small-typography; @@ -102,23 +106,6 @@ height: deprecated.$s-32; display: flex; align-items: center; - - button { - @include deprecated.button-style; - @include deprecated.flex-center; - - width: deprecated.$s-24; - height: 100%; - opacity: deprecated.$op-0; - - svg { - @extend %button-icon-small; - - color: transparent; - fill: none; - stroke: var(--icon-foreground); - } - } } .element-name { diff --git a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs index c332049ca1..3de2bb2fb1 100644 --- a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs +++ b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs @@ -17,6 +17,7 @@ [app.common.types.shape :as cts] [app.common.types.shape.layout :as ctl] [app.main.data.modal :as modal] + [app.main.data.workspace :as dw] [app.main.data.workspace.transforms :as dwt] [app.main.data.workspace.variants :as dwv] [app.main.features :as features] @@ -455,7 +456,10 @@ ;; blank canvas (first load) visible while shapes load. ;; The loading overlay is suppressed because on-shapes-ready ;; is set. - (wasm.api/initialize-viewport base-objects zoom vbox :background background) + (wasm.api/initialize-viewport base-objects zoom vbox + :background background + :on-shapes-ready + #(st/emit! (dw/check-file-position-data file-id))) (reset! initialized? true)) (when (and (some? vern) (not= vern (mf/ref-val last-vern-ref))) diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 74cc7478fe..c1ebc94839 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -121,9 +121,11 @@ pub extern "C" fn render(timestamp: i32) -> Result<()> { // modifier set, so the cost is paid once per rAF rather than // once per pointer move. if get_render_state().options.is_interactive_transform() { - let ids = state.shapes.modifier_ids(); + // Collect into an owned Vec to release the immutable borrow on + // `state.shapes` before the mutable `rebuild_modifier_tiles` call. + let ids = state.shapes.modifier_ids().to_vec(); if !ids.is_empty() { - state.rebuild_modifier_tiles(ids)?; + state.rebuild_modifier_tiles(&ids)?; } } state @@ -856,9 +858,8 @@ pub extern "C" fn set_modifiers() -> Result<()> { with_state!(state, { state.set_modifiers(modifiers); - // TO CHECK if !get_render_state().options.is_interactive_transform() { - state.rebuild_modifier_tiles(ids)?; + state.rebuild_modifier_tiles(&ids)?; } }); Ok(()) diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index 416c13bb0c..72cc2078f2 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -3040,24 +3040,27 @@ impl RenderState { // modified shapes (doc-space @ 100% zoom, scale=1.0). This is used as a cheap overlap // guard to decide when cached top-level crops are unsafe to reuse (something is moving // over/inside them), without doing expensive ancestor walks per node. - let moved_bounds = - if self.options.is_interactive_transform() && !tree.modifier_ids().is_empty() { - let mut acc: Option = None; - for id in tree.modifier_ids().iter() { - let Some(s) = tree.get(id) else { continue }; - let r = self.get_cached_extrect(s, tree, 1.0); - acc = Some(match acc { - None => r, - Some(mut prev) => { - prev.join(r); - prev - } - }); - } - acc - } else { - None - }; + // + // `modifier_ids` is pre-computed once here and reused throughout the loop to avoid + // repeated allocations (formerly O(N_shapes) HashMap builds) per node. + let modifier_ids = tree.modifier_ids(); + let moved_bounds = if self.options.is_interactive_transform() && !modifier_ids.is_empty() { + let mut acc: Option = None; + for id in modifier_ids.iter() { + let Some(s) = tree.get(id) else { continue }; + let r = self.get_cached_extrect(s, tree, 1.0); + acc = Some(match acc { + None => r, + Some(mut prev) => { + prev.join(r); + prev + } + }); + } + acc + } else { + None + }; while let Some(node_render_state) = self.pending_nodes.pop() { let node_id = node_render_state.id; @@ -3136,7 +3139,7 @@ impl RenderState { let use_cached = self.should_use_cached_top_level_during_interactive( node_id, tree, - &tree.modifier_ids(), + modifier_ids, moved_bounds, ); @@ -3857,7 +3860,7 @@ impl RenderState { pub fn rebuild_modifier_tiles( &mut self, tree: ShapesPoolMutRef<'_>, - ids: Vec, + ids: &[Uuid], ) -> Result<()> { // During interactive transform, skip ancestor invalidation: walking up to the // parent frame evicts every tile the frame covers, including dense tiles with @@ -3865,9 +3868,9 @@ impl RenderState { // `ShapesPool::set_modifiers`; the tile index is reconciled post-gesture by // the committing code path (rebuild_touched_tiles). if self.options.is_interactive_transform() { - self.update_tiles_shapes(&ids, tree)?; + self.update_tiles_shapes(ids, tree)?; } else { - let ancestors = all_with_ancestors(&ids, tree, false); + let ancestors = all_with_ancestors(ids, tree, false); self.update_tiles_shapes(&ancestors, tree)?; } Ok(()) diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index 5eed9d66fb..116e7a67c4 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -225,8 +225,7 @@ impl State { let _ = get_render_state().render_preview(&self.shapes, timestamp); } - pub fn rebuild_modifier_tiles(&mut self, ids: Vec) -> Result<()> { - // Index-based storage is safe + pub fn rebuild_modifier_tiles(&mut self, ids: &[Uuid]) -> Result<()> { get_render_state().rebuild_modifier_tiles(&mut self.shapes, ids) } diff --git a/render-wasm/src/state/shapes_pool.rs b/render-wasm/src/state/shapes_pool.rs index 9f19dbc50a..d51ce1cabe 100644 --- a/render-wasm/src/state/shapes_pool.rs +++ b/render-wasm/src/state/shapes_pool.rs @@ -49,6 +49,11 @@ pub struct ShapesPoolImpl { modified_shape_cache: HashMap>, /// Transform modifiers, keyed by index modifiers: HashMap, + /// UUIDs of shapes that have an active transform modifier, kept in sync + /// with `modifiers`. Stored explicitly so that `modifier_ids()` is O(K) + /// (K = number of modified shapes) instead of O(N_shapes) — avoids + /// building a full reverse-index HashMap on every call. + modifier_uuids: Vec, /// Structure entries, keyed by index structure: HashMap>, /// Scale content values, keyed by index @@ -69,6 +74,7 @@ impl ShapesPoolImpl { modified_shape_cache: HashMap::default(), modifiers: HashMap::default(), + modifier_uuids: Vec::new(), structure: HashMap::default(), scale_content: HashMap::default(), } @@ -238,7 +244,11 @@ impl ShapesPoolImpl { } self.modifiers = modifiers_with_idx; + // Compute ancestors before consuming `ids` so we can move it into + // `modifier_uuids` without a clone. let all_ids = shapes::all_with_ancestors(&ids, self, true); + // Keep modifier_uuids in sync so modifier_ids() is O(K) not O(N_shapes). + self.modifier_uuids = ids; for uuid in all_ids { if let Some(idx) = self.uuid_to_idx.get(&uuid).copied() { self.modified_shape_cache.insert(idx, OnceCell::new()); @@ -300,19 +310,9 @@ impl ShapesPoolImpl { pub fn clean_all(&mut self) -> Vec { self.clean_shape_cache(); - let modified_uuids: Vec = if self.modifiers.is_empty() { - Vec::new() - } else { - let mut idx_to_uuid: HashMap = - HashMap::with_capacity(self.uuid_to_idx.len()); - for (uuid, idx) in self.uuid_to_idx.iter() { - idx_to_uuid.insert(*idx, *uuid); - } - self.modifiers - .keys() - .filter_map(|idx| idx_to_uuid.get(idx).copied()) - .collect() - }; + // `modifier_uuids` is kept in sync with `modifiers` by `set_modifiers`, + // so we can take it directly — no need to rebuild a reverse index. + let modified_uuids = std::mem::take(&mut self.modifier_uuids); self.modifiers = HashMap::default(); self.structure = HashMap::default(); @@ -325,18 +325,12 @@ impl ShapesPoolImpl { /// Used by the throttled drag path so per-rAF tile invalidation can /// be done once with the current modifier set instead of once per /// pointer move. - pub fn modifier_ids(&self) -> Vec { - if self.modifiers.is_empty() { - return Vec::new(); - } - let mut idx_to_uuid: HashMap = HashMap::with_capacity(self.uuid_to_idx.len()); - for (uuid, idx) in self.uuid_to_idx.iter() { - idx_to_uuid.insert(*idx, *uuid); - } - self.modifiers - .keys() - .filter_map(|idx| idx_to_uuid.get(idx).copied()) - .collect() + /// + /// Returns a reference to avoid allocation on every call — callers + /// inside hot render loops should hold this reference rather than + /// calling `modifier_ids()` repeatedly. + pub fn modifier_ids(&self) -> &[Uuid] { + &self.modifier_uuids } pub fn subtree(&self, id: &Uuid) -> ShapesPoolImpl { @@ -363,6 +357,7 @@ impl ShapesPoolImpl { uuid_to_idx, modified_shape_cache: HashMap::default(), modifiers: HashMap::default(), + modifier_uuids: Vec::new(), structure: HashMap::default(), scale_content: HashMap::default(), } @@ -409,6 +404,7 @@ impl Clone for ShapesPoolImpl { // so it gets lazily rebuilt on demand rather than cloning OnceCell state. modified_shape_cache: HashMap::default(), modifiers: self.modifiers.clone(), + modifier_uuids: self.modifier_uuids.clone(), structure: self.structure.clone(), scale_content: self.scale_content.clone(), }