Merge branch 'staging-render' into develop

This commit is contained in:
Andrey Antukh 2025-12-29 10:43:00 +01:00
commit e01654ba43
13 changed files with 122 additions and 33 deletions

View File

@ -554,7 +554,7 @@
(when (features/active-feature? state "text-editor/v2") (when (features/active-feature? state "text-editor/v2")
(let [instance (:workspace-editor state) (let [instance (:workspace-editor state)
styles (some-> (editor.v2/getCurrentStyle instance) styles (some-> (editor.v2/getCurrentStyle instance)
(styles/get-styles-from-style-declaration) (styles/get-styles-from-style-declaration :removed-mixed true)
((comp update-node-fn migrate-node)) ((comp update-node-fn migrate-node))
(styles/attrs->styles))] (styles/attrs->styles))]
(editor.v2/applyStylesToSelection instance styles))))))) (editor.v2/applyStylesToSelection instance styles)))))))

View File

@ -238,12 +238,12 @@
:always :always
(ctm/resize scalev resize-origin shape-transform shape-transform-inverse) (ctm/resize scalev resize-origin shape-transform shape-transform-inverse)
(and (ctl/any-layout-immediate-child? objects shape) (and (or (ctl/any-layout-immediate-child? objects shape) (ctl/any-layout? shape))
(not= (:layout-item-h-sizing shape) :fix) (not= (:layout-item-h-sizing shape) :fix)
^boolean change-width?) ^boolean change-width?)
(ctm/change-property :layout-item-h-sizing :fix) (ctm/change-property :layout-item-h-sizing :fix)
(and (ctl/any-layout-immediate-child? objects shape) (and (or (ctl/any-layout-immediate-child? objects shape) (ctl/any-layout? shape))
(not= (:layout-item-v-sizing shape) :fix) (not= (:layout-item-v-sizing shape) :fix)
^boolean change-height?) ^boolean change-height?)
(ctm/change-property :layout-item-v-sizing :fix) (ctm/change-property :layout-item-v-sizing :fix)

View File

@ -50,7 +50,8 @@
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 (or (get-in @form [:errors input-name])
(get-in @form [:extra-errors input-name]))
value (get-in @form [:data input-name] "") value (get-in @form [:data input-name] "")

View File

