mirror of
https://github.com/penpot/penpot.git
synced 2026-08-01 10:56:20 +00:00
Merge tag '2.13.0-RC9'
This commit is contained in:
commit
abc1773f65
16
.github/workflows/plugins-deploy-api-doc.yml
vendored
16
.github/workflows/plugins-deploy-api-doc.yml
vendored
@ -11,7 +11,7 @@ on:
|
|||||||
- "plugins/libs/plugin-types/REAME.md"
|
- "plugins/libs/plugin-types/REAME.md"
|
||||||
- "plugins/tools/typedoc.css"
|
- "plugins/tools/typedoc.css"
|
||||||
- "plugins/CHANGELOG.md"
|
- "plugins/CHANGELOG.md"
|
||||||
- "plugins/wrangler-penpot-plugins-api-doc.toml"
|
- "plugins/wrangle-penpot-plugins-api-doc.toml"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
gh_ref:
|
gh_ref:
|
||||||
@ -98,16 +98,4 @@ jobs:
|
|||||||
workingDirectory: plugins
|
workingDirectory: plugins
|
||||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
command: deploy --config wrangler-penpot-plugins-api-doc.toml --name ${{ env.WORKER_NAME }}
|
command: deploy --config wrangle-penpot-plugins-api-doc.toml --name ${{ env.WORKER_NAME }}
|
||||||
|
|
||||||
- name: Notify Mattermost
|
|
||||||
if: failure()
|
|
||||||
uses: mattermost/action-mattermost-notify@master
|
|
||||||
with:
|
|
||||||
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK }}
|
|
||||||
MATTERMOST_CHANNEL: bot-alerts-cicd
|
|
||||||
TEXT: |
|
|
||||||
❌ 🧩📚 *[PENPOT PLUGINS] Error deploying API documentation.*
|
|
||||||
📄 Triggered from ref: `${{ inputs.gh_ref }}`
|
|
||||||
🔗 Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
||||||
@infra
|
|
||||||
|
|||||||
25
.github/workflows/tests.yml
vendored
25
.github/workflows/tests.yml
vendored
@ -21,7 +21,7 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
name: "Linter"
|
name: "Linter"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -34,7 +34,7 @@ jobs:
|
|||||||
|
|
||||||
test-common:
|
test-common:
|
||||||
name: "Common Tests"
|
name: "Common Tests"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -53,7 +53,8 @@ jobs:
|
|||||||
|
|
||||||
test-plugins:
|
test-plugins:
|
||||||
name: Plugins Runtime Linter & Tests
|
name: Plugins Runtime Linter & Tests
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
|
container: penpotapp/devenv:latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@ -98,7 +99,7 @@ jobs:
|
|||||||
|
|
||||||
test-frontend:
|
test-frontend:
|
||||||
name: "Frontend Tests"
|
name: "Frontend Tests"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -119,7 +120,7 @@ jobs:
|
|||||||
|
|
||||||
test-render-wasm:
|
test-render-wasm:
|
||||||
name: "Render WASM Tests"
|
name: "Render WASM Tests"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -143,7 +144,7 @@ jobs:
|
|||||||
|
|
||||||
test-backend:
|
test-backend:
|
||||||
name: "Backend Tests"
|
name: "Backend Tests"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
|
|
||||||
services:
|
services:
|
||||||
@ -182,7 +183,7 @@ jobs:
|
|||||||
|
|
||||||
test-library:
|
test-library:
|
||||||
name: "Library Tests"
|
name: "Library Tests"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -196,7 +197,7 @@ jobs:
|
|||||||
|
|
||||||
build-integration:
|
build-integration:
|
||||||
name: "Build Integration Bundle"
|
name: "Build Integration Bundle"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -217,7 +218,7 @@ jobs:
|
|||||||
|
|
||||||
test-integration-1:
|
test-integration-1:
|
||||||
name: "Integration Tests 1/4"
|
name: "Integration Tests 1/4"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
needs: build-integration
|
needs: build-integration
|
||||||
|
|
||||||
@ -247,7 +248,7 @@ jobs:
|
|||||||
|
|
||||||
test-integration-2:
|
test-integration-2:
|
||||||
name: "Integration Tests 2/4"
|
name: "Integration Tests 2/4"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
needs: build-integration
|
needs: build-integration
|
||||||
|
|
||||||
@ -277,7 +278,7 @@ jobs:
|
|||||||
|
|
||||||
test-integration-3:
|
test-integration-3:
|
||||||
name: "Integration Tests 3/4"
|
name: "Integration Tests 3/4"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
needs: build-integration
|
needs: build-integration
|
||||||
|
|
||||||
@ -307,7 +308,7 @@ jobs:
|
|||||||
|
|
||||||
test-integration-4:
|
test-integration-4:
|
||||||
name: "Integration Tests 4/4"
|
name: "Integration Tests 4/4"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-02
|
||||||
container: penpotapp/devenv:latest
|
container: penpotapp/devenv:latest
|
||||||
needs: build-integration
|
needs: build-integration
|
||||||
|
|
||||||
|
|||||||
40
.travis.yml
40
.travis.yml
@ -1,40 +0,0 @@
|
|||||||
dist: xenial
|
|
||||||
|
|
||||||
language: generic
|
|
||||||
sudo: required
|
|
||||||
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $HOME/.m2
|
|
||||||
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
- develop
|
|
||||||
|
|
||||||
install:
|
|
||||||
- curl -O https://download.clojure.org/install/linux-install-1.10.1.447.sh
|
|
||||||
- chmod +x linux-install-1.10.1.447.sh
|
|
||||||
- sudo ./linux-install-1.10.1.447.sh
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- env | sort
|
|
||||||
|
|
||||||
script:
|
|
||||||
- ./manage.sh build-devenv
|
|
||||||
- ./manage.sh run-frontend-tests
|
|
||||||
- ./manage.sh run-backend-tests
|
|
||||||
- ./manage.sh build-images
|
|
||||||
- ./manage.sh run
|
|
||||||
|
|
||||||
after_script:
|
|
||||||
- docker images
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
||||||
|
|
||||||
env:
|
|
||||||
- NODE_VERSION=10.16.0
|
|
||||||
@ -29,6 +29,13 @@
|
|||||||
- Fix missing text color token from selected shapes in selected colors list [Taiga #12956](https://tree.taiga.io/project/penpot/issue/12956)
|
- Fix missing text color token from selected shapes in selected colors list [Taiga #12956](https://tree.taiga.io/project/penpot/issue/12956)
|
||||||
- Fix dropdown option width in Guides columns dropdown [Taiga #12959](https://tree.taiga.io/project/penpot/issue/12959)
|
- Fix dropdown option width in Guides columns dropdown [Taiga #12959](https://tree.taiga.io/project/penpot/issue/12959)
|
||||||
- Fix typos on download modal [Taiga #12865](https://tree.taiga.io/project/penpot/issue/12865)
|
- Fix typos on download modal [Taiga #12865](https://tree.taiga.io/project/penpot/issue/12865)
|
||||||
|
- Fix unhandled exception tokens creation dialog [Github #8110](https://github.com/penpot/penpot/issues/8110)
|
||||||
|
- Fix allow negative spread values on shadow token creation [Taiga #13167](https://tree.taiga.io/project/penpot/issue/13167)
|
||||||
|
- Fix spanish translations on import export token modal [Taiga #13171](https://tree.taiga.io/project/penpot/issue/13171)
|
||||||
|
- Remove whitespaces from asset export filename [Github #8133](https://github.com/penpot/penpot/pull/8133)
|
||||||
|
- Fix exception on uploading large fonts [Github #8135](https://github.com/penpot/penpot/pull/8135)
|
||||||
|
- Fix unhandled exception on open-new-window helper [Github #7787](https://github.com/penpot/penpot/issues/7787)
|
||||||
|
- Fix incorrect handling of input values on layout gap and padding inputs [Github #8113](https://github.com/penpot/penpot/issues/8113)
|
||||||
|
|
||||||
|
|
||||||
## 2.12.1
|
## 2.12.1
|
||||||
|
|||||||
@ -124,8 +124,6 @@
|
|||||||
(throw (IllegalArgumentException. "invalid email body provided")))
|
(throw (IllegalArgumentException. "invalid email body provided")))
|
||||||
|
|
||||||
(doseq [[name content] attachments]
|
(doseq [[name content] attachments]
|
||||||
|
|
||||||
(prn "attachment" name)
|
|
||||||
(let [attachment-part (MimeBodyPart.)]
|
(let [attachment-part (MimeBodyPart.)]
|
||||||
(.setFileName attachment-part ^String name)
|
(.setFileName attachment-part ^String name)
|
||||||
(.setContent attachment-part ^String content (str "text/plain; charset=" charset))
|
(.setContent attachment-part ^String content (str "text/plain; charset=" charset))
|
||||||
|
|||||||
@ -27,7 +27,17 @@
|
|||||||
[app.rpc.helpers :as rph]
|
[app.rpc.helpers :as rph]
|
||||||
[app.rpc.quotes :as quotes]
|
[app.rpc.quotes :as quotes]
|
||||||
[app.storage :as sto]
|
[app.storage :as sto]
|
||||||
[app.util.services :as sv]))
|
[app.storage.tmp :as tmp]
|
||||||
|
[app.util.services :as sv]
|
||||||
|
[datoteka.io :as io])
|
||||||
|
(:import
|
||||||
|
java.io.InputStream
|
||||||
|
java.io.OutputStream
|
||||||
|
java.io.SequenceInputStream
|
||||||
|
java.util.Collections))
|
||||||
|
|
||||||
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
|
|
||||||
(def valid-weight #{100 200 300 400 500 600 700 800 900 950})
|
(def valid-weight #{100 200 300 400 500 600 700 800 900 950})
|
||||||
(def valid-style #{"normal" "italic"})
|
(def valid-style #{"normal" "italic"})
|
||||||
@ -105,7 +115,7 @@
|
|||||||
|
|
||||||
(defn create-font-variant
|
(defn create-font-variant
|
||||||
[{:keys [::sto/storage ::db/conn]} {:keys [data] :as params}]
|
[{:keys [::sto/storage ::db/conn]} {:keys [data] :as params}]
|
||||||
(letfn [(generate-missing! [data]
|
(letfn [(generate-missing [data]
|
||||||
(let [data (media/run {:cmd :generate-fonts :input data})]
|
(let [data (media/run {:cmd :generate-fonts :input data})]
|
||||||
(when (and (not (contains? data "font/otf"))
|
(when (and (not (contains? data "font/otf"))
|
||||||
(not (contains? data "font/ttf"))
|
(not (contains? data "font/ttf"))
|
||||||
@ -116,8 +126,26 @@
|
|||||||
:hint "invalid font upload, unable to generate missing font assets"))
|
:hint "invalid font upload, unable to generate missing font assets"))
|
||||||
data))
|
data))
|
||||||
|
|
||||||
|
(process-chunks [chunks]
|
||||||
|
(let [tmp (tmp/tempfile :prefix "penpot.tempfont." :suffix "")
|
||||||
|
streams (map io/input-stream chunks)
|
||||||
|
streams (Collections/enumeration streams)]
|
||||||
|
(with-open [^OutputStream output (io/output-stream tmp)
|
||||||
|
^InputStream input (SequenceInputStream. streams)]
|
||||||
|
(io/copy input output))
|
||||||
|
tmp))
|
||||||
|
|
||||||
|
(join-chunks [data]
|
||||||
|
(reduce-kv (fn [data mtype content]
|
||||||
|
(if (vector? content)
|
||||||
|
(assoc data mtype (process-chunks content))
|
||||||
|
data))
|
||||||
|
data
|
||||||
|
data))
|
||||||
|
|
||||||
(prepare-font [data mtype]
|
(prepare-font [data mtype]
|
||||||
(when-let [resource (get data mtype)]
|
(when-let [resource (get data mtype)]
|
||||||
|
|
||||||
(let [hash (sto/calculate-hash resource)
|
(let [hash (sto/calculate-hash resource)
|
||||||
content (-> (sto/content resource)
|
content (-> (sto/content resource)
|
||||||
(sto/wrap-with-hash hash))]
|
(sto/wrap-with-hash hash))]
|
||||||
@ -156,7 +184,8 @@
|
|||||||
:otf-file-id (:id otf)
|
:otf-file-id (:id otf)
|
||||||
:ttf-file-id (:id ttf)}))]
|
:ttf-file-id (:id ttf)}))]
|
||||||
|
|
||||||
(let [data (generate-missing! data)
|
(let [data (join-chunks data)
|
||||||
|
data (generate-missing data)
|
||||||
assets (persist-fonts-files! data)
|
assets (persist-fonts-files! data)
|
||||||
result (insert-font-variant! assets)]
|
result (insert-font-variant! assets)]
|
||||||
(vary-meta result assoc ::audit/replace-props (update params :data (comp vec keys))))))
|
(vary-meta result assoc ::audit/replace-props (update params :data (comp vec keys))))))
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
{:path path
|
{:path path
|
||||||
:mtype (mime/get type)
|
:mtype (mime/get type)
|
||||||
:name name
|
:name name
|
||||||
:filename (str/concat name (mime/get-extension type))
|
:filename (str/concat (str/slug name) (mime/get-extension type))
|
||||||
:id task-id}))
|
:id task-id}))
|
||||||
|
|
||||||
(defn create-zip
|
(defn create-zip
|
||||||
|
|||||||
@ -48,13 +48,13 @@
|
|||||||
"watch:app:main": "clojure -M:dev:shadow-cljs watch main worker storybook",
|
"watch:app:main": "clojure -M:dev:shadow-cljs watch main worker storybook",
|
||||||
"clear:shadow-cache": "rm -rf .shadow-cljs",
|
"clear:shadow-cache": "rm -rf .shadow-cljs",
|
||||||
"watch": "exit 0",
|
"watch": "exit 0",
|
||||||
"watch:app": "yarn run clear:shadow-cache && concurrently --kill-others-on-fail \"yarn run watch:app:assets\" \"yarn run watch:app:main\" \"yarn run watch:app:libs\"",
|
"watch:app": "yarn run clear:shadow-cache && yarn run build:wasm && concurrently --kill-others-on-fail \"yarn run watch:app:assets\" \"yarn run watch:app:main\" \"yarn run watch:app:libs\"",
|
||||||
"watch:storybook": "yarn run build:storybook:assets && concurrently --kill-others-on-fail \"storybook dev -p 6006 --no-open\" \"node ./scripts/watch-storybook.js\""
|
"watch:storybook": "yarn run build:storybook:assets && concurrently --kill-others-on-fail \"storybook dev -p 6006 --no-open\" \"node ./scripts/watch-storybook.js\""
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@penpot/draft-js": "portal:./packages/draft-js",
|
"@penpot/draft-js": "portal:./packages/draft-js",
|
||||||
"@penpot/mousetrap": "portal:./packages/mousetrap",
|
"@penpot/mousetrap": "portal:./packages/mousetrap",
|
||||||
"@penpot/plugins-runtime": "1.3.2",
|
"@penpot/plugins-runtime": "1.4.2",
|
||||||
"@penpot/svgo": "penpot/svgo#v3.2",
|
"@penpot/svgo": "penpot/svgo#v3.2",
|
||||||
"@penpot/text-editor": "portal:./text-editor",
|
"@penpot/text-editor": "portal:./text-editor",
|
||||||
"@playwright/test": "1.57.0",
|
"@playwright/test": "1.57.0",
|
||||||
|
|||||||
@ -1256,6 +1256,192 @@ test.describe("Tokens: Tokens Tab", () => {
|
|||||||
).toBeEnabled();
|
).toBeEnabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("User creates shadow token with negative spread", async ({ page }) => {
|
||||||
|
const emptyNameError = "Name should be at least 1 character";
|
||||||
|
|
||||||
|
const { tokensUpdateCreateModal, tokenThemesSetsSidebar } =
|
||||||
|
await setupEmptyTokensFile(page, {flags: ["enable-token-shadow"]});
|
||||||
|
|
||||||
|
// Open modal
|
||||||
|
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
||||||
|
|
||||||
|
const addTokenButton = tokensTabPanel.getByRole("button", {
|
||||||
|
name: `Add Token: Shadow`,
|
||||||
|
});
|
||||||
|
|
||||||
|
await addTokenButton.click();
|
||||||
|
await expect(tokensUpdateCreateModal).toBeVisible();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByPlaceholder(
|
||||||
|
"Enter a value or alias with {alias}",
|
||||||
|
),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
const nameField = tokensUpdateCreateModal.getByLabel("Name");
|
||||||
|
const colorField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||||
|
name: "Color",
|
||||||
|
});
|
||||||
|
const offsetXField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||||
|
name: "X",
|
||||||
|
});
|
||||||
|
const offsetYField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||||
|
name: "Y",
|
||||||
|
});
|
||||||
|
const blurField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||||
|
name: "Blur",
|
||||||
|
});
|
||||||
|
const spreadField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||||
|
name: "Spread",
|
||||||
|
});
|
||||||
|
const submitButton = tokensUpdateCreateModal.getByRole("button", {
|
||||||
|
name: "Save",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1. Check default values
|
||||||
|
await expect(offsetXField).toHaveValue("4");
|
||||||
|
await expect(offsetYField).toHaveValue("4");
|
||||||
|
await expect(blurField).toHaveValue("4");
|
||||||
|
await expect(spreadField).toHaveValue("0");
|
||||||
|
|
||||||
|
// 2. Name filled + empty value → disabled
|
||||||
|
await nameField.fill("my-token");
|
||||||
|
await expect(submitButton).toBeDisabled();
|
||||||
|
|
||||||
|
// 3. Invalid color → disabled + error message
|
||||||
|
await colorField.fill("1");
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText("Invalid color value: 1"),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await expect(submitButton).toBeDisabled();
|
||||||
|
|
||||||
|
await colorField.fill("{missing-reference}");
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText(
|
||||||
|
"Missing token references: missing-reference",
|
||||||
|
),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
// 4. Empty name → disabled + error message
|
||||||
|
await nameField.fill("");
|
||||||
|
|
||||||
|
const emptyNameErrorNode =
|
||||||
|
tokensUpdateCreateModal.getByText(emptyNameError);
|
||||||
|
|
||||||
|
await expect(emptyNameErrorNode).toBeVisible();
|
||||||
|
await expect(submitButton).toBeDisabled();
|
||||||
|
|
||||||
|
//
|
||||||
|
// ------- SUCCESSFUL FIELDS -------
|
||||||
|
//
|
||||||
|
|
||||||
|
// 5. Valid color → resolved
|
||||||
|
|
||||||
|
await colorField.fill("red");
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText("Resolved value: #ff0000"),
|
||||||
|
).toBeVisible();
|
||||||
|
const colorSwatch = tokensUpdateCreateModal.getByTestId(
|
||||||
|
"token-form-color-bullet",
|
||||||
|
);
|
||||||
|
await colorSwatch.click();
|
||||||
|
const rampSelector = tokensUpdateCreateModal.getByTestId(
|
||||||
|
"value-saturation-selector",
|
||||||
|
);
|
||||||
|
await expect(rampSelector).toBeVisible();
|
||||||
|
await rampSelector.click({ position: { x: 50, y: 50 } });
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText("Resolved value:"),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
const sliderOpacity = tokensUpdateCreateModal.getByTestId("slider-opacity");
|
||||||
|
await sliderOpacity.click({ position: { x: 50, y: 0 } });
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByRole("textbox", { name: "Color" }),
|
||||||
|
).toHaveValue(/rgba\s*\([^)]*\)/);
|
||||||
|
|
||||||
|
// 6. Valid offset → resolved
|
||||||
|
await offsetXField.fill("3 + 3");
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText("Resolved value: 6"),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await offsetYField.fill("3 + 7");
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText("Resolved value: 10"),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
// 7. Valid blur → resolved
|
||||||
|
|
||||||
|
await blurField.fill("3 + 1");
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText("Resolved value: 4"),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
// 8. Valid spread → resolved
|
||||||
|
|
||||||
|
await spreadField.fill("3 - 3");
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText("Resolved value: 0"),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await spreadField.fill("1 - 3");
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText("Resolved value: -2"),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await nameField.fill("my-token");
|
||||||
|
await expect(submitButton).toBeEnabled();
|
||||||
|
await submitButton.click();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
tokensTabPanel.getByRole("button", { name: "my-token" }),
|
||||||
|
).toBeEnabled();
|
||||||
|
|
||||||
|
//
|
||||||
|
// ------- SECOND TOKEN WITH VALID REFERENCE -------
|
||||||
|
//
|
||||||
|
await addTokenButton.click();
|
||||||
|
|
||||||
|
await nameField.fill("my-token-2");
|
||||||
|
const referenceToggle =
|
||||||
|
tokensUpdateCreateModal.getByTestId("reference-opt");
|
||||||
|
const compositeToggle =
|
||||||
|
tokensUpdateCreateModal.getByTestId("composite-opt");
|
||||||
|
await referenceToggle.click();
|
||||||
|
|
||||||
|
const referenceInput = tokensUpdateCreateModal.getByPlaceholder(
|
||||||
|
"Enter a token shadow alias",
|
||||||
|
);
|
||||||
|
await expect(referenceInput).toBeVisible();
|
||||||
|
|
||||||
|
await compositeToggle.click();
|
||||||
|
await expect(colorField).toBeVisible();
|
||||||
|
|
||||||
|
await referenceToggle.click();
|
||||||
|
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||||
|
name: "Reference",
|
||||||
|
});
|
||||||
|
await referenceField.fill("{my-token}");
|
||||||
|
await expect(
|
||||||
|
tokensUpdateCreateModal.getByText(
|
||||||
|
"Resolved value: - X: 6 - Y: 10 - Blur: 4 - Spread: -2",
|
||||||
|
),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await expect(submitButton).toBeEnabled();
|
||||||
|
await submitButton.click();
|
||||||
|
await expect(
|
||||||
|
tokensTabPanel.getByRole("button", { name: "my-token-2" }),
|
||||||
|
).toBeEnabled();
|
||||||
|
});
|
||||||
|
|
||||||
test("User creates typography token", async ({ page }) => {
|
test("User creates typography token", async ({ page }) => {
|
||||||
const emptyNameError = "Name should be at least 1 character";
|
const emptyNameError = "Name should be at least 1 character";
|
||||||
const { tokensUpdateCreateModal, tokenThemesSetsSidebar } =
|
const { tokensUpdateCreateModal, tokenThemesSetsSidebar } =
|
||||||
|
|||||||
@ -174,6 +174,7 @@ export async function watch(baseDir, predicate, callback) {
|
|||||||
const watcher = new Watcher(baseDir, {
|
const watcher = new Watcher(baseDir, {
|
||||||
persistent: true,
|
persistent: true,
|
||||||
recursive: true,
|
recursive: true,
|
||||||
|
debounce: 500
|
||||||
});
|
});
|
||||||
|
|
||||||
watcher.on("change", (path) => {
|
watcher.on("change", (path) => {
|
||||||
@ -181,8 +182,19 @@ export async function watch(baseDir, predicate, callback) {
|
|||||||
callback(path);
|
callback(path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
watcher.on("error", (cause) => {
|
||||||
|
console.log("WATCHER ERROR", cause);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function ensureDirectories() {
|
||||||
|
await fs.mkdir("./resources/public/js/worker/", { recursive: true });
|
||||||
|
await fs.mkdir("./resources/public/css/", { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function readManifestFile(resource) {
|
async function readManifestFile(resource) {
|
||||||
const manifestPath = "resources/public/" + resource;
|
const manifestPath = "resources/public/" + resource;
|
||||||
let content = await fs.readFile(manifestPath, { encoding: "utf8" });
|
let content = await fs.readFile(manifestPath, { encoding: "utf8" });
|
||||||
@ -260,6 +272,9 @@ const markedOptions = {
|
|||||||
marked.use(markedOptions);
|
marked.use(markedOptions);
|
||||||
|
|
||||||
export async function compileTranslations() {
|
export async function compileTranslations() {
|
||||||
|
const outputDir = "resources/public/js/";
|
||||||
|
await fs.mkdir(outputDir, { recursive: true });
|
||||||
|
|
||||||
const langs = [
|
const langs = [
|
||||||
"ar",
|
"ar",
|
||||||
"ca",
|
"ca",
|
||||||
@ -341,7 +356,6 @@ export async function compileTranslations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const esm = `export default ${JSON.stringify(result, null, 0)};\n`;
|
const esm = `export default ${JSON.stringify(result, null, 0)};\n`;
|
||||||
const outputDir = "resources/public/js/";
|
|
||||||
const outputFile = ph.join(outputDir, "translation." + lang + ".js");
|
const outputFile = ph.join(outputDir, "translation." + lang + ".js");
|
||||||
await fs.writeFile(outputFile, esm);
|
await fs.writeFile(outputFile, esm);
|
||||||
}
|
}
|
||||||
@ -499,17 +513,43 @@ export async function compileStyles() {
|
|||||||
export async function compileSvgSprites() {
|
export async function compileSvgSprites() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
log.info("init: compile svgsprite");
|
log.info("init: compile svgsprite");
|
||||||
await generateSvgSprites();
|
let error = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await generateSvgSprites();
|
||||||
|
} catch (cause) {
|
||||||
|
error = cause;
|
||||||
|
}
|
||||||
|
|
||||||
const end = process.hrtime(start);
|
const end = process.hrtime(start);
|
||||||
log.info("done: compile svgsprite", `(${ppt(end)})`);
|
|
||||||
|
if (error) {
|
||||||
|
log.error("error: compile svgsprite", `(${ppt(end)})`);
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
|
log.info("done: compile svgsprite", `(${ppt(end)})`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function compileTemplates() {
|
export async function compileTemplates() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
|
let error = false;
|
||||||
log.info("init: compile templates");
|
log.info("init: compile templates");
|
||||||
await generateTemplates();
|
|
||||||
|
try {
|
||||||
|
await generateTemplates();
|
||||||
|
} catch (cause) {
|
||||||
|
error = cause;
|
||||||
|
}
|
||||||
|
|
||||||
const end = process.hrtime(start);
|
const end = process.hrtime(start);
|
||||||
log.info("done: compile templates", `(${ppt(end)})`);
|
|
||||||
|
if (error) {
|
||||||
|
log.error("error: compile templates", `(${ppt(end)})`);
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
|
log.info("done: compile templates", `(${ppt(end)})`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function compilePolyfills() {
|
export async function compilePolyfills() {
|
||||||
|
|||||||
@ -28,14 +28,12 @@ async function compileFile(path) {
|
|||||||
],
|
],
|
||||||
sourceMap: false,
|
sourceMap: false,
|
||||||
});
|
});
|
||||||
// console.dir(result);
|
|
||||||
resolve({
|
resolve({
|
||||||
inputPath: path,
|
inputPath: path,
|
||||||
outputPath: dest,
|
outputPath: dest,
|
||||||
css: result.css,
|
css: result.css,
|
||||||
});
|
});
|
||||||
} catch (cause) {
|
} catch (cause) {
|
||||||
console.error(cause);
|
|
||||||
reject(cause);
|
reject(cause);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import * as h from "./_helpers.js";
|
import * as h from "./_helpers.js";
|
||||||
|
|
||||||
|
await h.ensureDirectories();
|
||||||
await h.compileStyles();
|
await h.compileStyles();
|
||||||
await h.copyAssets();
|
await h.copyAssets();
|
||||||
await h.copyWasmPlayground();
|
await h.copyWasmPlayground();
|
||||||
|
|||||||
@ -12,19 +12,31 @@ let sass = null;
|
|||||||
|
|
||||||
async function compileSassAll() {
|
async function compileSassAll() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
|
let error = false;
|
||||||
|
|
||||||
log.info("init: compile styles");
|
log.info("init: compile styles");
|
||||||
|
|
||||||
sass = await h.compileSassAll(worker);
|
try {
|
||||||
let output = await h.concatSass(sass);
|
sass = await h.compileSassAll(worker);
|
||||||
await fs.writeFile("./resources/public/css/main.css", output);
|
let output = await h.concatSass(sass);
|
||||||
|
await fs.writeFile("./resources/public/css/main.css", output);
|
||||||
|
|
||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
let debugCSS = await h.compileSassDebug(worker);
|
let debugCSS = await h.compileSassDebug(worker);
|
||||||
await fs.writeFile("./resources/public/css/debug.css", debugCSS);
|
await fs.writeFile("./resources/public/css/debug.css", debugCSS);
|
||||||
|
}
|
||||||
|
} catch (cause) {
|
||||||
|
error = cause;
|
||||||
}
|
}
|
||||||
|
|
||||||
const end = process.hrtime(start);
|
const end = process.hrtime(start);
|
||||||
log.info("done: compile styles", `(${ppt(end)})`);
|
|
||||||
|
if (error) {
|
||||||
|
log.error("error: compile styles", `(${ppt(end)})`);
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
|
log.info("done: compile styles", `(${ppt(end)})`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function compileSass(path) {
|
async function compileSass(path) {
|
||||||
@ -48,7 +60,7 @@ async function compileSass(path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.mkdir("./resources/public/css/", { recursive: true });
|
await h.ensureDirectories();
|
||||||
await compileSassAll();
|
await compileSassAll();
|
||||||
await h.copyAssets();
|
await h.copyAssets();
|
||||||
await h.copyWasmPlayground();
|
await h.copyWasmPlayground();
|
||||||
|
|||||||
@ -24,6 +24,20 @@
|
|||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
(def ^:const default-chunk-size
|
||||||
|
(* 1024 1024 4)) ;; 4MiB
|
||||||
|
|
||||||
|
(defn- chunk-array
|
||||||
|
[data chunk-size]
|
||||||
|
(let [total-size (alength data)]
|
||||||
|
(loop [offset 0
|
||||||
|
chunks []]
|
||||||
|
(if (< offset total-size)
|
||||||
|
(let [end (min (+ offset chunk-size) total-size)
|
||||||
|
chunk (.subarray ^js data offset end)]
|
||||||
|
(recur end (conj chunks chunk)))
|
||||||
|
chunks))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; General purpose events & IMPL
|
;; General purpose events & IMPL
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@ -116,9 +130,9 @@
|
|||||||
(not= hhea-descender win-descent)
|
(not= hhea-descender win-descent)
|
||||||
(and f-selection (or
|
(and f-selection (or
|
||||||
(not= hhea-ascender os2-ascent)
|
(not= hhea-ascender os2-ascent)
|
||||||
(not= hhea-descender os2-descent))))]
|
(not= hhea-descender os2-descent))))
|
||||||
|
data (js/Uint8Array. data)]
|
||||||
{:content {:data (js/Uint8Array. data)
|
{:content {:data (chunk-array data default-chunk-size)
|
||||||
:name name
|
:name name
|
||||||
:type type}
|
:type type}
|
||||||
:font-family (or family "")
|
:font-family (or family "")
|
||||||
|
|||||||
@ -126,7 +126,7 @@
|
|||||||
If the `value` is not parseable and/or has missing references returns a map with `:errors`.
|
If the `value` is not parseable and/or has missing references returns a map with `:errors`.
|
||||||
If the `value` is parseable but is out of range returns a map with `warnings`."
|
If the `value` is parseable but is out of range returns a map with `warnings`."
|
||||||
[value]
|
[value]
|
||||||
(let [missing-references? (seq (seq (cto/find-token-value-references value)))
|
(let [missing-references? (seq (cto/find-token-value-references value))
|
||||||
parsed-value (cft/parse-token-value value)
|
parsed-value (cft/parse-token-value value)
|
||||||
out-of-scope (not (<= 0 (:value parsed-value) 1))
|
out-of-scope (not (<= 0 (:value parsed-value) 1))
|
||||||
references (seq (cto/find-token-value-references value))]
|
references (seq (cto/find-token-value-references value))]
|
||||||
@ -152,15 +152,14 @@
|
|||||||
[value]
|
[value]
|
||||||
(let [missing-references? (seq (cto/find-token-value-references value))
|
(let [missing-references? (seq (cto/find-token-value-references value))
|
||||||
parsed-value (cft/parse-token-value value)
|
parsed-value (cft/parse-token-value value)
|
||||||
out-of-scope (< (:value parsed-value) 0)
|
out-of-scope (< (:value parsed-value) 0)]
|
||||||
references (seq (cto/find-token-value-references value))]
|
|
||||||
(cond
|
(cond
|
||||||
(and parsed-value (not out-of-scope))
|
(and parsed-value (not out-of-scope))
|
||||||
parsed-value
|
parsed-value
|
||||||
|
|
||||||
references
|
missing-references?
|
||||||
{:errors [(wte/error-with-value :error.style-dictionary/missing-reference references)]
|
{:errors [(wte/error-with-value :error.style-dictionary/missing-reference missing-references?)]
|
||||||
:references references}
|
:references missing-references?}
|
||||||
|
|
||||||
(and (not missing-references?) out-of-scope)
|
(and (not missing-references?) out-of-scope)
|
||||||
{:errors [(wte/error-with-value :error.style-dictionary/invalid-token-value-stroke-width value)]}
|
{:errors [(wte/error-with-value :error.style-dictionary/invalid-token-value-stroke-width value)]}
|
||||||
@ -365,7 +364,7 @@
|
|||||||
"Parses shadow spread value (non-negative number)."
|
"Parses shadow spread value (non-negative number)."
|
||||||
[value]
|
[value]
|
||||||
(let [parsed (parse-sd-token-general-value value)
|
(let [parsed (parse-sd-token-general-value value)
|
||||||
valid? (and (:value parsed) (>= (:value parsed) 0))]
|
valid? (:value parsed)]
|
||||||
(cond
|
(cond
|
||||||
valid?
|
valid?
|
||||||
parsed
|
parsed
|
||||||
|
|||||||
@ -480,6 +480,9 @@
|
|||||||
(def workspace-token-sets-tree
|
(def workspace-token-sets-tree
|
||||||
(l/derived (d/nilf ctob/get-set-tree) tokens-lib))
|
(l/derived (d/nilf ctob/get-set-tree) tokens-lib))
|
||||||
|
|
||||||
|
(def workspace-all-tokens-map
|
||||||
|
(l/derived (d/nilf ctob/get-all-tokens) tokens-lib))
|
||||||
|
|
||||||
(def workspace-active-theme-paths
|
(def workspace-active-theme-paths
|
||||||
(l/derived (d/nilf ctob/get-active-theme-paths) tokens-lib))
|
(l/derived (d/nilf ctob/get-active-theme-paths) tokens-lib))
|
||||||
|
|
||||||
|
|||||||
@ -193,16 +193,15 @@
|
|||||||
restore-fn
|
restore-fn
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(st/emit! (dd/restore-files-immediately
|
(st/emit! (dd/restore-files-immediately
|
||||||
(with-meta {:team-id (:id current-team)
|
(with-meta {:team-id current-team-id
|
||||||
:ids (into #{} d/xf:map-id files)}
|
:ids (into #{} d/xf:map-id files)}
|
||||||
{:on-success #(st/emit! (ntf/success (tr "dashboard.restore-success-notification" (:name file)))
|
{:on-success #(st/emit! (ntf/success (tr "dashboard.restore-success-notification" (:name file)))
|
||||||
(dd/fetch-projects (:id current-team))
|
(dd/fetch-projects current-team-id)
|
||||||
(dd/fetch-deleted-files (:id current-team)))
|
(dd/fetch-deleted-files current-team-id))
|
||||||
:on-error #(st/emit! (ntf/error (tr "dashboard.errors.error-on-restore-file" (:name file))))}))))
|
:on-error #(st/emit! (ntf/error (tr "dashboard.errors.error-on-restore-file" (:name file))))}))))
|
||||||
|
|
||||||
on-restore-immediately
|
on-restore-immediately
|
||||||
(fn []
|
(fn []
|
||||||
(prn files)
|
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(modal/show {:type :confirm
|
(modal/show {:type :confirm
|
||||||
:title (tr "dashboard-restore-file-confirmation.title")
|
:title (tr "dashboard-restore-file-confirmation.title")
|
||||||
@ -214,7 +213,7 @@
|
|||||||
on-delete-immediately
|
on-delete-immediately
|
||||||
(fn []
|
(fn []
|
||||||
(let [accept-fn #(st/emit! (dd/delete-files-immediately
|
(let [accept-fn #(st/emit! (dd/delete-files-immediately
|
||||||
{:team-id (:id current-team)
|
{:team-id current-team-id
|
||||||
:ids (into #{} d/xf:map-id files)}))]
|
:ids (into #{} d/xf:map-id files)}))]
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(modal/show {:type :confirm
|
(modal/show {:type :confirm
|
||||||
@ -244,8 +243,7 @@
|
|||||||
(for [project current-projects]
|
(for [project current-projects]
|
||||||
{:name (get-project-name project)
|
{:name (get-project-name project)
|
||||||
:id (get-project-id project)
|
:id (get-project-id project)
|
||||||
:handler (on-move (:id current-team)
|
:handler (on-move current-team-id (:id project))})
|
||||||
(:id project))})
|
|
||||||
(when (seq other-teams)
|
(when (seq other-teams)
|
||||||
[{:name (tr "dashboard.move-to-other-team")
|
[{:name (tr "dashboard.move-to-other-team")
|
||||||
:id "move-to-other-team"
|
:id "move-to-other-team"
|
||||||
|
|||||||
@ -628,6 +628,7 @@
|
|||||||
width: $sz-400;
|
width: $sz-400;
|
||||||
padding: var(--sp-xxxl);
|
padding: var(--sp-xxxl);
|
||||||
background-color: var(--color-background-primary);
|
background-color: var(--color-background-primary);
|
||||||
|
z-index: var(--z-index-set);
|
||||||
|
|
||||||
&.hero {
|
&.hero {
|
||||||
top: px2rem(216);
|
top: px2rem(216);
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
touched? (and (contains? (:data @form) input-name)
|
touched? (and (contains? (:data @form) input-name)
|
||||||
(get-in @form [:touched input-name]))
|
(get-in @form [:touched input-name]))
|
||||||
|
|
||||||
error (get-in @form [:errors input-name])
|
error (get-in @form [:errors input-name])
|
||||||
|
|
||||||
value (get-in @form [:data input-name] "")
|
value (get-in @form [:data input-name] "")
|
||||||
|
|||||||
@ -375,7 +375,7 @@
|
|||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps on-change ids)
|
(mf/deps on-change ids)
|
||||||
(fn [value attr event]
|
(fn [value attr event]
|
||||||
(if (or (string? value) (int? value))
|
(if (or (string? value) (number? value))
|
||||||
(on-change :simple attr value event)
|
(on-change :simple attr value event)
|
||||||
(do
|
(do
|
||||||
(let [resolved-value (:resolved-value (first value))
|
(let [resolved-value (:resolved-value (first value))
|
||||||
@ -489,7 +489,7 @@
|
|||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps on-change ids)
|
(mf/deps on-change ids)
|
||||||
(fn [value attr event]
|
(fn [value attr event]
|
||||||
(if (or (string? value) (int? value))
|
(if (or (string? value) (number? value))
|
||||||
(on-change :multiple attr value event)
|
(on-change :multiple attr value event)
|
||||||
(do
|
(do
|
||||||
(let [resolved-value (:resolved-value (first value))]
|
(let [resolved-value (:resolved-value (first value))]
|
||||||
@ -724,7 +724,7 @@
|
|||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps on-change wrap-type ids)
|
(mf/deps on-change wrap-type ids)
|
||||||
(fn [value event attr]
|
(fn [value event attr]
|
||||||
(if (or (string? value) (int? value))
|
(if (or (string? value) (number? value))
|
||||||
(on-change (= "nowrap" wrap-type) attr value event)
|
(on-change (= "nowrap" wrap-type) attr value event)
|
||||||
(do
|
(do
|
||||||
(let [resolved-value (:resolved-value (first value))]
|
(let [resolved-value (:resolved-value (first value))]
|
||||||
|
|||||||
@ -53,10 +53,12 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn- resolve-value
|
(defn- resolve-value
|
||||||
[tokens prev-token value]
|
[tokens prev-token token-name value]
|
||||||
(let [token
|
(let [token
|
||||||
{:value value
|
{:value value
|
||||||
:name "__PENPOT__TOKEN__NAME__PLACEHOLDER__"}
|
:name (if (str/blank? token-name)
|
||||||
|
"__PENPOT__TOKEN__NAME__PLACEHOLDER__"
|
||||||
|
token-name)}
|
||||||
|
|
||||||
tokens
|
tokens
|
||||||
(-> tokens
|
(-> tokens
|
||||||
@ -131,6 +133,7 @@
|
|||||||
|
|
||||||
(let [form (mf/use-ctx fc/context)
|
(let [form (mf/use-ctx fc/context)
|
||||||
input-name name
|
input-name name
|
||||||
|
token-name (get-in @form [:data :name] nil)
|
||||||
|
|
||||||
|
|
||||||
touched?
|
touched?
|
||||||
@ -140,6 +143,9 @@
|
|||||||
error
|
error
|
||||||
(get-in @form [:errors input-name])
|
(get-in @form [:errors input-name])
|
||||||
|
|
||||||
|
extra-error
|
||||||
|
(get-in @form [:extra-errors input-name])
|
||||||
|
|
||||||
value
|
value
|
||||||
(get-in @form [:data input-name] "")
|
(get-in @form [:data input-name] "")
|
||||||
|
|
||||||
@ -247,15 +253,20 @@
|
|||||||
:hint-type (:type hint)})
|
:hint-type (:type hint)})
|
||||||
|
|
||||||
props
|
props
|
||||||
(if (and error touched?)
|
(cond
|
||||||
|
(and error touched?)
|
||||||
(mf/spread-props props {:hint-type "error"
|
(mf/spread-props props {:hint-type "error"
|
||||||
:hint-message (:message error)})
|
:hint-message (:message error)})
|
||||||
|
(and extra-error touched?)
|
||||||
|
(mf/spread-props props {:hint-type "error"
|
||||||
|
:hint-message (:message extra-error)})
|
||||||
|
:else
|
||||||
props)]
|
props)]
|
||||||
|
|
||||||
(mf/with-effect [resolve-stream tokens token input-name]
|
(mf/with-effect [resolve-stream tokens token input-name token-name]
|
||||||
(let [subs (->> resolve-stream
|
(let [subs (->> resolve-stream
|
||||||
(rx/debounce 300)
|
(rx/debounce 300)
|
||||||
(rx/mapcat (partial resolve-value tokens token))
|
(rx/mapcat (partial resolve-value tokens token token-name))
|
||||||
(rx/map (fn [result]
|
(rx/map (fn [result]
|
||||||
(d/update-when result :error
|
(d/update-when result :error
|
||||||
(fn [error]
|
(fn [error]
|
||||||
@ -301,7 +312,7 @@
|
|||||||
|
|
||||||
(let [form (mf/use-ctx fc/context)
|
(let [form (mf/use-ctx fc/context)
|
||||||
input-name name
|
input-name name
|
||||||
|
token-name (get-in @form [:data :name] nil)
|
||||||
error
|
error
|
||||||
(get-in @form [:errors :value value-subfield index input-name])
|
(get-in @form [:errors :value value-subfield index input-name])
|
||||||
|
|
||||||
@ -414,10 +425,10 @@
|
|||||||
:hint-message (:message error)})
|
:hint-message (:message error)})
|
||||||
props)]
|
props)]
|
||||||
|
|
||||||
(mf/with-effect [resolve-stream tokens token input-name index value-subfield]
|
(mf/with-effect [resolve-stream tokens token input-name index value-subfield token-name]
|
||||||
(let [subs (->> resolve-stream
|
(let [subs (->> resolve-stream
|
||||||
(rx/debounce 300)
|
(rx/debounce 300)
|
||||||
(rx/mapcat (partial resolve-value tokens token))
|
(rx/mapcat (partial resolve-value tokens token token-name))
|
||||||
(rx/map (fn [result]
|
(rx/map (fn [result]
|
||||||
(d/update-when result :error
|
(d/update-when result :error
|
||||||
(fn [error]
|
(fn [error]
|
||||||
|
|||||||
@ -49,10 +49,12 @@
|
|||||||
;; validate data within the form state.
|
;; validate data within the form state.
|
||||||
|
|
||||||
(defn- resolve-value
|
(defn- resolve-value
|
||||||
[tokens prev-token value]
|
[tokens prev-token token-name value]
|
||||||
(let [token
|
(let [token
|
||||||
{:value (cto/split-font-family value)
|
{:value (cto/split-font-family value)
|
||||||
:name "__PENPOT__TOKEN__NAME__PLACEHOLDER__"}
|
:name (if (str/blank? token-name)
|
||||||
|
"__PENPOT__TOKEN__NAME__PLACEHOLDER__"
|
||||||
|
token-name)}
|
||||||
|
|
||||||
tokens
|
tokens
|
||||||
(-> tokens
|
(-> tokens
|
||||||
@ -73,6 +75,7 @@
|
|||||||
[{:keys [token tokens name] :rest props}]
|
[{:keys [token tokens name] :rest props}]
|
||||||
(let [form (mf/use-ctx fc/context)
|
(let [form (mf/use-ctx fc/context)
|
||||||
input-name name
|
input-name name
|
||||||
|
token-name (get-in @form [:data :name] nil)
|
||||||
|
|
||||||
touched?
|
touched?
|
||||||
(and (contains? (:data @form) input-name)
|
(and (contains? (:data @form) input-name)
|
||||||
@ -152,10 +155,10 @@
|
|||||||
:hint-message (:message error)})
|
:hint-message (:message error)})
|
||||||
props)]
|
props)]
|
||||||
|
|
||||||
(mf/with-effect [resolve-stream tokens token input-name touched?]
|
(mf/with-effect [resolve-stream tokens token input-name touched? token-name]
|
||||||
(let [subs (->> resolve-stream
|
(let [subs (->> resolve-stream
|
||||||
(rx/debounce 300)
|
(rx/debounce 300)
|
||||||
(rx/mapcat (partial resolve-value tokens token))
|
(rx/mapcat (partial resolve-value tokens token token-name))
|
||||||
(rx/map (fn [result]
|
(rx/map (fn [result]
|
||||||
(d/update-when result :error
|
(d/update-when result :error
|
||||||
(fn [error]
|
(fn [error]
|
||||||
@ -200,7 +203,7 @@
|
|||||||
[{:keys [token tokens name] :rest props}]
|
[{:keys [token tokens name] :rest props}]
|
||||||
(let [form (mf/use-ctx fc/context)
|
(let [form (mf/use-ctx fc/context)
|
||||||
input-name name
|
input-name name
|
||||||
|
token-name (get-in @form [:data :name] nil)
|
||||||
error
|
error
|
||||||
(get-in @form [:errors :value input-name])
|
(get-in @form [:errors :value input-name])
|
||||||
|
|
||||||
@ -276,10 +279,10 @@
|
|||||||
:hint-message (:message error)})
|
:hint-message (:message error)})
|
||||||
props)]
|
props)]
|
||||||
|
|
||||||
(mf/with-effect [resolve-stream tokens token input-name]
|
(mf/with-effect [resolve-stream tokens token input-name token-name]
|
||||||
(let [subs (->> resolve-stream
|
(let [subs (->> resolve-stream
|
||||||
(rx/debounce 300)
|
(rx/debounce 300)
|
||||||
(rx/mapcat (partial resolve-value tokens token))
|
(rx/mapcat (partial resolve-value tokens token token-name))
|
||||||
(rx/map (fn [result]
|
(rx/map (fn [result]
|
||||||
(d/update-when result :error
|
(d/update-when result :error
|
||||||
(fn [error]
|
(fn [error]
|
||||||
|
|||||||
@ -139,10 +139,12 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn- resolve-value
|
(defn- resolve-value
|
||||||
[tokens prev-token value]
|
[tokens prev-token token-name value]
|
||||||
(let [token
|
(let [token
|
||||||
{:value value
|
{:value value
|
||||||
:name "__PENPOT__TOKEN__NAME__PLACEHOLDER__"}
|
:name (if (str/blank? token-name)
|
||||||
|
"__PENPOT__TOKEN__NAME__PLACEHOLDER__"
|
||||||
|
token-name)}
|
||||||
tokens
|
tokens
|
||||||
(-> tokens
|
(-> tokens
|
||||||
;; Remove previous token when renaming a token
|
;; Remove previous token when renaming a token
|
||||||
@ -163,6 +165,7 @@
|
|||||||
|
|
||||||
(let [form (mf/use-ctx fc/context)
|
(let [form (mf/use-ctx fc/context)
|
||||||
input-name name
|
input-name name
|
||||||
|
token-name (get-in @form [:data :name] nil)
|
||||||
|
|
||||||
touched?
|
touched?
|
||||||
(and (contains? (:data @form) input-name)
|
(and (contains? (:data @form) input-name)
|
||||||
@ -206,11 +209,11 @@
|
|||||||
:hint-message (:message error)})
|
:hint-message (:message error)})
|
||||||
props)]
|
props)]
|
||||||
|
|
||||||
(mf/with-effect [resolve-stream tokens token input-name]
|
(mf/with-effect [resolve-stream tokens token input-name token-name]
|
||||||
|
|
||||||
(let [subs (->> resolve-stream
|
(let [subs (->> resolve-stream
|
||||||
(rx/debounce 300)
|
(rx/debounce 300)
|
||||||
(rx/mapcat (partial resolve-value tokens token))
|
(rx/mapcat (partial resolve-value tokens token token-name))
|
||||||
(rx/map (fn [result]
|
(rx/map (fn [result]
|
||||||
(d/update-when result :error
|
(d/update-when result :error
|
||||||
(fn [error]
|
(fn [error]
|
||||||
@ -236,12 +239,14 @@
|
|||||||
(on-composite-input-change form field value false))
|
(on-composite-input-change form field value false))
|
||||||
([form field value trim?]
|
([form field value trim?]
|
||||||
(letfn [(clean-errors [errors]
|
(letfn [(clean-errors [errors]
|
||||||
(-> errors
|
(some-> errors
|
||||||
(dissoc field)
|
(update :value #(when (map? %) (dissoc % field)))
|
||||||
(not-empty)))]
|
(update :value #(when (seq %) %))
|
||||||
|
(not-empty)))]
|
||||||
(swap! form (fn [state]
|
(swap! form (fn [state]
|
||||||
(-> state
|
(-> state
|
||||||
(assoc-in [:data :value field] (if trim? (str/trim value) value))
|
(assoc-in [:data :value field] (if trim? (str/trim value) value))
|
||||||
|
(assoc-in [:touched :value field] true)
|
||||||
(update :errors clean-errors)
|
(update :errors clean-errors)
|
||||||
(update :extra-errors clean-errors)))))))
|
(update :extra-errors clean-errors)))))))
|
||||||
|
|
||||||
@ -250,6 +255,7 @@
|
|||||||
|
|
||||||
(let [form (mf/use-ctx fc/context)
|
(let [form (mf/use-ctx fc/context)
|
||||||
input-name name
|
input-name name
|
||||||
|
token-name (get-in @form [:data :name] nil)
|
||||||
|
|
||||||
error
|
error
|
||||||
(get-in @form [:errors :value input-name])
|
(get-in @form [:errors :value input-name])
|
||||||
@ -257,6 +263,9 @@
|
|||||||
value
|
value
|
||||||
(get-in @form [:data :value input-name] "")
|
(get-in @form [:data :value input-name] "")
|
||||||
|
|
||||||
|
touched?
|
||||||
|
(get-in @form [:touched :value input-name])
|
||||||
|
|
||||||
resolve-stream
|
resolve-stream
|
||||||
(mf/with-memo [token]
|
(mf/with-memo [token]
|
||||||
(if-let [value (get-in token [:value input-name])]
|
(if-let [value (get-in token [:value input-name])]
|
||||||
@ -284,7 +293,7 @@
|
|||||||
:hint-message (:message hint)
|
:hint-message (:message hint)
|
||||||
:hint-type (:type hint)})
|
:hint-type (:type hint)})
|
||||||
props
|
props
|
||||||
(if error
|
(if (and touched? error)
|
||||||
(mf/spread-props props {:hint-type "error"
|
(mf/spread-props props {:hint-type "error"
|
||||||
:hint-message (:message error)})
|
:hint-message (:message error)})
|
||||||
props)
|
props)
|
||||||
@ -293,10 +302,10 @@
|
|||||||
(mf/spread-props props {:hint-formated true})
|
(mf/spread-props props {:hint-formated true})
|
||||||
props)]
|
props)]
|
||||||
|
|
||||||
(mf/with-effect [resolve-stream tokens token input-name name]
|
(mf/with-effect [resolve-stream tokens token input-name name token-name]
|
||||||
(let [subs (->> resolve-stream
|
(let [subs (->> resolve-stream
|
||||||
(rx/debounce 300)
|
(rx/debounce 300)
|
||||||
(rx/mapcat (partial resolve-value tokens token))
|
(rx/mapcat (partial resolve-value tokens token token-name))
|
||||||
(rx/map (fn [result]
|
(rx/map (fn [result]
|
||||||
(d/update-when result :error
|
(d/update-when result :error
|
||||||
(fn [error]
|
(fn [error]
|
||||||
@ -360,7 +369,7 @@
|
|||||||
|
|
||||||
(let [form (mf/use-ctx fc/context)
|
(let [form (mf/use-ctx fc/context)
|
||||||
input-name name
|
input-name name
|
||||||
|
token-name (get-in @form [:data :name] nil)
|
||||||
|
|
||||||
error
|
error
|
||||||
(get-in @form [:errors :value value-subfield index input-name])
|
(get-in @form [:errors :value value-subfield index input-name])
|
||||||
@ -405,10 +414,10 @@
|
|||||||
(mf/spread-props props {:hint-formated true})
|
(mf/spread-props props {:hint-formated true})
|
||||||
props)]
|
props)]
|
||||||
|
|
||||||
(mf/with-effect [resolve-stream tokens token input-name index value-subfield]
|
(mf/with-effect [resolve-stream tokens token input-name index value-subfield token-name]
|
||||||
(let [subs (->> resolve-stream
|
(let [subs (->> resolve-stream
|
||||||
(rx/debounce 300)
|
(rx/debounce 300)
|
||||||
(rx/mapcat (partial resolve-value tokens token))
|
(rx/mapcat (partial resolve-value tokens token token-name))
|
||||||
(rx/map (fn [result]
|
(rx/map (fn [result]
|
||||||
(d/update-when result :error
|
(d/update-when result :error
|
||||||
(fn [error]
|
(fn [error]
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
[app.main.constants :refer [max-input-length]]
|
[app.main.constants :refer [max-input-length]]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace.tokens.application :as dwta]
|
[app.main.data.workspace.tokens.application :as dwta]
|
||||||
|
[app.main.data.workspace.tokens.errors :as wte]
|
||||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||||
[app.main.data.workspace.tokens.propagation :as dwtp]
|
[app.main.data.workspace.tokens.propagation :as dwtp]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
@ -110,8 +111,7 @@
|
|||||||
|
|
||||||
token-title (str/lower (:title token-properties))
|
token-title (str/lower (:title token-properties))
|
||||||
|
|
||||||
tokens
|
tokens (mf/deref refs/workspace-all-tokens-map)
|
||||||
(mf/deref refs/workspace-active-theme-sets-tokens)
|
|
||||||
|
|
||||||
tokens
|
tokens
|
||||||
(mf/with-memo [tokens token]
|
(mf/with-memo [tokens token]
|
||||||
@ -207,7 +207,11 @@
|
|||||||
:value (:value valid-token)
|
:value (:value valid-token)
|
||||||
:description description}))
|
:description description}))
|
||||||
(dwtp/propagate-workspace-tokens)
|
(dwtp/propagate-workspace-tokens)
|
||||||
(modal/hide))))))))]
|
(modal/hide)))
|
||||||
|
(fn [{:keys [errors]}]
|
||||||
|
(let [error-messages (wte/humanize-errors errors)
|
||||||
|
error-message (first error-messages)]
|
||||||
|
(swap! form assoc-in [:extra-errors :value] {:message error-message}))))))))]
|
||||||
|
|
||||||
[:> fc/form* {:class (stl/css :form-wrapper)
|
[:> fc/form* {:class (stl/css :form-wrapper)
|
||||||
:form form
|
:form form
|
||||||
|
|||||||
@ -282,15 +282,11 @@
|
|||||||
(let [n (d/parse-double blur)]
|
(let [n (d/parse-double blur)]
|
||||||
(or (nil? n) (not (< n 0)))))]]]
|
(or (nil? n) (not (< n 0)))))]]]
|
||||||
[:spread {:optional true}
|
[:spread {:optional true}
|
||||||
[:and
|
[:maybe :string]]
|
||||||
[:maybe :string]
|
|
||||||
[:fn {:error/fn #(tr "workspace.tokens.shadow-token-spread-value-error")}
|
|
||||||
(fn [spread]
|
|
||||||
(let [n (d/parse-double spread)]
|
|
||||||
(or (nil? n) (not (< n 0)))))]]]
|
|
||||||
[:color {:optional true} [:maybe :string]]
|
[:color {:optional true} [:maybe :string]]
|
||||||
[:color-result {:optional true} ::sm/any]
|
[:color-result {:optional true} ::sm/any]
|
||||||
[:inset {:optional true} [:maybe :boolean]]]]]
|
[:inset {:optional true} [:maybe :boolean]]]]]
|
||||||
|
|
||||||
(if (= active-tab :reference)
|
(if (= active-tab :reference)
|
||||||
[:reference {:optional false} ::sm/text]
|
[:reference {:optional false} ::sm/text]
|
||||||
[:reference {:optional true} [:maybe :string]])]]
|
[:reference {:optional true} [:maybe :string]])]]
|
||||||
|
|||||||
@ -802,9 +802,10 @@
|
|||||||
([uri name]
|
([uri name]
|
||||||
(open-new-window uri name "noopener,noreferrer"))
|
(open-new-window uri name "noopener,noreferrer"))
|
||||||
([uri name features]
|
([uri name features]
|
||||||
(let [new-window (.open js/window (str uri) name features)]
|
(when-let [new-window (.open js/window (str uri) name features)]
|
||||||
(when (not= name "_blank")
|
(when (not= name "_blank")
|
||||||
(.reload (.-location new-window))))))
|
(when-let [location (.-location new-window)]
|
||||||
|
(.reload location))))))
|
||||||
|
|
||||||
(defn browser-back
|
(defn browser-back
|
||||||
[]
|
[]
|
||||||
|
|||||||
@ -7594,6 +7594,10 @@ msgstr "Error al importar: No se pudo procesar el JSON."
|
|||||||
msgid "workspace.tokens.export"
|
msgid "workspace.tokens.export"
|
||||||
msgstr "Exportar"
|
msgstr "Exportar"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/export/modal.cljs:125
|
||||||
|
msgid "workspace.tokens.export-tokens"
|
||||||
|
msgstr "Exportar tokens"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/tokens/export/modal.cljs:118
|
#: src/app/main/ui/workspace/tokens/export/modal.cljs:118
|
||||||
msgid "workspace.tokens.export.multiple-files"
|
msgid "workspace.tokens.export.multiple-files"
|
||||||
msgstr "Múltiples ficheros"
|
msgstr "Múltiples ficheros"
|
||||||
@ -7638,10 +7642,26 @@ msgstr "Nombre del grupo"
|
|||||||
msgid "workspace.tokens.grouping-set-alert"
|
msgid "workspace.tokens.grouping-set-alert"
|
||||||
msgstr "La agrupación de sets aun no está soportada."
|
msgstr "La agrupación de sets aun no está soportada."
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/import/modal.cljs:233
|
||||||
|
msgid "workspace.tokens.import-button-prefix"
|
||||||
|
msgstr "Importar %s"
|
||||||
|
|
||||||
#: src/app/main/data/workspace/tokens/errors.cljs:32, src/app/main/data/workspace/tokens/errors.cljs:37
|
#: src/app/main/data/workspace/tokens/errors.cljs:32, src/app/main/data/workspace/tokens/errors.cljs:37
|
||||||
msgid "workspace.tokens.import-error"
|
msgid "workspace.tokens.import-error"
|
||||||
msgstr "Error al importar:"
|
msgstr "Error al importar:"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/import/modal.cljs:273
|
||||||
|
msgid "workspace.tokens.import-menu-folder-option"
|
||||||
|
msgstr "Carpeta"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/import/modal.cljs:271
|
||||||
|
msgid "workspace.tokens.import-menu-json-option"
|
||||||
|
msgstr "Archivo JSON único"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/import/modal.cljs:272
|
||||||
|
msgid "workspace.tokens.import-menu-zip-option"
|
||||||
|
msgstr "Archivo ZIP"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/tokens/import/modal.cljs:241
|
#: src/app/main/ui/workspace/tokens/import/modal.cljs:241
|
||||||
msgid "workspace.tokens.import-multiple-files"
|
msgid "workspace.tokens.import-multiple-files"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -7656,7 +7676,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/app/main/ui/workspace/tokens/import/modal.cljs:237
|
#: src/app/main/ui/workspace/tokens/import/modal.cljs:237
|
||||||
msgid "workspace.tokens.import-tokens"
|
msgid "workspace.tokens.import-tokens"
|
||||||
msgstr "Import tokens"
|
msgstr "Importar tokens"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/tokens/sidebar.cljs:414, src/app/main/ui/workspace/tokens/sidebar.cljs:415
|
#: src/app/main/ui/workspace/tokens/sidebar.cljs:414, src/app/main/ui/workspace/tokens/sidebar.cljs:415
|
||||||
#, unused
|
#, unused
|
||||||
@ -7757,7 +7777,7 @@ msgstr "Line height (multiplicador, px o %) o {alias}"
|
|||||||
|
|
||||||
#: src/app/main/data/workspace/tokens/errors.cljs:57
|
#: src/app/main/data/workspace/tokens/errors.cljs:57
|
||||||
msgid "workspace.tokens.missing-references"
|
msgid "workspace.tokens.missing-references"
|
||||||
msgstr "Referéncias de tokens no encontradas:"
|
msgstr "Referencias de tokens no encontradas: "
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123
|
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123
|
||||||
msgid "workspace.tokens.more-options"
|
msgid "workspace.tokens.more-options"
|
||||||
|
|||||||
@ -1191,21 +1191,21 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@penpot/plugin-types@npm:^1.3.2":
|
"@penpot/plugin-types@npm:^1.4.2":
|
||||||
version: 1.3.2
|
version: 1.4.2
|
||||||
resolution: "@penpot/plugin-types@npm:1.3.2"
|
resolution: "@penpot/plugin-types@npm:1.4.2"
|
||||||
checksum: 10c0/3f624472c260721ad89bf8d944e75acf6a9c9577271a757acb77574102213914051d1a32d5ab16e6ba16ae077fff78cf7a0f6d11d18351dfc214426677a67468
|
checksum: 10c0/b0972fe75c97e697eb1044c89db660393886b3c30676f8436ff4ab56c5bf0397b2c675697ae1b9c5fe40bc95a803aecf6d7ac356dbf6d3535bf8baec5d05eab1
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@penpot/plugins-runtime@npm:1.3.2":
|
"@penpot/plugins-runtime@npm:1.4.2":
|
||||||
version: 1.3.2
|
version: 1.4.2
|
||||||
resolution: "@penpot/plugins-runtime@npm:1.3.2"
|
resolution: "@penpot/plugins-runtime@npm:1.4.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@penpot/plugin-types": "npm:^1.3.2"
|
"@penpot/plugin-types": "npm:^1.4.2"
|
||||||
ses: "npm:^1.1.0"
|
ses: "npm:^1.1.0"
|
||||||
zod: "npm:^3.22.4"
|
zod: "npm:^3.22.4"
|
||||||
checksum: 10c0/b6d2cb3a57bcbe58232db52b8224d1817495e96b34997bfa72421629b5f34a8c9cc71357c315dcab9d52ea036ed632a5efe0ac50f52e730901c02d498dfa1313
|
checksum: 10c0/af084d906cce9a6dea956fe5420111d7ea37c7620737a1e3d4f12958cb302a8f697c1229c237107c28fbb3b9f37eee308e6d16262b04ad56ae6f76c7a12f12e5
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -4176,7 +4176,7 @@ __metadata:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@penpot/draft-js": "portal:./packages/draft-js"
|
"@penpot/draft-js": "portal:./packages/draft-js"
|
||||||
"@penpot/mousetrap": "portal:./packages/mousetrap"
|
"@penpot/mousetrap": "portal:./packages/mousetrap"
|
||||||
"@penpot/plugins-runtime": "npm:1.3.2"
|
"@penpot/plugins-runtime": "npm:1.4.2"
|
||||||
"@penpot/svgo": "penpot/svgo#v3.2"
|
"@penpot/svgo": "penpot/svgo#v3.2"
|
||||||
"@penpot/text-editor": "portal:./text-editor"
|
"@penpot/text-editor": "portal:./text-editor"
|
||||||
"@playwright/test": "npm:1.57.0"
|
"@playwright/test": "npm:1.57.0"
|
||||||
|
|||||||
@ -1,3 +1,38 @@
|
|||||||
|
## 1.4.2 (2026-01-21)
|
||||||
|
|
||||||
|
- **plugin-types:** fix atob/btoa functions
|
||||||
|
|
||||||
|
## 1.4.0 (2026-01-21)
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- switch component ([7d68450](https://github.com/penpot/penpot-plugins/commit/7d68450))
|
||||||
|
- Add variants to plugins API ([04f3c26](https://github.com/penpot/penpot-plugins/commit/04f3c26))
|
||||||
|
- format ci job ([17b5834](https://github.com/penpot/penpot-plugins/commit/17b5834))
|
||||||
|
- fix problem with ci ([4b3c50f](https://github.com/penpot/penpot-plugins/commit/4b3c50f))
|
||||||
|
- change in workflow ([3a69f51](https://github.com/penpot/penpot-plugins/commit/3a69f51))
|
||||||
|
- **plugin-types:** add methods to modify the index for shapes ([4ad50af](https://github.com/penpot/penpot-plugins/commit/4ad50af))
|
||||||
|
- **plugin-types:** change content type and added new attributes ([dbb68a5](https://github.com/penpot/penpot-plugins/commit/dbb68a5))
|
||||||
|
- **plugins-runtime:** add data method to image data ([f077481](https://github.com/penpot/penpot-plugins/commit/f077481))
|
||||||
|
- **plugins-runtime:** fix problem with linter ([30f4984](https://github.com/penpot/penpot-plugins/commit/30f4984))
|
||||||
|
- **plugins-runtime:** allow openPage() to toggle opening on a new window or not ([da8288b](https://github.com/penpot/penpot-plugins/commit/da8288b))
|
||||||
|
|
||||||
|
### 🩹 Fixes
|
||||||
|
|
||||||
|
- package-lock.json ([d1d940a](https://github.com/penpot/penpot-plugins/commit/d1d940a))
|
||||||
|
- fonts gdpr & switch provider ([d63231e](https://github.com/penpot/penpot-plugins/commit/d63231e))
|
||||||
|
- missing changes ([b8fc936](https://github.com/penpot/penpot-plugins/commit/b8fc936))
|
||||||
|
- format ci ([e0fab2e](https://github.com/penpot/penpot-plugins/commit/e0fab2e))
|
||||||
|
- fetch main only in pr ([e48c5d4](https://github.com/penpot/penpot-plugins/commit/e48c5d4))
|
||||||
|
|
||||||
|
### ❤️ Thank You
|
||||||
|
|
||||||
|
- alonso.torres
|
||||||
|
- Juanfran @juanfran
|
||||||
|
- Michał Korczak
|
||||||
|
- Miguel de Benito Delgado
|
||||||
|
- Pablo Alba
|
||||||
|
|
||||||
## 1.3.2 (2025-07-04)
|
## 1.3.2 (2025-07-04)
|
||||||
|
|
||||||
### 🩹 Fixes
|
### 🩹 Fixes
|
||||||
|
|||||||
@ -7,6 +7,29 @@ This guide details the process of publishing `plugin-types`,
|
|||||||
for plugin development. Below is a walkthrough for publishing these
|
for plugin development. Below is a walkthrough for publishing these
|
||||||
packages and managing releases.
|
packages and managing releases.
|
||||||
|
|
||||||
|
**Warning**
|
||||||
|
Before generating the release, please, check the update the changelog with
|
||||||
|
the changes that will be released.
|
||||||
|
|
||||||
|
## Problem with pnpm
|
||||||
|
|
||||||
|
There is an issue with dependencies and release with pnpm. For it to work
|
||||||
|
you need to add the following into your `.npmrc`
|
||||||
|
|
||||||
|
```
|
||||||
|
link-workspace-packages=true
|
||||||
|
```
|
||||||
|
|
||||||
|
## NPM Authentication
|
||||||
|
|
||||||
|
You need to generate a temporary access token in the NPM website.
|
||||||
|
|
||||||
|
Once you have the token add the following to the `.npmrc`
|
||||||
|
|
||||||
|
```
|
||||||
|
//registry.npmjs.org/:_authToken=<TOKEN>
|
||||||
|
```
|
||||||
|
|
||||||
## Publishing Libraries
|
## Publishing Libraries
|
||||||
|
|
||||||
Publishing packages enables the distribution of types and styles
|
Publishing packages enables the distribution of types and styles
|
||||||
@ -35,28 +58,16 @@ pnpm run release -- --dry-run false
|
|||||||
|
|
||||||
This command will:
|
This command will:
|
||||||
|
|
||||||
- Update the `CHANGELOG.md`
|
|
||||||
- Update the library's `package.json` version
|
- Update the library's `package.json` version
|
||||||
- Generate a commit
|
- Generate a commit
|
||||||
- Create a new git tag
|
|
||||||
- Publish to NPM with the `latest` tag
|
- Publish to NPM with the `latest` tag
|
||||||
|
|
||||||
Ensure everything is correct before proceeding with the git push. Once
|
Ensure everything is correct before proceeding with the git push. Once
|
||||||
verified, execute the following commands:
|
verified, execute the following commands:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
git commit -m ":arrow_up: Updated plugins release to X.X.X"
|
||||||
git push
|
git push
|
||||||
git push origin vX.X.X
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace `vX.X.X` with the new version number.
|
|
||||||
|
|
||||||
> 📘 To update the documentation site, you must also update the `stable` branch:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git checkout stable
|
|
||||||
git merge main
|
|
||||||
git push origin stable
|
|
||||||
```
|
```
|
||||||
|
|
||||||
For detailed information, refer to the [Nx Release
|
For detailed information, refer to the [Nx Release
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@penpot/plugin-types",
|
"name": "@penpot/plugin-types",
|
||||||
"version": "1.3.2",
|
"version": "1.4.2",
|
||||||
"typings": "./index.d.ts",
|
"typings": "./index.d.ts",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "@penpot/plugins-runtime",
|
"name": "@penpot/plugins-runtime",
|
||||||
"version": "1.3.2",
|
"version": "1.4.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@penpot/plugin-types": "^1.3.2",
|
"@penpot/plugin-types": "^1.4.2",
|
||||||
"ses": "^1.1.0",
|
"ses": "^1.1.0",
|
||||||
"zod": "^3.22.4"
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -118,8 +118,8 @@ export function createSandbox(
|
|||||||
// Window properties
|
// Window properties
|
||||||
console: ses.harden(window.console),
|
console: ses.harden(window.console),
|
||||||
devicePixelRatio: ses.harden(window.devicePixelRatio),
|
devicePixelRatio: ses.harden(window.devicePixelRatio),
|
||||||
atob: ses.harden(window.atob),
|
atob: ses.harden(window.atob.bind(null)),
|
||||||
btoa: ses.harden(window.btoa),
|
btoa: ses.harden(window.btoa.bind(null)),
|
||||||
structuredClone: ses.harden(window.structuredClone),
|
structuredClone: ses.harden(window.structuredClone),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@penpot/plugin-styles",
|
"name": "@penpot/plugin-styles",
|
||||||
"version": "1.3.2",
|
"version": "1.4.2",
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|||||||
14
plugins/pnpm-lock.yaml
generated
14
plugins/pnpm-lock.yaml
generated
@ -230,8 +230,8 @@ importers:
|
|||||||
libs/plugins-runtime:
|
libs/plugins-runtime:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@penpot/plugin-types':
|
'@penpot/plugin-types':
|
||||||
specifier: ^1.3.2
|
specifier: ^1.4.2
|
||||||
version: 1.3.2
|
version: link:../plugin-types
|
||||||
ses:
|
ses:
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.14.0
|
version: 1.14.0
|
||||||
@ -4200,12 +4200,6 @@ packages:
|
|||||||
}
|
}
|
||||||
engines: { node: '>= 10.0.0' }
|
engines: { node: '>= 10.0.0' }
|
||||||
|
|
||||||
'@penpot/plugin-types@1.3.2':
|
|
||||||
resolution:
|
|
||||||
{
|
|
||||||
integrity: sha512-f0kmmZaFNs9sGtSmqmSJQYCs5Qt+KYgTD8RneUjL+Dv+zfNQnd5e4L+iHSYFJ4HWvcDvTiK7F/gya7PwMTu7WA==,
|
|
||||||
}
|
|
||||||
|
|
||||||
'@phenomnomnominal/tsquery@5.0.1':
|
'@phenomnomnominal/tsquery@5.0.1':
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@ -13194,6 +13188,7 @@ packages:
|
|||||||
integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==,
|
integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==,
|
||||||
}
|
}
|
||||||
engines: { node: '>=10' }
|
engines: { node: '>=10' }
|
||||||
|
deprecated: Old versions of tar 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 exhorbitant rates) by contacting i@izs.me
|
||||||
|
|
||||||
tar@7.5.2:
|
tar@7.5.2:
|
||||||
resolution:
|
resolution:
|
||||||
@ -13201,6 +13196,7 @@ packages:
|
|||||||
integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==,
|
integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==,
|
||||||
}
|
}
|
||||||
engines: { node: '>=18' }
|
engines: { node: '>=18' }
|
||||||
|
deprecated: Old versions of tar 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 exhorbitant rates) by contacting i@izs.me
|
||||||
|
|
||||||
terser-webpack-plugin@5.3.16:
|
terser-webpack-plugin@5.3.16:
|
||||||
resolution:
|
resolution:
|
||||||
@ -18203,8 +18199,6 @@ snapshots:
|
|||||||
'@parcel/watcher-win32-x64': 2.5.1
|
'@parcel/watcher-win32-x64': 2.5.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@penpot/plugin-types@1.3.2': {}
|
|
||||||
|
|
||||||
'@phenomnomnominal/tsquery@5.0.1(typescript@5.6.3)':
|
'@phenomnomnominal/tsquery@5.0.1(typescript@5.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
esquery: 1.6.0
|
esquery: 1.6.0
|
||||||
|
|||||||
@ -69,17 +69,6 @@ const determineArgs = async () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
await releaseChangelog({
|
|
||||||
dryRun: args.dryRun,
|
|
||||||
versionData: result.projectsVersionData,
|
|
||||||
version: result.workspaceVersion,
|
|
||||||
gitCommitMessage: `chore(release): publish ${result.workspaceVersion} [skip ci]`,
|
|
||||||
gitCommit: true,
|
|
||||||
gitTag: true,
|
|
||||||
verbose: args.verbose,
|
|
||||||
firstRelease: args.firstRelease,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!args.skipPublish) {
|
if (!args.skipPublish) {
|
||||||
await releasePublish({
|
await releasePublish({
|
||||||
dryRun: args.dryRun,
|
dryRun: args.dryRun,
|
||||||
|
|||||||
4
plugins/wrangle-penpot-plugins-api-doc.toml
Normal file
4
plugins/wrangle-penpot-plugins-api-doc.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
name = "penpot-plugins-api-doc"
|
||||||
|
compatibility_date = "2025-01-01"
|
||||||
|
|
||||||
|
assets = { directory = "dist/doc" }
|
||||||
Loading…
x
Reference in New Issue
Block a user