🎉 Add binary fills integration

This commit is contained in:
Andrey Antukh 2025-07-09 17:02:23 +02:00
parent 9ee488009f
commit 8bb210e7b6
25 changed files with 210 additions and 147 deletions

View File

@ -356,7 +356,7 @@
(first children) (first children)
(last children)) (last children))
fills (if (and (contains? head :svg-attrs) (empty? (:fills head))) fills (if (and (contains? head :svg-attrs) (empty? (:fills head)))
types.path/default-bool-fills (types.path/get-default-bool-fills)
(get head :fills))] (get head :fills))]
(-> bool-shape (-> bool-shape
(assoc :fills fills) (assoc :fills fills)

View File

@ -83,20 +83,12 @@
:else :else
(ex/raise :type :internal (ex/raise :type :internal
:code :invalid-type :code :invalid-type
:hint (str "cannot coerce " (pr-str o) "to fills")))) :hint (str "cannot coerce " (pr-str o) " to fills"))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; HELPERS ;; TYPE HELPERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; FIXME: duplicated of `assoc`
(defn assoc-fill
[fills position fill]
(if (nil? fills)
(impl/from-plain [fill])
(-> (coerce fills)
(c/assoc position fill))))
(defn get-image-ids (defn get-image-ids
[fills] [fills]
(if (vector? fills) (if (vector? fills)
@ -136,7 +128,7 @@
fills (apply f fills args)] fills (apply f fills args)]
(if (contains? flags/*current* :frontend-binary-fills) (if (contains? flags/*current* :frontend-binary-fills)
(impl/from-plain fills) (impl/from-plain fills)
fills))) (vec fills))))
(defn create (defn create
[& elements] [& elements]

View File

@ -378,7 +378,26 @@
(when (< i size) (when (< i size)
(cons (read-fill dbuffer mbuffer i) (cons (read-fill dbuffer mbuffer i)
(lazy-seq (next-seq (inc i)))))) (lazy-seq (next-seq (inc i))))))
0))))) 0)))
cljs.core/IPrintWithWriter
(-pr-writer [this writer _]
(binding [*print-dup* true]
(cljs.core/-write writer (str "#penpot/fills \"" (pr-str (vec this)) "\""))))))
#?(:clj
(defmethod print-method Fills
[o ^java.io.Writer writer]
(.write writer "#penpot/fills \"")
(print-dup (vec o) writer)
(.write writer "\"")))
#?(:clj
(defmethod print-dup Fills
[o ^java.io.Writer writer]
(.write writer "#penpot/fills \"")
(print-dup (vec o) writer)
(.write writer "\"")))
(defn from-plain (defn from-plain
[fills] [fills]

View File

@ -26,7 +26,9 @@
(def ^:cosnt bool-group-style-properties bool/group-style-properties) (def ^:cosnt bool-group-style-properties bool/group-style-properties)
(def ^:const bool-style-properties bool/style-properties) (def ^:const bool-style-properties bool/style-properties)
(def ^:const default-bool-fills bool/default-fills) (defn get-default-bool-fills
[]
(bool/get-default-fills))
(def schema:content impl/schema:content) (def schema:content impl/schema:content)
(def schema:segments impl/schema:segments) (def schema:segments impl/schema:segments)

View File

@ -7,16 +7,22 @@
(ns app.common.types.path.bool (ns app.common.types.path.bool
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.flags :as flags]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.rect :as grc] [app.common.geom.rect :as grc]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.types.color :as clr] [app.common.types.color :as clr]
[app.common.types.fills :as types.fills]
[app.common.types.path.helpers :as helpers] [app.common.types.path.helpers :as helpers]
[app.common.types.path.segment :as segment] [app.common.types.path.segment :as segment]
[app.common.types.path.subpath :as subpath])) [app.common.types.path.subpath :as subpath]))
(def default-fills (defn get-default-fills
[{:fill-color clr/black}]) []
(let [fills [{:fill-color clr/black}]]
(if (contains? flags/*current* :frontend-binary-fills)
(types.fills/from-plain fills)
fills)))
(def group-style-properties (def group-style-properties
#{:shadow :blur}) #{:shadow :blur})

View File

@ -415,12 +415,14 @@
;; Valid attributes ;; Valid attributes
(def ^:private allowed-shape-attrs #{:page-id :component-id :component-file :component-root :main-instance (def ^:private allowed-shape-attrs
:remote-synced :shape-ref :touched :blocked :collapsed :locked #{:page-id :component-id :component-file :component-root :main-instance
:hidden :masked-group :fills :proportion :proportion-lock :constraints-h :remote-synced :shape-ref :touched :blocked :collapsed :locked
:constraints-v :fixed-scroll :r1 :r2 :r3 :r4 :opacity :grids :exports :hidden :masked-group :fills :proportion :proportion-lock :constraints-h
:strokes :blend-mode :interactions :shadow :blur :grow-type :applied-tokens :constraints-v :fixed-scroll :r1 :r2 :r3 :r4 :opacity :grids :exports
:plugin-data}) :strokes :blend-mode :interactions :shadow :blur :grow-type :applied-tokens
:plugin-data})
(def ^:private allowed-shape-geom-attrs #{:x :y :width :height}) (def ^:private allowed-shape-geom-attrs #{:x :y :width :height})
(def ^:private allowed-shape-base-attrs #{:id :name :type :selrect :points :transform :transform-inverse :parent-id :frame-id}) (def ^:private allowed-shape-base-attrs #{:id :name :type :selrect :points :transform :transform-inverse :parent-id :frame-id})
(def ^:private allowed-bool-attrs #{:shapes :bool-type :content}) (def ^:private allowed-bool-attrs #{:shapes :bool-type :content})

View File

@ -8,7 +8,9 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.flags :as flags]
[app.common.types.color :as clr] [app.common.types.color :as clr]
[app.common.types.fills :as types.fills]
[clojure.set :as set] [clojure.set :as set]
[clojure.walk :as walk] [clojure.walk :as walk]
[cuerdas.core :as str])) [cuerdas.core :as str]))
@ -84,10 +86,12 @@
(def default-root-attrs (def default-root-attrs
{:vertical-align "top"}) {:vertical-align "top"})
(def default-text-fills
[{:fill-color clr/black
:fill-opacity 1}])
(def default-text-attrs (def default-text-attrs
{:typography-ref-file nil {:font-id "sourcesanspro"
:typography-ref-id nil
:font-id "sourcesanspro"
:font-family "sourcesanspro" :font-family "sourcesanspro"
:font-variant-id "regular" :font-variant-id "regular"
:font-size "14" :font-size "14"
@ -98,12 +102,22 @@
:text-transform "none" :text-transform "none"
:text-align "left" :text-align "left"
:text-decoration "none" :text-decoration "none"
:text-direction "ltr" :text-direction "ltr"})
:fills [{:fill-color clr/black
:fill-opacity 1}]})
(def default-attrs (defn get-default-text-fills
(merge default-root-attrs default-text-attrs)) "Return calculated default text fills"
[]
(if (contains? flags/*current* :frontend-binary-fills)
(types.fills/from-plain default-text-fills)
default-text-fills))
(defn get-default-text-attrs
"Return calculated default text attrs.
NOTE: is implemented as function because it needs resolve at runtime
the activated flag for properly encode the fills"
[]
(assoc default-text-attrs :fills (get-default-text-fills)))
(def typography-fields (def typography-fields
[:font-id [:font-id
@ -117,9 +131,9 @@
:text-transform]) :text-transform])
(def default-typography (def default-typography
(merge (-> default-text-attrs
{:name "Source Sans Pro Regular"} (select-keys typography-fields)
(select-keys default-text-attrs typography-fields))) (assoc :name "Source Sans Pro Regular")))
(defn node-seq (defn node-seq
([root] (node-seq identity root)) ([root] (node-seq identity root))

View File

@ -78,6 +78,23 @@
(filter selectable?) (filter selectable?)
selected))))) selected)))))
(defn split-text-shapes
"Split text shapes from non-text shapes"
[objects ids]
(loop [ids (seq ids)
text-ids []
shape-ids []]
(if-let [id (first ids)]
(let [shape (get objects id)]
(if (cfh/text-shape? shape)
(recur (rest ids)
(conj text-ids id)
shape-ids)
(recur (rest ids)
text-ids
(conj shape-ids id))))
[text-ids shape-ids])))
;; DEPRECATED ;; DEPRECATED
(defn lookup-selected-raw (defn lookup-selected-raw
[state] [state]

View File

@ -36,7 +36,7 @@
head head
(cond-> head (cond-> head
(and (contains? head :svg-attrs) (empty? (:fills head))) (and (contains? head :svg-attrs) (empty? (:fills head)))
(assoc :fills path/default-bool-fills)) (assoc :fills (path/get-default-bool-fills)))
shape shape
{:id shape-id {:id shape-id
@ -62,7 +62,7 @@
head (if (= type :difference) (first shapes) (last shapes)) head (if (= type :difference) (first shapes) (last shapes))
head (cond-> head head (cond-> head
(and (contains? head :svg-attrs) (empty? (:fills head))) (and (contains? head :svg-attrs) (empty? (:fills head)))
(assoc :fills path/default-bool-fills))] (assoc :fills (path/get-default-bool-fills)))]
(-> group (-> group
(assoc :type :bool) (assoc :type :bool)
(assoc :bool-type type) (assoc :bool-type type)

View File

@ -925,7 +925,7 @@
(let [paragraphs (->> (str/lines text) (let [paragraphs (->> (str/lines text)
(map str/trim) (map str/trim)
(mapv #(hash-map :type "paragraph" (mapv #(hash-map :type "paragraph"
:children [(merge txt/default-text-attrs {:text %})])))] :children [(merge (txt/get-default-text-attrs) {:text %})])))]
;; if text is composed only by line breaks paragraphs is an empty list and should be nil ;; if text is composed only by line breaks paragraphs is an empty list and should be nil
(when (d/not-empty? paragraphs) (when (d/not-empty? paragraphs)
{:type "root" {:type "root"

View File

@ -18,7 +18,6 @@
[app.common.types.text :as txt] [app.common.types.text :as txt]
[app.config :as cfg] [app.config :as cfg]
[app.main.broadcast :as mbc] [app.main.broadcast :as mbc]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh] [app.main.data.helpers :as dsh]
[app.main.data.modal :as md] [app.main.data.modal :as md]
[app.main.data.workspace.layout :as layout] [app.main.data.workspace.layout :as layout]
@ -103,11 +102,7 @@
(defn assoc-shape-fill (defn assoc-shape-fill
[shape position fill] [shape position fill]
(update shape :fills (update shape :fills types.fills/assoc position fill))
(fn [fills]
(if (nil? fills)
[fill]
(assoc fills position fill)))))
(defn transform-fill* (defn transform-fill*
"A lower-level companion function for `transform-fill`" "A lower-level companion function for `transform-fill`"
@ -167,17 +162,28 @@
(assoc-in [attr index] second) (assoc-in [attr index] second)
(assoc-in [attr new-index] first)))) (assoc-in [attr new-index] first))))
(defn- swap-fills-index
[fills index new-index]
(let [first (get fills index)
second (get fills new-index)]
(-> fills
(assoc index second)
(assoc new-index first))))
(defn reorder-fills (defn reorder-fills
[ids index new-index] [ids index new-index]
(ptk/reify ::reorder-fills (ptk/reify ::reorder-fills
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [objects (dsh/lookup-page-objects state) (let [objects
(dsh/lookup-page-objects state)
is-text? #(= :text (:type (get objects %))) [text-ids shape-ids]
text-ids (filter is-text? ids) (dsh/split-text-shapes objects ids)
shape-ids (remove is-text? ids)
transform-attrs #(swap-attrs % :fills index new-index)] transform-attrs
(fn [object]
(update object :fills types.fills/update swap-fills-index index new-index))]
(rx/concat (rx/concat
(rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids)) (rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids))
@ -207,7 +213,7 @@
(ptk/reify ::change-fill-and-clear (ptk/reify ::change-fill-and-clear
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [change-fn (fn [shape attrs] (assoc shape :fills [attrs])) (let [change-fn (fn [shape attrs] (assoc shape :fills (types.fills/create attrs)))
undo-id (js/Symbol)] undo-id (js/Symbol)]
(rx/concat (rx/concat
(rx/of (dwu/start-undo-transaction undo-id)) (rx/of (dwu/start-undo-transaction undo-id))
@ -225,8 +231,7 @@
(watch [_ state _] (watch [_ state _]
(let [change-fn (let [change-fn
(fn [shape attrs] (fn [shape attrs]
(-> shape (update shape :fills types.fills/prepend attrs))
(update :fills #(into [attrs] %))))
undo-id undo-id
(js/Symbol)] (js/Symbol)]
(rx/concat (rx/concat
@ -247,13 +252,13 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [detach-fn (let [detach-fn
(fn [values index] (fn [fills index]
(update values index dissoc :fill-color-ref-id :fill-color-ref-file)) (update fills index dissoc :fill-color-ref-id :fill-color-ref-file))
change-fn change-fn
;; The `node` can be a shape or a text content node ;; The `node` can be a shape or a text content node
(fn [node] (fn [node]
(update node :fills detach-fn position)) (update node :fills types.fills/update detach-fn position))
undo-id undo-id
(js/Symbol)] (js/Symbol)]
@ -275,17 +280,17 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [remove-fill-by-index (let [remove-fill-by-index
(fn [values index] (fn [fills index]
(into [] (into []
(comp (comp
(map-indexed (fn [i o] (when (not= i index) o))) (map-indexed (fn [i o] (when (not= i index) o)))
(filter some?)) (filter some?))
values)) fills))
change-fn change-fn
;; The `node` can be a shape or a text content node ;; The `node` can be a shape or a text content node
(fn [node] (fn [node]
(update node :fills remove-fill-by-index position)) (update node :fills types.fills/update remove-fill-by-index position))
undo-id undo-id
(js/Symbol)] (js/Symbol)]
@ -303,7 +308,7 @@
(ptk/reify ::remove-all-fills (ptk/reify ::remove-all-fills
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [change-fn (fn [node] (assoc node :fills [])) (let [change-fn (fn [node] (assoc node :fills (types.fills/create)))
undo-id (js/Symbol)] undo-id (js/Symbol)]
(rx/concat (rx/concat
(rx/of (dwu/start-undo-transaction undo-id)) (rx/of (dwu/start-undo-transaction undo-id))
@ -576,16 +581,26 @@
:fill-color-ref-file (:ref-file color) :fill-color-ref-file (:ref-file color)
:fill-color-gradient (:gradient color)})) :fill-color-gradient (:gradient color)}))
(defn change-text-color (defn- change-text-color
[old-color new-color index node] [old-color new-color index node]
(let [fills (map #(dissoc % :fill-color-ref-id :fill-color-ref-file) (:fills node)) (update node :fills types.fills/update
parsed-color (-> (color-att->text old-color) (fn [fills]
(dissoc :fill-color-ref-id :fill-color-ref-file)) (let [fills'
parsed-new-color (color-att->text new-color) (map #(dissoc % :fill-color-ref-id :fill-color-ref-file) fills)
has-color? (d/index-of fills parsed-color)]
(cond-> node parsed-color
(some? has-color?) (-> (color-att->text old-color)
(assoc-in [:fills index] parsed-new-color)))) (dissoc :fill-color-ref-id :fill-color-ref-file))
parsed-new-color
(color-att->text new-color)
has-color?
(d/index-of fills' parsed-color)]
(cond-> fills
(some? has-color?)
(assoc index parsed-new-color))))))
(def ^:private schema:change-color-operation (def ^:private schema:change-color-operation
[:map [:map
@ -1114,39 +1129,6 @@
(assoc :type :image) (assoc :type :image)
(dissoc :editing-stop :stops :gradient))))))) (dissoc :editing-stop :stops :gradient)))))))
(defn select-color
[position add-color]
;; FIXME: revisit
(ptk/reify ::select-color
ptk/WatchEvent
(watch [_ state _]
(let [selected (dsh/lookup-selected state)
shapes (dsh/lookup-shapes state selected)
shape (first shapes)
fills (if (cfh/text-shape? shape)
(:fills (dwt/current-text-values
{:editor-state (dm/get-in state [:workspace-editor-state (:id shape)])
:shape shape
:attrs (conj txt/text-fill-attrs :fills)}))
(:fills shape))
fill (first fills)
single? (and (= 1 (count selected))
(= 1 (count fills)))
data (if single?
(d/without-nils {:color (:fill-color fill)
:opacity (:fill-opacity fill)
:gradient (:fill-color-gradient fill)})
{:color "#406280"
:opacity 1})]
(rx/of (md/show :colorpicker
{:x (:x position)
:y (:y position)
:on-accept add-color
:data data
:position :right})
(ptk/event ::ev/event {::ev/name "add-asset-to-library"
:asset-type "color"}))))))
(defn- stroke->color-att (defn- stroke->color-att
[stroke file-id libraries] [stroke file-id libraries]
(let [ref-file (:stroke-color-ref-file stroke) (let [ref-file (:stroke-color-ref-file stroke)

View File

@ -16,6 +16,7 @@
[app.common.media :as media] [app.common.media :as media]
[app.common.schema :as sm] [app.common.schema :as sm]
[app.common.types.container :as ctn] [app.common.types.container :as ctn]
[app.common.types.fills :as types.fills]
[app.common.types.shape :as cts] [app.common.types.shape :as cts]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.config :as cf] [app.config :as cf]
@ -63,18 +64,22 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
(let [{:keys [name width height id mtype]} image (let [{:keys [name width height id mtype]} image
fills (types.fills/create
{:fill-opacity 1
:fill-image {:width width
:height height
:mtype mtype
:id id
:keep-aspect-ratio true}})
shape {:name name shape {:name name
:width width :width width
:height height :height height
:x (mth/round (- x (/ width 2))) :x (mth/round (- x (/ width 2)))
:y (mth/round (- y (/ height 2))) :y (mth/round (- y (/ height 2)))
:fills [{:fill-opacity 1 :fills fills}]
:fill-image {:name name
:width width
:height height
:mtype mtype
:id id
:keep-aspect-ratio true}}]}]
(rx/of (dwsh/create-and-add-shape :rect x y shape)))))) (rx/of (dwsh/create-and-add-shape :rect x y shape))))))
(defn svg-uploaded (defn svg-uploaded
@ -299,7 +304,7 @@
:name (:name root-svg-shape) :name (:name root-svg-shape)
:frame-id uuid/zero :frame-id uuid/zero
:parent-id uuid/zero :parent-id uuid/zero
:fills []}) :fills (types.fills/create)})
root-svg-shape root-svg-shape
(-> root-svg-shape (-> root-svg-shape
@ -335,19 +340,21 @@
:frame-id uuid/zero :frame-id uuid/zero
:parent-id uuid/zero}) :parent-id uuid/zero})
img-fills (types.fills/create
{:fill-opacity 1
:fill-image {:id id
:width width
:height height
:mtype mtype
:keep-aspect-ratio true}})
img-shape (cts/setup-shape img-shape (cts/setup-shape
{:type :rect {:type :rect
:x (:x pos) :x (:x pos)
:y (:y pos) :y (:y pos)
:width width :width width
:height height :height height
:fills [{:fill-opacity 1 :fills img-fills
:fill-image {:name name
:id id
:width width
:height height
:mtype mtype
:keep-aspect-ratio true}}]
:name name :name name
:frame-id (:id frame-shape) :frame-id (:id frame-shape)
:parent-id (:id frame-shape)})] :parent-id (:id frame-shape)})]

View File

@ -196,8 +196,8 @@
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [text-state (some->> content ted/import-content) (let [text-state (some->> content ted/import-content)
attrs (d/merge txt/default-text-attrs attrs (merge (txt/get-default-text-attrs)
(get-in state [:workspace-global :default-font])) (get-in state [:workspace-global :default-font]))
editor (cond-> (ted/create-editor-state text-state decorator) editor (cond-> (ted/create-editor-state text-state decorator)
(and (nil? content) (some? attrs)) (and (nil? content) (some? attrs))
(ted/update-editor-current-block-data attrs))] (ted/update-editor-current-block-data attrs))]
@ -237,7 +237,9 @@
(defn- to-new-fills (defn- to-new-fills
[data] [data]
[(d/without-nils (select-keys data types.fills/fill-attrs))]) ;; FIXME: maybe export this as a specific helper ?
(types.fills/create
(d/without-nils (select-keys data types.fills/fill-attrs))))
(defn- shape-current-values (defn- shape-current-values
[shape pred attrs] [shape pred attrs]
@ -245,7 +247,10 @@
nodes (->> (txt/node-seq pred root) nodes (->> (txt/node-seq pred root)
(map (fn [node] (map (fn [node]
(if (txt/is-text-node? node) (if (txt/is-text-node? node)
(let [fills (let [default-text-attrs
(txt/get-default-text-attrs)
fills
(cond (cond
(types.fills/has-valid-fill-attrs? node) (types.fills/has-valid-fill-attrs? node)
(to-new-fills node) (to-new-fills node)
@ -254,8 +259,9 @@
(:fills node) (:fills node)
:else :else
(:fills txt/default-text-attrs))] (:fills default-text-attrs))]
(-> (merge txt/default-text-attrs node)
(-> (merge default-text-attrs node)
(assoc :fills fills))) (assoc :fills fills)))
node))))] node))))]
(attrs/get-attrs-multi nodes attrs))) (attrs/get-attrs-multi nodes attrs)))
@ -290,7 +296,9 @@
[{:keys [editor-state attrs]}] [{:keys [editor-state attrs]}]
(let [result (-> (ted/get-editor-current-inline-styles editor-state) (let [result (-> (ted/get-editor-current-inline-styles editor-state)
(select-keys attrs)) (select-keys attrs))
result (if (empty? result) txt/default-text-attrs result)] result (if (empty? result)
(txt/get-default-text-attrs)
result)]
result)) result))
(defn current-text-values (defn current-text-values
@ -469,21 +477,21 @@
(let [color-attrs (not-empty (select-keys node types.fills/fill-attrs))] (let [color-attrs (not-empty (select-keys node types.fills/fill-attrs))]
(cond-> node (cond-> node
(nil? (:fills node)) (nil? (:fills node))
(assoc :fills []) (assoc :fills (types.fills/create))
;; Migrate old colors and remove the old fromat ;; Migrate old colors and remove the old fromat
color-attrs color-attrs
(-> (dissoc :fill-color :fill-opacity :fill-color-ref-id :fill-color-ref-file :fill-color-gradient) (-> (dissoc :fill-color :fill-opacity :fill-color-ref-id :fill-color-ref-file :fill-color-gradient)
(update :fills conj color-attrs)) (update :fills types.fills/update conj color-attrs))
;; We don't have the fills attribute. It's an old text without color ;; We don't have the fills attribute. It's an old text without color
;; so need to be black ;; so need to be black
(and (nil? (:fills node)) (empty? color-attrs)) (and (nil? (:fills node)) (empty? color-attrs))
(assoc :fills (:fills txt/default-text-attrs)) (assoc :fills (txt/get-default-text-fills))
;; Remove duplicates from the fills ;; Remove duplicates from the fills
:always :always
(update :fills (comp vec distinct))))) (update :fills types.fills/update distinct))))
(defn migrate-content (defn migrate-content
[content] [content]
@ -905,7 +913,7 @@
(ptk/reify ::v2-update-text-editor-styles (ptk/reify ::v2-update-text-editor-styles
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [merged-styles (merge txt/default-text-attrs (let [merged-styles (merge (txt/get-default-text-attrs)
(get-in state [:workspace-global :default-font]) (get-in state [:workspace-global :default-font])
new-styles)] new-styles)]
(update-in state [:workspace-v2-editor-state id] (fnil merge {}) merged-styles))))) (update-in state [:workspace-v2-editor-state id] (fnil merge {}) merged-styles)))))

View File

@ -295,7 +295,7 @@
(let [current-font (let [current-font
(if (some? font-id) (if (some? font-id)
(select-keys node [:font-id :font-variant-id]) (select-keys node [:font-id :font-variant-id])
(select-keys txt/default-text-attrs [:font-id :font-variant-id]))] (select-keys txt/default-typography [:font-id :font-variant-id]))]
(conj result current-font))) (conj result current-font)))
#{}))) #{})))

View File

@ -174,7 +174,7 @@
(let [style-text-blocks (->> (:content shape) (let [style-text-blocks (->> (:content shape)
(txt/content->text+styles) (txt/content->text+styles)
(remove (fn [[_ text]] (str/empty? (str/trim text)))) (remove (fn [[_ text]] (str/empty? (str/trim text))))
(mapv (fn [[style text]] (vector (merge txt/default-text-attrs style) text))))] (mapv (fn [[style text]] (vector (merge (txt/get-default-text-attrs) style) text))))]
(for [[idx [full-style text]] (map-indexed vector style-text-blocks)] (for [[idx [full-style text]] (map-indexed vector style-text-blocks)]
[:& typography-block {:key idx [:& typography-block {:key idx

View File

@ -17,7 +17,7 @@
(defn- load-fonts! (defn- load-fonts!
[content] [content]
(let [extract-fn (juxt :font-id :font-variant-id) (let [extract-fn (juxt :font-id :font-variant-id)
default (extract-fn txt/default-text-attrs)] default (extract-fn txt/default-typography)]
(->> (tree-seq map? :children content) (->> (tree-seq map? :children content)
(into #{default} (keep extract-fn)) (into #{default} (keep extract-fn))
(run! (fn [[font-id variant-id]] (run! (fn [[font-id variant-id]]

View File

@ -53,11 +53,11 @@
line-height line-height
(if (and (some? line-height) (not= "" line-height)) (if (and (some? line-height) (not= "" line-height))
line-height line-height
(:line-height txt/default-text-attrs)) (:line-height txt/default-typography))
text-align (:text-align data "start") text-align (:text-align data "start")
base #js {;; Fix a problem when exporting HTML base #js {;; Fix a problem when exporting HTML
:fontSize 0 ;;(str (:font-size data (:font-size txt/default-text-attrs)) "px") :fontSize 0
:lineHeight line-height :lineHeight line-height
:margin 0}] :margin 0}]
@ -75,7 +75,7 @@
text-transform (:text-transform data) text-transform (:text-transform data)
font-id (or (:font-id data) font-id (or (:font-id data)
(:font-id txt/default-text-attrs)) (:font-id txt/default-typography))
font-variant-id (:font-variant-id data) font-variant-id (:font-variant-id data)

View File

@ -41,7 +41,7 @@
(defn- get-fonts (defn- get-fonts
[content] [content]
(let [extract-fn (juxt :font-id :font-variant-id) (let [extract-fn (juxt :font-id :font-variant-id)
default (extract-fn txt/default-text-attrs)] default (extract-fn txt/default-typography)]
(->> (tree-seq map? :children content) (->> (tree-seq map? :children content)
(into #{default} (keep extract-fn))))) (into #{default} (keep extract-fn)))))
@ -67,7 +67,7 @@
style-defaults style-defaults
(styles/get-style-defaults (styles/get-style-defaults
(merge txt/default-text-attrs txt/default-root-attrs default-font)) (merge (txt/get-default-text-attrs) txt/default-root-attrs default-font))
options options
#js {:styleDefaults style-defaults #js {:styleDefaults style-defaults

View File

@ -217,7 +217,7 @@
(mf/use-fn (mf/use-fn
(mf/deps values) (mf/deps values)
(fn [ids attrs] (fn [ids attrs]
(st/emit! (dwt/save-font (-> (merge txt/default-text-attrs values attrs) (st/emit! (dwt/save-font (-> (merge (txt/get-default-text-attrs) values attrs)
(select-keys txt/text-node-attrs))) (select-keys txt/text-node-attrs)))
(dwt/update-all-attrs ids attrs)))) (dwt/update-all-attrs ids attrs))))

View File

@ -235,9 +235,9 @@
[{:keys [values on-change on-blur show-recent full-size-selector]}] [{:keys [values on-change on-blur show-recent full-size-selector]}]
(let [{:keys [font-id font-size font-variant-id]} values (let [{:keys [font-id font-size font-variant-id]} values
font-id (or font-id (:font-id txt/default-text-attrs)) font-id (or font-id (:font-id txt/default-typography))
font-size (or font-size (:font-size txt/default-text-attrs)) font-size (or font-size (:font-size txt/default-typography))
font-variant-id (or font-variant-id (:font-variant-id txt/default-text-attrs)) font-variant-id (or font-variant-id (:font-variant-id txt/default-typography))
fonts (mf/deref fonts/fontsdb) fonts (mf/deref fonts/fontsdb)
font (get fonts font-id) font (get fonts font-id)

View File

@ -203,6 +203,9 @@
[shapes objects attr-group] [shapes objects attr-group]
(let [attrs (group->attrs attr-group) (let [attrs (group->attrs attr-group)
default-text-attrs
(txt/get-default-text-attrs)
merge-attrs merge-attrs
(fn [v1 v2] (fn [v1 v2]
(cond (cond
@ -233,7 +236,7 @@
(let [shape-attrs (select-keys shape attrs) (let [shape-attrs (select-keys shape attrs)
content-attrs content-attrs
(attrs/get-text-attrs-multi shape txt/default-text-attrs attrs) (attrs/get-text-attrs-multi shape default-text-attrs attrs)
new-values new-values
(-> values (-> values

View File

@ -73,12 +73,12 @@
;; it affects to the height calculation the browser does ;; it affects to the height calculation the browser does
font-size (if (some #(not= "" (:text %)) (:children paragraph)) font-size (if (some #(not= "" (:text %)) (:children paragraph))
"0" "0"
(:font-size styles (:font-size txt/default-text-attrs))) (:font-size styles (:font-size txt/default-typography)))
line-height (:line-height styles) line-height (:line-height styles)
line-height (if (and (some? line-height) (not= "" line-height)) line-height (if (and (some? line-height) (not= "" line-height))
line-height line-height
(:line-height txt/default-text-attrs))] (:line-height txt/default-typography))]
(-> styles (-> styles
(assoc :font-size font-size :line-height line-height)))) (assoc :font-size font-size :line-height line-height))))

View File

@ -12,6 +12,7 @@
[app.common.files.validate :as cfv] [app.common.files.validate :as cfv]
[app.common.json :as json] [app.common.json :as json]
[app.common.logging :as l] [app.common.logging :as l]
[app.common.pprint :as pp]
[app.common.transit :as t] [app.common.transit :as t]
[app.common.types.file :as ctf] [app.common.types.file :as ctf]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
@ -197,6 +198,14 @@
(logjs "selected" result) (logjs "selected" result)
nil)) nil))
(defn ^:export dump-selected-edn
[]
(let [objects (dsh/lookup-page-objects @st/state)
result (->> (get-selected @st/state) (map #(get objects %)))]
(pp/pprint result {:length 30 :level 30})
nil))
(defn ^:export preview-selected (defn ^:export preview-selected
[] []
(st/emit! (dp/open-preview-selected))) (st/emit! (dp/open-preview-selected)))

View File

@ -412,7 +412,7 @@
(t/is (= (get c-frame1' :opacity) 0.9)) (t/is (= (get c-frame1' :opacity) 0.9))
(t/is (= (get-in c-frame1' [:strokes 0 :stroke-width]) 8)) (t/is (= (get-in c-frame1' [:strokes 0 :stroke-width]) 8))
(t/is (= (get-in c-frame1' [:strokes 0 :stroke-color]) "#ff0000")) (t/is (= (get-in c-frame1' [:strokes 0 :stroke-color]) "#ff0000"))
(t/is (= (get-in c-frame1' [:fills 0 :fill-color]) "#ff0000")) (t/is (= (-> c-frame1' :fills (nth 0) :fill-color) "#ff0000"))
(t/is (mth/close? (get c-frame1' :width) 200)) (t/is (mth/close? (get c-frame1' :width) 200))
(t/is (mth/close? (get c-frame1' :height) 200)) (t/is (mth/close? (get c-frame1' :height) 200))

View File

@ -219,19 +219,21 @@
secondary-target (toht/get-token file' "color.secondary") secondary-target (toht/get-token file' "color.secondary")
rect-1' (cths/get-shape file' :rect-1) rect-1' (cths/get-shape file' :rect-1)
rect-2' (cths/get-shape file' :rect-2)] rect-2' (cths/get-shape file' :rect-2)]
(t/testing "regular color" (t/testing "regular color"
(t/is (some? (:applied-tokens rect-1'))) (t/is (some? (:applied-tokens rect-1')))
(t/is (= (:fill (:applied-tokens rect-1')) (:name primary-target))) (t/is (= (:fill (:applied-tokens rect-1')) (:name primary-target)))
(t/is (= (get-in rect-1' [:fills 0 :fill-color]) "#ff0000")) (t/is (= (-> rect-1' :fills (nth 0) :fill-color) "#ff0000"))
(t/is (= (:stroke-color (:applied-tokens rect-1')) (:name primary-target))) (t/is (= (:stroke-color (:applied-tokens rect-1')) (:name primary-target)))
(t/is (= (get-in rect-1' [:strokes 0 :stroke-color]) "#ff0000"))) (t/is (= (get-in rect-1' [:strokes 0 :stroke-color]) "#ff0000")))
(t/testing "color with alpha channel" (t/testing "color with alpha channel"
(t/is (some? (:applied-tokens rect-2'))) (t/is (some? (:applied-tokens rect-2')))
(t/is (= (:fill (:applied-tokens rect-2')) (:name secondary-target))) (t/is (= (:fill (:applied-tokens rect-2')) (:name secondary-target)))
(t/is (= (get-in rect-2' [:fills 0 :fill-color]) "#ff0000")) (let [fills (get rect-2' :fills)]
(t/is (= (get-in rect-2' [:fills 0 :fill-opacity]) 0.5)) (t/is (= (-> fills (nth 0) :fill-color) "#ff0000"))
(t/is (= (-> fills (nth 0) :fill-opacity) 0.5)))
(t/is (= (:stroke-color (:applied-tokens rect-2')) (:name secondary-target))) (t/is (= (:stroke-color (:applied-tokens rect-2')) (:name secondary-target)))
(t/is (= (get-in rect-2' [:strokes 0 :stroke-color]) "#ff0000")) (t/is (= (get-in rect-2' [:strokes 0 :stroke-color]) "#ff0000"))
@ -758,4 +760,4 @@
(t/is (nil? (:typography-ref-id paragraph-3))) (t/is (nil? (:typography-ref-id paragraph-3)))
(t/is (nil? (:typography-ref-file paragraph-3))) (t/is (nil? (:typography-ref-file paragraph-3)))
(t/is (nil? (:typography-ref-id text-node-3))) (t/is (nil? (:typography-ref-id text-node-3)))
(t/is (nil? (:typography-ref-file text-node-3)))))))))) (t/is (nil? (:typography-ref-file text-node-3))))))))))