@ -18,16 +18,18 @@
(defn- on-error (defn- on-error
[form error] [form error]
(case (:code (ex-data error)) (let [data (ex-data error)]
:old-password-not-match (case (:code data)
(swap! form assoc-in [:errors :password-old] :old-password-not-match
{:message (tr "errors.wrong-old-password")}) (swap! form assoc-in [:extra-errors :password-old]
:email-as-password {:message (tr "errors.wrong-old-password")})
(swap! form assoc-in [:errors :password-1]
{:message (tr "errors.email-as-password")})
(let [msg (tr "generic.error")] :email-as-password
(st/emit! (ntf/error msg))))) (swap! form assoc-in [:extra-errors :password-1]
{:message (tr "errors.email-as-password")})
(let [msg (tr "generic.error")]
(st/emit! (ntf/error msg))))))
(defn- on-success (defn- on-success
[form] [form]

View File

@ -308,7 +308,7 @@
:title (tr "inspect.attributes.typography.font-family") :title (tr "inspect.attributes.typography.font-family")
:on-click #(reset! open-selector? true)} :on-click #(reset! open-selector? true)}
(cond (cond
(= :multiple font-id) (or (= :multiple font-id) (= "mixed" font-id))
"--" "--"
(some? font) (some? font)

View File

@ -135,8 +135,18 @@
(not extra-errors) (not extra-errors)
valid?))))) valid?)))))
(defn- make-initial-state
[initial-data]
(let [initial (if (fn? initial-data) (initial-data) initial-data)
initial (d/nilv initial {})]
{:initial initial
:data initial
:errors {}
:touched {}}))
(defn- create-form-mutator (defn- create-form-mutator
[internal-state rerender-fn wrap-update-fn initial opts] [internal-state rerender-fn wrap-update-fn opts]
(reify (reify
IDeref IDeref
(-deref [_] (-deref [_]
@ -145,7 +155,10 @@
IReset IReset
(-reset! [_ new-value] (-reset! [_ new-value]
(if (nil? new-value) (if (nil? new-value)
(mf/set-ref-val! internal-state (if (fn? initial) (initial) initial)) (let [initial (-> (mf/ref-val internal-state)
(get :initial)
(make-initial-state))]
(mf/set-ref-val! internal-state initial))
(mf/set-ref-val! internal-state new-value)) (mf/set-ref-val! internal-state new-value))
(rerender-fn)) (rerender-fn))
@ -176,26 +189,20 @@
initial initial
(mf/with-memo [initial] (mf/with-memo [initial]
{:data (if (fn? initial) (initial) initial) (make-initial-state initial))
:errors {}
:touched {}})
internal-state internal-state
(mf/use-ref nil) (mf/use-ref initial)
form-mutator form-mutator
(mf/with-memo [initial schema validators] (mf/with-memo [schema validators]
(let [mutator (create-form-mutator internal-state rerender-fn wrap-update-schema-fn (let [mutator (create-form-mutator internal-state rerender-fn wrap-update-schema-fn
initial
(select-keys opts [:schema :validators]))] (select-keys opts [:schema :validators]))]
(swap! mutator identity) (swap! mutator identity)
mutator))] mutator))]
(mf/with-effect [initial]
(mf/set-ref-val! internal-state initial))
;; Initialize internal state once ;; Initialize internal state once
(mf/with-layout-effect [] (mf/with-effect []
(mf/set-ref-val! internal-state initial)) (mf/set-ref-val! internal-state initial))
(mf/with-effect [initial] (mf/with-effect [initial]

View File

@ -187,19 +187,23 @@
style-value (normalize-style-value style-name v)] style-value (normalize-style-value style-name v)]
(assoc acc style-name style-value)))) {} style-defaults))) (assoc acc style-name style-value)))) {} style-defaults)))
(def mixed-values #{:mixed :multiple "mixed" "multiple"})
(defn get-styles-from-style-declaration (defn get-styles-from-style-declaration
"Returns a ClojureScript object compatible with text nodes" "Returns a ClojureScript object compatible with text nodes"
[style-declaration] [style-declaration & {:keys [removed-mixed] :or {removed-mixed false}}]
(reduce (reduce
(fn [acc k] (fn [acc k]
(if (contains? mapping k) (if (contains? mapping k)
(let [style-name (get-style-name-as-css-variable k) (let [style-name (get-style-name-as-css-variable k)
[_ style-decode] (get mapping k) [_ style-decode] (get mapping k)
style-value (.getPropertyValue style-declaration style-name)] style-value (.getPropertyValue style-declaration style-name)]
(assoc acc k (style-decode style-value))) (when (or (not removed-mixed) (not (contains? mixed-values style-value)))
(assoc acc k (style-decode style-value))))
(let [style-name (get-style-name k) (let [style-name (get-style-name k)
style-value (normalize-attr-value k (.getPropertyValue style-declaration style-name))] style-value (normalize-attr-value k (.getPropertyValue style-declaration style-name))]
(assoc acc k style-value)))) {} txt/text-style-attrs)) (when (or (not removed-mixed) (not (contains? mixed-values style-value)))
(assoc acc k style-value))))) {} txt/text-style-attrs))
(defn get-styles-from-event (defn get-styles-from-event
"Returns a ClojureScript object compatible with text nodes" "Returns a ClojureScript object compatible with text nodes"

View File

@ -1,5 +1,11 @@
# CHANGELOG # CHANGELOG
## 1.2.0-RC1
- Add the ability to add relations (with `addRelation` method)
## 1.1.0 ## 1.1.0
- Same as 1.1.0-RC2 - Same as 1.1.0-RC2

View File

@ -1,9 +1,9 @@
{ {
"name": "@penpot/library", "name": "@penpot/library",
"version": "1.1.0", "version": "1.2.0-RC1",
"license": "MPL-2.0", "license": "MPL-2.0",
"author": "Kaleidos INC", "author": "Kaleidos INC",
"packageManager": "yarn@4.11.0+sha512.4e54aeace9141df2f0177c266b05ec50dc044638157dae128c471ba65994ac802122d7ab35bcd9e81641228b7dcf24867d28e750e0bcae8a05277d600008ad54", "packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8",
"type": "module", "type": "module",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -0,0 +1,30 @@
import * as penpot from "#self";
import { writeFile, readFile } from "fs/promises";
(async function () {
const context = penpot.createBuildContext();
{
const file1 = context.addFile({ name: "Test File 1" });
const file2 = context.addFile({ name: "Test File 1" });
context.addRelation(file1, file2);
}
{
let result = await penpot.exportAsBytes(context);
await writeFile("sample-relations.zip", result);
}
})()
.catch((cause) => {
console.error(cause);
const innerCause = cause.cause;
if (innerCause) {
console.error("Inner cause:", innerCause);
}
process.exit(-1);
})
.finally(() => {
process.exit(0);
});

View File

@ -87,7 +87,8 @@
(try (try
(let [params (-> params decode-params fb/decode-file)] (let [params (-> params decode-params fb/decode-file)]
(-> (swap! state fb/add-file params) (-> (swap! state fb/add-file params)
(get ::fb/current-file-id))) (get ::fb/current-file-id)
(dm/str)))
(catch :default cause (catch :default cause
(handle-exception cause)))) (handle-exception cause))))
@ -273,6 +274,16 @@
(catch :default cause (catch :default cause
(handle-exception cause)))) (handle-exception cause))))
:addRelation
(fn [file-id library-id]
(let [file-id (uuid/parse file-id)
library-id (uuid/parse library-id)]
(if (and file-id library-id)
(do
(swap! state update :relations assoc file-id library-id)
true)
false)))
:genId :genId
(fn [] (fn []
(dm/str (uuid/next))) (dm/str (uuid/next)))

View File

@ -194,7 +194,8 @@
:generated-by "penpot-library/%version%" :generated-by "penpot-library/%version%"
:referer (get opts :referer) :referer (get opts :referer)
:files files :files files
:relations []} :relations (->> (:relations state)
(mapv vec))}
params (d/without-nils params)] params (d/without-nils params)]
["manifest.json" ["manifest.json"

View File

@ -54,6 +54,33 @@ test("create context with two file", () => {
assert.equal(file.data.pages.length, 0) assert.equal(file.data.pages.length, 0)
}); });
test("create context with two file and relation between", () => {
const context = penpot.createBuildContext();
const fileId_1 = context.addFile({name: "sample 1"});
const fileId_2 = context.addFile({name: "sample 2"});
context.addRelation(fileId_1, fileId_2);
const internalState = context.getInternalState();
assert.ok(internalState.files[fileId_1]);
assert.ok(internalState.files[fileId_2]);
assert.equal(internalState.files[fileId_1].name, "sample 1");
assert.equal(internalState.files[fileId_2].name, "sample 2");
assert.ok(internalState.relations[fileId_1]);
assert.equal(internalState.relations[fileId_1], fileId_2);
const file = internalState.files[fileId_2];
assert.ok(file.data);
assert.ok(file.data.pages);
assert.ok(file.data.pagesIndex);
assert.equal(file.data.pages.length, 0)
});
test("create context with file and page", () => { test("create context with file and page", () => {
const context = penpot.createBuildContext(); const context = penpot.createBuildContext();