diff --git a/common/src/app/common/attrs.cljc b/common/src/app/common/attrs.cljc index 1fdddae3b6..e990cb17c7 100644 --- a/common/src/app/common/attrs.cljc +++ b/common/src/app/common/attrs.cljc @@ -8,7 +8,7 @@ (:require [app.common.geom.shapes :as gsh] [app.common.math :as mth] - [app.common.text :as txt])) + [app.common.types.text :as txt])) (defn- get-attr [obj attr] diff --git a/common/src/app/common/buffer.cljc b/common/src/app/common/buffer.cljc index 390f3ffbf3..74514a3951 100644 --- a/common/src/app/common/buffer.cljc +++ b/common/src/app/common/buffer.cljc @@ -74,6 +74,13 @@ (let [target (with-meta target {:tag 'java.nio.ByteBuffer})] `(.put ~target ~offset (unchecked-byte ~value))))) +(defmacro write-bool + [target offset value] + (if (:ns &env) + `(.setInt8 ~target ~offset (if ~value 0x01 0x00) true) + (let [target (with-meta target {:tag 'java.nio.ByteBuffer})] + `(.put ~target ~offset (unchecked-byte (if ~value 0x01 0x00)))))) + (defmacro write-short [target offset value] (if (:ns &env) diff --git a/common/src/app/common/files/builder.cljc b/common/src/app/common/files/builder.cljc index aa8601bba3..181824c672 100644 --- a/common/src/app/common/files/builder.cljc +++ b/common/src/app/common/files/builder.cljc @@ -356,7 +356,7 @@ (first children) (last children)) fills (if (and (contains? head :svg-attrs) (empty? (:fills head))) - types.path/default-bool-fills + (types.path/get-default-bool-fills) (get head :fills))] (-> bool-shape (assoc :fills fills) diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index d9965ce556..1e9d5d039a 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -21,6 +21,7 @@ [app.common.types.container :as ctn] [app.common.types.file :as ctf] [app.common.types.grid :as ctg] + [app.common.types.library :as ctl] [app.common.types.page :as ctp] [app.common.types.pages-list :as ctpl] [app.common.types.path :as path] @@ -927,15 +928,15 @@ (defmethod process-change :add-color [data {:keys [color]}] - (ctc/add-color data color)) + (ctl/add-color data color)) (defmethod process-change :mod-color [data {:keys [color]}] - (ctc/set-color data color)) + (ctl/set-color data color)) (defmethod process-change :del-color [data {:keys [id]}] - (ctc/delete-color data id)) + (ctl/delete-color data id)) ;; DEPRECATED: remove before 2.3 (defmethod process-change :add-recent-color diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 5973451a94..9bff98e6d1 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -21,18 +21,17 @@ [app.common.math :as mth] [app.common.schema :as sm] [app.common.svg :as csvg] - [app.common.text :as txt] [app.common.types.color :as types.color] [app.common.types.component :as ctk] [app.common.types.container :as ctn] [app.common.types.file :as ctf] - [app.common.types.fill :as types.fill] + [app.common.types.fills :as types.fills] [app.common.types.path :as path] [app.common.types.path.segment :as path.segment] [app.common.types.shape :as cts] [app.common.types.shape.interactions :as ctsi] [app.common.types.shape.shadow :as ctss] - [app.common.types.text :as cttx] + [app.common.types.text :as types.text] [app.common.uuid :as uuid] [clojure.set :as set] [cuerdas.core :as str])) @@ -623,7 +622,7 @@ (let [invalid-node? (complement valid-node?)] (cond-> object (cfh/text-shape? object) - (update :content #(txt/transform-nodes invalid-node? fix-node %))))) + (update :content #(types.text/transform-nodes invalid-node? fix-node %))))) (update-container [container] (d/update-when container :objects d/update-vals update-object))] @@ -730,7 +729,7 @@ (let [shape (update-object shape)] (if (cfh/text-shape? shape) (-> shape - (update :content (partial txt/transform-nodes identity update-fill)) + (update :content (partial types.text/transform-nodes identity update-fill)) (d/update-when :position-data #(mapv update-object %))) shape))) @@ -838,7 +837,7 @@ (d/update-when :components d/update-vals update-container)))) (def ^:private valid-fill? - (sm/lazy-validator types.fill/schema:fill)) + (sm/lazy-validator types.fills/schema:fill)) (defmethod migrate-data "legacy-43" [data _] @@ -856,7 +855,7 @@ (update-object [object] (if (cfh/text-shape? object) - (update object :content #(txt/transform-nodes txt/is-content-node? update-text-node %)) + (update object :content #(types.text/transform-nodes types.text/is-content-node? update-text-node %)) object)) (update-container [container] @@ -1105,7 +1104,7 @@ ;; The text shape also can has fills on the text ;; fragments so we need to fix fills there (cond-> (cfh/text-shape? object) - (update :content (partial txt/transform-nodes txt/is-content-node? fix-fills))))) + (update :content (partial types.text/transform-nodes types.text/is-content-node? fix-fills))))) (update-container [container] (d/update-when container :objects d/update-vals update-object))] @@ -1423,7 +1422,7 @@ (update-object [object] (if (cfh/text-shape? object) - (update object :content (partial txt/transform-nodes txt/is-content-node? fix-fills)) + (update object :content (partial types.text/transform-nodes types.text/is-content-node? fix-fills)) object)) (update-container [container] @@ -1457,7 +1456,7 @@ ;; Fixes shapes with nested :fills in the :fills attribute ;; introduced in a migration `0006-fix-old-texts-fills` when - ;; txt/transform-nodes with identity pred was broken + ;; types.text/transform-nodes with identity pred was broken (remove-nested-fills [[fill :as fills]] (if (and (= 1 (count fills)) (contains? fill :fills)) @@ -1466,7 +1465,7 @@ (clear-fill [fill] (-> fill - (select-keys types.fill/fill-attrs) + (select-keys types.fills/fill-attrs) (d/update-when :fill-image clear-color-image) (d/update-when :fill-color-gradient clear-color-gradient))) @@ -1483,8 +1482,8 @@ (fix-text-content [content] (->> content - (txt/transform-nodes txt/is-content-node? fix-object) - (txt/transform-nodes txt/is-paragraph-set-node? #(dissoc % :fills)))) + (types.text/transform-nodes types.text/is-content-node? fix-object) + (types.text/transform-nodes types.text/is-paragraph-set-node? #(dissoc % :fills)))) (update-shape [object] (-> object @@ -1539,7 +1538,7 @@ ref-shape (ctf/find-ref-shape file page libs object {:include-deleted? true :with-context? true}) partial-touched (when ref-shape - (cttx/get-diff-type (:content object) (:content ref-shape)))] + (types.text/get-diff-type (:content object) (:content ref-shape)))] (if (seq partial-touched) (update object :touched (fn [touched] (reduce #(ctk/set-touched-group %1 %2) diff --git a/common/src/app/common/files/shapes_builder.cljc b/common/src/app/common/files/shapes_builder.cljc index 78cde6c764..044838eee9 100644 --- a/common/src/app/common/files/shapes_builder.cljc +++ b/common/src/app/common/files/shapes_builder.cljc @@ -7,7 +7,6 @@ (ns app.common.files.shapes-builder "A SVG to Shapes builder." (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.exceptions :as ex] @@ -21,6 +20,7 @@ [app.common.math :as mth] [app.common.schema :as sm :refer [max-safe-int min-safe-int]] [app.common.svg :as csvg] + [app.common.types.color :as clr] [app.common.types.path :as path] [app.common.types.path.segment :as path.segm] [app.common.types.shape :as cts] diff --git a/common/src/app/common/flags.cljc b/common/src/app/common/flags.cljc index 80f96fd8aa..49a71cd04e 100644 --- a/common/src/app/common/flags.cljc +++ b/common/src/app/common/flags.cljc @@ -10,6 +10,8 @@ [clojure.set :as set] [cuerdas.core :as str])) +(def ^:dynamic *current* #{}) + (def login "Flags related to login features" #{;; Allows registration with login / password diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index 3c1479dced..6f3ebfa772 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -17,19 +17,18 @@ [app.common.logic.shapes :as cls] [app.common.logic.variant-properties :as clvp] [app.common.spec :as us] - [app.common.text :as txt] - [app.common.types.color :as ctc] [app.common.types.component :as ctk] [app.common.types.components-list :as ctkl] [app.common.types.container :as ctn] [app.common.types.file :as ctf] + [app.common.types.library :as ctl] [app.common.types.page :as ctp] [app.common.types.pages-list :as ctpl] [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.types.shape.interactions :as ctsi] - [app.common.types.shape.layout :as ctl] - [app.common.types.text :as cttx] + [app.common.types.shape.layout :as ctsl] + [app.common.types.text :as txt] [app.common.types.token :as cto] [app.common.types.typography :as cty] [app.common.types.variant :as ctv] @@ -215,8 +214,8 @@ [(:frame-id new-main-instance-shape)] (fn [shape objects] (cond-> shape - (ctl/grid-layout? shape) - (ctl/assign-cells objects))) + (ctsl/grid-layout? shape) + (ctsl/assign-cells objects))) {:with-objects? true}))])) @@ -277,7 +276,7 @@ (->> ids-map vals (some #(= % (:parent-id first-shape)))) changes - (if (and (ctl/grid-layout? objects (:parent-id first-shape)) (not duplicated-parent?)) + (if (and (ctsl/grid-layout? objects (:parent-id first-shape)) (not duplicated-parent?)) (let [target-cell (-> position meta :cell) [row column] @@ -288,10 +287,10 @@ [(:parent-id first-shape)] (fn [shape objects] (-> shape - (ctl/assign-cells objects) + (ctsl/assign-cells objects) (cond-> (and (some? row) (some? column)) - (-> (ctl/push-into-cell [(:id first-shape)] row column) - (ctl/assign-cells objects))))) + (-> (ctsl/push-into-cell [(:id first-shape)] row column) + (ctsl/assign-cells objects))))) {:with-objects? true}) (pcb/reorder-grid-children [(:parent-id first-shape)]))) changes) @@ -576,8 +575,8 @@ (defmethod uses-assets? :colors [_ color-id shape library-id] (if (nil? color-id) - (ctc/uses-library-colors? shape library-id) - (ctc/uses-library-color? shape library-id color-id))) + (cts/uses-library-colors? shape library-id) + (cts/uses-library-color? shape library-id color-id))) (defmethod uses-assets? :typographies [_ typography-id shape library-id] @@ -605,7 +604,7 @@ (let [library-colors (get-in libraries [library-id :data :colors])] (pcb/update-shapes changes [(:id shape)] - #(ctc/sync-shape-colors % library-id library-colors)))) + #(ctl/sync-colors % library-id library-colors)))) (defmethod generate-sync-shape :typographies [_ changes library-id container shape libraries _] @@ -854,7 +853,7 @@ container omit-touched?) - (ctl/flex-layout? shape-main) + (ctsl/flex-layout? shape-main) (update-flex-child-copy-attrs shape-main shape-inst library @@ -973,7 +972,7 @@ changes (cond-> changes - (ctl/grid-layout? shape-inst) + (ctsl/grid-layout? shape-inst) (update-grid-copy-attrs (:id shape-inst) shape-main @@ -1063,14 +1062,14 @@ component-container {:copy-touched? true})) - (ctl/flex-layout? shape-main) + (ctsl/flex-layout? shape-main) (update-flex-child-main-attrs shape-main shape-inst component-container container omit-touched?) - (ctl/grid-layout? shape-main) + (ctsl/grid-layout? shape-main) (update-grid-main-attrs shape-main shape-inst component-container @@ -1670,16 +1669,16 @@ untouched-content ;; The :content of the main component touched] - (let [main-comps-diff (cttx/get-diff-type touched-content untouched-content) + (let [main-comps-diff (txt/get-diff-type touched-content untouched-content) diff-structure? (contains? main-comps-diff :text-content-structure) - touched-attrs (cttx/get-first-paragraph-text-attrs touched-content) + touched-attrs (txt/get-first-paragraph-text-attrs touched-content) ;; Have touched content an uniform style? - thed-unif-style? (cttx/equal-attrs? touched-content touched-attrs) + thed-unif-style? (txt/equal-attrs? touched-content touched-attrs) - untouched-attrs (cttx/get-first-paragraph-text-attrs untouched-content) + untouched-attrs (txt/get-first-paragraph-text-attrs untouched-content) ;; Have untouched content an uniform style? - untched-unif-style? (cttx/equal-attrs? untouched-content untouched-attrs)] + untched-unif-style? (txt/equal-attrs? untouched-content untouched-attrs)] (cond ;; Both text and attrs has been touched, keep the ;; touched-content @@ -1692,14 +1691,14 @@ ;; and both have uniform attributes, we keep the touched-content structure and ;; texts, updating its attrs to make them like the untouched-content (if (and (not (touched :text-content-attribute)) thed-unif-style? untched-unif-style?) - (cttx/copy-attrs-keys touched-content untouched-attrs) + (txt/copy-attrs-keys touched-content untouched-attrs) ;; In other case, we keep the touched content touched-content) (touched :text-content-text) ;; Keep the texts touched in touched-content, so copy the ;; texts from touched-content into untouched-content - (cttx/copy-text-keys touched-content untouched-content) + (txt/copy-text-keys touched-content untouched-content) (touched :text-content-attribute) ;; The untouched content has a different structure, but the touched content had't @@ -1708,20 +1707,19 @@ ;; If both have uniform attributes, we keep the untouched-content structure and ;; texts, updating its attrs to make them like the touched-content (if (and thed-unif-style? untched-unif-style?) - (cttx/copy-attrs-keys untouched-content touched-attrs) + (txt/copy-attrs-keys untouched-content touched-attrs) ;; In other case, we keep the touched content touched-content) ;; Keep the attrs touched in touched-content, so copy the ;; texts from untouched-content into touched-content - (cttx/copy-text-keys untouched-content touched-content)) + (txt/copy-text-keys untouched-content touched-content)) ;; Nothing is touched :else untouched-content))) - (defn- add-update-attr-operations [attr dest-shape roperations uoperations attr-val] (let [roperation {:type :set @@ -1852,20 +1850,20 @@ (let [;; We need the differences between the contents on the main ;; components. current-content is the content of a clean copy, ;; so for all effects its the same as the content on its main - main-comps-diff (cttx/get-diff-type ref-content current-content) + main-comps-diff (txt/get-diff-type ref-content current-content) can-keep-text? (not (contains? main-comps-diff :text-content-text)) can-keep-attr? (not (contains? main-comps-diff :text-content-attribute)) main-diff-structure? (contains? main-comps-diff :text-content-structure) - current-attrs (cttx/get-first-paragraph-text-attrs current-content) + current-attrs (txt/get-first-paragraph-text-attrs current-content) ;; Have current content an uniform style? - curr-unif-style? (cttx/equal-attrs? current-content current-attrs) - prev-attrs (cttx/get-first-paragraph-text-attrs prev-content) + curr-unif-style? (txt/equal-attrs? current-content current-attrs) + prev-attrs (txt/get-first-paragraph-text-attrs prev-content) ;; Have prev content an uniform style? - prev-unif-style? (cttx/equal-attrs? prev-content prev-attrs) - ref-attrs (cttx/get-first-paragraph-text-attrs ref-content) + prev-unif-style? (txt/equal-attrs? prev-content prev-attrs) + ref-attrs (txt/get-first-paragraph-text-attrs ref-content) ;; Have ref content an uniform style? - ref-unif-style? (cttx/equal-attrs? ref-content ref-attrs)] + ref-unif-style? (txt/equal-attrs? ref-content ref-attrs)] (cond ;; When the main components have a difference in structure ;; (different number of paragraph or text entries) @@ -1879,7 +1877,7 @@ ref-unif-style? prev-unif-style? (= ref-attrs current-attrs)) - (cttx/copy-attrs-keys current-content prev-attrs) + (txt/copy-attrs-keys current-content prev-attrs) ;; In any other case of structure change, we discard all ;; the overrides and keep the content of the current-shape current-content) @@ -1903,8 +1901,8 @@ curr-unif-style? prev-unif-style?) (if can-keep-text? - (cttx/copy-attrs-keys prev-content current-attrs) - (cttx/copy-attrs-keys current-content prev-attrs)) + (txt/copy-attrs-keys prev-content current-attrs) + (txt/copy-attrs-keys current-content prev-attrs)) ;; In any other case of structure change, we discard all ;; the overrides and keep the content of the current-shape @@ -1916,14 +1914,14 @@ ;; previous-shape over the attrs of current-shape (and (touched :text-content-text) can-keep-text?) - (cttx/copy-text-keys prev-content current-content) + (txt/copy-text-keys prev-content current-content) ;; When there is a change on :text-content-attribute, ;; and we can keep it, we copy the texts from current-shape ;; over the attrs of previous-shape (and (touched :text-content-attribute) can-keep-attr?) - (cttx/copy-text-keys current-content prev-content) + (txt/copy-text-keys current-content prev-content) ;; In any other case, we discard all the overrides ;; and keep the content of the current-shape @@ -2159,11 +2157,11 @@ (update cell :shapes #(filterv child? %))))))) ;; Take cells from main and remap the shapes to assign it to the copy copy-cells (-> shape-copy :layout-grid-cells (remove-orphan-cells shape-copy)) - main-cells (-> shape-main (ctl/remap-grid-cells ids-map) :layout-grid-cells)] + main-cells (-> shape-main (ctsl/remap-grid-cells ids-map) :layout-grid-cells)] (-> shape-copy (assoc :layout-grid-cells - (ctl/merge-cells main-cells copy-cells omit-touched?)) - (ctl/assign-cells objects)))) + (ctsl/merge-cells main-cells copy-cells omit-touched?)) + (ctsl/assign-cells objects)))) {:ignore-touched true :with-objects? true}))) (defn- update-grid-main-attrs @@ -2187,7 +2185,7 @@ [(:id shape-main)] (fn [shape-main] ;; Take cells from copy and remap the shapes to assign it to the copy - (let [new-cells (-> (ctl/remap-grid-cells shape-copy ids-map) :layout-grid-cells)] + (let [new-cells (-> (ctsl/remap-grid-cells shape-copy ids-map) :layout-grid-cells)] (assoc shape-main :layout-grid-cells new-cells))) {:ignore-touched true}))] (pcb/concat-changes changes new-changes))) @@ -2300,8 +2298,8 @@ parent-id (:parent-id shape) insert-before? - (and (ctl/flex-layout? objects parent-id) - (not (ctl/reverse? objects parent-id))) + (and (ctsl/flex-layout? objects parent-id) + (not (ctsl/reverse? objects parent-id))) objects (-> objects @@ -2317,7 +2315,7 @@ (pcb/with-objects objects) (pcb/resize-parents new-objects-ids) ;; Fix the order of the children inside the parent - (cond-> (ctl/any-layout? objects parent-id) + (cond-> (ctsl/any-layout? objects parent-id) (pcb/reorder-children parent-id (get-in objects [parent-id :shapes]))))] (assoc changes :file-id library-id))) @@ -2654,8 +2652,8 @@ (gsh/move delta) (d/update-when :interactions #(ctsi/remap-interactions % ids-map objects)) - (cond-> (ctl/grid-layout? obj) - (ctl/remap-grid-cells ids-map)) + (cond-> (ctsl/grid-layout? obj) + (ctsl/remap-grid-cells ids-map)) (cond-> (ctk/is-variant-container? parent) (assoc :variant-id parent-id)) @@ -2671,8 +2669,8 @@ ;; We want the first added object to touch it's parent, but not subsequent children changes (-> (pcb/add-object changes new-obj {:ignore-touched (and duplicating-component? child?)}) (pcb/amend-last-change #(assoc % :old-id (:id obj))) - (cond-> (ctl/grid-layout? objects (:parent-id obj)) - (-> (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells {:with-objects? true}) + (cond-> (ctsl/grid-layout? objects (:parent-id obj)) + (-> (pcb/update-shapes [(:parent-id obj)] ctsl/assign-cells {:with-objects? true}) (pcb/reorder-grid-children [(:parent-id obj)])))) changes (cond-> changes diff --git a/common/src/app/common/test_helpers/compositions.cljc b/common/src/app/common/test_helpers/compositions.cljc index bf7c64ae51..982a76b0e8 100644 --- a/common/src/app/common/test_helpers/compositions.cljc +++ b/common/src/app/common/test_helpers/compositions.cljc @@ -17,9 +17,9 @@ [app.common.test-helpers.files :as thf] [app.common.test-helpers.ids-map :as thi] [app.common.test-helpers.shapes :as ths] - [app.common.text :as txt] [app.common.types.container :as ctn] - [app.common.types.shape :as cts])) + [app.common.types.shape :as cts] + [app.common.types.text :as txt])) ;; ----- File building @@ -35,7 +35,7 @@ (defn add-text [file text-label content & {:keys [text-params] :as text}] (let [shape (-> (cts/setup-shape {:type :text :x 0 :y 0}) - (txt/change-text content))] + (update :content txt/change-text content))] (ths/add-sample-shape file text-label (merge shape text-params)))) @@ -74,7 +74,7 @@ (defn add-frame-with-text [file frame-label child-label text & {:keys [frame-params child-params]}] (let [shape (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width}) - (txt/change-text text) + (update :content txt/change-text text) (assoc :position-data nil :parent-label frame-label))] (-> file diff --git a/common/src/app/common/test_helpers/shapes.cljc b/common/src/app/common/test_helpers/shapes.cljc index f8fc5aae65..b212984e06 100644 --- a/common/src/app/common/test_helpers/shapes.cljc +++ b/common/src/app/common/test_helpers/shapes.cljc @@ -6,18 +6,18 @@ (ns app.common.test-helpers.shapes (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.files.helpers :as cfh] [app.common.test-helpers.files :as thf] [app.common.test-helpers.ids-map :as thi] - [app.common.text :as txt] - [app.common.types.color :as ctc] + [app.common.types.color :as clr] [app.common.types.container :as ctn] + [app.common.types.library :as ctl] [app.common.types.pages-list :as ctpl] [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.types.shape.interactions :as ctsi] + [app.common.types.text :as txt] [app.common.types.typographies-list :as cttl] [app.common.types.typography :as ctt])) @@ -125,7 +125,7 @@ (defn add-sample-library-color [file label & {:keys [] :as params}] (let [color (sample-library-color label params)] - (update file :data ctc/add-color color))) + (update file :data ctl/add-color color))) (defn sample-typography [label & {:keys [] :as params}] @@ -149,4 +149,4 @@ (fn [file-data] (ctpl/update-page file-data (:id page) - #(ctst/set-shape % (assoc origin :interactions interactions))))))) \ No newline at end of file + #(ctst/set-shape % (assoc origin :interactions interactions))))))) diff --git a/common/src/app/common/test_helpers/variants.cljc b/common/src/app/common/test_helpers/variants.cljc index 7b5d928798..ca1b6d59d3 100644 --- a/common/src/app/common/test_helpers/variants.cljc +++ b/common/src/app/common/test_helpers/variants.cljc @@ -9,8 +9,8 @@ [app.common.test-helpers.components :as thc] [app.common.test-helpers.ids-map :as thi] [app.common.test-helpers.shapes :as ths] - [app.common.text :as txt] - [app.common.types.shape :as cts])) + [app.common.types.shape :as cts] + [app.common.types.text :as txt])) (defn add-variant [file variant-label component1-label root1-label component2-label root2-label @@ -60,11 +60,11 @@ [file variant-label component1-label root1-label component2-label root2-label child1-label child2-label text1 text2 & {:keys [text1-params text2-params]}] (let [text1 (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width}) - (txt/change-text text1) + (update :content txt/change-text text1) (assoc :position-data nil :parent-label root1-label)) text2 (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width}) - (txt/change-text text2) + (update :content txt/change-text text2) (assoc :position-data nil :parent-label root2-label)) diff --git a/common/src/app/common/text.cljc b/common/src/app/common/text.cljc index 469fda6eb3..30345ae801 100644 --- a/common/src/app/common/text.cljc +++ b/common/src/app/common/text.cljc @@ -5,186 +5,16 @@ ;; Copyright (c) KALEIDOS INC (ns app.common.text + "Legacy editor helpers (draftjs). + + NOTE: this namespace should be not used for new code related to texts" (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.transit :as t] - [clojure.walk :as walk] + [app.common.types.text :as types.text] [cuerdas.core :as str])) -;; -- Attrs - -(def text-typography-attrs - [:typography-ref-id - :typography-ref-file]) - -(def text-fill-attrs - [:fill-color - :fill-opacity - :fill-color-ref-id - :fill-color-ref-file - :fill-color-gradient]) - -(def text-font-attrs - [:font-id - :font-family - :font-variant-id - :font-size - :font-weight - :font-style]) - -(def text-align-attrs - [:text-align]) - -(def text-direction-attrs - [:text-direction]) - -(def text-spacing-attrs - [:line-height - :letter-spacing]) - -(def text-valign-attrs - [:vertical-align]) - -(def text-decoration-attrs - [:text-decoration]) - -(def text-transform-attrs - [:text-transform]) - -(def text-fills - [:fills]) - -(def shape-attrs - [:grow-type]) - -(def root-attrs - text-valign-attrs) - -(def paragraph-attrs - (d/concat-vec - text-align-attrs - text-direction-attrs)) - -(def text-node-attrs - (d/concat-vec - text-typography-attrs - text-font-attrs - text-spacing-attrs - text-decoration-attrs - text-transform-attrs - text-fills)) - -(def text-all-attrs (d/concat-set shape-attrs root-attrs paragraph-attrs text-node-attrs)) - -(def text-style-attrs - (d/concat-vec root-attrs paragraph-attrs text-node-attrs)) - -(def default-root-attrs - {:vertical-align "top"}) - -(def default-text-attrs - {:typography-ref-file nil - :typography-ref-id nil - :font-id "sourcesanspro" - :font-family "sourcesanspro" - :font-variant-id "regular" - :font-size "14" - :font-weight "400" - :font-style "normal" - :line-height "1.2" - :letter-spacing "0" - :text-transform "none" - :text-align "left" - :text-decoration "none" - :text-direction "ltr" - :fills [{:fill-color clr/black - :fill-opacity 1}]}) - -(def default-attrs - (merge default-root-attrs default-text-attrs)) - -(def typography-fields - [:font-id - :font-family - :font-variant-id - :font-size - :font-weight - :font-style - :line-height - :letter-spacing - :text-transform]) - -(def default-typography - (merge - {:name "Source Sans Pro Regular"} - (select-keys default-text-attrs typography-fields))) - -(defn node-seq - ([root] (node-seq identity root)) - ([match? root] - (->> (tree-seq map? :children root) - (filter match?) - (seq)))) - -(defn is-text-node? - [node] - (and (nil? (:type node)) - (string? (:text node)))) - -(defn is-paragraph-set-node? - [node] - (= "paragraph-set" (:type node))) - -(defn is-paragraph-node? - [node] - (= "paragraph" (:type node))) - -(defn is-root-node? - [node] - (= "root" (:type node))) - -(defn is-node? - [node] - (or ^boolean (is-text-node? node) - ^boolean (is-paragraph-node? node) - ^boolean (is-paragraph-set-node? node) - ^boolean (is-root-node? node))) - -(defn is-content-node? - "Only matches content nodes, ignoring the paragraph-set nodes." - [node] - (or ^boolean (is-text-node? node) - ^boolean (is-paragraph-node? node) - ^boolean (is-root-node? node))) - -(defn transform-nodes - ([transform root] - (transform-nodes identity transform root)) - ([pred transform root] - (walk/postwalk - (fn [item] - (if (and (is-node? item) (pred item)) - (transform item) - item)) - root))) - -(defn update-text-content - [shape pred-fn update-fn attrs] - (let [update-attrs-fn #(update-fn % attrs) - transform #(transform-nodes pred-fn update-attrs-fn %)] - (-> shape - (update :content transform)))) - -(defn generate-shape-name - [text] - (subs text 0 (min 280 (count text)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; DraftJS <-> Penpot Conversion -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (defn encode-style-value [v] (t/encode-str v)) @@ -369,7 +199,7 @@ :entityRanges [] :inlineStyleRanges (calc-ranges paragraph)})] - {:blocks (reduce #(conj %1 (build-block %2)) [] (node-seq #(= (:type %) "paragraph") root)) + {:blocks (reduce #(conj %1 (build-block %2)) [] (types.text/node-seq #(= (:type %) "paragraph") root)) :entityMap {}})) (defn content->text+styles @@ -377,13 +207,13 @@ [node] (letfn [(rec-style-text-map [acc node style] - (let [node-style (merge style (select-keys node text-all-attrs)) + (let [node-style (merge style (select-keys node types.text/text-all-attrs)) head (or (-> acc first) [{} ""]) [head-style head-text] head new-acc (cond - (not (is-text-node? node)) + (not (types.text/is-text-node? node)) (reduce #(rec-style-text-map %1 %2 node-style) acc (:children node)) (not= head-style node-style) @@ -403,82 +233,6 @@ (-> (rec-style-text-map [] node {}) reverse))) -(defn content-range->text+styles - "Given a root node of a text content extracts the texts with its associated styles" - [node start end] - (let [sss (content->text+styles node)] - (loop [styles (seq sss) - taking? false - acc 0 - result []] - (if styles - (let [[node-style text] (first styles) - from acc - to (+ acc (count text)) - taking? (or taking? (and (<= from start) (< start to))) - text (subs text (max 0 (- start acc)) (- end acc)) - result (cond-> result - (and taking? (d/not-empty? text)) - (conj (assoc node-style :text text))) - continue? (or (> from end) (>= end to))] - (recur (when continue? (rest styles)) taking? to result)) - result)))) - -(defn content->text - "Given a root node of a text content extracts the texts with its associated styles" - [content] - (letfn [(add-node [acc node] - (cond - (is-paragraph-node? node) - (conj acc []) - - (is-text-node? node) - (let [i (dec (count acc))] - (update acc i conj (:text node))) - - :else - acc))] - (->> (node-seq content) - (reduce add-node []) - (map #(str/join "" %)) - (str/join "\n")))) - -(defn change-text - "Changes the content of the text shape to use the text as argument. Will use the styles of the - first paragraph and text that is present in the shape (and override the rest)" - [shape text] - (let [content (:content shape) - - root-styles (select-keys content root-attrs) - - paragraph-style (merge - default-text-attrs - (select-keys (->> content (node-seq is-paragraph-node?) first) text-all-attrs)) - text-style (merge - default-text-attrs - (select-keys (->> content (node-seq is-text-node?) first) text-all-attrs)) - - paragraph-texts (str/split text "\n") - - paragraphs - (->> paragraph-texts - (mapv - (fn [pt] - (merge - paragraph-style - {:type "paragraph" - :children [(merge {:text pt} text-style)]})))) - - new-content - (d/patch-object - {:type "root" - :children - [{:type "paragraph-set" - :children paragraphs}]} - root-styles)] - - (assoc shape :content new-content))) - (defn index-content "Adds a property `$id` that identifies the current node inside" ([content] diff --git a/common/src/app/common/types/color.cljc b/common/src/app/common/types/color.cljc index 37c909d4a2..f80aebf693 100644 --- a/common/src/app/common/types/color.cljc +++ b/common/src/app/common/types/color.cljc @@ -5,15 +5,15 @@ ;; Copyright (c) KALEIDOS INC (ns app.common.types.color + (:refer-clojure :exclude [test]) (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.math :as mth] [app.common.media :as cm] [app.common.schema :as sm] [app.common.schema.generators :as sg] [app.common.schema.openapi :as-alias oapi] - [app.common.text :as txt] - [app.common.time :as dt] [app.common.types.plugins :as ctpg] [clojure.set :as set] [cuerdas.core :as str])) @@ -163,11 +163,183 @@ (def check-color (sm/check-fn schema:color :hint "expected valid color")) +;: FIXME: maybe declare it under types.library ? (def check-library-color (sm/check-fn schema:library-color :hint "expected valid color")) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; HELPERS +;; CONSTANTS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(def ^:const black "#000000") +(def ^:const default-layout "#DE4762") +(def ^:const gray-20 "#B1B2B5") +(def ^:const info "#59B9E2") +(def ^:const test "#fabada") +(def ^:const white "#FFFFFF") +(def ^:const warning "#FC8802") + +;; new-css-system colors +(def ^:const new-primary "#7efff5") +(def ^:const new-danger "#ff3277") +(def ^:const new-warning "#fe4811") +(def ^:const new-primary-light "#6911d4") +(def ^:const background-quaternary "#2e3434") +(def ^:const background-quaternary-light "#eef0f2") +(def ^:const canvas "#E8E9EA") + +(def names + {"aliceblue" "#f0f8ff" + "antiquewhite" "#faebd7" + "aqua" "#00ffff" + "aquamarine" "#7fffd4" + "azure" "#f0ffff" + "beige" "#f5f5dc" + "bisque" "#ffe4c4" + "black" "#000000" + "blanchedalmond" "#ffebcd" + "blue" "#0000ff" + "blueviolet" "#8a2be2" + "brown" "#a52a2a" + "burlywood" "#deb887" + "cadetblue" "#5f9ea0" + "chartreuse" "#7fff00" + "chocolate" "#d2691e" + "coral" "#ff7f50" + "cornflowerblue" "#6495ed" + "cornsilk" "#fff8dc" + "crimson" "#dc143c" + "cyan" "#00ffff" + "darkblue" "#00008b" + "darkcyan" "#008b8b" + "darkgoldenrod" "#b8860b" + "darkgray" "#a9a9a9" + "darkgreen" "#006400" + "darkgrey" "#a9a9a9" + "darkkhaki" "#bdb76b" + "darkmagenta" "#8b008b" + "darkolivegreen" "#556b2f" + "darkorange" "#ff8c00" + "darkorchid" "#9932cc" + "darkred" "#8b0000" + "darksalmon" "#e9967a" + "darkseagreen" "#8fbc8f" + "darkslateblue" "#483d8b" + "darkslategray" "#2f4f4f" + "darkslategrey" "#2f4f4f" + "darkturquoise" "#00ced1" + "darkviolet" "#9400d3" + "deeppink" "#ff1493" + "deepskyblue" "#00bfff" + "dimgray" "#696969" + "dimgrey" "#696969" + "dodgerblue" "#1e90ff" + "firebrick" "#b22222" + "floralwhite" "#fffaf0" + "forestgreen" "#228b22" + "fuchsia" "#ff00ff" + "gainsboro" "#dcdcdc" + "ghostwhite" "#f8f8ff" + "gold" "#ffd700" + "goldenrod" "#daa520" + "gray" "#808080" + "green" "#008000" + "greenyellow" "#adff2f" + "grey" "#808080" + "honeydew" "#f0fff0" + "hotpink" "#ff69b4" + "indianred" "#cd5c5c" + "indigo" "#4b0082" + "ivory" "#fffff0" + "khaki" "#f0e68c" + "lavender" "#e6e6fa" + "lavenderblush" "#fff0f5" + "lawngreen" "#7cfc00" + "lemonchiffon" "#fffacd" + "lightblue" "#add8e6" + "lightcoral" "#f08080" + "lightcyan" "#e0ffff" + "lightgoldenrodyellow" "#fafad2" + "lightgray" "#d3d3d3" + "lightgreen" "#90ee90" + "lightgrey" "#d3d3d3" + "lightpink" "#ffb6c1" + "lightsalmon" "#ffa07a" + "lightseagreen" "#20b2aa" + "lightskyblue" "#87cefa" + "lightslategray" "#778899" + "lightslategrey" "#778899" + "lightsteelblue" "#b0c4de" + "lightyellow" "#ffffe0" + "lime" "#00ff00" + "limegreen" "#32cd32" + "linen" "#faf0e6" + "magenta" "#ff00ff" + "maroon" "#800000" + "mediumaquamarine" "#66cdaa" + "mediumblue" "#0000cd" + "mediumorchid" "#ba55d3" + "mediumpurple" "#9370db" + "mediumseagreen" "#3cb371" + "mediumslateblue" "#7b68ee" + "mediumspringgreen" "#00fa9a" + "mediumturquoise" "#48d1cc" + "mediumvioletred" "#c71585" + "midnightblue" "#191970" + "mintcream" "#f5fffa" + "mistyrose" "#ffe4e1" + "moccasin" "#ffe4b5" + "navajowhite" "#ffdead" + "navy" "#000080" + "oldlace" "#fdf5e6" + "olive" "#808000" + "olivedrab" "#6b8e23" + "orange" "#ffa500" + "orangered" "#ff4500" + "orchid" "#da70d6" + "palegoldenrod" "#eee8aa" + "palegreen" "#98fb98" + "paleturquoise" "#afeeee" + "palevioletred" "#db7093" + "papayawhip" "#ffefd5" + "peachpuff" "#ffdab9" + "peru" "#cd853f" + "pink" "#ffc0cb" + "plum" "#dda0dd" + "powderblue" "#b0e0e6" + "purple" "#800080" + "red" "#ff0000" + "rosybrown" "#bc8f8f" + "royalblue" "#4169e1" + "saddlebrown" "#8b4513" + "salmon" "#fa8072" + "sandybrown" "#f4a460" + "seagreen" "#2e8b57" + "seashell" "#fff5ee" + "sienna" "#a0522d" + "silver" "#c0c0c0" + "skyblue" "#87ceeb" + "slateblue" "#6a5acd" + "slategray" "#708090" + "slategrey" "#708090" + "snow" "#fffafa" + "springgreen" "#00ff7f" + "steelblue" "#4682b4" + "tan" "#d2b48c" + "teal" "#008080" + "thistle" "#d8bfd8" + "tomato" "#ff6347" + "turquoise" "#40e0d0" + "violet" "#ee82ee" + "wheat" "#f5deb3" + "white" "#ffffff" + "whitesmoke" "#f5f5f5" + "yellow" "#ffff00" + "yellowgreen" "#9acd32"}) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; HELPERS (FIXME: this helpers are not in the correct place) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn library-color->color @@ -181,42 +353,6 @@ :path (get lcolor :path) :name (get lcolor :name)))) -;; --- fill - -(defn fill->color - [fill] - (d/without-nils - {:color (:fill-color fill) - :opacity (:fill-opacity fill) - :gradient (:fill-color-gradient fill) - :image (:fill-image fill) - :ref-id (:fill-color-ref-id fill) - :ref-file (:fill-color-ref-file fill)})) - -(defn set-fill-color - [shape position color opacity gradient image] - (update-in shape [:fills position] - (fn [fill] - (d/without-nils (assoc fill - :fill-color color - :fill-opacity opacity - :fill-color-gradient gradient - :fill-image image))))) - -(defn attach-fill-color - [shape position ref-id ref-file] - (d/update-in-when shape [:fills position] - (fn [fill] - (-> fill - (assoc :fill-color-ref-file ref-file) - (assoc :fill-color-ref-id ref-id))))) - -(defn detach-fill-color - [shape position] - (d/update-in-when shape [:fills position] dissoc :fill-color-ref-id :fill-color-ref-file)) - -;; stroke - (defn stroke->color [stroke] (d/without-nils @@ -227,59 +363,10 @@ :ref-id (:stroke-color-ref-id stroke) :ref-file (:stroke-color-ref-file stroke)})) -(defn set-stroke-color - [shape position color opacity gradient image] - (d/update-in-when shape [:strokes position] - (fn [stroke] - (-> stroke - (assoc :stroke-color color) - (assoc :stroke-opacity opacity) - (assoc :stroke-color-gradient gradient) - (assoc :stroke-image image) - (d/without-nils))))) - -(defn attach-stroke-color - [shape position ref-id ref-file] - (d/update-in-when shape [:strokes position] - (fn [stroke] - (-> stroke - (assoc :stroke-color-ref-id ref-id) - (assoc :stroke-color-ref-file ref-file))))) - -(defn detach-stroke-color - [shape position] - (d/update-in-when shape [:strokes position] dissoc :stroke-color-ref-id :stroke-color-ref-file)) - -;; shadow - (defn shadow->color [shadow] (:color shadow)) -(defn set-shadow-color - [shape position color opacity gradient] - (d/update-in-when shape [:shadow position :color] - (fn [shadow-color] - (-> shadow-color - (assoc :color color) - (assoc :opacity opacity) - (assoc :gradient gradient) - (d/without-nils))))) - -(defn attach-shadow-color - [shape position ref-id ref-file] - (d/update-in-when shape [:shadow position :color] - (fn [color] - (-> color - (assoc :ref-id ref-id) - (assoc :ref-file ref-file))))) - -(defn detach-shadow-color - [shape position] - (d/update-in-when shape [:shadow position :color] dissoc :ref-id :ref-file)) - -;; grid - ;: FIXME: revisit colors...... WTF (defn grid->color [grid] @@ -291,291 +378,374 @@ :ref-id (-> color :id) :ref-file (-> color :file-id)}))) -(defn set-grid-color - [shape position color opacity gradient] - (d/update-in-when shape [:grids position :params :color] - (fn [grid-color] - (-> grid-color - (assoc :color color) - (assoc :opacity opacity) - (assoc :gradient gradient) - (d/without-nils))))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; HELPERS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn attach-grid-color - [shape position ref-id ref-file] - (d/update-in-when shape [:grids position :params :color] - (fn [color] - (-> color - (assoc :ref-id ref-id) - (assoc :ref-file ref-file))))) +(def ^:private hex-color-re + #"\#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})") -(defn detach-grid-color - [shape position] - (d/update-in-when shape [:grids position :params :color] dissoc :ref-id :ref-file)) +(def ^:private rgb-color-re + #"(?:|rgb)\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\)") -;; --- Helpers for all colors in a shape - -(defn get-text-node-colors - "Get all colors used by a node of a text shape" - [node] - (concat (map fill->color (:fills node)) - (map stroke->color (:strokes node)))) - -(defn get-all-colors - "Get all colors used by a shape, in any section." - [shape] - (concat (map fill->color (:fills shape)) - (map stroke->color (:strokes shape)) - (map shadow->color (:shadow shape)) - (when (= (:type shape) :frame) - (map grid->color (:grids shape))) - (when (= (:type shape) :text) - (reduce (fn [colors node] - (concat colors (get-text-node-colors node))) - () - (txt/node-seq (:content shape)))))) - -(defn uses-library-colors? - "Check if the shape uses any color in the given library." - [shape library-id] - (let [all-colors (get-all-colors shape)] - (some #(and (some? (:ref-id %)) - (= (:ref-file %) library-id)) - all-colors))) - -(defn uses-library-color? - "Check if the shape uses the given library color." - [shape library-id color-id] - (let [all-colors (get-all-colors shape)] - (some #(and (= (:ref-id %) color-id) - (= (:ref-file %) library-id)) - all-colors))) - -(defn- process-shape-colors - "Execute an update function on all colors of a shape." - [shape process-fn] - (let [process-fill (fn [shape [position fill]] - (process-fn shape - position - (fill->color fill) - set-fill-color - attach-fill-color - detach-fill-color)) - - process-stroke (fn [shape [position stroke]] - (process-fn shape - position - (stroke->color stroke) - set-stroke-color - attach-stroke-color - detach-stroke-color)) - - process-shadow (fn [shape [position shadow]] - (process-fn shape - position - (shadow->color shadow) - set-shadow-color - attach-shadow-color - detach-shadow-color)) - - process-grid (fn [shape [position grid]] - (process-fn shape - position - (grid->color grid) - set-grid-color - attach-grid-color - detach-grid-color)) - - process-text-node (fn [node] - (as-> node $ - (reduce process-fill $ (d/enumerate (:fills $))) - (reduce process-stroke $ (d/enumerate (:strokes $))))) - - process-text (fn [shape] - (let [content (:content shape) - new-content (txt/transform-nodes process-text-node content)] - (if (not= content new-content) - (assoc shape :content new-content) - shape)))] - - (as-> shape $ - (reduce process-fill $ (d/enumerate (:fills $))) - (reduce process-stroke $ (d/enumerate (:strokes $))) - (reduce process-shadow $ (d/enumerate (:shadow $))) - (reduce process-grid $ (d/enumerate (:grids $))) - (process-text $)))) - -(defn remap-colors - "Change the shape so that any use of the given color now points to - the given library." - [shape library-id color] - (letfn [(remap-color [shape position shape-color _ attach-fn _] - (if (= (:ref-id shape-color) (:id color)) - (attach-fn shape - position - (:id color) - library-id) - shape))] - - (process-shape-colors shape remap-color))) - -(defn sync-shape-colors - "Look for usage of any color of the given library inside the shape, - and, in this case, copy the library color into the shape." - [shape library-id library-colors] - (letfn [(sync-color [shape position shape-color set-fn _ detach-fn] - (if (= (:ref-file shape-color) library-id) - (let [library-color (get library-colors (:ref-id shape-color))] - (if (some? library-color) - (set-fn shape - position - (:color library-color) - (:opacity library-color) - (:gradient library-color) - (:image library-color)) - (detach-fn shape position))) - shape))] - - (process-shape-colors shape sync-color))) - -(defn- stroke->color-att - [stroke file-id libraries] - (let [ref-file (:stroke-color-ref-file stroke) - ref-id (:stroke-color-ref-id stroke) - shared-colors (dm/get-in libraries [ref-file :data :colors]) - is-shared? (contains? shared-colors ref-id) - has-color? (or (:stroke-color stroke) - (:stroke-color-gradient stroke)) - attrs (cond-> (stroke->color stroke) - (not (or is-shared? (= ref-file file-id))) - (dissoc :ref-id :ref-file))] - (when has-color? - {:attrs attrs - :prop :stroke - :shape-id (:shape-id stroke) - :index (:index stroke)}))) - -(defn- shadow->color-att - [shadow file-id libraries] - (let [color (get shadow :color) - ref-file (get color :ref-file) - ref-id (get color :ref-id) - shared-colors (dm/get-in libraries [ref-file :data :colors]) - is-shared? (contains? shared-colors ref-id) - attrs (cond-> (shadow->color shadow) - (not (or is-shared? (= ref-file file-id))) - (dissoc :ref-file :ref-id))] - {:attrs attrs - :prop :shadow - :shape-id (:shape-id shadow) - :index (:index shadow)})) - -(defn- text->color-att - [fill file-id libraries] - (let [ref-file (:fill-color-ref-file fill) - ref-id (:fill-color-ref-id fill) - shared-colors (dm/get-in libraries [ref-file :data :colors]) - is-shared? (contains? shared-colors ref-id) - attrs (cond-> (fill->color fill) - (not (or is-shared? (= ref-file file-id))) - (dissoc :ref-file :ref-id))] - - {:attrs attrs - :prop :content - :shape-id (:shape-id fill) - :index (:index fill)})) - -(defn- treat-node - [node shape-id] - (map-indexed #(assoc %2 :shape-id shape-id :index %1) node)) - -(defn- extract-text-colors - [text file-id libraries] - (->> (txt/node-seq txt/is-text-node? (:content text)) - (map :fills) - (mapcat #(treat-node % (:id text))) - (map #(text->color-att % file-id libraries)))) - -(defn- fill->color-att - [fill file-id libraries] - (let [ref-file (:fill-color-ref-file fill) - ref-id (:fill-color-ref-id fill) - shared-colors (dm/get-in libraries [ref-file :data :colors]) - is-shared? (contains? shared-colors ref-id) - has-color? (or (:fill-color fill) - (:fill-color-gradient fill)) - attrs (cond-> (fill->color fill) - (not (or is-shared? (= ref-file file-id))) - (dissoc :ref-file :ref-id))] - - (when has-color? - {:attrs attrs - :prop :fill - :shape-id (:shape-id fill) - :index (:index fill)}))) - -(defn extract-all-colors - [shapes file-id libraries] - (reduce - (fn [result shape] - (let [fill-obj (map-indexed #(assoc %2 :shape-id (:id shape) :index %1) (:fills shape)) - stroke-obj (map-indexed #(assoc %2 :shape-id (:id shape) :index %1) (:strokes shape)) - shadow-obj (map-indexed #(assoc %2 :shape-id (:id shape) :index %1) (:shadow shape))] - (if (= :text (:type shape)) - (-> result - (into (map #(stroke->color-att % file-id libraries)) stroke-obj) - (into (map #(shadow->color-att % file-id libraries)) shadow-obj) - (into (extract-text-colors shape file-id libraries))) - - (-> result - (into (map #(fill->color-att % file-id libraries)) fill-obj) - (into (map #(stroke->color-att % file-id libraries)) stroke-obj) - (into (map #(shadow->color-att % file-id libraries)) shadow-obj))))) - [] - shapes)) - -(defn colors-seq - [file-data] - (vals (:colors file-data))) - -(defn- touch +(defn valid-hex-color? [color] - (assoc color :modified-at (dt/now))) + (and (string? color) + (some? (re-matches hex-color-re color)))) -(defn add-color - [file-data color] - (update file-data :colors assoc (:id color) (touch color))) +(defn parse-rgb + [color] + (let [result (re-matches rgb-color-re color)] + (when (some? result) + (let [r (parse-long (nth result 1)) + g (parse-long (nth result 2)) + b (parse-long (nth result 3))] + (when (and (<= 0 r 255) (<= 0 g 255) (<= 0 b 255)) + [r g b]))))) -(defn get-color - [file-data color-id] - (get-in file-data [:colors color-id])) +(defn valid-rgb-color? + [color] + (if (string? color) + (let [result (parse-rgb color)] + (some? result)) + false)) -(defn get-ref-color - [library-data color] - (when (= (:ref-file color) (:id library-data)) - (get-color library-data (:ref-id color)))) +(defn- normalize-hex + [color] + (if (= (count color) 4) ; of the form #RGB + (-> color + (str/replace #"\#(.)(.)(.)" "#$1$1$2$2$3$3") + (str/lower)) + (str/lower color))) -(defn set-color - [file-data color] - (d/assoc-in-when file-data [:colors (:id color)] (touch color))) +(defn rgb->str + [[r g b a]] + (if (some? a) + (str/ffmt "rgba(%,%,%,%)" r g b a) + (str/ffmt "rgb(%,%,%)" r g b))) -(defn update-color - [file-data color-id f & args] - (d/update-in-when file-data [:colors color-id] #(-> (apply f % args) - (touch)))) +(defn rgb->hsv + [[red green blue]] + (let [max (d/max red green blue) + min (d/min red green blue) + val max] + (if (= min max) + [0 0 val] + (let [delta (- max min) + sat (/ delta max) + hue (if (= red max) + (/ (- green blue) delta) + (if (= green max) + (+ 2 (/ (- blue red) delta)) + (+ 4 (/ (- red green) delta)))) + hue (* 60 hue) + hue (if (< hue 0) + (+ hue 360) + hue) + hue (if (> hue 360) + (- hue 360) + hue)] + [hue sat val])))) -(defn delete-color - [file-data color-id] - (update file-data :colors dissoc color-id)) +(defn hsv->rgb + [[h s brightness]] + (if (= s 0) + [brightness brightness brightness] + (let [sextant (int (mth/floor (/ h 60))) + remainder (- (/ h 60) sextant) + brightness (d/nilv brightness 0) + val1 (int (* brightness (- 1 s))) + val2 (int (* brightness (- 1 (* s remainder)))) + val3 (int (* brightness (- 1 (* s (- 1 remainder)))))] + (case sextant + 1 [val2 brightness val1] + 2 [val1 brightness val3] + 3 [val1 val2 brightness] + 4 [val3 val1 brightness] + 5 [brightness val1 val2] + 6 [brightness val3 val1] + 0 [brightness val3 val1])))) -(defn used-colors-changed-since - "Find all usages of any color in the library by the given shape, of colors - that have ben modified after the date." - [shape library since-date] - (->> (get-all-colors shape) - (keep #(get-ref-color (:data library) %)) - (remove #(< (:modified-at %) since-date)) ;; Note that :modified-at may be nil - (map (fn [color] {:shape-id (:id shape) - :asset-id (:id color) - :asset-type :color})))) +(defn hex->rgb + [color] + (try + (let [rgb #?(:clj (Integer/parseInt (subs color 1) 16) + :cljs (js/parseInt (subs color 1) 16)) + r (bit-shift-right rgb 16) + g (bit-and (bit-shift-right rgb 8) 255) + b (bit-and rgb 255)] + [r g b]) + (catch #?(:clj Throwable :cljs :default) _cause + [0 0 0]))) +(defn hex->lum + [color] + (let [[r g b] (hex->rgb color)] + (mth/sqrt (+ (* 0.241 r) + (* 0.691 g) + (* 0.068 b))))) + +(defn- int->hex + "Convert integer to hex string" + [v] + #?(:clj (Integer/toHexString v) + :cljs (.toString v 16))) + +(defn rgb->hex + [[r g b]] + (let [r (int r) + g (int g) + b (int b)] + (if (or (not= r (bit-and r 255)) + (not= g (bit-and g 255)) + (not= b (bit-and b 255))) + (throw (ex-info "not valid rgb" {:r r :g g :b b})) + (let [rgb (bit-or (bit-shift-left r 16) + (bit-shift-left g 8) b)] + (if (< r 16) + (dm/str "#" (subs (int->hex (bit-or 0x1000000 rgb)) 1)) + (dm/str "#" (int->hex rgb))))))) + +(defn rgb->hsl + [[r g b]] + (let [norm-r (/ r 255.0) + norm-g (/ g 255.0) + norm-b (/ b 255.0) + max (d/max norm-r norm-g norm-b) + min (d/min norm-r norm-g norm-b) + l (/ (+ max min) 2.0) + h (if (= max min) 0 + (if (= max norm-r) + (* 60 (/ (- norm-g norm-b) (- max min))) + (if (= max norm-g) + (+ 120 (* 60 (/ (- norm-b norm-r) (- max min)))) + (+ 240 (* 60 (/ (- norm-r norm-g) (- max min))))))) + s (if (and (> l 0) (<= l 0.5)) + (/ (- max min) (* 2 l)) + (/ (- max min) (- 2 (* 2 l))))] + [(mod (+ h 360) 360) s l])) + +(defn hex->hsv + [v] + (-> v hex->rgb rgb->hsv)) + +(defn hex->rgba + [data opacity] + (-> (hex->rgb data) + (conj opacity))) + +(defn hex->hsl [hex] + (try + (-> hex hex->rgb rgb->hsl) + (catch #?(:clj Throwable :cljs :default) _e + [0 0 0]))) + +(defn hex->hsla + [data opacity] + (-> (hex->hsl data) + (conj opacity))) + +(defn format-hsla + [[h s l a]] + (let [precision 2 + rounded-h (int h) + rounded-s (d/format-number (* 100 s) precision) + rounded-l (d/format-number (* 100 l) precision) + rounded-a (d/format-number a precision)] + (str/concat "" rounded-h ", " rounded-s "%, " rounded-l "%, " rounded-a))) + +(defn format-rgba + [[r g b a]] + (let [precision 2 + rounded-a (d/format-number a precision)] + (str/ffmt "%, %, %, %" r g b rounded-a))) + +(defn- hue->rgb + "Helper for hsl->rgb" + [v1 v2 vh] + (let [vh (if (< vh 0) + (+ vh 1) + (if (> vh 1) + (- vh 1) + vh))] + (cond + (< (* 6 vh) 1) (+ v1 (* (- v2 v1) 6 vh)) + (< (* 2 vh) 1) v2 + (< (* 3 vh) 2) (+ v1 (* (- v2 v1) (- (/ 2 3) vh) 6)) + :else v1))) + +(defn hsl->rgb + [[h s l]] + (if (= s 0) + (let [o (* l 255)] + [o o o]) + (let [norm-h (/ h 360.0) + temp2 (if (< l 0.5) + (* l (+ 1 s)) + (- (+ l s) + (* s l))) + temp1 (- (* l 2) temp2)] + + [(mth/round (* 255 (hue->rgb temp1 temp2 (+ norm-h (/ 1 3))))) + (mth/round (* 255 (hue->rgb temp1 temp2 norm-h))) + (mth/round (* 255 (hue->rgb temp1 temp2 (- norm-h (/ 1 3)))))]))) + +(defn hsl->hex + [v] + (-> v hsl->rgb rgb->hex)) + +(defn hsl->hsv + [hsl] + (-> hsl hsl->rgb rgb->hsv)) + +(defn hsv->hex + [hsv] + (-> hsv hsv->rgb rgb->hex)) + +(defn hsv->hsl + [hsv] + (-> hsv hsv->hex hex->hsl)) + +(defn expand-hex + [v] + (cond + (re-matches #"^[0-9A-Fa-f]$" v) + (dm/str v v v v v v) + + (re-matches #"^[0-9A-Fa-f]{2}$" v) + (dm/str v v v) + + (re-matches #"^[0-9A-Fa-f]{3}$" v) + (let [a (nth v 0) + b (nth v 1) + c (nth v 2)] + (dm/str a a b b c c)) + + :else + v)) + +(defn prepend-hash + [color] + (if (= "#" (subs color 0 1)) + color + (dm/str "#" color))) + +(defn remove-hash + [color] + (if (str/starts-with? color "#") + (subs color 1) + color)) + +(defn color-string? + [color] + (and (string? color) + (or (valid-hex-color? color) + (valid-rgb-color? color) + (contains? names color)))) + +(defn parse + [color] + (when (string? color) + (if (or (valid-hex-color? color) + (valid-hex-color? (dm/str "#" color))) + (normalize-hex color) + (or (some-> (parse-rgb color) (rgb->hex)) + (get names (str/lower color)))))) + +(def color-names + (into [] (keys names))) + +(def empty-color + (into {} (map #(vector % nil)) [:color :id :file-id :gradient :opacity])) + +(defn next-rgb + "Given a color in rgb returns the next color" + [[r g b]] + (cond + (and (= 255 r) (= 255 g) (= 255 b)) + (throw (ex-info "cannot get next color" {:r r :g g :b b})) + + (and (= 255 g) (= 255 b)) + [(inc r) 0 0] + + (= 255 b) + [r (inc g) 0] + + :else + [r g (inc b)])) + +(defn reduce-range + [value range] + (/ (mth/floor (* value range)) range)) + +(defn sort-colors + [a b] + (let [[ah _ av] (hex->hsv (:color a)) + [bh _ bv] (hex->hsv (:color b)) + ah (reduce-range (/ ah 60) 8) + bh (reduce-range (/ bh 60) 8) + av (/ av 255) + bv (/ bv 255) + a (+ (* ah 100) (* av 10)) + b (+ (* bh 100) (* bv 10))] + (compare a b))) + +(defn interpolate-color + [c1 c2 offset] + (cond + (<= offset (:offset c1)) (assoc c1 :offset offset) + (>= offset (:offset c2)) (assoc c2 :offset offset) + + :else + (let [tr-offset (/ (- offset (:offset c1)) (- (:offset c2) (:offset c1))) + [r1 g1 b1] (hex->rgb (:color c1)) + [r2 g2 b2] (hex->rgb (:color c2)) + a1 (:opacity c1) + a2 (:opacity c2) + r (+ r1 (* (- r2 r1) tr-offset)) + g (+ g1 (* (- g2 g1) tr-offset)) + b (+ b1 (* (- b2 b1) tr-offset)) + a (+ a1 (* (- a2 a1) tr-offset))] + {:color (rgb->hex [r g b]) + :opacity a + :r r + :g g + :b b + :alpha a + :offset offset}))) + +(defn- offset-spread + [from to num] + (->> (range 0 num) + (map #(mth/precision (+ from (* (/ (- to from) (dec num)) %)) 2)))) + +(defn uniform-spread? + "Checks if the gradient stops are spread uniformly" + [stops] + (let [cs (count stops) + from (first stops) + to (last stops) + expect-vals (offset-spread (:offset from) (:offset to) cs) + + calculate-expected + (fn [expected-offset stop] + (and (mth/close? (:offset stop) expected-offset) + (let [ec (interpolate-color from to expected-offset)] + (and (= (:color ec) (:color stop)) + (= (:opacity ec) (:opacity stop))))))] + (->> (map calculate-expected expect-vals stops) + (every? true?)))) + +(defn uniform-spread + "Assign an uniform spread to the offset values for the gradient" + [from to num-stops] + (->> (offset-spread (:offset from) (:offset to) num-stops) + (mapv (fn [offset] + (interpolate-color from to offset))))) + +(defn interpolate-gradient + [stops offset] + (let [idx (d/index-of-pred stops #(<= offset (:offset %))) + start (if (= idx 0) (first stops) (get stops (dec idx))) + end (if (nil? idx) (last stops) (get stops idx))] + (interpolate-color start end offset))) diff --git a/common/src/app/common/types/file.cljc b/common/src/app/common/types/file.cljc index 651b1b58c4..a814d031be 100644 --- a/common/src/app/common/types/file.cljc +++ b/common/src/app/common/types/file.cljc @@ -16,15 +16,17 @@ [app.common.geom.shapes.tree-seq :as gsts] [app.common.logging :as l] [app.common.schema :as sm] - [app.common.text :as ct] [app.common.types.color :as ctc] [app.common.types.component :as ctk] [app.common.types.components-list :as ctkl] [app.common.types.container :as ctn] + [app.common.types.library :as ctlb] [app.common.types.page :as ctp] [app.common.types.pages-list :as ctpl] [app.common.types.plugins :refer [schema:plugin-data]] + [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] + [app.common.types.text :as txt] [app.common.types.tokens-lib :refer [schema:tokens-lib]] [app.common.types.typographies-list :as ctyl] [app.common.types.typography :as cty] @@ -521,7 +523,7 @@ (defmethod uses-asset? :color [_ shape library-id color] - (ctc/uses-library-color? shape library-id (:id color))) + (cts/uses-library-color? shape library-id (:id color))) (defmethod uses-asset? :typography [_ shape library-id typography] @@ -533,10 +535,10 @@ Returns a list ((asset ((container shapes) (container shapes)...))...)" [file-data library-data asset-type] - (let [assets-seq (case asset-type - :component (ctkl/components-seq library-data) - :color (ctc/colors-seq library-data) - :typography (ctyl/typographies-seq library-data)) + (let [assets (case asset-type + :component (ctkl/components-seq library-data) + :color (vals (ctlb/get-colors library-data)) + :typography (ctyl/typographies-seq library-data)) find-usages-in-container (fn [container asset] @@ -553,7 +555,7 @@ (let [instances (find-asset-usages file-data asset)] (when (d/not-empty? instances) [[asset instances]]))) - assets-seq))) + assets))) (defn used-in? "Checks if a specific asset is used in a given file (by any shape in its pages or in @@ -574,7 +576,7 @@ (letfn [(used-assets-shape [shape] (concat (ctkl/used-components-changed-since shape library since-date) - (ctc/used-colors-changed-since shape library since-date) + (ctlb/used-colors-changed-since shape library since-date) (ctyl/used-typographies-changed-since shape library since-date))) (used-assets-container [container] @@ -693,11 +695,12 @@ (add-component-grid file-data (sort-by #(:name (first %)) used-components)))) +;: FIXME: this can be moved to library (defn- absorb-colors [file-data used-colors] (let [absorb-color (fn [file-data [color usages]] - (let [remap-shape #(ctc/remap-colors % (:id file-data) color) + (let [remap-shape #(cts/remap-colors % (:id file-data) color) remap-shapes (fn [file-data [container shapes]] @@ -710,7 +713,7 @@ % shapes)))] (as-> file-data $ - (ctc/add-color $ color) + (ctlb/add-color $ color) (reduce remap-shapes $ usages))))] (reduce absorb-color @@ -1046,7 +1049,7 @@ (let [detach-text (fn [content] (->> content - (ct/transform-nodes + (txt/transform-nodes #(cond-> % (not= file-id (:fill-color-ref-file %)) (dissoc :fill-color-ref-id :fill-color-ref-file) diff --git a/common/src/app/common/types/fill.cljc b/common/src/app/common/types/fill.cljc deleted file mode 100644 index 827b7e24fc..0000000000 --- a/common/src/app/common/types/fill.cljc +++ /dev/null @@ -1,68 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) KALEIDOS INC - -(ns app.common.types.fill - (:require - [app.common.schema :as sm] - [app.common.types.color :as types.color] - [app.common.types.fill.impl :as impl] - [clojure.set :as set])) - -(def ^:const MAX-GRADIENT-STOPS impl/MAX-GRADIENT-STOPS) -(def ^:const MAX-FILLS impl/MAX-FILLS) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; SCHEMAS -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(def schema:fill-attrs - [:map {:title "FillAttrs" :closed true} - [:fill-color-ref-file {:optional true} ::sm/uuid] - [:fill-color-ref-id {:optional true} ::sm/uuid] - [:fill-opacity {:optional true} [::sm/number {:min 0 :max 1}]] - [:fill-color {:optional true} types.color/schema:hex-color] - [:fill-color-gradient {:optional true} types.color/schema:gradient] - [:fill-image {:optional true} types.color/schema:image]]) - -(def fill-attrs - "A set of attrs that corresponds to fill data type" - (sm/keys schema:fill-attrs)) - -(def valid-fill-attrs - "A set used for proper check if color should contain only one of the - attrs listed in this set." - #{:fill-image :fill-color :fill-color-gradient}) - -(defn has-valid-fill-attrs? - "Check if color has correct color attrs" - [color] - (let [attrs (set (keys color)) - result (set/intersection attrs valid-fill-attrs)] - (= 1 (count result)))) - -(def schema:fill - [:and schema:fill-attrs - [:fn has-valid-fill-attrs?]]) - -(def check-fill - (sm/check-fn schema:fill)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; HELPERS -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; CONSTRUCTORS -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defn from-plain - [o] - (assert (every? check-fill o) "expected valid fills vector") - (impl/from-plain o)) - -(defn fills? - [o] - (impl/fills? o)) diff --git a/common/src/app/common/types/fills.cljc b/common/src/app/common/types/fills.cljc new file mode 100644 index 0000000000..910f476a69 --- /dev/null +++ b/common/src/app/common/types/fills.cljc @@ -0,0 +1,156 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.common.types.fills + (:refer-clojure :exclude [assoc update]) + (:require + [app.common.data :as d] + [app.common.exceptions :as ex] + [app.common.flags :as flags] + [app.common.schema :as sm] + [app.common.types.color :as types.color] + [app.common.types.fills.impl :as impl] + [clojure.core :as c] + [clojure.set :as set])) + +(def ^:const MAX-GRADIENT-STOPS impl/MAX-GRADIENT-STOPS) +(def ^:const MAX-FILLS impl/MAX-FILLS) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; SCHEMAS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(def schema:fill-attrs + [:map {:title "FillAttrs" :closed true} + [:fill-color-ref-file {:optional true} ::sm/uuid] + [:fill-color-ref-id {:optional true} ::sm/uuid] + [:fill-opacity {:optional true} [::sm/number {:min 0 :max 1}]] + [:fill-color {:optional true} types.color/schema:hex-color] + [:fill-color-gradient {:optional true} types.color/schema:gradient] + [:fill-image {:optional true} types.color/schema:image]]) + +(def fill-attrs + "A set of attrs that corresponds to fill data type" + (sm/keys schema:fill-attrs)) + +(def valid-fill-attrs + "A set used for proper check if color should contain only one of the + attrs listed in this set." + #{:fill-image :fill-color :fill-color-gradient}) + +(defn has-valid-fill-attrs? + "Check if color has correct color attrs" + [color] + (let [attrs (set (keys color)) + result (set/intersection attrs valid-fill-attrs)] + (= 1 (count result)))) + +(def schema:fill + [:and schema:fill-attrs + [:fn has-valid-fill-attrs?]]) + +(def check-fill + (sm/check-fn schema:fill)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; CONSTRUCTORS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn from-plain + [o] + (assert (every? check-fill o) "expected valid fills vector") + (impl/from-plain o)) + +(defn fills? + [o] + (impl/fills? o)) + +(defn coerce + [o] + (cond + (nil? o) + (impl/from-plain []) + + (impl/fills? o) + o + + (vector? o) + (impl/from-plain o) + + :else + (ex/raise :type :internal + :code :invalid-type + :hint (str "cannot coerce " (pr-str o) " to fills")))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; TYPE HELPERS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn get-image-ids + [fills] + (if (vector? fills) + (into #{} + (comp (keep :fill-image) + (map :id)) + fills) + (impl/-get-image-ids fills))) + +(defn get-byte-size + [fills] + (impl/-get-byte-size fills)) + +(defn write-to + [fills buffer offset] + (impl/-write-to fills buffer offset)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; TRANSFORMATION & CREATION HELPERS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn assoc + [fills position fill] + (if (contains? flags/*current* :frontend-binary-fills) + (if (nil? fills) + (impl/from-plain [fill]) + (-> (coerce fills) + (c/assoc position fill))) + (if (nil? fills) + [fill] + (-> (coerce fills) + (c/assoc position fill))))) + +(defn update + [fills f & args] + (let [fills (vec fills) + fills (apply f fills args)] + (if (contains? flags/*current* :frontend-binary-fills) + (impl/from-plain fills) + (vec fills)))) + +(defn create + [& elements] + (let [fills (vec elements)] + (if (contains? flags/*current* :frontend-binary-fills) + (impl/from-plain fills) + fills))) + +(defn prepend + "Prepend a fill to existing fills" + [fills fill] + (let [fills (into [fill] fills)] + (if (contains? flags/*current* :frontend-binary-fills) + (impl/from-plain fills) + fills))) + +(defn fill->color + [fill] + (d/without-nils + {:color (:fill-color fill) + :opacity (:fill-opacity fill) + :gradient (:fill-color-gradient fill) + :image (:fill-image fill) + :ref-id (:fill-color-ref-id fill) + :ref-file (:fill-color-ref-file fill)})) diff --git a/common/src/app/common/types/fill/impl.cljc b/common/src/app/common/types/fills/impl.cljc similarity index 81% rename from common/src/app/common/types/fill/impl.cljc rename to common/src/app/common/types/fills/impl.cljc index 5094e4b296..fb41340a45 100644 --- a/common/src/app/common/types/fill/impl.cljc +++ b/common/src/app/common/types/fills/impl.cljc @@ -4,13 +4,14 @@ ;; ;; Copyright (c) KALEIDOS INC -(ns app.common.types.fill.impl +(ns app.common.types.fills.impl (:require #?(:clj [clojure.data.json :as json]) #?(:cljs [app.common.weak-map :as weak-map]) [app.common.buffer :as buf] [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.exceptions :as ex] [app.common.math :as mth] [app.common.transit :as t])) @@ -22,7 +23,7 @@ (def ^:const GRADIENT-STOP-SIZE 8) (def ^:const GRADIENT-BYTE-SIZE 156) (def ^:const SOLID-BYTE-SIZE 4) -(def ^:const IMAGE-BYTE-SIZE 28) +(def ^:const IMAGE-BYTE-SIZE 36) (def ^:const METADATA-BYTE-SIZE 36) (def ^:const FILL-BYTE-SIZE (+ 4 (mth/max GRADIENT-BYTE-SIZE @@ -35,6 +36,13 @@ (def ^:private xf:take-fills (take MAX-FILLS)) +(defprotocol IHeapWritable + (-write-to [_ buffer offset] "write the content to the specified buffer") + (-get-byte-size [_] "get byte size")) + +(defprotocol IBinaryFills + (-get-image-ids [_] "get referenced image ids")) + (defn- hex->rgb "Encode an hex string as rgb (int32)" [hex] @@ -64,16 +72,16 @@ n (unsigned-bit-shift-right n 24)] (mth/precision (/ (float n) 0xff) 2))) -(defn- write-solid-fill - [offset buffer color alpha] +(defn write-solid-fill + [offset buffer opacity color] (buf/write-byte buffer (+ offset 0) 0x00) (buf/write-int buffer (+ offset 4) (-> (hex->rgb color) - (rgb->rgba alpha))) + (rgb->rgba opacity))) (+ offset FILL-BYTE-SIZE)) -(defn- write-gradient-fill - [offset buffer gradient opacity] +(defn write-gradient-fill + [offset buffer opacity gradient] (let [start-x (:start-x gradient) start-y (:start-y gradient) end-x (:end-x gradient) @@ -108,16 +116,18 @@ (+ offset' GRADIENT-STOP-SIZE))) (+ offset FILL-BYTE-SIZE))))) -(defn- write-image-fill +(defn write-image-fill [offset buffer opacity image] - (let [image-id (get image :id) - image-width (get image :width) - image-height (get image :height)] + (let [image-id (get image :id) + image-width (get image :width) + image-height (get image :height) + keep-aspect-ratio (get image :keep-aspect-ratio false)] (buf/write-byte buffer (+ offset 0) 0x03) (buf/write-uuid buffer (+ offset 4) image-id) (buf/write-float buffer (+ offset 20) opacity) (buf/write-int buffer (+ offset 24) image-width) (buf/write-int buffer (+ offset 28) image-height) + (buf/write-bool buffer (+ offset 32) keep-aspect-ratio) (+ offset FILL-BYTE-SIZE))) (defn- write-metadata @@ -128,21 +138,21 @@ (when mtype (let [val (case mtype - "image/jpeg" 0x01 - "image/png" 0x02 - "image/gif" 0x03 - "image/webp" 0x04 + "image/jpeg" 0x01 + "image/png" 0x02 + "image/gif" 0x03 + "image/webp" 0x04 "image/svg+xml" 0x05)] (buf/write-short buffer (+ offset 2) val))) (if (and (some? ref-file) (some? ref-id)) (do - (buf/write-byte buffer (+ offset 0) 0x01) + (buf/write-bool buffer (+ offset 0) true) (buf/write-uuid buffer (+ offset 4) ref-file) (buf/write-uuid buffer (+ offset 20) ref-id)) (do - (buf/write-byte buffer (+ offset 0) 0x00))))) + (buf/write-bool buffer (+ offset 0) false))))) (defn- read-stop [buffer offset] @@ -193,7 +203,8 @@ :type type}}) 3 - (let [id (buf/read-uuid dbuffer (+ doffset 4)) + (let [ratio (buf/read-bool dbuffer (+ doffset 32)) + id (buf/read-uuid dbuffer (+ doffset 4)) alpha (buf/read-float dbuffer (+ doffset 20)) width (buf/read-int dbuffer (+ doffset 24)) height (buf/read-int dbuffer (+ doffset 28)) @@ -209,6 +220,7 @@ :width width :height height :mtype mtype + :keep-aspect-ratio ratio ;; FIXME: we are not encodign the name, looks useless :name "sample"}}))] @@ -278,7 +290,20 @@ :cljs #_:clj-kondo/ignore - (deftype Fills [size dbuffer mbuffer cache ^:mutable __hash] + (deftype Fills [size dbuffer mbuffer image-ids cache ^:mutable __hash] + + IHeapWritable + (-get-byte-size [_] + (- (.-byteLength dbuffer) 4)) + + (-write-to [_ heap offset] + (let [buffer' (.-buffer ^js/DataView dbuffer)] + (.set heap (js/Uint32Array. buffer' 4) offset))) + + IBinaryFills + (-get-image-ids [_] + image-ids) + cljs.core/ISequential cljs.core/IEquiv (-equiv [this other] @@ -353,7 +378,26 @@ (when (< i size) (cons (read-fill dbuffer mbuffer 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 [fills] @@ -364,8 +408,9 @@ (buf/write-byte dbuffer 0 total) - (loop [index 0] - (when (< index total) + (loop [index 0 + image-ids #{}] + (if (< index total) (let [fill (nth fills index) doffset (+ 4 (* index FILL-BYTE-SIZE)) moffset (* index METADATA-BYTE-SIZE) @@ -373,23 +418,26 @@ (if-let [color (get fill :fill-color)] (do - (write-solid-fill doffset dbuffer color opacity) + (write-solid-fill doffset dbuffer opacity color) (write-metadata moffset mbuffer fill) - (recur (inc index))) + (recur (inc index) image-ids)) (if-let [gradient (get fill :fill-color-gradient)] (do - (write-gradient-fill doffset dbuffer gradient opacity) + (write-gradient-fill doffset dbuffer opacity gradient) (write-metadata moffset mbuffer fill) - (recur (inc index))) + (recur (inc index) image-ids)) (if-let [image (get fill :fill-image)] (do (write-image-fill doffset dbuffer opacity image) (write-metadata moffset mbuffer fill) - (recur (inc index))) - (recur (inc index)))))))) + (recur (inc index) + (conj image-ids (get image :id)))) + (ex/raise :type :internal + :code :invalid-fill + :hint "found invalid fill on encoding fills to binary format"))))) - #?(:cljs (Fills. total dbuffer mbuffer (weak-map/create) nil) - :clj (Fills. total dbuffer mbuffer nil)))) + #?(:cljs (Fills. total dbuffer mbuffer image-ids (weak-map/create) nil) + :clj (Fills. total dbuffer mbuffer nil)))))) (defn fills? [o] diff --git a/common/src/app/common/types/grid.cljc b/common/src/app/common/types/grid.cljc index af63385209..4b63a3cd8d 100644 --- a/common/src/app/common/types/grid.cljc +++ b/common/src/app/common/types/grid.cljc @@ -6,9 +6,8 @@ (ns app.common.types.grid (:require - [app.common.colors :as clr] [app.common.schema :as sm] - [app.common.types.color :refer [schema:hex-color]])) + [app.common.types.color :as clr])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SCHEMA @@ -16,7 +15,7 @@ (def schema:grid-color [:map {:title "PageGridColor"} - [:color schema:hex-color] + [:color clr/schema:hex-color] [:opacity ::sm/safe-number]]) (def schema:column-params diff --git a/common/src/app/common/types/library.cljc b/common/src/app/common/types/library.cljc new file mode 100644 index 0000000000..1af2f0bd12 --- /dev/null +++ b/common/src/app/common/types/library.cljc @@ -0,0 +1,87 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.common.types.library + "Exposes file library type data helpers. + + WARNING: It belongs to FILE types in hierarchy of types so: file + types can import this ns but, but this ns can't import file types." + (:require + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.common.time :as dt] + [app.common.types.shape :as types.shape])) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; COLOR LIBRARY +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn get-colors + [file-data] + (:colors file-data)) + +(defn get-color + [file-data color-id] + (dm/get-in file-data [:colors color-id])) + +(defn get-ref-color + [library-data color] + (when (= (:ref-file color) (:id library-data)) + (get-color library-data (:ref-id color)))) + +(defn- touch + [color] + (assoc color :modified-at (dt/now))) + +(defn add-color + [file-data color] + (update file-data :colors assoc (:id color) (touch color))) + +(defn set-color + [file-data color] + (d/assoc-in-when file-data [:colors (:id color)] (touch color))) + +(defn update-color + [file-data color-id f & args] + (d/update-in-when file-data [:colors color-id] #(-> (apply f % args) + (touch)))) +(defn delete-color + [file-data color-id] + (update file-data :colors dissoc color-id)) + +(defn used-colors-changed-since + "Find all usages of any color in the library by the given shape, of colors + that have ben modified after the date." + [shape library since-date] + (->> (types.shape/get-all-colors shape) + (keep #(get-ref-color (:data library) %)) + (remove #(< (:modified-at %) since-date)) ;; Note that :modified-at may be nil + (map (fn [color] + {:shape-id (:id shape) + :asset-id (:id color) + :asset-type :color})))) + +;: FIXME: revisit the API of this, i think we should pass the whole +;; library data here instead of only colors +(defn sync-colors + "Look for usage of any color of the given library inside the shape, + and, in this case, copy the library color into the shape." + [shape library-id library-colors] + (letfn [(sync-color [shape position shape-color set-fn _ detach-fn] + (if (= (:ref-file shape-color) library-id) + (let [library-color (get library-colors (:ref-id shape-color))] + (if (some? library-color) + (set-fn shape + position + (:color library-color) + (:opacity library-color) + (:gradient library-color) + (:image library-color)) + (detach-fn shape position))) + shape))] + + (types.shape/process-shape-colors shape sync-color))) + diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 7ddbd20150..17aa9853a5 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -17,8 +17,8 @@ [app.common.geom.shapes.effects :as gse] [app.common.geom.shapes.strokes :as gss] [app.common.math :as mth] - [app.common.text :as txt] [app.common.types.shape.layout :as ctl] + [app.common.types.text :as txt] [clojure.core :as c])) ;; --- Modifiers diff --git a/common/src/app/common/types/path.cljc b/common/src/app/common/types/path.cljc index bcfc69fbcb..34aba833b8 100644 --- a/common/src/app/common/types/path.cljc +++ b/common/src/app/common/types/path.cljc @@ -25,7 +25,10 @@ (def ^:cosnt bool-group-style-properties bool/group-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:segments impl/schema:segments) diff --git a/common/src/app/common/types/path/bool.cljc b/common/src/app/common/types/path/bool.cljc index af9be976b2..f52cbbf301 100644 --- a/common/src/app/common/types/path/bool.cljc +++ b/common/src/app/common/types/path/bool.cljc @@ -6,17 +6,23 @@ (ns app.common.types.path.bool (:require - [app.common.colors :as clr] [app.common.data :as d] + [app.common.flags :as flags] [app.common.geom.point :as gpt] [app.common.geom.rect :as grc] [app.common.math :as mth] + [app.common.types.color :as clr] + [app.common.types.fills :as types.fills] [app.common.types.path.helpers :as helpers] [app.common.types.path.segment :as segment] [app.common.types.path.subpath :as subpath])) -(def default-fills - [{:fill-color clr/black}]) +(defn get-default-fills + [] + (let [fills [{:fill-color clr/black}]] + (if (contains? flags/*current* :frontend-binary-fills) + (types.fills/from-plain fills) + fills))) (def group-style-properties #{:shadow :blur}) diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index 9f3b055c2a..eaa85e40a1 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -7,7 +7,6 @@ (ns app.common.types.shape (:require #?(:clj [app.common.fressian :as fres]) - [app.common.colors :as clr] [app.common.data :as d] [app.common.files.helpers :as cfh] [app.common.geom.matrix :as gmt] @@ -18,10 +17,9 @@ [app.common.record :as cr] [app.common.schema :as sm] [app.common.schema.generators :as sg] - [app.common.text :as txt] [app.common.transit :as t] - [app.common.types.color :as types.color] - [app.common.types.fill :refer [schema:fill]] + [app.common.types.color :as clr] + [app.common.types.fills :refer [schema:fill fill->color]] [app.common.types.grid :as ctg] [app.common.types.path :as path] [app.common.types.path.segment :as path.segment] @@ -33,6 +31,7 @@ [app.common.types.shape.layout :as ctsl] [app.common.types.shape.shadow :as ctss] [app.common.types.shape.text :as ctsx] + [app.common.types.text :as txt] [app.common.types.token :as cto] [app.common.types.variant :as ctv] [app.common.uuid :as uuid] @@ -148,9 +147,9 @@ [::sm/one-of stroke-caps]] [:stroke-cap-end {:optional true} [::sm/one-of stroke-caps]] - [:stroke-color {:optional true} types.color/schema:hex-color] - [:stroke-color-gradient {:optional true} types.color/schema:gradient] - [:stroke-image {:optional true} types.color/schema:image]]) + [:stroke-color {:optional true} clr/schema:hex-color] + [:stroke-color-gradient {:optional true} clr/schema:gradient] + [:stroke-image {:optional true} clr/schema:image]]) (def stroke-attrs "A set of attrs that corresponds to stroke data type" @@ -416,12 +415,14 @@ ;; Valid attributes -(def ^:private allowed-shape-attrs #{:page-id :component-id :component-file :component-root :main-instance - :remote-synced :shape-ref :touched :blocked :collapsed :locked - :hidden :masked-group :fills :proportion :proportion-lock :constraints-h - :constraints-v :fixed-scroll :r1 :r2 :r3 :r4 :opacity :grids :exports - :strokes :blend-mode :interactions :shadow :blur :grow-type :applied-tokens - :plugin-data}) +(def ^:private allowed-shape-attrs + #{:page-id :component-id :component-file :component-root :main-instance + :remote-synced :shape-ref :touched :blocked :collapsed :locked + :hidden :masked-group :fills :proportion :proportion-lock :constraints-h + :constraints-v :fixed-scroll :r1 :r2 :r3 :r4 :opacity :grids :exports + :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-base-attrs #{:id :name :type :selrect :points :transform :transform-inverse :parent-id :frame-id}) (def ^:private allowed-bool-attrs #{:shapes :bool-type :content}) @@ -755,3 +756,201 @@ (d/patch-object (select-keys props basic-extract-props)) (cond-> (cfh/text-shape? shape) (patch-text-props props)) (cond-> (cfh/frame-shape? shape) (patch-layout-props props))))) + + + +(defn- set-fill-color + [shape position color opacity gradient image] + (update-in shape [:fills position] + (fn [fill] + (d/without-nils (assoc fill + :fill-color color + :fill-opacity opacity + :fill-color-gradient gradient + :fill-image image))))) + + +(defn- attach-fill-color + [shape position ref-id ref-file] + (d/update-in-when shape [:fills position] + (fn [fill] + (-> fill + (assoc :fill-color-ref-file ref-file) + (assoc :fill-color-ref-id ref-id))))) + +(defn- detach-fill-color + [shape position] + (d/update-in-when shape [:fills position] dissoc :fill-color-ref-id :fill-color-ref-file)) + + +(defn- set-stroke-color + [shape position color opacity gradient image] + (d/update-in-when shape [:strokes position] + (fn [stroke] + (-> stroke + (assoc :stroke-color color) + (assoc :stroke-opacity opacity) + (assoc :stroke-color-gradient gradient) + (assoc :stroke-image image) + (d/without-nils))))) + +(defn- attach-stroke-color + [shape position ref-id ref-file] + (d/update-in-when shape [:strokes position] + (fn [stroke] + (-> stroke + (assoc :stroke-color-ref-id ref-id) + (assoc :stroke-color-ref-file ref-file))))) + +(defn- detach-stroke-color + [shape position] + (d/update-in-when shape [:strokes position] dissoc :stroke-color-ref-id :stroke-color-ref-file)) + +(defn- set-shadow-color + [shape position color opacity gradient] + (d/update-in-when shape [:shadow position :color] + (fn [shadow-color] + (-> shadow-color + (assoc :color color) + (assoc :opacity opacity) + (assoc :gradient gradient) + (d/without-nils))))) + +(defn- attach-shadow-color + [shape position ref-id ref-file] + (d/update-in-when shape [:shadow position :color] + (fn [color] + (-> color + (assoc :ref-id ref-id) + (assoc :ref-file ref-file))))) + +(defn- detach-shadow-color + [shape position] + (d/update-in-when shape [:shadow position :color] dissoc :ref-id :ref-file)) + +(defn- set-grid-color + [shape position color opacity gradient] + (d/update-in-when shape [:grids position :params :color] + (fn [grid-color] + (-> grid-color + (assoc :color color) + (assoc :opacity opacity) + (assoc :gradient gradient) + (d/without-nils))))) + +(defn- attach-grid-color + [shape position ref-id ref-file] + (d/update-in-when shape [:grids position :params :color] + (fn [color] + (-> color + (assoc :ref-id ref-id) + (assoc :ref-file ref-file))))) + +(defn- detach-grid-color + [shape position] + (d/update-in-when shape [:grids position :params :color] dissoc :ref-id :ref-file)) + +(defn process-shape-colors + "Execute an update function on all colors of a shape." + [shape process-fn] + (let [process-fill (fn [shape [position fill]] + (process-fn shape + position + (fill->color fill) + set-fill-color + attach-fill-color + detach-fill-color)) + + process-stroke (fn [shape [position stroke]] + (process-fn shape + position + (clr/stroke->color stroke) + set-stroke-color + attach-stroke-color + detach-stroke-color)) + + process-shadow (fn [shape [position shadow]] + (process-fn shape + position + (clr/shadow->color shadow) + set-shadow-color + attach-shadow-color + detach-shadow-color)) + + process-grid (fn [shape [position grid]] + (process-fn shape + position + (clr/grid->color grid) + set-grid-color + attach-grid-color + detach-grid-color)) + + process-text-node (fn [node] + (as-> node $ + (reduce process-fill $ (d/enumerate (:fills $))) + (reduce process-stroke $ (d/enumerate (:strokes $))))) + + process-text (fn [shape] + (let [content (:content shape) + new-content (txt/transform-nodes process-text-node content)] + (if (not= content new-content) + (assoc shape :content new-content) + shape)))] + + (as-> shape $ + (reduce process-fill $ (d/enumerate (:fills $))) + (reduce process-stroke $ (d/enumerate (:strokes $))) + (reduce process-shadow $ (d/enumerate (:shadow $))) + (reduce process-grid $ (d/enumerate (:grids $))) + (process-text $)))) + +(defn- get-text-node-colors + "Get all colors used by a node of a text shape" + [node] + (concat (map fill->color (:fills node)) + (map clr/stroke->color (:strokes node)))) + +(defn get-all-colors + "Get all colors used by a shape, in any section." + [shape] + ;; FIXME: all this functions should be really in color? + (concat (map fill->color (:fills shape)) + (map clr/stroke->color (:strokes shape)) + (map clr/shadow->color (:shadow shape)) + (when (= (:type shape) :frame) + (map clr/grid->color (:grids shape))) + (when (= (:type shape) :text) + (reduce (fn [colors node] + (concat colors (get-text-node-colors node))) + () + (txt/node-seq (:content shape)))))) + +(defn uses-library-color? + "Check if the shape uses the given library color." + [shape library-id color-id] + (let [all-colors (get-all-colors shape)] + (some #(and (= (:ref-id %) color-id) + (= (:ref-file %) library-id)) + all-colors))) + +(defn uses-library-colors? + "Check if the shape uses any color in the given library." + [shape library-id] + (let [all-colors (get-all-colors shape)] + (some #(and (some? (:ref-id %)) + (= (:ref-file %) library-id)) + all-colors))) + +(defn remap-colors + "Change the shape so that any use of the given color now points to + the given library." + [shape library-id color] + (letfn [(remap-color [shape position shape-color _ attach-fn _] + (if (= (:ref-id shape-color) (:id color)) + (attach-fn shape + position + (:id color) + library-id) + shape))] + + (process-shape-colors shape remap-color))) diff --git a/common/src/app/common/types/shape/attrs.cljc b/common/src/app/common/types/shape/attrs.cljc index 49d5a01a26..7bdc3c17a3 100644 --- a/common/src/app/common/types/shape/attrs.cljc +++ b/common/src/app/common/types/shape/attrs.cljc @@ -6,7 +6,7 @@ (ns app.common.types.shape.attrs (:require - [app.common.colors :as clr])) + [app.common.types.color :as clr])) (def default-color clr/gray-20) diff --git a/common/src/app/common/types/shape/text.cljc b/common/src/app/common/types/shape/text.cljc index 03dca9fb74..25c2c8e072 100644 --- a/common/src/app/common/types/shape/text.cljc +++ b/common/src/app/common/types/shape/text.cljc @@ -7,7 +7,7 @@ (ns app.common.types.shape.text (:require [app.common.schema :as sm] - [app.common.types.fill :refer [schema:fill]] + [app.common.types.fills :refer [schema:fill]] [app.common.types.shape :as-alias shape] [app.common.types.shape.text.position-data :as-alias position-data])) diff --git a/common/src/app/common/types/text.cljc b/common/src/app/common/types/text.cljc index 04fe4a168d..f124abf50b 100644 --- a/common/src/app/common/types/text.cljc +++ b/common/src/app/common/types/text.cljc @@ -6,8 +6,194 @@ (ns app.common.types.text (:require + [app.common.data :as d] [app.common.data.macros :as dm] - [clojure.set :as set])) + [app.common.flags :as flags] + [app.common.types.color :as clr] + [app.common.types.fills :as types.fills] + [clojure.set :as set] + [clojure.walk :as walk] + [cuerdas.core :as str])) + +;; -- Attrs + +(def text-typography-attrs + [:typography-ref-id + :typography-ref-file]) + +(def text-fill-attrs + [:fill-color + :fill-opacity + :fill-color-ref-id + :fill-color-ref-file + :fill-color-gradient]) + +(def text-font-attrs + [:font-id + :font-family + :font-variant-id + :font-size + :font-weight + :font-style]) + +(def text-align-attrs + [:text-align]) + +(def text-direction-attrs + [:text-direction]) + +(def text-spacing-attrs + [:line-height + :letter-spacing]) + +(def text-valign-attrs + [:vertical-align]) + +(def text-decoration-attrs + [:text-decoration]) + +(def text-transform-attrs + [:text-transform]) + +(def text-fills + [:fills]) + +(def shape-attrs + [:grow-type]) + +(def root-attrs + text-valign-attrs) + +(def paragraph-attrs + (d/concat-vec + text-align-attrs + text-direction-attrs)) + +(def text-node-attrs + (d/concat-vec + text-typography-attrs + text-font-attrs + text-spacing-attrs + text-decoration-attrs + text-transform-attrs + text-fills)) + +(def text-all-attrs (d/concat-set shape-attrs root-attrs paragraph-attrs text-node-attrs)) + +(def text-style-attrs + (d/concat-vec root-attrs paragraph-attrs text-node-attrs)) + +(def default-root-attrs + {:vertical-align "top"}) + +(def default-text-fills + [{:fill-color clr/black + :fill-opacity 1}]) + +(def default-text-attrs + {:font-id "sourcesanspro" + :font-family "sourcesanspro" + :font-variant-id "regular" + :font-size "14" + :font-weight "400" + :font-style "normal" + :line-height "1.2" + :letter-spacing "0" + :text-transform "none" + :text-align "left" + :text-decoration "none" + :text-direction "ltr"}) + +(defn get-default-text-fills + "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 + [:font-id + :font-family + :font-variant-id + :font-size + :font-weight + :font-style + :line-height + :letter-spacing + :text-transform]) + +(def default-typography + (-> default-text-attrs + (select-keys typography-fields) + (assoc :name "Source Sans Pro Regular"))) + +(defn node-seq + ([root] (node-seq identity root)) + ([match? root] + (->> (tree-seq map? :children root) + (filter match?) + (seq)))) + +(defn is-text-node? + [node] + (and (nil? (:type node)) + (string? (:text node)))) + +(defn is-paragraph-set-node? + [node] + (= "paragraph-set" (:type node))) + +(defn is-paragraph-node? + [node] + (= "paragraph" (:type node))) + +(defn is-root-node? + [node] + (= "root" (:type node))) + +(defn is-node? + [node] + (or ^boolean (is-text-node? node) + ^boolean (is-paragraph-node? node) + ^boolean (is-paragraph-set-node? node) + ^boolean (is-root-node? node))) + +(defn is-content-node? + "Only matches content nodes, ignoring the paragraph-set nodes." + [node] + (or ^boolean (is-text-node? node) + ^boolean (is-paragraph-node? node) + ^boolean (is-root-node? node))) + +(defn transform-nodes + ([transform root] + (transform-nodes identity transform root)) + ([pred transform root] + (walk/postwalk + (fn [item] + (if (and (is-node? item) (pred item)) + (transform item) + item)) + root))) + +(defn update-text-content + [shape pred-fn update-fn attrs] + (let [update-attrs-fn #(update-fn % attrs) + transform #(transform-nodes pred-fn update-attrs-fn %)] + (-> shape + (update :content transform)))) + +(defn generate-shape-name + [text] + (subs text 0 (min 280 (count text)))) (defn- compare-text-content "Given two content text structures, conformed by maps and vectors, @@ -158,3 +344,91 @@ (if (= :children k) [k (vec (map #(copy-attrs-keys %1 attrs) v))] [k (get attrs k v)])))) + + +(defn content->text + "Given a root node of a text content extracts the texts with its associated styles" + [content] + (letfn [(add-node [acc node] + (cond + (is-paragraph-node? node) + (conj acc []) + + (is-text-node? node) + (let [i (dec (count acc))] + (update acc i conj (:text node))) + + :else + acc))] + (->> (node-seq content) + (reduce add-node []) + (map #(str/join "" %)) + (str/join "\n")))) + +(defn content->text+styles + "Given a root node of a text content extracts the texts with its associated styles" + [node] + (letfn + [(rec-style-text-map [acc node style] + (let [node-style (merge style (select-keys node text-all-attrs)) + head (or (-> acc first) [{} ""]) + [head-style head-text] head + + new-acc + (cond + (not (is-text-node? node)) + (reduce #(rec-style-text-map %1 %2 node-style) acc (:children node)) + + (not= head-style node-style) + (cons [node-style (:text node "")] acc) + + :else + (cons [node-style (dm/str head-text "" (:text node))] (rest acc))) + + ;; We add an end-of-line when finish a paragraph + new-acc + (if (= (:type node) "paragraph") + (let [[hs ht] (first new-acc)] + (cons [hs (dm/str ht "\n")] (rest new-acc))) + new-acc)] + new-acc))] + + (-> (rec-style-text-map [] node {}) + reverse))) + +(defn change-text + "Changes the content of the text shape to use the text as argument. Will use the styles of the + first paragraph and text that is present in the shape (and override the rest)" + [content text] + (let [root-styles (select-keys content root-attrs) + + paragraph-style + (merge + default-text-attrs + (select-keys (->> content (node-seq is-paragraph-node?) first) text-all-attrs)) + + text-style + (merge + default-text-attrs + (select-keys (->> content (node-seq is-text-node?) first) text-all-attrs)) + + paragraph-texts + (str/split text "\n") + + paragraphs + (->> paragraph-texts + (mapv + (fn [pt] + (merge + paragraph-style + {:type "paragraph" + :children [(merge {:text pt} text-style)]}))))] + + + (d/patch-object + {:type "root" + :children + [{:type "paragraph-set" + :children paragraphs}]} + root-styles))) + diff --git a/common/src/app/common/types/typographies_list.cljc b/common/src/app/common/types/typographies_list.cljc index 0ef3e7c5e7..91f3ac0b01 100644 --- a/common/src/app/common/types/typographies_list.cljc +++ b/common/src/app/common/types/typographies_list.cljc @@ -7,8 +7,8 @@ (ns app.common.types.typographies-list (:require [app.common.data :as d] - [app.common.text :as txt] - [app.common.time :as dt])) + [app.common.time :as dt] + [app.common.types.text :as txt])) (defn typographies-seq [file-data] diff --git a/common/src/app/common/types/typography.cljc b/common/src/app/common/types/typography.cljc index fd172a8e4a..9b2edddd77 100644 --- a/common/src/app/common/types/typography.cljc +++ b/common/src/app/common/types/typography.cljc @@ -8,8 +8,8 @@ (:require [app.common.data :as d] [app.common.schema :as sm] - [app.common.text :as txt] [app.common.types.plugins :as ctpg] + [app.common.types.text :as txt] [app.common.uuid :as uuid])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -59,6 +59,8 @@ :text-transform (or text-transform "none")} (d/without-nils))) + +;; FIXME: this function should not be here it belongs to shape and not typography (defn uses-library-typographies? "Check if the shape uses any typography in the given library." [shape library-id] @@ -70,6 +72,7 @@ #(and (some? (:typography-ref-id %)) (= (:typography-ref-file %) library-id)))))) +;; FIXME: this function should not be here it belongs to shape and not typography (defn uses-library-typography? "Check if the shape uses the given library typography." [shape library-id typography-id] diff --git a/common/test/common_tests/colors_test.cljc b/common/test/common_tests/colors_test.cljc index 8c088b9dee..9e296bef03 100644 --- a/common/test/common_tests/colors_test.cljc +++ b/common/test/common_tests/colors_test.cljc @@ -7,7 +7,7 @@ (ns common-tests.colors-test (:require #?(:cljs [goog.color :as gcolors]) - [app.common.colors :as colors] + [app.common.types.color :as colors] [clojure.test :as t])) (t/deftest valid-hex-color @@ -51,8 +51,8 @@ (t/is (= [1 2 3] (colors/hex->rgb "#010203")))) (t/deftest format-hsla - (t/is (= "210 50% 0.78% / 1" (colors/format-hsla [210.0 0.5 0.00784313725490196 1]))) - (t/is (= "220 5% 30% / 0.8" (colors/format-hsla [220.0 0.05 0.3 0.8])))) + (t/is (= "210, 50%, 0.78%, 1" (colors/format-hsla [210.0 0.5 0.00784313725490196 1]))) + (t/is (= "220, 5%, 30%, 0.8" (colors/format-hsla [220.0 0.05 0.3 0.8])))) (t/deftest format-rgba (t/is (= "210, 199, 12, 0.08" (colors/format-rgba [210 199 12 0.08]))) diff --git a/common/test/common_tests/logic/text_sync_test.cljc b/common/test/common_tests/logic/text_sync_test.cljc index 3f1fb18c68..77abc14a77 100644 --- a/common/test/common_tests/logic/text_sync_test.cljc +++ b/common/test/common_tests/logic/text_sync_test.cljc @@ -19,7 +19,7 @@ (t/use-fixtures :each thi/test-fixture) -(t/deftest test-sync-unchanged-copy-when-changed-attribute +(t/deftest sync-unchanged-copy-when-changed-attribute (let [;; ==== Setup file (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -55,7 +55,7 @@ (t/is (= "32" (:font-size line))) (t/is (= "hello world" (:text line))))) -(t/deftest test-sync-unchanged-copy-when-changed-text +(t/deftest sync-unchanged-copy-when-changed-text (let [;; ==== Setup file (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -91,7 +91,7 @@ (t/is (= "14" (:font-size line))) (t/is (= "Bye" (:text line))))) -(t/deftest test-sync-unchanged-copy-when-changed-both +(t/deftest sync-unchanged-copy-when-changed-both (let [;; ==== Setup file (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -129,7 +129,7 @@ (t/is (= "32" (:font-size line))) (t/is (= "Bye" (:text line))))) -(t/deftest test-sync-updated-attr-copy-when-changed-attribute +(t/deftest sync-updated-attr-copy-when-changed-attribute (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -176,7 +176,7 @@ (t/is (= "14" (:font-size line))) (t/is (= "hello world" (:text line))))) -(t/deftest test-sync-updated-attr-copy-when-changed-text +(t/deftest sync-updated-attr-copy-when-changed-text (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -223,7 +223,7 @@ ;; The text is updated because only attrs were touched (t/is (= "Bye" (:text line))))) -(t/deftest test-sync-updated-attr-copy-when-changed-both +(t/deftest sync-updated-attr-copy-when-changed-both (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -273,7 +273,7 @@ ;; The text is updated because only attrs were touched (t/is (= "Bye" (:text line))))) -(t/deftest test-sync-updated-text-copy-when-changed-attribute +(t/deftest sync-updated-text-copy-when-changed-attribute (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -320,7 +320,7 @@ (t/is (= "32" (:font-size line))) (t/is (= "Hi" (:text line))))) -(t/deftest test-sync-updated-text-copy-when-changed-text +(t/deftest sync-updated-text-copy-when-changed-text (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -367,7 +367,7 @@ ;; The text doesn't change, because it was touched (t/is (= "Hi" (:text line))))) -(t/deftest test-sync-updated-text-copy-when-changed-both +(t/deftest sync-updated-text-copy-when-changed-both (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -417,7 +417,7 @@ ;; The text doesn't change, because it was touched (t/is (= "Hi" (:text line))))) -(t/deftest test-sync-updated-both-copy-when-changed-attribute +(t/deftest sync-updated-both-copy-when-changed-attribute (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -466,7 +466,7 @@ (t/is (= "14" (:font-size line))) (t/is (= "Hi" (:text line))))) -(t/deftest test-sync-updated-both-copy-when-changed-text +(t/deftest sync-updated-both-copy-when-changed-text (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -515,7 +515,7 @@ ;; The text doesn't change, because it was touched (t/is (= "Hi" (:text line))))) -(t/deftest test-sync-updated-both-copy-when-changed-both +(t/deftest sync-updated-both-copy-when-changed-both (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -567,7 +567,7 @@ ;; The text doesn't change, because it was touched (t/is (= "Hi" (:text line))))) -(t/deftest test-sync-updated-structure-same-attrs-copy-when-changed-attribute +(t/deftest sync-updated-structure-same-attrs-copy-when-changed-attribute (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -619,7 +619,7 @@ (t/is (= "32" (:font-size line))) (t/is (= "hello world" (:text line))))) -(t/deftest test-sync-updated-structure-same-attrs-copy-when-changed-text +(t/deftest sync-updated-structure-same-attrs-copy-when-changed-text (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -668,7 +668,7 @@ ;; The text doesn't change, because the structure was touched (t/is (= "hello world" (:text line))))) -(t/deftest test-sync-updated-structure-same-attrs-copy-when-changed-both +(t/deftest sync-updated-structure-same-attrs-copy-when-changed-both (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -722,7 +722,7 @@ ;; The text doesn't change, because the structure was touched (t/is (= "hello world" (:text line))))) -(t/deftest test-sync-updated-structure-diff-attrs-copy-when-changed-attribute +(t/deftest sync-updated-structure-diff-attrs-copy-when-changed-attribute (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -775,7 +775,7 @@ (t/is (= "14" (:font-size line))) (t/is (= "hello world" (:text line))))) -(t/deftest test-sync-updated-structure-diff-attrs-copy-when-changed-text +(t/deftest sync-updated-structure-diff-attrs-copy-when-changed-text (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -825,7 +825,7 @@ ;; The text doesn't change, because the structure was touched (t/is (= "hello world" (:text line))))) -(t/deftest test-sync-updated-structure-diff-attrs-copy-when-changed-both +(t/deftest sync-updated-structure-diff-attrs-copy-when-changed-both (let [;; ==== Setup file0 (-> (thf/sample-file :file1) (tho/add-frame-with-text :main-root :main-child "hello world") @@ -878,4 +878,4 @@ ;; The attr doesn't change, because not all the attrs on the structure are equal (t/is (= "14" (:font-size line))) ;; The text doesn't change, because the structure was touched - (t/is (= "hello world" (:text line))))) \ No newline at end of file + (t/is (= "hello world" (:text line))))) diff --git a/common/test/common_tests/logic/token_apply_test.cljc b/common/test/common_tests/logic/token_apply_test.cljc index 384f534e8a..16cc0cd199 100644 --- a/common/test/common_tests/logic/token_apply_test.cljc +++ b/common/test/common_tests/logic/token_apply_test.cljc @@ -14,8 +14,8 @@ [app.common.test-helpers.ids-map :as thi] [app.common.test-helpers.shapes :as ths] [app.common.test-helpers.tokens :as tht] - [app.common.text :as txt] [app.common.types.container :as ctn] + [app.common.types.text :as txt] [app.common.types.token :as cto] [app.common.types.tokens-lib :as ctob] [clojure.test :as t])) diff --git a/common/test/common_tests/types/absorb_assets_test.cljc b/common/test/common_tests/types/absorb_assets_test.cljc index fefb5a043f..526b3b988b 100644 --- a/common/test/common_tests/types/absorb_assets_test.cljc +++ b/common/test/common_tests/types/absorb_assets_test.cljc @@ -12,12 +12,12 @@ [app.common.test-helpers.files :as thf] [app.common.test-helpers.ids-map :as thi] [app.common.test-helpers.shapes :as ths] - [app.common.text :as txt] - [app.common.types.color :as ctc] [app.common.types.component :as ctk] [app.common.types.components-list :as ctkl] [app.common.types.file :as ctf] + [app.common.types.library :as ctl] [app.common.types.pages-list :as ctpl] + [app.common.types.text :as txt] [app.common.types.typographies-list :as ctyl] [clojure.test :as t])) @@ -80,7 +80,7 @@ _ (thf/validate-file! file') ;; Get - colors' (ctc/colors-seq (ctf/file-data file')) + colors' (vals (ctl/get-colors (ctf/file-data file'))) shape1' (ths/get-shape file' :shape1) fill' (first (:fills shape1'))] diff --git a/common/test/common_tests/types/fill_test.cljc b/common/test/common_tests/types/fill_test.cljc index de1514cccb..308778bcc1 100644 --- a/common/test/common_tests/types/fill_test.cljc +++ b/common/test/common_tests/types/fill_test.cljc @@ -6,16 +6,11 @@ (ns common-tests.types.fill-test (:require - #?(:clj [app.common.fressian :as fres]) [app.common.data :as d] - [app.common.exceptions :as ex] [app.common.math :as mth] - [app.common.pprint :as pp] - [app.common.pprint :as pp] [app.common.schema.generators :as sg] [app.common.schema.test :as smt] - [app.common.transit :as trans] - [app.common.types.fill :as types.fill] + [app.common.types.fills :as types.fills] [app.common.uuid :as uuid] [clojure.test :as t])) @@ -85,8 +80,8 @@ :fill-opacity 0.7}) (t/deftest build-from-plain-1 - (let [fills (types.fill/from-plain [sample-fill-1])] - (t/is (types.fill/fills? fills)) + (let [fills (types.fills/from-plain [sample-fill-1])] + (t/is (types.fills/fills? fills)) (t/is (= 1 (count fills))) (t/is (equivalent-fill? (first fills) sample-fill-1)))) @@ -99,8 +94,8 @@ :keep-aspect-ratio false}}) (t/deftest build-from-plain-2 - (let [fills (types.fill/from-plain [sample-fill-2])] - (t/is (types.fill/fills? fills)) + (let [fills (types.fills/from-plain [sample-fill-2])] + (t/is (types.fills/fills? fills)) (t/is (= 1 (count fills))) (t/is (equivalent-fill? (first fills) sample-fill-2)))) @@ -117,8 +112,8 @@ :stops [{:color "#631aa8", :offset 0.5}]}}) (t/deftest build-from-plain-3 - (let [fills (types.fill/from-plain [sample-fill-3])] - (t/is (types.fill/fills? fills)) + (let [fills (types.fills/from-plain [sample-fill-3])] + (t/is (types.fills/fills? fills)) (t/is (= 1 (count fills))) (t/is (equivalent-fill? (first fills) sample-fill-3)))) @@ -136,8 +131,8 @@ :fill-color-ref-id #uuid "2eef07f1-e38a-8062-8006-3aa264d5b785"}) (t/deftest build-from-plain-4 - (let [fills (types.fill/from-plain [sample-fill-4])] - (t/is (types.fill/fills? fills)) + (let [fills (types.fills/from-plain [sample-fill-4])] + (t/is (types.fills/fills? fills)) (t/is (= 1 (count fills))) (t/is (equivalent-fill? (first fills) sample-fill-4)))) @@ -154,8 +149,8 @@ :stops [{:color "#bba1aa", :opacity 0.37, :offset 0.84}]}}) (t/deftest build-from-plain-5 - (let [fills (types.fill/from-plain [sample-fill-5])] - (t/is (types.fill/fills? fills)) + (let [fills (types.fills/from-plain [sample-fill-5])] + (t/is (types.fills/fills? fills)) (t/is (= 1 (count fills))) (t/is (equivalent-fill? (first fills) sample-fill-5)))) @@ -170,14 +165,14 @@ :stops [{:color "#e15610", :offset 0.4} {:color "#005a9e", :opacity 0.62, :offset 0.81}]}}) (t/deftest build-from-plain-6 - (let [fills (types.fill/from-plain [sample-fill-6])] - (t/is (types.fill/fills? fills)) + (let [fills (types.fills/from-plain [sample-fill-6])] + (t/is (types.fills/fills? fills)) (t/is (= 1 (count fills))) (t/is (equivalent-fill? (first fills) sample-fill-6)))) (t/deftest fills-datatype-roundtrip (smt/check! - (smt/for [fill (->> (sg/generator types.fill/schema:fill) + (smt/for [fill (->> (sg/generator types.fills/schema:fill) (sg/fmap d/without-nils) (sg/fmap (fn [fill] (cond-> fill @@ -187,27 +182,27 @@ (contains? fill :fill-color-ref-file))) (-> (assoc :fill-color-ref-file (uuid/next)) (assoc :fill-color-ref-id (uuid/next)))))))] - (let [bfills (types.fill/from-plain [fill])] + (let [bfills (types.fills/from-plain [fill])] (and (= (count bfills) 1) (equivalent-fill? (first bfills) fill)))) {:num 2000})) (t/deftest equality-operation - (let [fills1 (types.fill/from-plain [sample-fill-6]) - fills2 (types.fill/from-plain [sample-fill-6])] + (let [fills1 (types.fills/from-plain [sample-fill-6]) + fills2 (types.fills/from-plain [sample-fill-6])] (t/is (= fills1 fills2)))) (t/deftest reduce-impl - (let [fills1 (types.fill/from-plain [sample-fill-6]) + (let [fills1 (types.fills/from-plain [sample-fill-6]) fills2 (reduce (fn [result fill] (conj result fill)) [] fills1) - fills3 (types.fill/from-plain fills2)] + fills3 (types.fills/from-plain fills2)] (t/is (= fills1 fills3)))) (t/deftest indexed-access - (let [fills1 (types.fill/from-plain [sample-fill-6]) + (let [fills1 (types.fills/from-plain [sample-fill-6]) fill0 (nth fills1 0) fill1 (nth fills1 1)] (t/is (nil? fill1)) diff --git a/common/test/common_tests/types/text_test.cljc b/common/test/common_tests/types/text_test.cljc index 6535cf83ee..53043eabad 100644 --- a/common/test/common_tests/types/text_test.cljc +++ b/common/test/common_tests/types/text_test.cljc @@ -7,26 +7,36 @@ (ns common-tests.types.text-test (:require - [app.common.text :as txt] [app.common.types.shape :as cts] [app.common.types.text :as cttx] [clojure.test :as t :include-macros true])) -(def content-base (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width}) - (txt/change-text "hello world") - (assoc :position-data nil) - :content)) +(def content-base + (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width}) + (get :content) + (cttx/change-text "hello world"))) -(def content-changed-text (assoc-in content-base [:children 0 :children 0 :children 0 :text] "changed")) -(def content-changed-attr (assoc-in content-base [:children 0 :children 0 :children 0 :font-size] "32")) -(def content-changed-both (-> content-base - (assoc-in [:children 0 :children 0 :children 0 :text] "changed") - (assoc-in [:children 0 :children 0 :children 0 :font-size] "32"))) -(def line (get-in content-base [:children 0 :children 0 :children 0])) -(def content-changed-structure (update-in content-base [:children 0 :children 0 :children] - #(conj % (assoc line :font-weight "700")))) -(def content-changed-structure-same-attrs (update-in content-base [:children 0 :children 0 :children] - #(conj % line))) +(def content-changed-text + (assoc-in content-base [:children 0 :children 0 :children 0 :text] "changed")) + +(def content-changed-attr + (assoc-in content-base [:children 0 :children 0 :children 0 :font-size] "32")) + +(def content-changed-both + (-> content-base + (assoc-in [:children 0 :children 0 :children 0 :text] "changed") + (assoc-in [:children 0 :children 0 :children 0 :font-size] "32"))) + +(def line + (get-in content-base [:children 0 :children 0 :children 0])) + +(def content-changed-structure + (update-in content-base [:children 0 :children 0 :children] + #(conj % (assoc line :font-weight "700")))) + + +(def content-changed-structure-same-attrs + (update-in content-base [:children 0 :children 0 :children] #(conj % line))) (t/deftest test-get-diff-type (let [diff-text (cttx/get-diff-type content-base content-changed-text) diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs index 11ff04b2d9..0f1d2c41e6 100644 --- a/frontend/src/app/config.cljs +++ b/frontend/src/app/config.cljs @@ -37,12 +37,12 @@ check-safari-16? (fn [] (and (check-safari?) (str/includes? user-agent "version/16"))) check-safari-17? (fn [] (and (check-safari?) (str/includes? user-agent "version/17")))] (cond - (check-edge?) :edge - (check-chrome?) :chrome - (check-firefox?) :firefox - (check-safari-16?) :safari-16 - (check-safari-17?) :safari-17 - (check-safari?) :safari + ^boolean (check-edge?) :edge + ^boolean (check-chrome?) :chrome + ^boolean (check-firefox?) :firefox + ^boolean (check-safari-16?) :safari-16 + ^boolean (check-safari-17?) :safari-17 + ^boolean (check-safari?) :safari :else :other))) (defn- parse-platform @@ -52,9 +52,9 @@ check-linux? (fn [] (str/includes? user-agent "linux")) check-macos? (fn [] (str/includes? user-agent "mac os"))] (cond - (check-windows?) :windows - (check-linux?) :linux - (check-macos?) :macos + ^boolean (check-windows?) :windows + ^boolean (check-linux?) :linux + ^boolean (check-macos?) :macos :else :other))) (defn- parse-target @@ -104,6 +104,12 @@ (def plugins-whitelist (into #{} (obj/get global "penpotPluginsWhitelist" []))) (def templates-uri (obj/get global "penpotTemplatesUri" "https://penpot.github.io/penpot-files/")) + +;; We set the current parsed flags under common for make +;; it available for common code without the need to pass +;; the flags all arround on parameters. +(set! app.common.flags/*current* flags) + (defn- normalize-uri [uri-str] (let [uri (u/uri uri-str)] diff --git a/frontend/src/app/main/data/helpers.cljs b/frontend/src/app/main/data/helpers.cljs index 9a97d36e16..ee3d406c53 100644 --- a/frontend/src/app/main/data/helpers.cljs +++ b/frontend/src/app/main/data/helpers.cljs @@ -78,6 +78,23 @@ (filter selectable?) 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 (defn lookup-selected-raw [state] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 42150c4af1..f8a927684d 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -20,9 +20,11 @@ [app.common.logic.shapes :as cls] [app.common.transit :as t] [app.common.types.component :as ctc] + [app.common.types.fills :as types.fills] [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] + [app.config :as cf] [app.main.data.changes :as dch] [app.main.data.comments :as dcmt] [app.main.data.common :as dcm] @@ -80,6 +82,7 @@ [app.util.timers :as tm] [app.util.webapi :as wapi] [beicon.v2.core :as rx] + [clojure.walk :as walk] [cuerdas.core :as str] [potok.v2.core :as ptk])) @@ -133,10 +136,30 @@ (rx/of [k v]))))))) (rx/reduce conj {}))) + +(defn process-fills + "A function responsible to analyze the file data or shape for references + and apply lookup-index on it." + [data] + (letfn [(process-map-form [form] + (let [fills (get form :fills)] + (if (vector? fills) + (assoc form :fills (types.fills/from-plain fills)) + form))) + + (process-form [form] + (if (map? form) + (process-map-form form) + form))] + (if (contains? cf/flags :frontend-binary-fills) + (walk/postwalk process-form data) + data))) + (defn- resolve-file [file] (->> (fpmap/resolve-file file) (rx/map :data) + (rx/map process-fills) (rx/mapcat (fn [{:keys [pages-index] :as data}] (->> (rx/from (seq pages-index)) diff --git a/frontend/src/app/main/data/workspace/bool.cljs b/frontend/src/app/main/data/workspace/bool.cljs index 9819813869..fe493660c5 100644 --- a/frontend/src/app/main/data/workspace/bool.cljs +++ b/frontend/src/app/main/data/workspace/bool.cljs @@ -36,7 +36,7 @@ head (cond-> head (and (contains? head :svg-attrs) (empty? (:fills head))) - (assoc :fills path/default-bool-fills)) + (assoc :fills (path/get-default-bool-fills))) shape {:id shape-id @@ -62,7 +62,7 @@ head (if (= type :difference) (first shapes) (last shapes)) head (cond-> head (and (contains? head :svg-attrs) (empty? (:fills head))) - (assoc :fills path/default-bool-fills))] + (assoc :fills (path/get-default-bool-fills)))] (-> group (assoc :type :bool) (assoc :bool-type type) diff --git a/frontend/src/app/main/data/workspace/clipboard.cljs b/frontend/src/app/main/data/workspace/clipboard.cljs index 1a40e0ed3b..202d1082da 100644 --- a/frontend/src/app/main/data/workspace/clipboard.cljs +++ b/frontend/src/app/main/data/workspace/clipboard.cljs @@ -19,7 +19,6 @@ [app.common.geom.shapes.grid-layout :as gslg] [app.common.logic.libraries :as cll] [app.common.schema :as sm] - [app.common.text :as txt] [app.common.transit :as t] [app.common.types.component :as ctc] [app.common.types.container :as ctn] @@ -28,6 +27,7 @@ [app.common.types.shape-tree :as ctst] [app.common.types.shape.layout :as ctl] [app.common.types.shape.text :as types.text] + [app.common.types.text :as txt] [app.common.types.typography :as ctt] [app.common.uuid :as uuid] [app.config :as cf] @@ -925,7 +925,7 @@ (let [paragraphs (->> (str/lines text) (map str/trim) (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 (when (d/not-empty? paragraphs) {:type "root" diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index 0ed40e3e2e..8ed474cb22 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -6,19 +6,18 @@ (ns app.main.data.workspace.colors (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.schema :as sm] - [app.common.text :as txt] - [app.common.types.color :as types.color] - [app.common.types.fill :as types.fill] + [app.common.types.color :as clr] + [app.common.types.fills :as types.fills] + [app.common.types.library :as ctl] [app.common.types.shape :as shp] [app.common.types.shape.shadow :refer [check-shadow]] + [app.common.types.text :as txt] [app.config :as cfg] [app.main.broadcast :as mbc] - [app.main.data.event :as ev] [app.main.data.helpers :as dsh] [app.main.data.modal :as md] [app.main.data.workspace.layout :as layout] @@ -103,11 +102,7 @@ (defn assoc-shape-fill [shape position fill] - (update shape :fills - (fn [fills] - (if (nil? fills) - [fill] - (assoc fills position fill))))) + (update shape :fills types.fills/assoc position fill)) (defn transform-fill* "A lower-level companion function for `transform-fill`" @@ -153,7 +148,7 @@ (d/without-nils) :always - (types.fill/check-fill)) + (types.fills/check-fill)) transform-attrs #(transform % fill)] @@ -167,17 +162,28 @@ (assoc-in [attr index] second) (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 [ids index new-index] (ptk/reify ::reorder-fills ptk/WatchEvent (watch [_ state _] - (let [objects (dsh/lookup-page-objects state) + (let [objects + (dsh/lookup-page-objects state) - is-text? #(= :text (:type (get objects %))) - text-ids (filter is-text? ids) - shape-ids (remove is-text? ids) - transform-attrs #(swap-attrs % :fills index new-index)] + [text-ids shape-ids] + (dsh/split-text-shapes objects ids) + + transform-attrs + (fn [object] + (update object :fills types.fills/update swap-fills-index index new-index))] (rx/concat (rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids)) @@ -190,7 +196,7 @@ (assert (every? uuid? ids) "expect a coll of uuids for `ids`") (assert (number? position) "expect a number for position") - (let [color (types.color/check-color color)] + (let [color (clr/check-color color)] (ptk/reify ::change-fill ptk/WatchEvent (watch [_ state _] @@ -207,7 +213,7 @@ (ptk/reify ::change-fill-and-clear ptk/WatchEvent (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)] (rx/concat (rx/of (dwu/start-undo-transaction undo-id)) @@ -219,14 +225,13 @@ ([ids color options] (assert (every? uuid? ids) "expected a valid coll of uuid's") - (let [color (types.color/check-color color)] + (let [color (clr/check-color color)] (ptk/reify ::add-fill ptk/WatchEvent (watch [_ state _] (let [change-fn (fn [shape attrs] - (-> shape - (update :fills #(into [attrs] %)))) + (update shape :fills types.fills/prepend attrs)) undo-id (js/Symbol)] (rx/concat @@ -247,13 +252,13 @@ ptk/WatchEvent (watch [_ state _] (let [detach-fn - (fn [values index] - (update values index dissoc :fill-color-ref-id :fill-color-ref-file)) + (fn [fills index] + (update fills index dissoc :fill-color-ref-id :fill-color-ref-file)) change-fn ;; The `node` can be a shape or a text content node (fn [node] - (update node :fills detach-fn position)) + (update node :fills types.fills/update detach-fn position)) undo-id (js/Symbol)] @@ -275,17 +280,17 @@ ptk/WatchEvent (watch [_ state _] (let [remove-fill-by-index - (fn [values index] + (fn [fills index] (into [] (comp (map-indexed (fn [i o] (when (not= i index) o))) (filter some?)) - values)) + fills)) change-fn ;; The `node` can be a shape or a text content node (fn [node] - (update node :fills remove-fill-by-index position)) + (update node :fills types.fills/update remove-fill-by-index position)) undo-id (js/Symbol)] @@ -303,7 +308,7 @@ (ptk/reify ::remove-all-fills ptk/WatchEvent (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)] (rx/concat (rx/of (dwu/start-undo-transaction undo-id)) @@ -560,7 +565,7 @@ (assoc-in [:workspace-global :picking-color?] true) (assoc ::md/modal {:id (random-uuid) :type :colorpicker - :props {:data {:color cc/black + :props {:data {:color clr/black :opacity 1} :disable-opacity false :disable-gradient false @@ -576,16 +581,26 @@ :fill-color-ref-file (:ref-file color) :fill-color-gradient (:gradient color)})) -(defn change-text-color +(defn- change-text-color [old-color new-color index node] - (let [fills (map #(dissoc % :fill-color-ref-id :fill-color-ref-file) (:fills node)) - parsed-color (-> (color-att->text old-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-> node - (some? has-color?) - (assoc-in [:fills index] parsed-new-color)))) + (update node :fills types.fills/update + (fn [fills] + (let [fills' + (map #(dissoc % :fill-color-ref-id :fill-color-ref-file) fills) + + parsed-color + (-> (color-att->text old-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 [:map @@ -601,17 +616,9 @@ (defn change-color-in-selected [operations new-color old-color] - - (assert (check-change-color-operations operations) - "expected valid color operations") - - (assert - (types.color/check-color new-color) - "expected valid color structure") - - (assert - (types.color/check-color old-color) - "expected valid color structure") + (assert (check-change-color-operations operations)) + (assert (clr/check-color new-color)) + (assert (clr/check-color old-color)) (ptk/reify ::change-color-in-selected ptk/WatchEvent @@ -632,7 +639,7 @@ (defn apply-color-from-palette [color stroke?] - (let [color (types.color/check-color color)] + (let [color (clr/check-color color)] (ptk/reify ::apply-color-from-palette ptk/WatchEvent (watch [_ state _] @@ -667,7 +674,7 @@ (defn apply-color-from-colorpicker [color] - (let [color (types.color/check-color color)] + (let [color (clr/check-color color)] (ptk/reify ::apply-color-from-colorpicker ptk/UpdateEvent (update [_ state] @@ -708,7 +715,7 @@ (defn add-recent-color [color] - (let [color (types.color/check-color color)] + (let [color (clr/check-color color)] (ptk/reify ::add-recent-color ptk/UpdateEvent (update [_ state] @@ -728,11 +735,11 @@ (defn apply-color-from-assets [file-id color stroke?] - (let [color (types.color/check-library-color color)] + (let [color (clr/check-library-color color)] (ptk/reify ::apply-color-from-asserts ptk/WatchEvent (watch [_ _ _] - (let [color (types.color/library-color->color color file-id)] + (let [color (clr/library-color->color color file-id)] (rx/of (apply-color-from-palette color stroke?) (add-recent-color color))))))) @@ -742,9 +749,9 @@ (defn split-color-components [{:keys [color opacity] :as data}] - (let [value (if (cc/valid-hex-color? color) color cc/black) - [r g b] (cc/hex->rgb value) - [h s v] (cc/hex->hsv value)] + (let [value (if (clr/valid-hex-color? color) color clr/black) + [r g b] (clr/hex->rgb value) + [h s v] (clr/hex->hsv value)] (merge data {:hex (or value "000000") :alpha (or opacity 1) @@ -893,11 +900,11 @@ (update state :colorpicker (fn [{:keys [stops editing-stop] :as state}] (let [cap-stops? (or (features/active-feature? state "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills)) - can-add-stop? (or (not cap-stops?) (< (count stops) types.fill/MAX-GRADIENT-STOPS))] + can-add-stop? (or (not cap-stops?) (< (count stops) types.fills/MAX-GRADIENT-STOPS))] (if can-add-stop? - (if (cc/uniform-spread? stops) + (if (clr/uniform-spread? stops) ;; Add to uniform - (let [stops (->> (cc/uniform-spread (first stops) (last stops) (inc (count stops))) + (let [stops (->> (clr/uniform-spread (first stops) (last stops) (inc (count stops))) (mapv split-color-components))] (-> state (assoc :current-color (get stops editing-stop)) @@ -918,7 +925,7 @@ half-point-offset (+ from-offset (/ (- to-offset from-offset) 2)) - new-stop (-> (cc/interpolate-gradient stops half-point-offset) + new-stop (-> (clr/interpolate-gradient stops half-point-offset) (split-color-components)) stops (conj stops new-stop) @@ -938,18 +945,24 @@ (update state :colorpicker (fn [state] (let [stops (:stops state) - cap-stops? (or (features/active-feature? state "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills)) - can-add-stop? (or (not cap-stops?) (< (count stops) types.fill/MAX-GRADIENT-STOPS))] - (if can-add-stop? (let [new-stop (-> (cc/interpolate-gradient stops offset) - (split-color-components)) - stops (conj stops new-stop) - stops (into [] (sort-by :offset stops)) - editing-stop (d/index-of-pred stops #(= new-stop %))] - (-> state - (assoc :editing-stop editing-stop) - (assoc :current-color (get stops editing-stop)) - (assoc :stops stops))) - state))))))) + cap-stops? + (or (features/active-feature? state "render-wasm/v1") + (contains? cfg/flags :frontend-binary-fills)) + + can-add-stop? + (or (not cap-stops?) (< (count stops) types.fills/MAX-GRADIENT-STOPS))] + + (if can-add-stop? + (let [new-stop (-> (clr/interpolate-gradient stops offset) + (split-color-components)) + stops (conj stops new-stop) + stops (into [] (sort-by :offset stops)) + editing-stop (d/index-of-pred stops #(= new-stop %))] + (-> state + (assoc :editing-stop editing-stop) + (assoc :current-color (get stops editing-stop)) + (assoc :stops stops))) + state))))))) (defn update-colorpicker-stops [stops] @@ -963,7 +976,7 @@ (contains? cfg/flags :frontend-binary-fills)) stops (mapv split-color-components (if cap-stops? - (take types.fill/MAX-GRADIENT-STOPS stops) + (take types.fills/MAX-GRADIENT-STOPS stops) stops))] (-> state (assoc :current-color (get stops stop)) @@ -1116,35 +1129,114 @@ (assoc :type :image) (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 + [stroke file-id libraries] + (let [ref-file (:stroke-color-ref-file stroke) + ref-id (:stroke-color-ref-id stroke) + + colors (-> libraries + (get ref-file) + (get :data) + (ctl/get-colors)) + + is-shared? (contains? colors ref-id) + has-color? (or (:stroke-color stroke) + (:stroke-color-gradient stroke)) + attrs (cond-> (clr/stroke->color stroke) + (not (or is-shared? (= ref-file file-id))) + (dissoc :ref-id :ref-file))] + + (when has-color? + {:attrs attrs + :prop :stroke + :shape-id (:shape-id stroke) + :index (:index stroke)}))) + +(defn- shadow->color-att + [shadow file-id libraries] + (let [color (get shadow :color) + ref-file (get color :ref-file) + ref-id (get color :ref-id) + colors (-> libraries + (get ref-id) + (get :data) + (ctl/get-colors)) + shared? (contains? colors ref-id) + attrs (cond-> (clr/shadow->color shadow) + (not (or shared? (= ref-file file-id))) + (dissoc :ref-file :ref-id))] + {:attrs attrs + :prop :shadow + :shape-id (:shape-id shadow) + :index (:index shadow)})) + +(defn- text->color-att + [fill file-id libraries] + (let [ref-file (:fill-color-ref-file fill) + ref-id (:fill-color-ref-id fill) + colors (-> libraries + (get ref-id) + (get :data) + (ctl/get-colors)) + + shared? (contains? colors ref-id) + attrs (cond-> (types.fills/fill->color fill) + (not (or shared? (= ref-file file-id))) + (dissoc :ref-file :ref-id))] + + {:attrs attrs + :prop :content + :shape-id (:shape-id fill) + :index (:index fill)})) + +(defn- extract-text-colors + [text file-id libraries] + (let [treat-node + (fn [node shape-id] + (map-indexed #(assoc %2 :shape-id shape-id :index %1) node))] + (->> (txt/node-seq txt/is-text-node? (:content text)) + (map :fills) + (mapcat #(treat-node % (:id text))) + (map #(text->color-att % file-id libraries))))) + +(defn- fill->color-att + [fill file-id libraries] + (let [ref-file (:fill-color-ref-file fill) + ref-id (:fill-color-ref-id fill) + + colors (-> libraries + (get ref-id) + (get :data) + (ctl/get-colors)) + shared? (contains? colors ref-id) + has-color? (or (:fill-color fill) + (:fill-color-gradient fill)) + attrs (cond-> (types.fills/fill->color fill) + (not (or shared? (= ref-file file-id))) + (dissoc :ref-file :ref-id))] + + (when has-color? + {:attrs attrs + :prop :fill + :shape-id (:shape-id fill) + :index (:index fill)}))) + +(defn extract-all-colors + [shapes file-id libraries] + (reduce + (fn [result shape] + (let [fill-obj (map-indexed #(assoc %2 :shape-id (:id shape) :index %1) (:fills shape)) + stroke-obj (map-indexed #(assoc %2 :shape-id (:id shape) :index %1) (:strokes shape)) + shadow-obj (map-indexed #(assoc %2 :shape-id (:id shape) :index %1) (:shadow shape))] + (if (= :text (:type shape)) + (-> result + (into (keep #(stroke->color-att % file-id libraries)) stroke-obj) + (into (map #(shadow->color-att % file-id libraries)) shadow-obj) + (into (extract-text-colors shape file-id libraries))) + + (-> result + (into (keep #(fill->color-att % file-id libraries)) fill-obj) + (into (keep #(stroke->color-att % file-id libraries)) stroke-obj) + (into (map #(shadow->color-att % file-id libraries)) shadow-obj))))) + [] + shapes)) diff --git a/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs b/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs index 0b6cb61d53..1ffe8a1ba4 100644 --- a/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs +++ b/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs @@ -7,7 +7,7 @@ (ns app.main.data.workspace.fix-deleted-fonts (:require [app.common.files.helpers :as cfh] - [app.common.text :as txt] + [app.common.types.text :as txt] [app.main.data.changes :as dwc] [app.main.data.helpers :as dsh] [app.main.fonts :as fonts] diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 4a06dd72c5..99de5340bb 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -22,7 +22,8 @@ [app.common.types.components-list :as ctkl] [app.common.types.container :as ctn] [app.common.types.file :as ctf] - [app.common.types.shape.layout :as ctl] + [app.common.types.library :as ctl] + [app.common.types.shape.layout :as ctsl] [app.common.types.typography :as ctt] [app.common.uuid :as uuid] [app.config :as cf] @@ -195,7 +196,7 @@ (if (str/empty? new-name) (rx/empty) (let [data (dsh/lookup-file-data state) - color (-> (ctc/get-color data id) + color (-> (ctl/get-color data id) (assoc :name new-name) (d/without-nils) (ctc/check-library-color))] @@ -962,8 +963,8 @@ orig-shapes (when keep-touched? (cfh/get-children-with-self objects (:id shape))) ;; If the target parent is a grid layout we need to pass the target cell - target-cell (when (ctl/grid-layout? parent) - (ctl/get-cell-by-shape-id parent (:id shape))) + target-cell (when (ctsl/grid-layout? parent) + (ctsl/get-cell-by-shape-id parent (:id shape))) index (find-shape-index objects (:parent-id shape) (:id shape)) diff --git a/frontend/src/app/main/data/workspace/media.cljs b/frontend/src/app/main/data/workspace/media.cljs index eafd055708..3cb250afc5 100644 --- a/frontend/src/app/main/data/workspace/media.cljs +++ b/frontend/src/app/main/data/workspace/media.cljs @@ -16,6 +16,7 @@ [app.common.media :as media] [app.common.schema :as sm] [app.common.types.container :as ctn] + [app.common.types.fills :as types.fills] [app.common.types.shape :as cts] [app.common.uuid :as uuid] [app.config :as cf] @@ -63,18 +64,22 @@ ptk/WatchEvent (watch [_ _ _] (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 :width width :height height :x (mth/round (- x (/ width 2))) :y (mth/round (- y (/ height 2))) - :fills [{:fill-opacity 1 - :fill-image {:name name - :width width - :height height - :mtype mtype - :id id - :keep-aspect-ratio true}}]}] + :fills fills}] + (rx/of (dwsh/create-and-add-shape :rect x y shape)))))) (defn svg-uploaded @@ -299,7 +304,7 @@ :name (:name root-svg-shape) :frame-id uuid/zero :parent-id uuid/zero - :fills []}) + :fills (types.fills/create)}) root-svg-shape (-> root-svg-shape @@ -335,19 +340,21 @@ :frame-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 {:type :rect :x (:x pos) :y (:y pos) :width width :height height - :fills [{:fill-opacity 1 - :fill-image {:name name - :id id - :width width - :height height - :mtype mtype - :keep-aspect-ratio true}}] + :fills img-fills :name name :frame-id (:id frame-shape) :parent-id (:id frame-shape)})] diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 9880d68293..187a307341 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -6,7 +6,6 @@ (ns app.main.data.workspace.shape-layout (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] @@ -16,6 +15,7 @@ [app.common.geom.shapes.flex-layout :as flex] [app.common.geom.shapes.grid-layout :as grid] [app.common.logic.libraries :as cll] + [app.common.types.color :as clr] [app.common.types.component :as ctc] [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl] diff --git a/frontend/src/app/main/data/workspace/text/shortcuts.cljs b/frontend/src/app/main/data/workspace/text/shortcuts.cljs index 4521bc4f4e..e245adad49 100644 --- a/frontend/src/app/main/data/workspace/text/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/text/shortcuts.cljs @@ -8,7 +8,7 @@ (:require [app.common.data :as d] [app.common.files.helpers :as cfh] - [app.common.text :as txt] + [app.common.types.text :as txt] [app.main.data.shortcuts :as ds] [app.main.data.workspace.texts :as dwt] [app.main.data.workspace.undo :as dwu] diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 2e10a5318b..5043bd4543 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -15,9 +15,9 @@ [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.math :as mth] - [app.common.text :as txt] - [app.common.types.fill :as types.fill] + [app.common.types.fills :as types.fills] [app.common.types.modifiers :as ctm] + [app.common.types.text :as txt] [app.common.uuid :as uuid] [app.main.data.event :as ev] [app.main.data.helpers :as dsh] @@ -196,8 +196,8 @@ ptk/UpdateEvent (update [_ state] (let [text-state (some->> content ted/import-content) - attrs (d/merge txt/default-text-attrs - (get-in state [:workspace-global :default-font])) + attrs (merge (txt/get-default-text-attrs) + (get-in state [:workspace-global :default-font])) editor (cond-> (ted/create-editor-state text-state decorator) (and (nil? content) (some? attrs)) (ted/update-editor-current-block-data attrs))] @@ -237,7 +237,9 @@ (defn- to-new-fills [data] - [(d/without-nils (select-keys data types.fill/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 [shape pred attrs] @@ -245,17 +247,21 @@ nodes (->> (txt/node-seq pred root) (map (fn [node] (if (txt/is-text-node? node) - (let [fills + (let [default-text-attrs + (txt/get-default-text-attrs) + + fills (cond - (types.fill/has-valid-fill-attrs? node) + (types.fills/has-valid-fill-attrs? node) (to-new-fills node) (some? (:fills node)) (:fills node) :else - (:fills txt/default-text-attrs))] - (-> (merge txt/default-text-attrs node) + (:fills default-text-attrs))] + + (-> (merge default-text-attrs node) (assoc :fills fills))) node))))] (attrs/get-attrs-multi nodes attrs))) @@ -290,7 +296,9 @@ [{:keys [editor-state attrs]}] (let [result (-> (ted/get-editor-current-inline-styles editor-state) (select-keys attrs)) - result (if (empty? result) txt/default-text-attrs result)] + result (if (empty? result) + (txt/get-default-text-attrs) + result)] result)) (defn current-text-values @@ -466,24 +474,24 @@ (defn migrate-node [node] - (let [color-attrs (not-empty (select-keys node types.fill/fill-attrs))] + (let [color-attrs (not-empty (select-keys node types.fills/fill-attrs))] (cond-> node (nil? (:fills node)) - (assoc :fills []) + (assoc :fills (types.fills/create)) ;; Migrate old colors and remove the old fromat color-attrs (-> (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 ;; so need to be black (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 :always - (update :fills (comp vec distinct))))) + (update :fills types.fills/update distinct)))) (defn migrate-content [content] @@ -905,9 +913,9 @@ (ptk/reify ::v2-update-text-editor-styles ptk/UpdateEvent (update [_ state] - (let [merged-styles (d/merge txt/default-text-attrs - (get-in state [:workspace-global :default-font]) - new-styles)] + (let [merged-styles (merge (txt/get-default-text-attrs) + (get-in state [:workspace-global :default-font]) + new-styles)] (update-in state [:workspace-v2-editor-state id] (fnil merge {}) merged-styles))))) (defn v2-update-text-shape-position-data diff --git a/frontend/src/app/main/data/workspace/tokens/application.cljs b/frontend/src/app/main/data/workspace/tokens/application.cljs index 0ae82fd980..35b0cb8266 100644 --- a/frontend/src/app/main/data/workspace/tokens/application.cljs +++ b/frontend/src/app/main/data/workspace/tokens/application.cljs @@ -8,9 +8,9 @@ (:require [app.common.data :as d] [app.common.files.tokens :as cft] - [app.common.text :as txt] [app.common.types.shape.layout :as ctsl] [app.common.types.shape.radius :as ctsr] + [app.common.types.text :as txt] [app.common.types.token :as ctt] [app.common.types.tokens-lib :as ctob] [app.common.types.typography :as cty] diff --git a/frontend/src/app/main/data/workspace/variants.cljs b/frontend/src/app/main/data/workspace/variants.cljs index 29e2518c93..41e8cefaa8 100644 --- a/frontend/src/app/main/data/workspace/variants.cljs +++ b/frontend/src/app/main/data/workspace/variants.cljs @@ -6,7 +6,6 @@ (ns app.main.data.workspace.variants (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.files.changes-builder :as pcb] [app.common.files.helpers :as cfh] @@ -14,6 +13,7 @@ [app.common.geom.point :as gpt] [app.common.logic.variant-properties :as clvp] [app.common.logic.variants :as clv] + [app.common.types.color :as clr] [app.common.types.component :as ctc] [app.common.types.components-list :as ctkl] [app.common.types.shape.layout :as ctsl] diff --git a/frontend/src/app/main/fonts.cljs b/frontend/src/app/main/fonts.cljs index bd460e299f..9f1d216cd1 100644 --- a/frontend/src/app/main/fonts.cljs +++ b/frontend/src/app/main/fonts.cljs @@ -11,7 +11,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.logging :as log] - [app.common.text :as txt] + [app.common.types.text :as txt] [app.config :as cf] [app.util.dom :as dom] [app.util.globals :as globals] @@ -295,7 +295,7 @@ (let [current-font (if (some? font-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))) #{}))) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index f634741270..2b939a86de 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -13,7 +13,6 @@ (:require ["react-dom/server" :as rds] - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] @@ -23,6 +22,7 @@ [app.common.geom.shapes.bounds :as gsb] [app.common.logging :as l] [app.common.math :as mth] + [app.common.types.color :as clr] [app.common.types.components-list :as ctkl] [app.common.types.file :as ctf] [app.common.types.modifiers :as ctm] diff --git a/frontend/src/app/main/ui/components/color_input.cljs b/frontend/src/app/main/ui/components/color_input.cljs index d0797e004c..10e6a493fa 100644 --- a/frontend/src/app/main/ui/components/color_input.cljs +++ b/frontend/src/app/main/ui/components/color_input.cljs @@ -6,8 +6,8 @@ (ns app.main.ui.components.color-input (:require - [app.common.colors :as cc] [app.common.data :as d] + [app.common.types.color :as cc] [app.main.ui.hooks :as hooks] [app.util.dom :as dom] [app.util.globals :as globals] diff --git a/frontend/src/app/main/ui/exports/assets.cljs b/frontend/src/app/main/ui/exports/assets.cljs index 4544fc171a..88f80255f1 100644 --- a/frontend/src/app/main/ui/exports/assets.cljs +++ b/frontend/src/app/main/ui/exports/assets.cljs @@ -9,9 +9,9 @@ "Assets exportation common components." (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.types.color :as clr] [app.main.data.exports.assets :as de] [app.main.data.modal :as modal] [app.main.refs :as refs] diff --git a/frontend/src/app/main/ui/inspect/attributes/common.cljs b/frontend/src/app/main/ui/inspect/attributes/common.cljs index 79e953a812..f1311884f2 100644 --- a/frontend/src/app/main/ui/inspect/attributes/common.cljs +++ b/frontend/src/app/main/ui/inspect/attributes/common.cljs @@ -7,10 +7,10 @@ (ns app.main.ui.inspect.attributes.common (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.media :as cm] + [app.common.types.color :as cc] [app.config :as cf] [app.main.refs :as refs] [app.main.store :as st] diff --git a/frontend/src/app/main/ui/inspect/attributes/fill.cljs b/frontend/src/app/main/ui/inspect/attributes/fill.cljs index 7a40aefa56..7557a9d444 100644 --- a/frontend/src/app/main/ui/inspect/attributes/fill.cljs +++ b/frontend/src/app/main/ui/inspect/attributes/fill.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.inspect.attributes.fill (:require-macros [app.main.style :as stl]) (:require - [app.common.types.color :as types.color] + [app.common.types.fills :as types.fills] [app.main.ui.components.title-bar :refer [inspect-title-bar*]] [app.main.ui.inspect.attributes.common :refer [color-row]] [app.util.code-gen.style-css :as css] @@ -31,7 +31,7 @@ ;; FIXME: this looks broken code, because shape does not ;; longer contains :fill-xxxx attributes but it is preserved ;; as it was just moved the impl; this need to be fixed - color (types.color/fill->color shape) + color (types.fills/fill->color shape) on-change (mf/use-fn (fn [format] diff --git a/frontend/src/app/main/ui/inspect/attributes/text.cljs b/frontend/src/app/main/ui/inspect/attributes/text.cljs index f4a527058d..5dab13e6b5 100644 --- a/frontend/src/app/main/ui/inspect/attributes/text.cljs +++ b/frontend/src/app/main/ui/inspect/attributes/text.cljs @@ -9,8 +9,8 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.text :as txt] - [app.common.types.color :as ctc] + [app.common.types.fills :as types.fills] + [app.common.types.text :as txt] [app.main.fonts :as fonts] [app.main.refs :as refs] [app.main.store :as st] @@ -18,8 +18,6 @@ [app.main.ui.components.title-bar :refer [inspect-title-bar*]] [app.main.ui.formats :as fmt] [app.main.ui.inspect.attributes.common :refer [color-row]] - [app.util.code-gen.style-css-formats :refer [format-color]] - [app.util.color :as uc] [app.util.i18n :refer [tr]] [cuerdas.core :as str] [okulary.core :as l] @@ -43,21 +41,6 @@ (map #(dm/str (d/name %) ": " (get style %) ";")) (str/join "\n"))) -(defn- format-gradient-css - "Converts a gradient object to a CSS string." - [gradient] - (str "background-image: " (uc/gradient->css gradient) ";" - "background-clip: text;" - "color: transparent;")) - -(defn- copy-color-data - "Converts a fill object to CSS color string in the specified format." - [fill format] - (let [color (ctc/fill->color fill)] - (if-let [gradient (:gradient color)] - (format-gradient-css gradient) - (format-color color {:format format})))) - (mf/defc typography-block [{:keys [text style]}] (let [typography-library-ref @@ -83,10 +66,10 @@ (when (:fills style) (for [[idx fill] (map-indexed vector (:fills style))] [:& color-row {:key idx - :format color-format* - :color (ctc/fill->color fill) - :copy-data (copy-color-data fill color-format*) - :on-change-format #(reset! color-format! %)}])) + :format @color-format* + :color (types.fills/fill->color fill) + :copy-data (copy-style-data fill :fill-color :fill-color-gradient) + :on-change-format #(reset! color-format* %)}])) (when (:typography-ref-id style) [:div {:class (stl/css :text-row)} @@ -191,7 +174,7 @@ (let [style-text-blocks (->> (:content shape) (txt/content->text+styles) (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)] [:& typography-block {:key idx diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index dfb6094843..6c6bfd58e1 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -6,13 +6,13 @@ (ns app.main.ui.shapes.attrs (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.geom.shapes :as gsh] [app.common.json :as json] [app.common.svg :as csvg] + [app.common.types.color :as clr] [app.common.types.shape :refer [stroke-caps-line stroke-caps-marker]] [app.common.types.shape.radius :as ctsr] [app.util.object :as obj] diff --git a/frontend/src/app/main/ui/shapes/filters.cljs b/frontend/src/app/main/ui/shapes/filters.cljs index ae24f34519..9dcbd0672e 100644 --- a/frontend/src/app/main/ui/shapes/filters.cljs +++ b/frontend/src/app/main/ui/shapes/filters.cljs @@ -6,11 +6,11 @@ (ns app.main.ui.shapes.filters (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.shapes.bounds :as gsb] [app.common.math :as mth] + [app.common.types.color :as cc] [app.common.uuid :as uuid] [cuerdas.core :as str] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/shapes/text.cljs b/frontend/src/app/main/ui/shapes/text.cljs index 9a7c50c092..0b1d47e602 100644 --- a/frontend/src/app/main/ui/shapes/text.cljs +++ b/frontend/src/app/main/ui/shapes/text.cljs @@ -6,7 +6,7 @@ (ns app.main.ui.shapes.text (:require - [app.common.text :as txt] + [app.common.types.text :as txt] [app.main.fonts :as fonts] [app.main.ui.context :as ctx] [app.main.ui.shapes.text.fo-text :as fo] @@ -17,7 +17,7 @@ (defn- load-fonts! [content] (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) (into #{default} (keep extract-fn)) (run! (fn [[font-id variant-id]] diff --git a/frontend/src/app/main/ui/shapes/text/fo_text.cljs b/frontend/src/app/main/ui/shapes/text/fo_text.cljs index 1f7836cc0c..aed6e6e0b9 100644 --- a/frontend/src/app/main/ui/shapes/text/fo_text.cljs +++ b/frontend/src/app/main/ui/shapes/text/fo_text.cljs @@ -6,10 +6,10 @@ (ns app.main.ui.shapes.text.fo-text (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.shapes :as gsh] + [app.common.types.color :as cc] [app.main.ui.shapes.text.styles :as sts] [app.util.object :as obj] [cuerdas.core :as str] diff --git a/frontend/src/app/main/ui/shapes/text/html_text.cljs b/frontend/src/app/main/ui/shapes/text/html_text.cljs index fd3995c38e..ff86df2e8e 100644 --- a/frontend/src/app/main/ui/shapes/text/html_text.cljs +++ b/frontend/src/app/main/ui/shapes/text/html_text.cljs @@ -8,7 +8,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.text :as txt] + [app.common.text :as legacy.txt] [app.main.ui.shapes.text.styles :as sts] [app.util.object :as obj] [rumext.v2 :as mf])) @@ -99,7 +99,7 @@ code? (obj/get props "code?") {:keys [id x y width height content]} shape - content (if code? (txt/index-content content) content) + content (if code? (legacy.txt/index-content content) content) style (when-not code? diff --git a/frontend/src/app/main/ui/shapes/text/styles.cljs b/frontend/src/app/main/ui/shapes/text/styles.cljs index 67c3a03562..e691e22952 100644 --- a/frontend/src/app/main/ui/shapes/text/styles.cljs +++ b/frontend/src/app/main/ui/shapes/text/styles.cljs @@ -6,10 +6,10 @@ (ns app.main.ui.shapes.text.styles (:require - [app.common.colors :as cc] [app.common.data :as d] - [app.common.text :as txt] [app.common.transit :as transit] + [app.common.types.color :as cc] + [app.common.types.text :as txt] [app.main.fonts :as fonts] [app.main.ui.formats :as fmt] [app.util.color :as uc] @@ -53,11 +53,11 @@ line-height (if (and (some? line-height) (not= "" line-height)) line-height - (:line-height txt/default-text-attrs)) + (:line-height txt/default-typography)) text-align (:text-align data "start") 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 :margin 0}] @@ -75,7 +75,7 @@ text-transform (:text-transform 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) diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index e6a460f05d..a78ec4f19f 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -13,8 +13,8 @@ [app.common.files.helpers :as cfh] [app.common.geom.point :as gpt] [app.common.geom.shapes.bounds :as gsb] - [app.common.text :as txt] [app.common.types.shape.interactions :as ctsi] + [app.common.types.text :as txt] [app.main.data.comments :as dcm] [app.main.data.viewer :as dv] [app.main.data.viewer.shortcuts :as sc] diff --git a/frontend/src/app/main/ui/workspace/color_palette.cljs b/frontend/src/app/main/ui/workspace/color_palette.cljs index 6799a15100..f96ca2579a 100644 --- a/frontend/src/app/main/ui/workspace/color_palette.cljs +++ b/frontend/src/app/main/ui/workspace/color_palette.cljs @@ -9,6 +9,7 @@ (:require [app.common.data.macros :as dm] [app.common.types.color :as ctc] + [app.common.types.library :as ctl] [app.main.data.event :as ev] [app.main.data.workspace.colors :as mdc] [app.main.refs :as refs] @@ -170,7 +171,8 @@ ;; how it was saved first time (if (and ref-id ref-file) (let [fdata (dm/get-in libraries [ref-file :data])] - (or (some-> (ctc/get-color fdata ref-id) + ;; FIXME: get a direct helper for obtain plain color + (or (some-> (ctl/get-color fdata ref-id) (ctc/library-color->color ref-file)) (dissoc color :ref-id :ref-file))) color))) diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 147aa74991..72f08e4d91 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -7,12 +7,12 @@ (ns app.main.ui.workspace.colorpicker (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] - [app.common.types.fill :as types.fill] + [app.common.types.color :as cc] + [app.common.types.fills :as types.fills] [app.config :as cfg] [app.main.data.event :as-alias ev] [app.main.data.modal :as modal] @@ -413,7 +413,7 @@ (when (= selected-mode :gradient) [:> gradients* {:type (:type state) - :stops (if cap-stops? (vec (take types.fill/MAX-GRADIENT-STOPS (:stops state))) (:stops state)) + :stops (if cap-stops? (vec (take types.fills/MAX-GRADIENT-STOPS (:stops state))) (:stops state)) :editing-stop (:editing-stop state) :on-stop-edit-start handle-stop-edit-start :on-stop-edit-finish handle-stop-edit-finish diff --git a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs index 5bf07553e3..f7b9cabc20 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs @@ -7,9 +7,9 @@ (ns app.main.ui.workspace.colorpicker.color-inputs (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.math :as mth] + [app.common.types.color :as cc] [app.util.dom :as dom] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs index 6ebfc2a1d1..93443d7c41 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs @@ -7,11 +7,11 @@ (ns app.main.ui.workspace.colorpicker.gradients (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.math :as mth] - [app.common.types.fill :as types.fill] + [app.common.types.color :as cc] + [app.common.types.fills :as types.fills] [app.config :as cfg] [app.main.features :as features] [app.main.ui.components.numeric-input :refer [numeric-input*]] @@ -288,7 +288,7 @@ (when on-reverse-stops (on-reverse-stops)))) cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills)) - add-stop-disabled? (when cap-stops? (>= (count stops) types.fill/MAX-GRADIENT-STOPS))] + add-stop-disabled? (when cap-stops? (>= (count stops) types.fills/MAX-GRADIENT-STOPS))] [:div {:class (stl/css :gradient-panel)} [:div {:class (stl/css :gradient-preview)} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs index 361a51f7e1..c043899551 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs @@ -7,10 +7,10 @@ (ns app.main.ui.workspace.colorpicker.harmony (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as cc] [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.math :as mth] + [app.common.types.color :as cc] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [app.util.dom :as dom] [app.util.object :as obj] diff --git a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs index cf4554b6e3..9a7d240f55 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.workspace.colorpicker.hsva (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as cc] + [app.common.types.color :as cc] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index bc1d3f83cb..6e2329afb2 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.workspace.colorpicker.libraries (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as c] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.types.color :as ctc] @@ -109,7 +108,7 @@ (map-indexed (fn [index color] (let [color (if (map? color) color {:color color})] (vary-meta color assoc ::id (dm/str index))))) - (sort c/sort-colors)) + (sort ctc/sort-colors)) (->> (dm/get-in libraries [file-id :data :colors]) (vals) (filter valid-color?) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs index 64879eed2e..154587fc7b 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs @@ -7,9 +7,9 @@ (ns app.main.ui.workspace.colorpicker.ramp (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.math :as mth] + [app.common.types.color :as cc] [app.main.ui.components.color-bullet :as cb] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [app.util.dom :as dom] diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index eb2f01d001..dd609e7a34 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -9,9 +9,9 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.types.color :as ctc] [app.common.types.components-list :as ctkl] [app.common.types.file :as ctf] + [app.common.types.library :as ctl] [app.common.types.typographies-list :as ctyl] [app.common.uuid :as uuid] [app.main.data.dashboard :as dd] @@ -407,7 +407,7 @@ (sort-by #(str/lower (:name %))) (truncate :components)) colors (->> color-ids - (map #(ctc/get-color (:data library) %)) + (map #(ctl/get-color (:data library) %)) (sort-by #(str/lower (:name %))) (truncate :colors)) typographies (->> typography-ids diff --git a/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs index 8fe5c89200..3f86bbc748 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs @@ -13,7 +13,7 @@ [app.common.geom.shapes :as gsh] [app.common.geom.shapes.text :as gst] [app.common.math :as mth] - [app.common.text :as txt] + [app.common.text :as legacy.txt] [app.config :as cf] [app.main.data.workspace :as dw] [app.main.data.workspace.texts :as dwt] @@ -65,7 +65,7 @@ (-> ^js (.getData content) (.toJS) (js->clj :keywordize-keys true)) - (txt/styles-to-attrs styles))] + (legacy.txt/styles-to-attrs styles))] (sts/generate-text-styles shape data {:show-text? false}))) (def default-decorator diff --git a/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs b/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs index 1af9cae6a8..8a42dde614 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs @@ -12,7 +12,7 @@ [app.common.geom.shapes :as gsh] [app.common.geom.shapes.text :as gst] [app.common.math :as mth] - [app.common.text :as txt] + [app.common.types.text :as txt] [app.config :as cf] [app.main.data.workspace :as dw] [app.main.data.workspace.texts :as dwt] @@ -41,7 +41,7 @@ (defn- get-fonts [content] (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) (into #{default} (keep extract-fn))))) @@ -67,7 +67,7 @@ style-defaults (styles/get-style-defaults - (merge txt/default-attrs default-font)) + (merge (txt/get-default-text-attrs) txt/default-root-attrs default-font)) options #js {:styleDefaults style-defaults diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index 4e84088cee..19a10a1757 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -13,8 +13,8 @@ [app.common.geom.shapes :as gsh] [app.common.geom.shapes.text :as gsht] [app.common.math :as mth] - [app.common.text :as txt] [app.common.types.modifiers :as ctm] + [app.common.types.text :as txt] [app.common.uuid :as uuid] [app.main.data.workspace.modifiers :as mdwm] [app.main.data.workspace.texts :as dwt] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs index bd8579138b..a9978188ae 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs @@ -8,8 +8,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] - [app.common.types.color :as ctc] - [app.main.data.workspace.colors :as dc] + [app.main.data.workspace.colors :as dwc] [app.main.data.workspace.selection :as dws] [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar]] @@ -20,7 +19,7 @@ (defn- prepare-colors [shapes file-id libraries] - (let [data (into [] (remove nil? (ctc/extract-all-colors shapes file-id libraries))) + (let [data (into [] (remove nil? (dwc/extract-all-colors shapes file-id libraries))) groups (d/group-by :attrs #(dissoc % :attrs) data) all-colors (distinct (mapv :attrs data)) @@ -82,7 +81,7 @@ (mf/set-ref-val! prev-colors-ref (conj prev-colors color)))) - (st/emit! (dc/change-color-in-selected cops new-color old-color))))) + (st/emit! (dwc/change-color-in-selected cops new-color old-color))))) on-open (mf/use-fn #(mf/set-ref-val! prev-colors-ref [])) @@ -96,7 +95,7 @@ (let [groups (mf/ref-val groups-ref) cops (get groups color) color' (dissoc color :id :file-id)] - (st/emit! (dc/change-color-in-selected cops color' color))))) + (st/emit! (dwc/change-color-in-selected cops color' color))))) select-only (mf/use-fn diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs index fd39a007ed..a22f552034 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs @@ -7,8 +7,8 @@ (ns app.main.ui.workspace.sidebar.options.menus.fill (:require-macros [app.main.style :as stl]) (:require - [app.common.types.color :as ctc] - [app.common.types.fill :as types.fill] + [app.common.types.color :as clr] + [app.common.types.fills :as types.fills] [app.common.types.shape.attrs :refer [default-color]] [app.config :as cfg] [app.main.data.workspace :as udw] @@ -28,13 +28,13 @@ (def ^:private xf:take-max-fills - (take types.fill/MAX-FILLS)) + (take types.fills/MAX-FILLS)) (def ^:private xf:enumerate (map-indexed (fn [index item] - (let [color (ctc/fill->color item)] + (let [color (types.fills/fill->color item)] (with-meta item {:index index :color color}))))) (def ^:private ^boolean binary-fills-enabled? @@ -101,7 +101,7 @@ can-add-fills? (if binary-fills-enabled? (and (not multiple?) - (< (count fills) types.fill/MAX-FILLS)) + (< (count fills) types.fills/MAX-FILLS)) (not ^boolean multiple?)) label @@ -125,8 +125,7 @@ (mf/use-fn (mf/deps ids) (fn [color index] - (let [color (select-keys color ctc/color-attrs)] - (st/emit! (udw/trigger-bounding-box-cloaking ids)) + (let [color (select-keys color clr/color-attrs)] (st/emit! (dc/change-fill ids color index))))) on-reorder diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs index 6df60e9d20..5372321259 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs @@ -7,9 +7,9 @@ (ns app.main.ui.workspace.sidebar.options.menus.shadow (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.types.color :as clr] [app.common.types.shape.shadow :as ctss] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs index b513bdc190..c1ba291098 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs @@ -7,9 +7,9 @@ (ns app.main.ui.workspace.sidebar.options.menus.stroke (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.types.color :as clr] [app.main.data.workspace :as udw] [app.main.data.workspace.colors :as dc] [app.main.store :as st] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs index 84bf713ae0..ac1f35506f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs @@ -8,7 +8,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] - [app.common.text :as txt] + [app.common.types.text :as txt] [app.common.uuid :as uuid] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.shapes :as dwsh] @@ -217,7 +217,7 @@ (mf/use-fn (mf/deps values) (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))) (dwt/update-all-attrs ids attrs)))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs index 92fab80bad..2faae0ddca 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs @@ -11,7 +11,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.exceptions :as ex] - [app.common.text :as txt] + [app.common.types.text :as txt] [app.main.constants :refer [max-input-length]] [app.main.data.common :as dcm] [app.main.data.fonts :as fts] @@ -235,9 +235,9 @@ [{:keys [values on-change on-blur show-recent full-size-selector]}] (let [{:keys [font-id font-size font-variant-id]} values - font-id (or font-id (:font-id txt/default-text-attrs)) - font-size (or font-size (:font-size txt/default-text-attrs)) - font-variant-id (or font-variant-id (:font-variant-id txt/default-text-attrs)) + font-id (or font-id (:font-id txt/default-typography)) + font-size (or font-size (:font-size txt/default-typography)) + font-variant-id (or font-variant-id (:font-variant-id txt/default-typography)) fonts (mf/deref fonts/fontsdb) font (get fonts font-id) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs index 3619913254..db6c17d2c0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs @@ -8,8 +8,8 @@ "Page options menu entries." (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as clr] [app.common.data :as d] + [app.common.types.color :as clr] [app.main.data.workspace :as dw] [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs index ceb3a31d7f..95ff3813d4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -7,10 +7,9 @@ (ns app.main.ui.workspace.sidebar.options.rows.color-row (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.types.color :as types.color] + [app.common.types.color :as clr] [app.common.types.shape.attrs :refer [default-color]] [app.main.data.modal :as modal] [app.main.data.workspace.colors :as dwc] @@ -116,7 +115,7 @@ (let [color (-> color (assoc :color value) (dissoc :gradient) - (select-keys types.color/color-attrs))] + (select-keys clr/color-attrs))] (st/emit! (dwc/add-recent-color color) (on-change color index))))) @@ -127,7 +126,7 @@ (let [color (-> color (assoc :opacity (/ value 100)) (dissoc :ref-id :ref-file) - (select-keys types.color/color-attrs))] + (select-keys clr/color-attrs))] (st/emit! (dwc/add-recent-color color) (on-change color index))))) @@ -256,7 +255,7 @@ [:span {:class (stl/css :color-input-wrapper)} [:> color-input* {:value (if multiple-colors? "" - (-> color :color cc/remove-hash)) + (-> color :color clr/remove-hash)) :placeholder (tr "settings.multiple") :data-index index :class (stl/css :color-input) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index 742bcc698b..2429021307 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -10,11 +10,11 @@ [app.common.attrs :as attrs] [app.common.data :as d] [app.common.geom.shapes :as gsh] - [app.common.text :as txt] [app.common.types.component :as ctk] [app.common.types.path :as path] [app.common.types.shape.attrs :refer [editable-attrs]] [app.common.types.shape.layout :as ctl] + [app.common.types.text :as txt] [app.main.refs :as refs] [app.main.ui.hooks :as hooks] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-attrs blur-menu]] @@ -203,6 +203,9 @@ [shapes objects attr-group] (let [attrs (group->attrs attr-group) + default-text-attrs + (txt/get-default-text-attrs) + merge-attrs (fn [v1 v2] (cond @@ -233,7 +236,7 @@ (let [shape-attrs (select-keys shape 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 (-> values diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs index 303c20aec0..66dc19614f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs @@ -6,8 +6,8 @@ (ns app.main.ui.workspace.sidebar.options.shapes.svg-raw (:require - [app.common.colors :as cc] [app.common.data :as d] + [app.common.types.color :as cc] [app.common.types.shape.layout :as ctl] [app.main.refs :as refs] [app.main.ui.hooks :as hooks] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs index a99fab3c79..4cc88c624b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs @@ -7,8 +7,8 @@ (ns app.main.ui.workspace.sidebar.options.shapes.text (:require [app.common.data :as d] - [app.common.text :as txt] [app.common.types.shape.layout :as ctl] + [app.common.types.text :as txt] [app.main.data.workspace.texts :as dwt] [app.main.features :as features] [app.main.refs :as refs] diff --git a/frontend/src/app/main/ui/workspace/tokens/management/create/form.cljs b/frontend/src/app/main/ui/workspace/tokens/management/create/form.cljs index 0e627ecf0f..d5d1a8c532 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/create/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/create/form.cljs @@ -7,10 +7,10 @@ (ns app.main.ui.workspace.tokens.management.create.form (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as c] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.tokens :as cft] + [app.common.types.color :as c] [app.common.types.tokens-lib :as ctob] [app.main.constants :refer [max-input-length]] [app.main.data.modal :as modal] diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 87f4504c84..e496500259 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -7,11 +7,11 @@ (ns app.main.ui.workspace.viewport (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.geom.shapes :as gsh] + [app.common.types.color :as clr] [app.common.types.path :as path] [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctt] diff --git a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs index 2d75db9457..8de28cd740 100644 --- a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.workspace.viewport.gradients "Gradients handlers and renders" (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.matrix :as gmt] @@ -15,7 +14,8 @@ [app.common.geom.shapes :as gsh] [app.common.geom.shapes.points :as gsp] [app.common.math :as mth] - [app.common.types.fill :as types.fill] + [app.common.types.color :as cc] + [app.common.types.fills :as types.fills] [app.config :as cfg] [app.main.data.workspace.colors :as dc] [app.main.features :as features] @@ -135,7 +135,7 @@ handler-state (mf/use-state {:display? false :offset 0 :hover nil}) cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills)) - can-add-stop? (if cap-stops? (< (count stops) types.fill/MAX-GRADIENT-STOPS) true) + can-add-stop? (if cap-stops? (< (count stops) types.fills/MAX-GRADIENT-STOPS) true) endpoint-on-pointer-down (fn [position event] @@ -527,7 +527,7 @@ gradient (:gradient state) cap-stops? (or (features/use-feature "render-wasm/v1") (contains? cfg/flags :frontend-binary-fills)) stops (if cap-stops? - (vec (take types.fill/MAX-GRADIENT-STOPS (:stops state))) + (vec (take types.fills/MAX-GRADIENT-STOPS (:stops state))) (:stops state)) editing-stop (:editing-stop state)] diff --git a/frontend/src/app/main/ui/workspace/viewport/guides.cljs b/frontend/src/app/main/ui/workspace/viewport/guides.cljs index 5e6963be9e..af21882f21 100644 --- a/frontend/src/app/main/ui/workspace/viewport/guides.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/guides.cljs @@ -6,12 +6,12 @@ (ns app.main.ui.workspace.viewport.guides (:require - [app.common.colors :as colors] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.math :as mth] + [app.common.types.color :as colors] [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] diff --git a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs index 76640fd88d..87ee8d3656 100644 --- a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs @@ -6,10 +6,10 @@ (ns app.main.ui.workspace.viewport.scroll-bars (:require - [app.common.colors :as clr] [app.common.files.helpers :as cfh] [app.common.geom.rect :as grc] [app.common.geom.shapes :as gsh] + [app.common.types.color :as clr] [app.main.data.workspace :as dw] [app.main.store :as st] [app.main.ui.workspace.viewport.viewport-ref :refer [point->viewport]] diff --git a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs index ab5c05b849..a7c201d375 100644 --- a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs +++ b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs @@ -7,11 +7,11 @@ (ns app.main.ui.workspace.viewport-wasm (:require-macros [app.main.style :as stl]) (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.geom.shapes :as gsh] + [app.common.types.color :as clr] [app.common.types.path :as path] [app.common.types.shape :as cts] [app.common.types.shape.layout :as ctl] diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs index 28e8ed6b7b..9e3e26c648 100644 --- a/frontend/src/app/plugins/api.cljs +++ b/frontend/src/app/plugins/api.cljs @@ -12,9 +12,9 @@ [app.common.files.helpers :as cfh] [app.common.geom.point :as gpt] [app.common.schema :as sm] - [app.common.text :as txt] [app.common.types.color :as ctc] [app.common.types.shape :as cts] + [app.common.types.text :as txt] [app.common.uuid :as uuid] [app.main.data.changes :as ch] [app.main.data.common :as dcm] @@ -174,7 +174,7 @@ file-id (:current-file-id @st/state) shared-libs (:files @st/state)] - (->> (ctc/extract-all-colors shapes file-id shared-libs) + (->> (dwc/extract-all-colors shapes file-id shared-libs) (group-by :attrs) (format/format-array format/format-color-result))))) @@ -202,7 +202,7 @@ (mapcat #(cfh/get-children-with-self objects %))) shapes-by-color - (->> (ctc/extract-all-colors shapes file-id shared-libs) + (->> (dwc/extract-all-colors shapes file-id shared-libs) (group-by :attrs))] (when-let [operations (get shapes-by-color old-color)] diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index 43e3d7ecd2..711df32cec 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -7,12 +7,11 @@ (ns app.plugins.library "RPC for plugins runtime." (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.schema :as sm] - [app.common.types.color :as ctc] + [app.common.types.color :as clr] [app.common.types.file :as ctf] [app.common.types.typography :as ctt] [app.common.uuid :as uuid] @@ -91,7 +90,7 @@ :set (fn [self value] (cond - (or (not (string? value)) (not (cc/valid-hex-color? value))) + (or (not (string? value)) (not (clr/valid-hex-color? value))) (u/display-not-valid :color value) (not (r/check-permission plugin-id "library:write")) @@ -126,7 +125,7 @@ (fn [self value] (let [value (parser/parse-gradient value)] (cond - (not (sm/validate ctc/schema:gradient value)) + (not (sm/validate clr/schema:gradient value)) (u/display-not-valid :gradient value) (not (r/check-permission plugin-id "library:write")) @@ -144,7 +143,7 @@ (fn [self value] (let [value (parser/parse-image-data value)] (cond - (not (sm/validate ctc/schema:image value)) + (not (sm/validate clr/schema:image value)) (u/display-not-valid :image value) (not (r/check-permission plugin-id "library:write")) diff --git a/frontend/src/app/plugins/page.cljs b/frontend/src/app/plugins/page.cljs index b451787854..ef49eca02d 100644 --- a/frontend/src/app/plugins/page.cljs +++ b/frontend/src/app/plugins/page.cljs @@ -6,12 +6,12 @@ (ns app.plugins.page (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.geom.point :as gpt] [app.common.spec :as us] + [app.common.types.color :as cc] [app.common.uuid :as uuid] [app.main.data.comments :as dc] [app.main.data.common :as dcm] diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 2af5681994..1b82f8d2bb 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -6,7 +6,6 @@ (ns app.plugins.shape (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] @@ -16,11 +15,11 @@ [app.common.schema :as sm] [app.common.spec :as us] [app.common.svg.path :as svg.path] - [app.common.text :as txt] + [app.common.types.color :as clr] [app.common.types.component :as ctk] [app.common.types.container :as ctn] [app.common.types.file :as ctf] - [app.common.types.fill :as types.fill] + [app.common.types.fills :as types.fills] [app.common.types.grid :as ctg] [app.common.types.path :as path] [app.common.types.path.segment :as path.segm] @@ -31,6 +30,7 @@ [app.common.types.shape.layout :as ctl] [app.common.types.shape.radius :as ctsr] [app.common.types.shape.shadow :as ctss] + [app.common.types.text :as txt] [app.common.uuid :as uuid] [app.main.data.plugins :as dp] [app.main.data.workspace :as dw] @@ -709,7 +709,7 @@ id (:id shape) value (parser/parse-fills value)] (cond - (not (sm/validate [:vector types.fill/schema:fill] value)) + (not (sm/validate [:vector types.fills/schema:fill] value)) (u/display-not-valid :fills value) (cfh/text-shape? shape) diff --git a/frontend/src/app/plugins/text.cljs b/frontend/src/app/plugins/text.cljs index 6c90f658d5..1a1e83ac20 100644 --- a/frontend/src/app/plugins/text.cljs +++ b/frontend/src/app/plugins/text.cljs @@ -10,8 +10,8 @@ [app.common.data.macros :as dm] [app.common.record :as crc] [app.common.schema :as sm] - [app.common.text :as txt] [app.common.types.shape :as cts] + [app.common.types.text :as txt] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.texts :as dwt] [app.main.fonts :as fonts] @@ -59,6 +59,27 @@ (dwt/current-paragraph-values {:shape shape :attrs txt/paragraph-attrs}) (dwt/current-text-values {:shape shape :attrs txt/text-node-attrs}))) +(defn- content-range->text+styles + "Given a root node of a text content extracts the texts with its associated styles" + [node start end] + (let [sss (txt/content->text+styles node)] + (loop [styles (seq sss) + taking? false + acc 0 + result []] + (if styles + (let [[node-style text] (first styles) + from acc + to (+ acc (count text)) + taking? (or taking? (and (<= from start) (< start to))) + text (subs text (max 0 (- start acc)) (- end acc)) + result (cond-> result + (and taking? (d/not-empty? text)) + (conj (assoc node-style :text text))) + continue? (or (> from end) (>= end to))] + (recur (when continue? (rest styles)) taking? to result)) + result)))) + (defn text-range-proxy? [range] (obj/type-of? range "TextRange")) @@ -80,7 +101,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :text) (str/join ""))))} :fontId @@ -88,7 +109,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :font-id) u/mixed-value))) :set @@ -110,7 +131,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :font-family) u/mixed-value))) :set @@ -132,7 +153,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :font-variant-id) u/mixed-value))) :set (fn [self value] @@ -153,7 +174,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :font-size) u/mixed-value))) :set (fn [_ value] @@ -173,7 +194,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :font-weight) u/mixed-value))) :set @@ -200,7 +221,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :font-style) u/mixed-value))) :set (fn [self value] @@ -226,7 +247,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :line-height) u/mixed-value))) :set (fn [_ value] @@ -246,7 +267,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :letter-spacing) u/mixed-value))) :set (fn [_ value] @@ -266,7 +287,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :text-transform) u/mixed-value))) :set (fn [_ value] @@ -285,7 +306,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :text-decoration) u/mixed-value))) :set (fn [_ value] @@ -304,7 +325,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :direction) u/mixed-value))) :set (fn [_ value] @@ -323,7 +344,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :text-align) u/mixed-value))) :set (fn [_ value] @@ -342,7 +363,7 @@ :get (fn [self] (let [range-data - (-> self u/proxy->shape :content (txt/content-range->text+styles start end))] + (-> self u/proxy->shape :content (content-range->text+styles start end))] (->> range-data (map :fills) u/mixed-value format/format-fills))) :set (fn [_ value] @@ -388,14 +409,15 @@ (let [shape (u/proxy->shape self) editor (-> shape + (get :content) (txt/change-text value) - :content ted/import-content ted/create-editor-state)] (st/emit! (dwt/update-editor-state shape editor))) :else - (st/emit! (dwsh/update-shapes [id] #(txt/change-text % value))))))} + (st/emit! (dwsh/update-shapes [id] + #(update % :content txt/change-text value))))))} {:name "growType" :get #(-> % u/proxy->shape :grow-type d/name) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index b598dd36f7..0bf4096577 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -12,7 +12,8 @@ [app.common.data.macros :as dm] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] - [app.common.types.fill :as types.fill] + [app.common.types.fills :as types.fills] + [app.common.types.fills.impl :as types.fills.impl] [app.common.types.path :as path] [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] @@ -28,7 +29,6 @@ [app.render-wasm.performance :as perf] [app.render-wasm.serializers :as sr] [app.render-wasm.serializers.color :as sr-clr] - [app.render-wasm.serializers.fills :as sr-fills] [app.render-wasm.wasm :as wasm] [app.util.debug :as dbg] [app.util.functions :as fns] @@ -201,6 +201,9 @@ (rx/map :body) (rx/mapcat wapi/read-file-as-array-buffer) (rx/map (fn [image] + ;; FIXME use bigger heap ptr size if it + ;; is possible (if image size modulo + ;; permits it) (let [size (.-byteLength image) offset (mem/alloc-bytes size) heap (mem/get-heap-u8) @@ -248,28 +251,19 @@ [shape-id fills] (if (empty? fills) (h/call wasm/internal-module "_clear_shape_fills") - (let [fills (take types.fill/MAX-FILLS fills) - image-fills (filter :fill-image fills) - offset (mem/alloc-bytes (* (count fills) sr-fills/FILL-BYTE-SIZE)) - heap (mem/get-heap-u8) - dview (js/DataView. (.-buffer heap))] + (let [fills (types.fills/coerce fills) + offset (mem/alloc-bytes-32 (types.fills/get-byte-size fills)) + heap (mem/get-heap-u32)] - ;; write fill data to heap - (loop [fills (seq fills) - current-offset offset] - (when-not (empty? fills) - (let [fill (first fills) - new-offset (sr-fills/write-fill! current-offset dview fill)] - (recur (rest fills) new-offset)))) + ;; write fills to the heap + (types.fills/write-to fills heap offset) ;; send fills to wasm (h/call wasm/internal-module "_set_shape_fills") ;; load images for image fills if not cached - (keep (fn [fill] - (let [image (:fill-image fill) - id (dm/get-prop image :id) - buffer (uuid/get-u32 id) + (keep (fn [id] + (let [buffer (uuid/get-u32 id) cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) @@ -277,7 +271,8 @@ (aget buffer 3))] (when (zero? cached-image?) (fetch-image shape-id id)))) - image-fills)))) + + (types.fills/get-image-ids fills))))) (defn set-shape-strokes [shape-id strokes] @@ -292,7 +287,7 @@ style (-> stroke :stroke-style sr/translate-stroke-style) cap-start (-> stroke :stroke-cap-start sr/translate-stroke-cap) cap-end (-> stroke :stroke-cap-end sr/translate-stroke-cap) - offset (mem/alloc-bytes sr-fills/FILL-BYTE-SIZE) + offset (mem/alloc-bytes types.fills.impl/FILL-BYTE-SIZE) heap (mem/get-heap-u8) dview (js/DataView. (.-buffer heap))] (case align @@ -303,23 +298,21 @@ (cond (some? gradient) (do - (sr-fills/write-gradient-fill! offset dview gradient opacity) + (types.fills.impl/write-gradient-fill offset dview opacity gradient) (h/call wasm/internal-module "_add_shape_stroke_fill")) (some? image) (let [image-id (dm/get-prop image :id) buffer (uuid/get-u32 image-id) cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))] - (sr-fills/write-image-fill! offset dview image-id opacity - (dm/get-prop image :width) - (dm/get-prop image :height)) + (types.fills.impl/write-image-fill offset dview opacity image) (h/call wasm/internal-module "_add_shape_stroke_fill") (when (== cached-image? 0) (fetch-image shape-id image-id))) (some? color) (do - (sr-fills/write-solid-fill! offset dview (sr-clr/hex->u32argb color opacity)) + (types.fills.impl/write-solid-fill offset dview opacity color) (h/call wasm/internal-module "_add_shape_stroke_fill"))))) strokes)) diff --git a/frontend/src/app/render_wasm/api/texts.cljs b/frontend/src/app/render_wasm/api/texts.cljs index 70418f0099..976e982e24 100644 --- a/frontend/src/app/render_wasm/api/texts.cljs +++ b/frontend/src/app/render_wasm/api/texts.cljs @@ -6,13 +6,11 @@ (ns app.render-wasm.api.texts (:require - [app.common.data.macros :as dm] + [app.common.types.fills.impl :as types.fills.impl] [app.render-wasm.api.fonts :as f] [app.render-wasm.helpers :as h] [app.render-wasm.mem :as mem] [app.render-wasm.serializers :as sr] - [app.render-wasm.serializers.color :as sr-clr] - [app.render-wasm.serializers.fills :as sr-fills] [app.render-wasm.wasm :as wasm])) (defn utf8->buffer [text] @@ -26,21 +24,18 @@ color (:fill-color fill) gradient (:fill-color-gradient fill) image (:fill-image fill)] + (cond (some? color) - (sr-fills/write-solid-fill! offset dview (sr-clr/hex->u32argb color opacity)) + (types.fills.impl/write-solid-fill offset dview opacity color) (some? gradient) - (sr-fills/write-gradient-fill! offset dview gradient opacity) + (types.fills.impl/write-gradient-fill offset dview opacity gradient) (some? image) - (sr-fills/write-image-fill! offset dview - (dm/get-prop image :id) - opacity - (dm/get-prop image :width) - (dm/get-prop image :height))) + (types.fills.impl/write-image-fill offset dview opacity image)) - (+ offset sr-fills/FILL-BYTE-SIZE))) + (+ offset types.fills.impl/FILL-BYTE-SIZE))) current-offset fills)) @@ -56,7 +51,7 @@ num-leaves (count leaves) paragraph-attr-size 48 total-fills (total-fills-count leaves) - total-fills-size (* sr-fills/FILL-BYTE-SIZE total-fills) + total-fills-size (* types.fills.impl/FILL-BYTE-SIZE total-fills) leaf-attr-size 56 metadata-size (+ paragraph-attr-size (* num-leaves leaf-attr-size) total-fills-size) text-buffer (utf8->buffer text) diff --git a/frontend/src/app/render_wasm/serializers/fills.cljs b/frontend/src/app/render_wasm/serializers/fills.cljs deleted file mode 100644 index b39e4a0dbd..0000000000 --- a/frontend/src/app/render_wasm/serializers/fills.cljs +++ /dev/null @@ -1,81 +0,0 @@ -(ns app.render-wasm.serializers.fills - (:require - [app.common.data.macros :as dm] - [app.common.types.fill :as types.fill] - [app.common.uuid :as uuid] - [app.render-wasm.serializers.color :as clr])) - -(def ^:private GRADIENT-STOP-SIZE 8) - -(def GRADIENT-BYTE-SIZE 156) -(def SOLID-BYTE-SIZE 4) -(def IMAGE-BYTE-SIZE 28) - -;; FIXME: get it from the wasm module -(def FILL-BYTE-SIZE (+ 4 (max GRADIENT-BYTE-SIZE IMAGE-BYTE-SIZE SOLID-BYTE-SIZE))) - - -(defn write-solid-fill! - [offset dview argb] - (.setUint8 dview offset 0x00 true) - (.setUint32 dview (+ offset 4) argb true) - (+ offset FILL-BYTE-SIZE)) - -(defn write-image-fill! - [offset dview id opacity width height] - (let [uuid-buffer (uuid/get-u32 id)] - (.setUint8 dview offset 0x03 true) - (.setUint32 dview (+ offset 4) (aget uuid-buffer 0) true) - (.setUint32 dview (+ offset 8) (aget uuid-buffer 1) true) - (.setUint32 dview (+ offset 12) (aget uuid-buffer 2) true) - (.setUint32 dview (+ offset 16) (aget uuid-buffer 3) true) - (.setFloat32 dview (+ offset 20) opacity true) - (.setInt32 dview (+ offset 24) width true) - (.setInt32 dview (+ offset 28) height true) - (+ offset FILL-BYTE-SIZE))) - -(defn write-gradient-fill! - [offset dview gradient opacity] - (let [start-x (:start-x gradient) - start-y (:start-y gradient) - end-x (:end-x gradient) - end-y (:end-y gradient) - width (or (:width gradient) 0) - stops (take types.fill/MAX-GRADIENT-STOPS (:stops gradient)) - type (if (= (:type gradient) :linear) 0x01 0x02)] - (.setUint8 dview offset type true) - (.setFloat32 dview (+ offset 4) start-x true) - (.setFloat32 dview (+ offset 8) start-y true) - (.setFloat32 dview (+ offset 12) end-x true) - (.setFloat32 dview (+ offset 16) end-y true) - (.setFloat32 dview (+ offset 20) opacity true) - (.setFloat32 dview (+ offset 24) width true) - (.setUint8 dview (+ offset 28) (count stops) true) - (loop [stops (seq stops) loop-offset (+ offset 32)] - (if (empty? stops) - (+ offset FILL-BYTE-SIZE) - (let [stop (first stops) - hex-color (:color stop) - stop-opacity (:opacity stop) - argb (clr/hex->u32argb hex-color stop-opacity) - stop-offset (:offset stop)] - (.setUint32 dview loop-offset argb true) - (.setFloat32 dview (+ loop-offset 4) stop-offset true) - (recur (rest stops) (+ loop-offset GRADIENT-STOP-SIZE))))))) - -(defn write-fill! - [offset dview fill] - (let [opacity (or (:fill-opacity fill) 1.0) - color (:fill-color fill) - gradient (:fill-color-gradient fill) - image (:fill-image fill)] - (cond - (some? color) - (write-solid-fill! offset dview (clr/hex->u32argb color opacity)) - - (some? gradient) - (write-gradient-fill! offset dview gradient opacity) - - (some? image) - (let [id (dm/get-prop image :id)] - (write-image-fill! offset dview id opacity (dm/get-prop image :width) (dm/get-prop image :height)))))) diff --git a/frontend/src/app/util/code_gen/style_css.cljs b/frontend/src/app/util/code_gen/style_css.cljs index 8845441723..4a235339e6 100644 --- a/frontend/src/app/util/code_gen/style_css.cljs +++ b/frontend/src/app/util/code_gen/style_css.cljs @@ -12,8 +12,9 @@ [app.common.geom.matrix :as gmt] [app.common.geom.shapes.bounds :as gsb] [app.common.geom.shapes.points :as gpo] - [app.common.text :as txt] + [app.common.text :as legacy.txt] [app.common.types.shape.layout :as ctl] + [app.common.types.text :as types.text] [app.main.ui.shapes.text.styles :as sts] [app.util.code-gen.common :as cgc] [app.util.code-gen.style-css-formats :refer [format-value format-shadow]] @@ -232,8 +233,8 @@ body { (let [selector (cgc/shape->selector shape)] (->> shape :content - (txt/index-content) - (txt/node-seq) + (legacy.txt/index-content) + (types.text/node-seq) (map #(node->css shape selector %)) (str/join "\n")))) diff --git a/frontend/src/app/util/color.cljs b/frontend/src/app/util/color.cljs index e44fbad2ff..789f0566ee 100644 --- a/frontend/src/app/util/color.cljs +++ b/frontend/src/app/util/color.cljs @@ -8,12 +8,12 @@ "FIXME: this is legacy namespace, all functions of this ns should be relocated under app.common.types on the respective colors related namespace. All generic color conversion and other helpers are moved to - app.common.colors namespace." + app.common.types.color namespace." (:require - [app.common.colors :as cc] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.math :as mth] + [app.common.types.color :as cc] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str])) diff --git a/frontend/src/app/util/text/content/from_dom.cljs b/frontend/src/app/util/text/content/from_dom.cljs index 32d03a4d17..840568bc6d 100644 --- a/frontend/src/app/util/text/content/from_dom.cljs +++ b/frontend/src/app/util/text/content/from_dom.cljs @@ -7,7 +7,7 @@ (ns app.util.text.content.from-dom (:require [app.common.data :as d] - [app.common.text :as txt] + [app.common.types.text :as txt] [app.util.text.content.styles :as styles])) (defn is-text-node diff --git a/frontend/src/app/util/text/content/styles.cljs b/frontend/src/app/util/text/content/styles.cljs index 9a99e8aa0c..975ddd0623 100644 --- a/frontend/src/app/util/text/content/styles.cljs +++ b/frontend/src/app/util/text/content/styles.cljs @@ -6,8 +6,8 @@ (ns app.util.text.content.styles (:require - [app.common.text :as txt] [app.common.transit :as transit] + [app.common.types.text :as txt] [cuerdas.core :as str])) (defn encode diff --git a/frontend/src/app/util/text/content/to_dom.cljs b/frontend/src/app/util/text/content/to_dom.cljs index f1f6a994d2..061aba9b6f 100644 --- a/frontend/src/app/util/text/content/to_dom.cljs +++ b/frontend/src/app/util/text/content/to_dom.cljs @@ -7,7 +7,7 @@ (ns app.util.text.content.to-dom (:require [app.common.data :as d] - [app.common.text :as txt] + [app.common.types.text :as txt] [app.util.dom :as dom] [app.util.text.content.styles :as styles])) @@ -73,12 +73,12 @@ ;; it affects to the height calculation the browser does font-size (if (some #(not= "" (:text %)) (:children paragraph)) "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 (if (and (some? line-height) (not= "" line-height)) line-height - (:line-height txt/default-text-attrs))] + (:line-height txt/default-typography))] (-> styles (assoc :font-size font-size :line-height line-height)))) diff --git a/frontend/src/app/util/text_editor.cljs b/frontend/src/app/util/text_editor.cljs index da4820b67c..8b7367a1c3 100644 --- a/frontend/src/app/util/text_editor.cljs +++ b/frontend/src/app/util/text_editor.cljs @@ -8,7 +8,7 @@ "Draft related abstraction functions." (:require ["@penpot/draft-js" :as impl] - [app.common.text :as txt])) + [app.common.text :as legacy.txt])) ;; --- CONVERSION @@ -33,14 +33,14 @@ (defn import-content [content] - (-> content txt/convert-to-draft clj->js impl/convertFromRaw)) + (-> content legacy.txt/convert-to-draft clj->js impl/convertFromRaw)) (defn export-content [content] (-> content (impl/convertToRaw) (js->clj :keywordize-keys true) - (txt/convert-from-draft))) + (legacy.txt/convert-from-draft))) (defn get-editor-current-plain-text [state] @@ -81,7 +81,7 @@ (if (impl/isCurrentEmpty state) (get-editor-current-block-data state) (-> (.getCurrentInlineStyle ^js state) - (txt/styles-to-attrs) + (legacy.txt/styles-to-attrs) (dissoc :text-align :text-direction)))) (defn update-editor-current-block-data @@ -96,20 +96,20 @@ (impl/updateBlockData state block-key (clj->js attrs)) (let [attrs (-> (impl/getInlineStyle state block-key 0) - (txt/styles-to-attrs) + (legacy.txt/styles-to-attrs) (dissoc :text-align :text-direction))] (impl/updateBlockData state block-key (clj->js attrs))))) - state (impl/applyInlineStyle state (txt/attrs-to-styles attrs)) + state (impl/applyInlineStyle state (legacy.txt/attrs-to-styles attrs)) selected (impl/getSelectedBlocks state)] (reduce update-blocks state selected))) (defn update-editor-current-inline-styles-fn [state update-fn] (let [attrs (-> (.getCurrentInlineStyle ^js state) - (txt/styles-to-attrs) + (legacy.txt/styles-to-attrs) (update-fn))] - (impl/applyInlineStyle state (txt/attrs-to-styles attrs)))) + (impl/applyInlineStyle state (legacy.txt/attrs-to-styles attrs)))) (defn editor-split-block [state] @@ -148,13 +148,13 @@ (js->clj :keywordize-keys true))] (-> state (impl/selectBlock bkey) - (impl/applyInlineStyle (txt/attrs-to-styles attrs)))))] + (impl/applyInlineStyle (legacy.txt/attrs-to-styles attrs)))))] (as-> state $ (reduce redfn $ blocks) (impl/setSelection $ selection))))) (defn insert-text [state text attrs] - (let [style (txt/attrs-to-styles attrs)] + (let [style (legacy.txt/attrs-to-styles attrs)] (impl/insertText state text (clj->js attrs) (clj->js style)))) (defn get-style-override [state] diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index e934f851b5..aa3e4d09cb 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -12,6 +12,7 @@ [app.common.files.validate :as cfv] [app.common.json :as json] [app.common.logging :as l] + [app.common.pprint :as pp] [app.common.transit :as t] [app.common.types.file :as ctf] [app.common.uuid :as uuid] @@ -197,6 +198,14 @@ (logjs "selected" result) 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 [] (st/emit! (dp/open-preview-selected))) diff --git a/frontend/test/frontend_tests/helpers_shapes_test.cljs b/frontend/test/frontend_tests/helpers_shapes_test.cljs index e8169a54fc..6ad7e16d28 100644 --- a/frontend/test/frontend_tests/helpers_shapes_test.cljs +++ b/frontend/test/frontend_tests/helpers_shapes_test.cljs @@ -6,9 +6,9 @@ (ns frontend-tests.helpers-shapes-test (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.geom.point :as gpt] + [app.common.types.color :as clr] [app.main.data.workspace.libraries :as dwl] [beicon.v2.core :as rx] [cljs.pprint :refer [pprint]] diff --git a/frontend/test/frontend_tests/logic/components_and_tokens.cljs b/frontend/test/frontend_tests/logic/components_and_tokens.cljs index 2add7ecf4e..7b1751a496 100644 --- a/frontend/test/frontend_tests/logic/components_and_tokens.cljs +++ b/frontend/test/frontend_tests/logic/components_and_tokens.cljs @@ -412,7 +412,7 @@ (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-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' :height) 200)) diff --git a/frontend/test/frontend_tests/test_helpers_shapes.cljs b/frontend/test/frontend_tests/test_helpers_shapes.cljs index 46ad76b40e..ce66082283 100644 --- a/frontend/test/frontend_tests/test_helpers_shapes.cljs +++ b/frontend/test/frontend_tests/test_helpers_shapes.cljs @@ -1,8 +1,8 @@ (ns frontend-tests.test-helpers-shapes (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.geom.point :as gpt] + [app.common.types.color :as clr] [app.main.data.workspace.libraries :as dwl] [app.test-helpers.events :as the] [app.test-helpers.libraries :as thl] diff --git a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs index 8c87194ddd..03af45b67c 100644 --- a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs +++ b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs @@ -10,7 +10,7 @@ [app.common.test-helpers.files :as cthf] [app.common.test-helpers.ids-map :as cthi] [app.common.test-helpers.shapes :as cths] - [app.common.text :as txt] + [app.common.types.text :as txt] [app.common.types.tokens-lib :as ctob] [app.main.data.workspace.tokens.application :as dwta] [cljs.test :as t :include-macros true] @@ -219,19 +219,21 @@ secondary-target (toht/get-token file' "color.secondary") rect-1' (cths/get-shape file' :rect-1) rect-2' (cths/get-shape file' :rect-2)] + (t/testing "regular color" (t/is (some? (:applied-tokens rect-1'))) (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 (= (get-in rect-1' [:strokes 0 :stroke-color]) "#ff0000"))) + (t/testing "color with alpha channel" (t/is (some? (:applied-tokens rect-2'))) (t/is (= (:fill (:applied-tokens rect-2')) (:name secondary-target))) - (t/is (= (get-in rect-2' [:fills 0 :fill-color]) "#ff0000")) - (t/is (= (get-in rect-2' [:fills 0 :fill-opacity]) 0.5)) + (let [fills (get rect-2' :fills)] + (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 (= (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-file paragraph-3))) (t/is (nil? (:typography-ref-id text-node-3))) - (t/is (nil? (:typography-ref-file text-node-3)))))))))) \ No newline at end of file + (t/is (nil? (:typography-ref-file text-node-3)))))))))) diff --git a/render-wasm/src/wasm/fills/image.rs b/render-wasm/src/wasm/fills/image.rs index c35c5426d9..07ae137d37 100644 --- a/render-wasm/src/wasm/fills/image.rs +++ b/render-wasm/src/wasm/fills/image.rs @@ -11,6 +11,7 @@ pub struct RawImageFillData { opacity: f32, width: i32, height: i32, + keep_aspect_ratio: i32, } impl From for ImageFill { @@ -18,7 +19,12 @@ impl From for ImageFill { let id = uuid_from_u32_quartet(value.a, value.b, value.c, value.d); let opacity = (value.opacity * 255.).floor() as u8; - // TODO: read keep_aspect_ratio from RawImageFillData when implemented - Self::new(id, opacity, value.width, value.height, true) + Self::new( + id, + opacity, + value.width, + value.height, + value.keep_aspect_ratio != 0, + ) } }