mirror of
https://github.com/penpot/penpot.git
synced 2025-08-04 08:28:23 +02:00
Merge remote-tracking branch 'origin/develop' into token-studio-develop
This commit is contained in:
commit
78a1a615d9
1048 changed files with 33616 additions and 55030 deletions
|
@ -1,5 +1,5 @@
|
|||
{:deps
|
||||
{org.clojure/clojure {:mvn/version "1.11.2"}
|
||||
{org.clojure/clojure {:mvn/version "1.12.0"}
|
||||
org.clojure/data.json {:mvn/version "2.5.0"}
|
||||
org.clojure/tools.cli {:mvn/version "1.1.230"}
|
||||
org.clojure/clojurescript {:mvn/version "1.11.132"}
|
||||
|
@ -7,19 +7,19 @@
|
|||
org.clojure/data.fressian {:mvn/version "1.1.0"}
|
||||
|
||||
;; Logging
|
||||
org.apache.logging.log4j/log4j-api {:mvn/version "2.23.1"}
|
||||
org.apache.logging.log4j/log4j-core {:mvn/version "2.23.1"}
|
||||
org.apache.logging.log4j/log4j-web {:mvn/version "2.23.1"}
|
||||
org.apache.logging.log4j/log4j-jul {:mvn/version "2.23.1"}
|
||||
org.apache.logging.log4j/log4j-slf4j2-impl {:mvn/version "2.23.1"}
|
||||
org.slf4j/slf4j-api {:mvn/version "2.0.13"}
|
||||
org.apache.logging.log4j/log4j-api {:mvn/version "2.24.1"}
|
||||
org.apache.logging.log4j/log4j-core {:mvn/version "2.24.1"}
|
||||
org.apache.logging.log4j/log4j-web {:mvn/version "2.24.1"}
|
||||
org.apache.logging.log4j/log4j-jul {:mvn/version "2.24.1"}
|
||||
org.apache.logging.log4j/log4j-slf4j2-impl {:mvn/version "2.24.1"}
|
||||
org.slf4j/slf4j-api {:mvn/version "2.0.16"}
|
||||
pl.tkowalcz.tjahzi/log4j2-appender {:mvn/version "0.9.32"}
|
||||
|
||||
selmer/selmer {:mvn/version "1.12.61"}
|
||||
criterium/criterium {:mvn/version "0.4.6"}
|
||||
|
||||
metosin/jsonista {:mvn/version "0.3.8"}
|
||||
metosin/malli {:mvn/version "0.16.1"}
|
||||
metosin/jsonista {:mvn/version "0.3.11"}
|
||||
metosin/malli {:mvn/version "0.16.4"}
|
||||
|
||||
expound/expound {:mvn/version "0.9.0"}
|
||||
com.cognitect/transit-clj {:mvn/version "1.0.333"}
|
||||
|
@ -27,9 +27,6 @@
|
|||
java-http-clj/java-http-clj {:mvn/version "0.4.3"}
|
||||
integrant/integrant {:mvn/version "0.8.1"}
|
||||
|
||||
org.apache.commons/commons-pool2 {:mvn/version "2.12.0"}
|
||||
org.graalvm.js/js {:mvn/version "23.0.4"}
|
||||
|
||||
funcool/tubax {:mvn/version "2021.05.20-0"}
|
||||
funcool/cuerdas {:mvn/version "2023.11.09-407"}
|
||||
funcool/promesa
|
||||
|
@ -37,8 +34,8 @@
|
|||
:git/url "https://github.com/funcool/promesa"}
|
||||
|
||||
funcool/datoteka
|
||||
{:git/sha "5ac3781"
|
||||
:git/tag "3.0.0"
|
||||
{:git/tag "4.0.0"
|
||||
:git/sha "3372f3a"
|
||||
:git/url "https://github.com/funcool/datoteka"}
|
||||
|
||||
lambdaisland/uri {:mvn/version "1.19.155"
|
||||
|
@ -53,8 +50,8 @@
|
|||
fipp/fipp {:mvn/version "0.6.26"}
|
||||
|
||||
io.github.eerohele/pp
|
||||
{:git/tag "2024-01-04.60"
|
||||
:git/sha "e8a9773"}
|
||||
{:git/tag "2024-09-09.69"
|
||||
:git/sha "de4b20f"}
|
||||
|
||||
io.aviso/pretty {:mvn/version "1.4.4"}
|
||||
environ/environ {:mvn/version "1.2.0"}}
|
||||
|
@ -63,7 +60,7 @@
|
|||
{:dev
|
||||
{:extra-deps
|
||||
{org.clojure/tools.namespace {:mvn/version "RELEASE"}
|
||||
thheller/shadow-cljs {:mvn/version "2.28.8"}
|
||||
thheller/shadow-cljs {:mvn/version "2.28.18"}
|
||||
com.clojure-goes-fast/clj-async-profiler {:mvn/version "RELEASE"}
|
||||
com.bhauman/rebel-readline {:mvn/version "RELEASE"}
|
||||
criterium/criterium {:mvn/version "RELEASE"}
|
||||
|
@ -72,7 +69,7 @@
|
|||
|
||||
:build
|
||||
{:extra-deps
|
||||
{io.github.clojure/tools.build {:git/tag "v0.10.3" :git/sha "15ead66"}}
|
||||
{io.github.clojure/tools.build {:git/tag "v0.10.5" :git/sha "2a21b7a"}}
|
||||
:ns-default build}
|
||||
|
||||
:test
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
"sax": "^1.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"shadow-cljs": "2.28.11",
|
||||
"shadow-cljs": "2.28.18",
|
||||
"source-map-support": "^0.5.21",
|
||||
"ws": "^8.17.0"
|
||||
},
|
||||
"scripts": {
|
||||
"fmt:clj:check": "cljfmt check --parallel=false src/ test/",
|
||||
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
||||
"lint:clj": "clj-kondo --parallel --lint src/",
|
||||
"lint:clj": "clj-kondo --parallel=true --lint src/",
|
||||
"test:watch": "clojure -M:dev:shadow-cljs watch test",
|
||||
"test:compile": "clojure -M:dev:shadow-cljs compile test --config-merge '{:autorun false}'",
|
||||
"test:run": "node target/test.js",
|
||||
|
|
|
@ -229,14 +229,15 @@
|
|||
coll))))
|
||||
|
||||
(defn seek
|
||||
"Find the first boletus croquetta, settles for jamon if none found."
|
||||
([pred coll]
|
||||
(seek pred coll nil))
|
||||
([pred coll not-found]
|
||||
([pred coll ham]
|
||||
(reduce (fn [_ x]
|
||||
(if (pred x)
|
||||
(reduced x)
|
||||
not-found))
|
||||
not-found coll)))
|
||||
ham))
|
||||
ham coll)))
|
||||
|
||||
(defn index-by
|
||||
"Return a indexed map of the collection keyed by the result of
|
||||
|
|
|
@ -501,7 +501,8 @@
|
|||
(cts/shape? shape-new))
|
||||
(ex/raise :type :assertion
|
||||
:code :data-validation
|
||||
:hint "invalid shape found after applying changes")))))]
|
||||
:hint "invalid shape found after applying changes"
|
||||
::sm/explain (cts/explain-shape shape-new))))))]
|
||||
|
||||
(->> (into #{} (map :page-id) items)
|
||||
(mapcat (fn [page-id]
|
||||
|
@ -549,7 +550,7 @@
|
|||
#?(:clj (validate-shapes! data result items))
|
||||
result))))
|
||||
|
||||
;; DEPRECATED: remove before 2.3 release
|
||||
;; DEPRECATED: remove after 2.3 release
|
||||
(defmethod process-change :set-option
|
||||
[data _]
|
||||
data)
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
[app.common.types.component :as ctk]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.common.types.tokens-lib :as ctob]))
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.uuid :as uuid]))
|
||||
|
||||
;; Auxiliary functions to help create a set of changes (undo + redo)
|
||||
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
|
||||
(ns app.common.files.defaults)
|
||||
|
||||
(def version 55)
|
||||
(def version 57)
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.shapes.common :as gco]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.set :as set]
|
||||
[cuerdas.core :as str]))
|
||||
|
@ -369,17 +367,6 @@
|
|||
[container]
|
||||
(= (:type container) :component))
|
||||
|
||||
(defn get-container
|
||||
[file type id]
|
||||
(dm/assert! (map? file))
|
||||
(dm/assert! (keyword? type))
|
||||
(dm/assert! (uuid? id))
|
||||
|
||||
(-> (if (= type :page)
|
||||
(ctpl/get-page file id)
|
||||
(ctkl/get-component file id))
|
||||
(assoc :type type)))
|
||||
|
||||
(defn component-touched?
|
||||
"Check if any shape in the component is touched"
|
||||
[objects root-id]
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.common.files.defaults :as cfd]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.path :as gsp]
|
||||
|
@ -499,7 +500,7 @@
|
|||
object
|
||||
(-> object
|
||||
(update :selrect grc/make-rect)
|
||||
(cts/map->Shape))))
|
||||
(cts/create-shape))))
|
||||
(update-container [container]
|
||||
(d/update-when container :objects update-vals update-object))]
|
||||
(-> data
|
||||
|
@ -1075,6 +1076,60 @@
|
|||
|
||||
(update data :pages-index d/update-vals update-page)))
|
||||
|
||||
(defn migrate-up-56
|
||||
[data]
|
||||
(letfn [(fix-fills [object]
|
||||
(d/update-when object :fills (partial filterv valid-fill?)))
|
||||
|
||||
(update-object [object]
|
||||
(-> object
|
||||
(fix-fills)
|
||||
|
||||
;; If shape contains shape-ref but has a nil value, we
|
||||
;; should remove it from shape object
|
||||
(cond-> (and (contains? object :shape-ref)
|
||||
(nil? (get object :shape-ref)))
|
||||
(dissoc :shape-ref))
|
||||
|
||||
;; 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 identity fix-fills)))))
|
||||
|
||||
(update-container [container]
|
||||
(d/update-when container :objects update-vals update-object))]
|
||||
|
||||
(-> data
|
||||
(update :pages-index update-vals update-container)
|
||||
(update :components update-vals update-container))))
|
||||
|
||||
|
||||
(defn migrate-up-57
|
||||
[data]
|
||||
(letfn [(fix-thread-positions [positions]
|
||||
(reduce-kv (fn [result id {:keys [position] :as data}]
|
||||
(let [data (cond
|
||||
(gpt/point? position)
|
||||
data
|
||||
|
||||
(and (map? position)
|
||||
(gpt/valid-point-attrs? position))
|
||||
(assoc data :position (gpt/point position))
|
||||
|
||||
:else
|
||||
(assoc data :position (gpt/point 0 0)))]
|
||||
(assoc result id data)))
|
||||
positions
|
||||
positions))
|
||||
|
||||
(update-page [page]
|
||||
(d/update-when page :comment-thread-positions fix-thread-positions))]
|
||||
|
||||
(-> data
|
||||
(update :pages (fn [pages] (into [] (remove nil?) pages)))
|
||||
(update :pages-index dissoc nil)
|
||||
(update :pages-index update-vals update-page))))
|
||||
|
||||
(def migrations
|
||||
"A vector of all applicable migrations"
|
||||
[{:id 2 :migrate-up migrate-up-2}
|
||||
|
@ -1121,4 +1176,7 @@
|
|||
{:id 52 :migrate-up migrate-up-52}
|
||||
{:id 53 :migrate-up migrate-up-26}
|
||||
{:id 54 :migrate-up migrate-up-54}
|
||||
{:id 55 :migrate-up migrate-up-55}])
|
||||
{:id 55 :migrate-up migrate-up-55}
|
||||
{:id 56 :migrate-up migrate-up-56}
|
||||
{:id 57 :migrate-up migrate-up-57}])
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@
|
|||
:class clojure.lang.ISeq
|
||||
:wfn write-list-like
|
||||
:rfn (comp sequence read-object!)}
|
||||
|
||||
|
||||
{:name "linked/set"
|
||||
:class LinkedSet
|
||||
:wfn write-list-like
|
||||
|
|
|
@ -308,6 +308,17 @@
|
|||
(reduce calculate-modifiers [modif-tree bounds])
|
||||
(first))))
|
||||
|
||||
(defn filter-layouts-ids
|
||||
"Returns a list of ids without the root-frames with only move"
|
||||
[objects modif-tree]
|
||||
(->> modif-tree
|
||||
(remove (fn [[id {:keys [modifiers]}]]
|
||||
(or (ctm/empty? modifiers)
|
||||
(and (cfh/root-frame? objects id)
|
||||
(ctm/only-move? modifiers)))))
|
||||
(map first)
|
||||
(set)))
|
||||
|
||||
(defn set-objects-modifiers
|
||||
"Applies recursively the modifiers and calculate the layouts and constraints for all the items to be placed correctly"
|
||||
([modif-tree objects]
|
||||
|
@ -331,9 +342,13 @@
|
|||
(cgt/apply-structure-modifiers modif-tree))
|
||||
|
||||
;; Creates the sequence of shapes with the shapes that are modified
|
||||
shapes-tree
|
||||
shapes-tree-all
|
||||
(cgst/resolve-tree (-> modif-tree keys set) objects)
|
||||
|
||||
;; This second sequence is used to recalculate layouts (we remove moved root-frames)
|
||||
shapes-tree-layout
|
||||
(cgst/resolve-tree (filter-layouts-ids objects modif-tree) objects)
|
||||
|
||||
bounds-map
|
||||
(cond-> (cgb/objects->bounds-map objects)
|
||||
(some? old-modif-tree)
|
||||
|
@ -347,13 +362,13 @@
|
|||
|
||||
;; Propagates the modifiers to the normal shapes with constraints
|
||||
modif-tree
|
||||
(propagate-modifiers-constraints objects bounds-map ignore-constraints modif-tree shapes-tree)
|
||||
(propagate-modifiers-constraints objects bounds-map ignore-constraints modif-tree shapes-tree-all)
|
||||
|
||||
bounds-map
|
||||
(cgb/transform-bounds-map bounds-map objects modif-tree)
|
||||
|
||||
modif-tree-layout
|
||||
(propagate-modifiers-layouts objects bounds-map ignore-constraints shapes-tree)
|
||||
(propagate-modifiers-layouts objects bounds-map ignore-constraints shapes-tree-layout)
|
||||
|
||||
modif-tree
|
||||
(cgt/merge-modif-tree modif-tree modif-tree-layout)
|
||||
|
@ -363,7 +378,7 @@
|
|||
(cgb/transform-bounds-map bounds-map objects modif-tree-layout)
|
||||
|
||||
;; Find layouts with auto width/height
|
||||
sizing-auto-layouts (find-auto-layouts objects shapes-tree)
|
||||
sizing-auto-layouts (find-auto-layouts objects shapes-tree-layout)
|
||||
|
||||
modif-tree
|
||||
(sizing-auto-modifiers modif-tree sizing-auto-layouts objects bounds-map ignore-constraints)
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
[:x ::sm/safe-number]
|
||||
[:y ::sm/safe-number]])
|
||||
|
||||
(def valid-point-attrs?
|
||||
(sm/validator schema:point-attrs))
|
||||
|
||||
(def valid-point?
|
||||
(sm/validator
|
||||
[:and [:fn point?] schema:point-attrs]))
|
||||
|
|
|
@ -139,6 +139,7 @@
|
|||
:width (mth/abs (- x2 x1))
|
||||
:height (mth/abs (- y2 y1))))
|
||||
|
||||
;; FIXME: looks unused
|
||||
:position
|
||||
(let [x (dm/get-prop rect :x)
|
||||
y (dm/get-prop rect :y)
|
||||
|
@ -158,22 +159,22 @@
|
|||
y (dm/get-prop rect :y)
|
||||
w (dm/get-prop rect :width)
|
||||
h (dm/get-prop rect :height)]
|
||||
(rc/assoc! rect
|
||||
:x1 x
|
||||
:y1 y
|
||||
:x2 (+ x w)
|
||||
:y2 (+ y h)))
|
||||
(assoc rect
|
||||
:x1 x
|
||||
:y1 y
|
||||
:x2 (+ x w)
|
||||
:y2 (+ y h)))
|
||||
|
||||
:corners
|
||||
(let [x1 (dm/get-prop rect :x1)
|
||||
y1 (dm/get-prop rect :y1)
|
||||
x2 (dm/get-prop rect :x2)
|
||||
y2 (dm/get-prop rect :y2)]
|
||||
(rc/assoc! rect
|
||||
:x (mth/min x1 x2)
|
||||
:y (mth/min y1 y2)
|
||||
:width (mth/abs (- x2 x1))
|
||||
:height (mth/abs (- y2 y1))))))
|
||||
(assoc rect
|
||||
:x (mth/min x1 x2)
|
||||
:y (mth/min y1 y2)
|
||||
:width (mth/abs (- x2 x1))
|
||||
:height (mth/abs (- y2 y1))))))
|
||||
|
||||
(defn close-rect?
|
||||
[rect1 rect2]
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
[app.common.geom.shapes.common :as gco]
|
||||
[app.common.geom.shapes.path :as gpa]
|
||||
[app.common.math :as mth]
|
||||
[app.common.record :as cr]
|
||||
[app.common.types.modifiers :as ctm]))
|
||||
|
||||
#?(:clj (set! *warn-on-reflection* true))
|
||||
|
@ -280,7 +279,7 @@
|
|||
transform (calculate-transform points center selrect)]
|
||||
[selrect transform (when (some? transform) (gmt/inverse transform))]))
|
||||
|
||||
(defn- adjust-shape-flips!
|
||||
(defn- adjust-shape-flips
|
||||
"After some tranformations the flip-x/flip-y flags can change we need
|
||||
to check this before adjusting the selrect"
|
||||
[shape points]
|
||||
|
@ -299,16 +298,16 @@
|
|||
|
||||
(cond-> shape
|
||||
(neg? dot-x)
|
||||
(cr/update! :flip-x not)
|
||||
(update :flip-x not)
|
||||
|
||||
(neg? dot-x)
|
||||
(cr/update! :rotation -)
|
||||
(update :rotation -)
|
||||
|
||||
(neg? dot-y)
|
||||
(cr/update! :flip-y not)
|
||||
(update :flip-y not)
|
||||
|
||||
(neg? dot-y)
|
||||
(cr/update! :rotation -))))
|
||||
(update :rotation -))))
|
||||
|
||||
(defn- apply-transform-move
|
||||
"Given a new set of points transformed, set up the rectangle so it keeps
|
||||
|
@ -318,9 +317,6 @@
|
|||
points (gco/transform-points (dm/get-prop shape :points) transform-mtx)
|
||||
selrect (gco/transform-selrect (dm/get-prop shape :selrect) transform-mtx)
|
||||
|
||||
;; NOTE: ensure we start with a fresh copy of shape for mutabilty
|
||||
shape (cr/clone shape)
|
||||
|
||||
shape (if (= type :bool)
|
||||
(update shape :bool-content gpa/transform-content transform-mtx)
|
||||
shape)
|
||||
|
@ -329,14 +325,14 @@
|
|||
shape)
|
||||
shape (if (= type :path)
|
||||
(update shape :content gpa/transform-content transform-mtx)
|
||||
(cr/assoc! shape
|
||||
:x (dm/get-prop selrect :x)
|
||||
:y (dm/get-prop selrect :y)
|
||||
:width (dm/get-prop selrect :width)
|
||||
:height (dm/get-prop selrect :height)))]
|
||||
(assoc shape
|
||||
:x (dm/get-prop selrect :x)
|
||||
:y (dm/get-prop selrect :y)
|
||||
:width (dm/get-prop selrect :width)
|
||||
:height (dm/get-prop selrect :height)))]
|
||||
(-> shape
|
||||
(cr/assoc! :selrect selrect)
|
||||
(cr/assoc! :points points))))
|
||||
(assoc :selrect selrect)
|
||||
(assoc :points points))))
|
||||
|
||||
|
||||
(defn- apply-transform-generic
|
||||
|
@ -346,9 +342,7 @@
|
|||
(let [points (-> (dm/get-prop shape :points)
|
||||
(gco/transform-points transform-mtx))
|
||||
|
||||
;; NOTE: ensure we have a fresh shallow copy of shape
|
||||
shape (cr/clone shape)
|
||||
shape (adjust-shape-flips! shape points)
|
||||
shape (adjust-shape-flips shape points)
|
||||
|
||||
center (gco/points->center points)
|
||||
selrect (calculate-selrect points center)
|
||||
|
@ -367,17 +361,17 @@
|
|||
|
||||
shape (if (= type :path)
|
||||
(update shape :content gpa/transform-content transform-mtx)
|
||||
(cr/assoc! shape
|
||||
:x (dm/get-prop selrect :x)
|
||||
:y (dm/get-prop selrect :y)
|
||||
:width (dm/get-prop selrect :width)
|
||||
:height (dm/get-prop selrect :height)))]
|
||||
(assoc shape
|
||||
:x (dm/get-prop selrect :x)
|
||||
:y (dm/get-prop selrect :y)
|
||||
:width (dm/get-prop selrect :width)
|
||||
:height (dm/get-prop selrect :height)))]
|
||||
(-> shape
|
||||
(cr/assoc! :transform transform)
|
||||
(cr/assoc! :transform-inverse inverse)
|
||||
(cr/assoc! :selrect selrect)
|
||||
(cr/assoc! :points points)
|
||||
(cr/assoc! :rotation rotation))))))
|
||||
(assoc :transform transform)
|
||||
(assoc :transform-inverse inverse)
|
||||
(assoc :selrect selrect)
|
||||
(assoc :points points)
|
||||
(assoc :rotation rotation))))))
|
||||
|
||||
(defn- apply-transform
|
||||
"Given a new set of points transformed, set up the rectangle so it keeps
|
||||
|
|
|
@ -1,77 +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.jsrt
|
||||
"A JS runtime for the JVM"
|
||||
(:refer-clojure :exclude [run!])
|
||||
(:require
|
||||
[clojure.java.io :as io])
|
||||
(:import
|
||||
org.apache.commons.pool2.ObjectPool
|
||||
org.apache.commons.pool2.PooledObject
|
||||
org.apache.commons.pool2.PooledObjectFactory
|
||||
org.apache.commons.pool2.impl.DefaultPooledObject
|
||||
org.apache.commons.pool2.impl.SoftReferenceObjectPool
|
||||
org.graalvm.polyglot.Context
|
||||
org.graalvm.polyglot.Source
|
||||
org.graalvm.polyglot.Value))
|
||||
|
||||
(defn resource->source
|
||||
[path]
|
||||
(let [resource (io/resource path)]
|
||||
(.. (Source/newBuilder "js" resource)
|
||||
(build))))
|
||||
|
||||
(defn pool?
|
||||
[o]
|
||||
(instance? ObjectPool o))
|
||||
|
||||
(defn pool
|
||||
[& {:keys [init]}]
|
||||
(SoftReferenceObjectPool.
|
||||
(reify PooledObjectFactory
|
||||
(activateObject [_ _])
|
||||
(destroyObject [_ o]
|
||||
(let [context (.getObject ^PooledObject o)]
|
||||
(.close ^java.lang.AutoCloseable context)))
|
||||
|
||||
(destroyObject [_ o _]
|
||||
(let [context (.getObject ^PooledObject o)]
|
||||
(.close ^java.lang.AutoCloseable context)))
|
||||
|
||||
(passivateObject [_ _])
|
||||
(validateObject [_ _] true)
|
||||
|
||||
(makeObject [_]
|
||||
(let [context (Context/create (into-array String ["js"]))]
|
||||
(.initialize ^Context context "js")
|
||||
(when (instance? Source init)
|
||||
(.eval ^Context context ^Source init))
|
||||
(DefaultPooledObject. context))))))
|
||||
|
||||
(defn run!
|
||||
[^ObjectPool pool f]
|
||||
(let [ctx (.borrowObject pool)]
|
||||
(try
|
||||
(f ctx)
|
||||
(finally
|
||||
(.returnObject pool ctx)))))
|
||||
|
||||
(defn eval!
|
||||
[context data & {:keys [as] :or {as :string}}]
|
||||
(let [result (.eval ^Context context "js" ^String data)]
|
||||
(case as
|
||||
(:string :str) (.asString ^Value result)
|
||||
:long (.asLong ^Value result)
|
||||
:int (.asInt ^Value result)
|
||||
:float (.asFloat ^Value result)
|
||||
:double (.asDouble ^Value result))))
|
||||
|
||||
(defn set!
|
||||
[context attr value]
|
||||
(let [bindings (.getBindings ^Context context "js")]
|
||||
(.putMember ^Value bindings ^String attr ^String value)
|
||||
context))
|
|
@ -288,7 +288,8 @@
|
|||
|
||||
(when (ex/exception? cause)
|
||||
(let [data (ex-data cause)
|
||||
explain (ex/explain data)]
|
||||
explain (or (:explain data)
|
||||
(ex/explain data))]
|
||||
(when explain
|
||||
(js/console.log "Explain:")
|
||||
(js/console.log explain))
|
||||
|
|
|
@ -232,6 +232,7 @@
|
|||
[(:parent-id first-shape)]
|
||||
(fn [shape objects]
|
||||
(-> shape
|
||||
(ctl/assign-cells objects)
|
||||
(ctl/push-into-cell [(:id first-shape)] row column)
|
||||
(ctl/assign-cells objects)))
|
||||
{:with-objects? true})
|
||||
|
@ -1831,7 +1832,7 @@
|
|||
"Generate changes for remove all references to components in the shape,
|
||||
with the given id and all its children, at the current page."
|
||||
[changes id file page-id libraries]
|
||||
(let [container (cfh/get-container file :page page-id)]
|
||||
(let [container (ctn/get-container file :page page-id)]
|
||||
(-> changes
|
||||
(pcb/with-container container)
|
||||
(pcb/with-objects (:objects container))
|
||||
|
@ -1988,7 +1989,8 @@
|
|||
(+ (:position guide) (- (:y new-frame) (:y frame))))
|
||||
guide {:id guide-id
|
||||
:frame-id new-id
|
||||
:position position}]
|
||||
:position position
|
||||
:axis (:axis guide)}]
|
||||
(pcb/set-guide changes guide-id guide))
|
||||
changes))
|
||||
changes
|
||||
|
|
|
@ -29,8 +29,7 @@
|
|||
|
||||
(defprotocol ILazySchema
|
||||
(-validate [_ o])
|
||||
(-explain [_ o])
|
||||
(-decode [_ o]))
|
||||
(-explain [_ o]))
|
||||
|
||||
(def default-options
|
||||
{:registry sr/default-registry})
|
||||
|
@ -194,11 +193,9 @@
|
|||
|
||||
(defn humanize-explain
|
||||
"Returns a string representation of the explain data structure"
|
||||
[{:keys [schema errors value]} & {:keys [length level]}]
|
||||
[{:keys [errors value]} & {:keys [length level]}]
|
||||
(let [errors (mapv #(update % :schema form) errors)]
|
||||
(with-out-str
|
||||
(println "Schema: ")
|
||||
(println (pp/pprint-str (form schema) {:width 100 :level 15 :length 20}))
|
||||
(println "Errors:")
|
||||
(println (pp/pprint-str errors {:width 100 :level 15 :length 20}))
|
||||
(println "Value:")
|
||||
|
@ -273,7 +270,18 @@
|
|||
(fast-check! s type code hint value)))
|
||||
|
||||
(defn register! [type s]
|
||||
(let [s (if (map? s) (m/-simple-schema s) s)]
|
||||
(let [s (if (map? s)
|
||||
(cond
|
||||
(= :set (:type s))
|
||||
(m/-collection-schema s)
|
||||
|
||||
(= :vec (:type s))
|
||||
(m/-collection-schema s)
|
||||
|
||||
:else
|
||||
(m/-simple-schema s))
|
||||
s)]
|
||||
|
||||
(swap! sr/registry assoc type s)
|
||||
nil))
|
||||
|
||||
|
@ -328,9 +336,7 @@
|
|||
(-validate [_ o]
|
||||
(@validator o))
|
||||
(-explain [_ o]
|
||||
(@explainer o))
|
||||
(-decode [_ o]
|
||||
(@decoder o)))))
|
||||
(@explainer o)))))
|
||||
|
||||
;; --- BUILTIN SCHEMAS
|
||||
|
||||
|
@ -402,7 +408,7 @@
|
|||
|
||||
;; NOTE: this is general purpose set spec and should be used over the other
|
||||
|
||||
(register! ::set
|
||||
(def type:set
|
||||
{:type :set
|
||||
:min 0
|
||||
:max 1
|
||||
|
@ -479,6 +485,7 @@
|
|||
|
||||
|
||||
{:pred pred
|
||||
:empty #{}
|
||||
:type-properties
|
||||
{:title "set"
|
||||
:description "Set of Strings"
|
||||
|
@ -493,6 +500,7 @@
|
|||
::oapi/items {:type "string"}
|
||||
::oapi/unique-items true}}))})
|
||||
|
||||
(register! ::set type:set)
|
||||
|
||||
(register! ::vec
|
||||
{:type :vector
|
||||
|
@ -686,8 +694,8 @@
|
|||
pred)
|
||||
pred (if (some? max)
|
||||
(fn [v]
|
||||
(and (>= max v)
|
||||
(pred v)))
|
||||
(and (pred v)
|
||||
(>= max v)))
|
||||
pred)]
|
||||
|
||||
{:pred pred
|
||||
|
@ -724,8 +732,8 @@
|
|||
pred)
|
||||
pred (if (some? max)
|
||||
(fn [v]
|
||||
(and (>= max v)
|
||||
(pred v)))
|
||||
(and (pred v)
|
||||
(>= max v)))
|
||||
pred)]
|
||||
|
||||
{:pred pred
|
||||
|
@ -754,8 +762,8 @@
|
|||
pred)
|
||||
pred (if (some? max)
|
||||
(fn [v]
|
||||
(and (>= max v)
|
||||
(pred v)))
|
||||
(and (pred v)
|
||||
(>= max v)))
|
||||
pred)
|
||||
|
||||
gen (sg/one-of
|
||||
|
|
|
@ -92,8 +92,8 @@
|
|||
(defmethod visit :select-keys [_ schema _ options] (describe* (m/deref schema) options))
|
||||
(defmethod visit :and [_ s children _] (str (str/join ", and " children) (-titled s)))
|
||||
(defmethod visit :enum [_ s children _options] (str "enum" (-titled s) " of " (str/join ", " children)))
|
||||
(defmethod visit :maybe [_ _ children _] (str (first children) "?"))
|
||||
(defmethod visit :tuple [_ s children _] (str "vector " (-titled s) "with exactly " (count children) " items of type: " (str/join ", " children)))
|
||||
(defmethod visit :maybe [_ _ children _] (str (first children) " nullable"))
|
||||
(defmethod visit :tuple [_ _ children _] (str "(" (str/join ", " children) ")"))
|
||||
(defmethod visit :re [_ s _ options] (str "regex pattern " (-titled s) "matching " (pr-str (first (m/children s options)))))
|
||||
(defmethod visit :any [_ s _ _] (str "anything" (-titled s)))
|
||||
(defmethod visit :some [_ _ _ _] "anything but null")
|
||||
|
|
|
@ -442,4 +442,3 @@
|
|||
cause
|
||||
(when (ex/error? cause)
|
||||
(validation-error? (ex-data cause)))))
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
(:require
|
||||
#?(:clj [clojure.xml :as xml]
|
||||
:cljs [tubax.core :as tubax])
|
||||
#?(:cljs ["./svg/optimizer.js" :as svgo])
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
|
@ -1052,10 +1051,3 @@
|
|||
:clj (let [text (strip-doctype text)]
|
||||
(dm/with-open [istream (IOUtils/toInputStream text "UTF-8")]
|
||||
(xml/parse istream secure-parser-factory)))))
|
||||
|
||||
;; FIXME pass correct plugin set
|
||||
#?(:cljs
|
||||
(defn optimize
|
||||
([input] (optimize input nil))
|
||||
([input options]
|
||||
(svgo/optimize input (clj->js options)))))
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -22,7 +22,7 @@
|
|||
;; ----- Files
|
||||
|
||||
(defn sample-file
|
||||
[label & {:keys [page-label name] :as params}]
|
||||
[label & {:keys [page-label name view-only?] :as params}]
|
||||
(binding [ffeat/*current* #{"components/v2"}]
|
||||
(let [params (cond-> params
|
||||
label
|
||||
|
@ -35,7 +35,8 @@
|
|||
(assoc :name "Test file"))
|
||||
|
||||
file (-> (ctf/make-file (dissoc params :page-label))
|
||||
(assoc :features #{"components/v2"}))
|
||||
(assoc :features #{"components/v2"})
|
||||
(assoc :permissions {:can-edit (not (true? view-only?))}))
|
||||
|
||||
page (-> file
|
||||
:data
|
||||
|
|
|
@ -5,14 +5,29 @@
|
|||
|
||||
(defn fmt-object-id
|
||||
"Returns ids formatted as a string (object-id)"
|
||||
[file-id page-id frame-id tag]
|
||||
(str/ffmt "%/%/%/%" file-id page-id frame-id tag))
|
||||
([object]
|
||||
(fmt-object-id (:file-id object)
|
||||
(:page-id object)
|
||||
(:frame-id object)
|
||||
(:tag object)))
|
||||
([file-id page-id frame-id tag]
|
||||
(str/ffmt "%/%/%/%" file-id page-id frame-id tag)))
|
||||
|
||||
;; FIXME: rename to a proper name
|
||||
|
||||
(defn file-id?
|
||||
"Returns ids formatted as a string (file-id)"
|
||||
[object-id file-id]
|
||||
(str/starts-with? object-id (str/concat file-id "/")))
|
||||
|
||||
(defn parse-object-id
|
||||
[object-id]
|
||||
(let [[file-id page-id frame-id tag] (str/split object-id "/")]
|
||||
{:file-id (parse-uuid file-id)
|
||||
:page-id (parse-uuid page-id)
|
||||
:frame-id (parse-uuid frame-id)
|
||||
:tag tag}))
|
||||
|
||||
(defn get-file-id
|
||||
[object-id]
|
||||
(uuid/uuid (str/slice object-id 0 (str/index-of object-id "/"))))
|
||||
|
|
|
@ -56,8 +56,8 @@
|
|||
(def schema:image-color
|
||||
[:map {:title "ImageColor"}
|
||||
[:name {:optional true} :string]
|
||||
[:width :int]
|
||||
[:height :int]
|
||||
[:width ::sm/int]
|
||||
[:height ::sm/int]
|
||||
[:mtype {:optional true} [:maybe :string]]
|
||||
[:id ::sm/uuid]
|
||||
[:keep-aspect-ratio {:optional true} :boolean]])
|
||||
|
|
|
@ -7,9 +7,36 @@
|
|||
(ns app.common.types.component
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.page :as ctp]
|
||||
[app.common.types.plugins :as ctpg]
|
||||
[app.common.uuid :as uuid]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SCHEMA
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(def schema:component
|
||||
[:map
|
||||
[:id ::sm/uuid]
|
||||
[:name :string]
|
||||
[:path {:optional true} [:maybe :string]]
|
||||
[:modified-at {:optional true} ::sm/inst]
|
||||
[:objects {:gen/max 10 :optional true} ::ctp/objects]
|
||||
[:main-instance-id ::sm/uuid]
|
||||
[:main-instance-page ::sm/uuid]
|
||||
[:plugin-data {:optional true} ::ctpg/plugin-data]])
|
||||
|
||||
(sm/register! ::component schema:component)
|
||||
|
||||
(def check-component!
|
||||
(sm/check-fn schema:component))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; INIT & HELPERS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Attributes that may be synced in components, and the group they belong to.
|
||||
;; When one attribute is modified in a shape inside a component, the corresponding
|
||||
;; group is marked as :touched. Then, if the shape is synced with the remote shape
|
||||
|
@ -303,4 +330,4 @@
|
|||
(and (swap-slot? group)
|
||||
(some? (group->swap-slot group))))
|
||||
(catch #?(:clj Throwable :cljs :default) _
|
||||
false)))
|
||||
false)))
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.plugins :as ctpg]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.token-theme :as ctt]
|
||||
[app.common.types.tokens-lib :as ctl]
|
||||
[app.common.types.typographies-list :as ctyl]
|
||||
[app.common.types.typography :as cty]
|
||||
|
@ -38,38 +36,64 @@
|
|||
;; SCHEMA
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(sm/register! ::media-object
|
||||
(def schema:media
|
||||
"A schema that represents the file media object"
|
||||
[:map {:title "FileMediaObject"}
|
||||
[:id ::sm/uuid]
|
||||
[:created-at ::sm/inst]
|
||||
[:deleted-at {:optional true} ::sm/inst]
|
||||
[:name :string]
|
||||
[:width ::sm/safe-int]
|
||||
[:height ::sm/safe-int]
|
||||
[:mtype :string]
|
||||
[:path {:optional true} [:maybe :string]]])
|
||||
[:file-id {:optional true} ::sm/uuid]
|
||||
[:media-id ::sm/uuid]
|
||||
[:thumbnail-id {:optional true} ::sm/uuid]
|
||||
[:is-local :boolean]])
|
||||
|
||||
(sm/register! ::data
|
||||
(def schema:colors
|
||||
[:map-of {:gen/max 5} ::sm/uuid ::ctc/color])
|
||||
|
||||
(def schema:components
|
||||
[:map-of {:gen/max 5} ::sm/uuid ::ctn/container])
|
||||
|
||||
(def schema:typographies
|
||||
[:map-of {:gen/max 2} ::sm/uuid ::cty/typography])
|
||||
|
||||
(def schema:pages-index
|
||||
[:map-of {:gen/max 5} ::sm/uuid ::ctp/page])
|
||||
|
||||
(def schema:data
|
||||
[:map {:title "FileData"}
|
||||
[:pages [:vector ::sm/uuid]]
|
||||
[:pages-index
|
||||
[:map-of {:gen/max 5} ::sm/uuid ::ctp/page]]
|
||||
[:colors {:optional true}
|
||||
[:map-of {:gen/max 5} ::sm/uuid ::ctc/color]]
|
||||
[:components {:optional true}
|
||||
[:map-of {:gen/max 5} ::sm/uuid ::ctn/container]]
|
||||
[:recent-colors {:optional true}
|
||||
[:vector {:gen/max 3} ::ctc/recent-color]]
|
||||
[:typographies {:optional true}
|
||||
[:map-of {:gen/max 2} ::sm/uuid ::cty/typography]]
|
||||
[:media {:optional true}
|
||||
[:map-of {:gen/max 5} ::sm/uuid ::media-object]]
|
||||
[:pages-index schema:pages-index]
|
||||
[:colors {:optional true} schema:colors]
|
||||
[:components {:optional true} schema:components]
|
||||
[:typographies {:optional true} schema:typographies]
|
||||
[:plugin-data {:optional true} ::ctpg/plugin-data]
|
||||
[:tokens-lib {:optional true} ::ctl/tokens-lib]])
|
||||
|
||||
(def schema:file
|
||||
"A schema for validate a file data structure; data is optional
|
||||
because sometimes we want to validate file without the data."
|
||||
[:map {:title "file"}
|
||||
[:id ::sm/uuid]
|
||||
[:data {:optional true} schema:data]
|
||||
[:features ::cfeat/features]])
|
||||
|
||||
(sm/register! ::data schema:data)
|
||||
(sm/register! ::file schema:file)
|
||||
(sm/register! ::media schema:media)
|
||||
(sm/register! ::colors schema:colors)
|
||||
(sm/register! ::typographies schema:typographies)
|
||||
|
||||
(sm/register! ::media-object schema:media)
|
||||
|
||||
(def check-file-data!
|
||||
(sm/check-fn ::data))
|
||||
|
||||
(def check-media-object!
|
||||
(sm/check-fn ::media-object))
|
||||
(sm/check-fn schema:media))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; INITIALIZATION
|
||||
|
@ -112,6 +136,7 @@
|
|||
:project-id project-id
|
||||
:name name
|
||||
:revn revn
|
||||
:vern 0
|
||||
:is-shared is-shared
|
||||
:version version
|
||||
:data data
|
||||
|
|
|
@ -33,8 +33,7 @@
|
|||
[:id ::sm/uuid]
|
||||
[:axis [::sm/one-of #{:x :y}]]
|
||||
[:position ::sm/safe-number]
|
||||
;; FIXME: remove maybe?
|
||||
[:frame-id {:optional true} [:maybe ::sm/uuid]]])
|
||||
[:frame-id {:optional true} ::sm/uuid]])
|
||||
|
||||
(def schema:guides
|
||||
[:map-of {:gen/max 2} ::sm/uuid schema:guide])
|
||||
|
@ -51,6 +50,7 @@
|
|||
[:map {:title "FilePage"}
|
||||
[:id ::sm/uuid]
|
||||
[:name :string]
|
||||
[:index {:optional true} ::sm/int]
|
||||
[:objects schema:objects]
|
||||
[:default-grids {:optional true} ::ctg/default-grids]
|
||||
[:flows {:optional true} schema:flows]
|
||||
|
@ -59,12 +59,9 @@
|
|||
[:background {:optional true} ::ctc/rgb-color]
|
||||
|
||||
[:comment-thread-positions {:optional true}
|
||||
[:map-of ::sm/uuid schema:comment-thread-position]]
|
||||
|
||||
[:options
|
||||
;; DEPERECATED: remove after 2.3 release
|
||||
[:map {:title "PageOptions"}]]])
|
||||
[:map-of ::sm/uuid schema:comment-thread-position]]])
|
||||
|
||||
(sm/register! ::objects schema:objects)
|
||||
(sm/register! ::page schema:page)
|
||||
(sm/register! ::guide schema:guide)
|
||||
(sm/register! ::flow schema:flow)
|
||||
|
@ -72,7 +69,6 @@
|
|||
(def valid-guide?
|
||||
(sm/lazy-validator schema:guide))
|
||||
|
||||
;; FIXME: convert to validator
|
||||
(def check-page!
|
||||
(sm/check-fn schema:page))
|
||||
|
||||
|
|
|
@ -6,7 +6,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.geom.matrix :as gmt]
|
||||
|
@ -14,16 +13,15 @@
|
|||
[app.common.geom.proportions :as gpr]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.record :as cr]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.transit :as t]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.grid :as ctg]
|
||||
[app.common.types.plugins :as ctpg]
|
||||
[app.common.types.shape.attrs :refer [default-color]]
|
||||
[app.common.types.shape.blur :as ctsb]
|
||||
[app.common.types.shape.export :as ctse]
|
||||
[app.common.types.shape.impl :as impl]
|
||||
[app.common.types.shape.interactions :as ctsi]
|
||||
[app.common.types.shape.layout :as ctsl]
|
||||
[app.common.types.shape.path :as ctsp]
|
||||
|
@ -33,11 +31,9 @@
|
|||
[app.common.uuid :as uuid]
|
||||
[clojure.set :as set]))
|
||||
|
||||
(cr/defrecord Shape [id name type x y width height rotation selrect points transform transform-inverse parent-id frame-id flip-x flip-y])
|
||||
|
||||
(defn shape?
|
||||
[o]
|
||||
(instance? Shape o))
|
||||
(impl/shape? o))
|
||||
|
||||
(def stroke-caps-line #{:round :square})
|
||||
(def stroke-caps-marker #{:line-arrow :triangle-arrow :square-marker :circle-marker :diamond-marker})
|
||||
|
@ -151,6 +147,7 @@
|
|||
;; FIXME: rename to shape-generic-attrs
|
||||
(def schema:shape-attrs
|
||||
[:map {:title "ShapeAttrs"}
|
||||
[:page-id {:optional true} ::sm/uuid]
|
||||
[:component-id {:optional true} ::sm/uuid]
|
||||
[:component-file {:optional true} ::sm/uuid]
|
||||
[:component-root {:optional true} :boolean]
|
||||
|
@ -226,8 +223,8 @@
|
|||
[:map {:title "ImageAttrs"}
|
||||
[:metadata
|
||||
[:map
|
||||
[:width {:gen/gen (sg/small-int :min 1)} :int]
|
||||
[:height {:gen/gen (sg/small-int :min 1)} :int]
|
||||
[:width {:gen/gen (sg/small-int :min 1)} ::sm/int]
|
||||
[:height {:gen/gen (sg/small-int :min 1)} ::sm/int]
|
||||
[:mtype {:optional true
|
||||
:gen/gen (sg/elements ["image/jpeg"
|
||||
"image/png"])}
|
||||
|
@ -245,7 +242,7 @@
|
|||
(defn- decode-shape
|
||||
[o]
|
||||
(if (map? o)
|
||||
(map->Shape o)
|
||||
(impl/map->Shape o)
|
||||
o))
|
||||
|
||||
(defn- shape-generator
|
||||
|
@ -269,7 +266,7 @@
|
|||
(= type :bool))
|
||||
(merge attrs1 shape attrs3)
|
||||
(merge attrs1 shape attrs2 attrs3)))))
|
||||
(sg/fmap map->Shape)))
|
||||
(sg/fmap impl/map->Shape)))
|
||||
|
||||
(def schema:shape
|
||||
[:and {:title "Shape"
|
||||
|
@ -363,6 +360,9 @@
|
|||
(def valid-shape?
|
||||
(sm/lazy-validator schema:shape))
|
||||
|
||||
(def explain-shape
|
||||
(sm/lazy-explainer schema:shape))
|
||||
|
||||
(defn has-images?
|
||||
[{:keys [fills strokes]}]
|
||||
(or (some :fill-image fills)
|
||||
|
@ -453,27 +453,30 @@
|
|||
;; NOTE: used for create ephimeral shapes for multiple selection
|
||||
:multiple minimal-multiple-attrs))
|
||||
|
||||
(defn create-shape
|
||||
"A low level function that creates a Shape data structure
|
||||
from a attrs map without performing other transformations"
|
||||
[attrs]
|
||||
(impl/create-shape attrs))
|
||||
|
||||
(defn- make-minimal-shape
|
||||
[type]
|
||||
(let [type (if (= type :curve) :path type)
|
||||
attrs (get-minimal-shape type)]
|
||||
attrs (get-minimal-shape type)
|
||||
attrs (cond-> attrs
|
||||
(and (not= :path type)
|
||||
(not= :bool type))
|
||||
(-> (assoc :x 0)
|
||||
(assoc :y 0)
|
||||
(assoc :width 0.01)
|
||||
(assoc :height 0.01)))
|
||||
attrs (-> attrs
|
||||
(assoc :id (uuid/next))
|
||||
(assoc :frame-id uuid/zero)
|
||||
(assoc :parent-id uuid/zero)
|
||||
(assoc :rotation 0))]
|
||||
|
||||
(cond-> attrs
|
||||
(and (not= :path type)
|
||||
(not= :bool type))
|
||||
(-> (assoc :x 0)
|
||||
(assoc :y 0)
|
||||
(assoc :width 0.01)
|
||||
(assoc :height 0.01))
|
||||
|
||||
:always
|
||||
(assoc :id (uuid/next)
|
||||
:frame-id uuid/zero
|
||||
:parent-id uuid/zero
|
||||
:rotation 0)
|
||||
|
||||
:always
|
||||
(map->Shape))))
|
||||
(impl/create-shape attrs)))
|
||||
|
||||
(defn setup-rect
|
||||
"Initializes the selrect and points for a shape."
|
||||
|
@ -528,17 +531,3 @@
|
|||
(assoc :transform-inverse (gmt/matrix)))
|
||||
(gpr/setup-proportions))))
|
||||
|
||||
;; --- SHAPE SERIALIZATION
|
||||
|
||||
(t/add-handlers!
|
||||
{:id "shape"
|
||||
:class Shape
|
||||
:wfn #(into {} %)
|
||||
:rfn map->Shape})
|
||||
|
||||
#?(:clj
|
||||
(fres/add-handlers!
|
||||
{:name "penpot/shape"
|
||||
:class Shape
|
||||
:wfn fres/write-map-like
|
||||
:rfn (comp map->Shape fres/read-map-like)}))
|
||||
|
|
227
common/src/app/common/types/shape/impl.cljc
Normal file
227
common/src/app/common/types/shape/impl.cljc
Normal file
|
@ -0,0 +1,227 @@
|
|||
;; 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.shape.impl
|
||||
(:require
|
||||
#?(:clj [app.common.fressian :as fres])
|
||||
#?(:cljs [app.common.data.macros :as dm])
|
||||
#?(:cljs [app.common.geom.rect :as grc])
|
||||
#?(:cljs [cuerdas.core :as str])
|
||||
[app.common.record :as cr]
|
||||
[app.common.transit :as t]
|
||||
[clojure.core :as c]))
|
||||
|
||||
(def enabled-wasm-ready-shape false)
|
||||
|
||||
#?(:cljs
|
||||
(do
|
||||
(def ArrayBuffer js/ArrayBuffer)
|
||||
(def Float32Array js/Float32Array)))
|
||||
|
||||
(cr/defrecord Shape [id name type x y width height rotation selrect points
|
||||
transform transform-inverse parent-id frame-id flip-x flip-y])
|
||||
|
||||
(declare ^:private clone-f32-array)
|
||||
(declare ^:private impl-assoc)
|
||||
(declare ^:private impl-conj)
|
||||
(declare ^:private impl-dissoc)
|
||||
(declare ^:private read-selrect)
|
||||
(declare ^:private write-selrect)
|
||||
|
||||
;; TODO: implement lazy MapEntry
|
||||
|
||||
#?(:cljs
|
||||
(deftype ShapeWithBuffer [buffer delegate]
|
||||
Object
|
||||
(toString [coll]
|
||||
(str "{" (str/join ", " (for [[k v] coll] (str k " " v))) "}"))
|
||||
|
||||
(equiv [this other]
|
||||
(-equiv this other))
|
||||
|
||||
;; ICloneable
|
||||
;; (-clone [_]
|
||||
;; (let [bf32 (clone-float32-array buffer)]
|
||||
;; (ShapeWithBuffer. bf32 delegate)))
|
||||
|
||||
IWithMeta
|
||||
(-with-meta [_ meta]
|
||||
(ShapeWithBuffer. buffer (with-meta delegate meta)))
|
||||
|
||||
IMeta
|
||||
(-meta [_] (meta delegate))
|
||||
|
||||
ICollection
|
||||
(-conj [coll entry]
|
||||
(impl-conj coll entry))
|
||||
|
||||
IEquiv
|
||||
(-equiv [coll other]
|
||||
(c/equiv-map coll other))
|
||||
|
||||
IHash
|
||||
(-hash [coll] (hash (into {} coll)))
|
||||
|
||||
ISequential
|
||||
|
||||
ISeqable
|
||||
(-seq [coll]
|
||||
(cons (find coll :selrect)
|
||||
(seq delegate)))
|
||||
|
||||
ICounted
|
||||
(-count [_]
|
||||
(+ 1 (count delegate)))
|
||||
|
||||
ILookup
|
||||
(-lookup [coll k]
|
||||
(-lookup coll k nil))
|
||||
|
||||
(-lookup [_ k not-found]
|
||||
(if (= k :selrect)
|
||||
(read-selrect buffer)
|
||||
(c/-lookup delegate k not-found)))
|
||||
|
||||
IFind
|
||||
(-find [_ k]
|
||||
(if (= k :selrect)
|
||||
(c/MapEntry. k (read-selrect buffer) nil) ; Replace with lazy MapEntry
|
||||
(c/-find delegate k)))
|
||||
|
||||
IAssociative
|
||||
(-assoc [coll k v]
|
||||
(impl-assoc coll k v))
|
||||
|
||||
(-contains-key? [_ k]
|
||||
(or (= k :selrect)
|
||||
(contains? delegate k)))
|
||||
|
||||
IMap
|
||||
(-dissoc [coll k]
|
||||
(impl-dissoc coll k))
|
||||
|
||||
IFn
|
||||
(-invoke [coll k]
|
||||
(-lookup coll k))
|
||||
|
||||
(-invoke [coll k not-found]
|
||||
(-lookup coll k not-found))
|
||||
|
||||
IPrintWithWriter
|
||||
(-pr-writer [_ writer _]
|
||||
(-write writer (str "#penpot/shape " (:id delegate))))))
|
||||
|
||||
(defn shape?
|
||||
[o]
|
||||
#?(:clj (instance? Shape o)
|
||||
:cljs (or (instance? Shape o)
|
||||
(instance? ShapeWithBuffer o))))
|
||||
|
||||
;; --- SHAPE IMPL
|
||||
|
||||
#?(:cljs
|
||||
(defn- clone-f32-array
|
||||
[^Float32Array src]
|
||||
(let [copy (new Float32Array (.-length src))]
|
||||
(.set copy src)
|
||||
copy)))
|
||||
|
||||
#?(:cljs
|
||||
(defn- write-selrect
|
||||
"Write the selrect into the buffer"
|
||||
[data selrect]
|
||||
(assert (instance? Float32Array data) "expected instance of float32array")
|
||||
|
||||
(aset data 0 (dm/get-prop selrect :x1))
|
||||
(aset data 1 (dm/get-prop selrect :y1))
|
||||
(aset data 2 (dm/get-prop selrect :x2))
|
||||
(aset data 3 (dm/get-prop selrect :y2))))
|
||||
|
||||
#?(:cljs
|
||||
(defn- read-selrect
|
||||
"Read selrect from internal buffer"
|
||||
[^Float32Array buffer]
|
||||
(let [x1 (aget buffer 0)
|
||||
y1 (aget buffer 1)
|
||||
x2 (aget buffer 2)
|
||||
y2 (aget buffer 3)]
|
||||
(grc/make-rect x1 y1
|
||||
(- x2 x1)
|
||||
(- y2 y1)))))
|
||||
|
||||
#?(:cljs
|
||||
(defn- impl-assoc
|
||||
[coll k v]
|
||||
(if (= k :selrect)
|
||||
(let [buffer (clone-f32-array (.-buffer coll))]
|
||||
(write-selrect buffer v)
|
||||
(ShapeWithBuffer. buffer (.-delegate ^ShapeWithBuffer coll)))
|
||||
|
||||
(let [delegate (.-delegate ^ShapeWithBuffer coll)
|
||||
delegate' (assoc delegate k v)]
|
||||
(if (identical? delegate' delegate)
|
||||
coll
|
||||
(let [buffer (clone-f32-array (.-buffer coll))]
|
||||
(ShapeWithBuffer. buffer delegate')))))))
|
||||
|
||||
#?(:cljs
|
||||
(defn- impl-dissoc
|
||||
[coll k]
|
||||
(let [delegate (.-delegate ^ShapeWithBuffer coll)
|
||||
delegate' (dissoc delegate k)]
|
||||
(if (identical? delegate delegate')
|
||||
coll
|
||||
(let [buffer (clone-f32-array (.-buffer coll))]
|
||||
(ShapeWithBuffer. buffer delegate'))))))
|
||||
|
||||
#?(:cljs
|
||||
(defn- impl-conj
|
||||
[coll entry]
|
||||
(if (vector? entry)
|
||||
(-assoc coll (-nth entry 0) (-nth entry 1))
|
||||
(loop [ret coll es (seq entry)]
|
||||
(if (nil? es)
|
||||
ret
|
||||
(let [e (first es)]
|
||||
(if (vector? e)
|
||||
(recur (-assoc ret (-nth e 0) (-nth e 1))
|
||||
(next es))
|
||||
(throw (js/Error. "conj on a map takes map entries or seqables of map entries")))))))))
|
||||
|
||||
(defn create-shape
|
||||
"Instanciate a shape from a map"
|
||||
[attrs]
|
||||
#?(:cljs
|
||||
(if enabled-wasm-ready-shape
|
||||
(let [selrect (:selrect attrs)
|
||||
buffer (new Float32Array 4)]
|
||||
(write-selrect buffer selrect)
|
||||
(ShapeWithBuffer. buffer (dissoc attrs :selrect)))
|
||||
(map->Shape attrs))
|
||||
|
||||
:clj (map->Shape attrs)))
|
||||
|
||||
;; --- SHAPE SERIALIZATION
|
||||
|
||||
(t/add-handlers!
|
||||
{:id "shape"
|
||||
:class Shape
|
||||
:wfn #(into {} %)
|
||||
:rfn create-shape})
|
||||
|
||||
#?(:cljs
|
||||
(t/add-handlers!
|
||||
{:id "shape"
|
||||
:class ShapeWithBuffer
|
||||
:wfn #(into {} %)
|
||||
:rfn create-shape}))
|
||||
|
||||
#?(:clj
|
||||
(fres/add-handlers!
|
||||
{:name "penpot/shape"
|
||||
:class Shape
|
||||
:wfn fres/write-map-like
|
||||
:rfn (comp create-shape fres/read-map-like)}))
|
17
common/src/app/common/types/team.cljc
Normal file
17
common/src/app/common/types/team.cljc
Normal file
|
@ -0,0 +1,17 @@
|
|||
;; 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.team)
|
||||
|
||||
(def valid-roles
|
||||
#{:owner :admin :editor :viewer})
|
||||
|
||||
(def permissions-for-role
|
||||
{:viewer {:can-edit false :is-admin false :is-owner false}
|
||||
:editor {:can-edit true :is-admin false :is-owner false}
|
||||
:admin {:can-edit true :is-admin true :is-owner false}
|
||||
:owner {:can-edit true :is-admin true :is-owner true}})
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
;; SCHEMA
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(sm/register! ::typography
|
||||
(def schema:typography
|
||||
[:map {:title "Typography"}
|
||||
[:id ::sm/uuid]
|
||||
[:name :string]
|
||||
|
@ -33,6 +33,8 @@
|
|||
[:path {:optional true} [:maybe :string]]
|
||||
[:plugin-data {:optional true} ::ctpg/plugin-data]])
|
||||
|
||||
(sm/register! ::typography schema:typography)
|
||||
|
||||
(def check-typography!
|
||||
(sm/check-fn ::typography))
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
(ns common-tests.types.tokens-lib-test
|
||||
(:require
|
||||
#?(:clj [app.common.fressian :as fres])
|
||||
#?(:clj [clojure.data.json :as json])
|
||||
[app.common.data :as d]
|
||||
[app.common.time :as dt]
|
||||
[app.common.transit :as tr]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[clojure.data.json :as json]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(t/testing "token"
|
||||
|
@ -49,9 +49,9 @@
|
|||
|
||||
(t/deftest find-token-value-references
|
||||
(t/testing "finds references inside curly braces in a string"
|
||||
(t/is (= #{"foo" "bar"} (ctob/find-token-value-references "{foo} + {bar}")))
|
||||
(t/testing "ignores extra text"
|
||||
(t/is (= #{"foo.bar.baz"} (ctob/find-token-value-references "{foo.bar.baz} + something")))))
|
||||
(t/is (= #{"foo" "bar"} (ctob/find-token-value-references "{foo} + {bar}")))
|
||||
(t/testing "ignores extra text"
|
||||
(t/is (= #{"foo.bar.baz"} (ctob/find-token-value-references "{foo.bar.baz} + something")))))
|
||||
(t/testing "ignores string without references"
|
||||
(t/is (nil? (ctob/find-token-value-references "1 + 2"))))
|
||||
(t/testing "handles edge-case for extra curly braces"
|
||||
|
@ -395,9 +395,8 @@
|
|||
;; Ignore this set
|
||||
(ctob/add-set (ctob/make-token-set :name "inactive-set"))
|
||||
(ctob/add-token-in-set "inactive-set" (ctob/make-token :name "inactive-set-token"
|
||||
:type :boolean
|
||||
:value true)))
|
||||
|
||||
:type :boolean
|
||||
:value true)))
|
||||
|
||||
expected-order (ctob/get-ordered-set-names tokens-lib)
|
||||
expected-tokens (ctob/get-active-themes-set-tokens tokens-lib)
|
||||
|
@ -425,13 +424,13 @@
|
|||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-theme "" "test-token-theme"
|
||||
(fn [token-theme]
|
||||
(assoc token-theme
|
||||
:description "some description")))
|
||||
(fn [token-theme]
|
||||
(assoc token-theme
|
||||
:description "some description")))
|
||||
(ctob/update-theme "" "not-existing-theme"
|
||||
(fn [token-theme]
|
||||
(assoc token-theme
|
||||
:description "no-effect"))))
|
||||
(fn [token-theme]
|
||||
(assoc token-theme
|
||||
:description "no-effect"))))
|
||||
|
||||
token-theme (ctob/get-theme tokens-lib "" "test-token-theme")
|
||||
token-theme' (ctob/get-theme tokens-lib' "" "test-token-theme")]
|
||||
|
@ -472,20 +471,20 @@
|
|||
(t/is (nil? token-theme'))))
|
||||
|
||||
(t/deftest toggle-set-in-theme
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "token-set-1"))
|
||||
(ctob/add-set (ctob/make-token-set :name "token-set-2"))
|
||||
(ctob/add-set (ctob/make-token-set :name "token-set-3"))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "test-token-theme")))
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/toggle-set-in-theme "" "test-token-theme" "token-set-1")
|
||||
(ctob/toggle-set-in-theme "" "test-token-theme" "token-set-2")
|
||||
(ctob/toggle-set-in-theme "" "test-token-theme" "token-set-2"))
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "token-set-1"))
|
||||
(ctob/add-set (ctob/make-token-set :name "token-set-2"))
|
||||
(ctob/add-set (ctob/make-token-set :name "token-set-3"))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "test-token-theme")))
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/toggle-set-in-theme "" "test-token-theme" "token-set-1")
|
||||
(ctob/toggle-set-in-theme "" "test-token-theme" "token-set-2")
|
||||
(ctob/toggle-set-in-theme "" "test-token-theme" "token-set-2"))
|
||||
|
||||
token-theme (ctob/get-theme tokens-lib "" "test-token-theme")
|
||||
token-theme' (ctob/get-theme tokens-lib' "" "test-token-theme")]
|
||||
token-theme (ctob/get-theme tokens-lib "" "test-token-theme")
|
||||
token-theme' (ctob/get-theme tokens-lib' "" "test-token-theme")]
|
||||
|
||||
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))))
|
||||
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))))
|
||||
|
||||
|
||||
(t/testing "serialization"
|
||||
|
@ -797,8 +796,8 @@
|
|||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-set "group1/token-set-2"
|
||||
(fn [token-set]
|
||||
(assoc token-set :description "some description"))))
|
||||
(fn [token-set]
|
||||
(assoc token-set :description "some description"))))
|
||||
|
||||
sets-tree (ctob/get-set-tree tokens-lib)
|
||||
sets-tree' (ctob/get-set-tree tokens-lib')
|
||||
|
@ -823,9 +822,9 @@
|
|||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-set "group1/token-set-2"
|
||||
(fn [token-set]
|
||||
(assoc token-set
|
||||
:name "group1/updated-name"))))
|
||||
(fn [token-set]
|
||||
(assoc token-set
|
||||
:name "group1/updated-name"))))
|
||||
|
||||
sets-tree (ctob/get-set-tree tokens-lib)
|
||||
sets-tree' (ctob/get-set-tree tokens-lib')
|
||||
|
@ -850,9 +849,9 @@
|
|||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-set "group1/token-set-2"
|
||||
(fn [token-set]
|
||||
(assoc token-set
|
||||
:name "group2/updated-name"))))
|
||||
(fn [token-set]
|
||||
(assoc token-set
|
||||
:name "group2/updated-name"))))
|
||||
|
||||
sets-tree (ctob/get-set-tree tokens-lib)
|
||||
sets-tree' (ctob/get-set-tree tokens-lib')
|
||||
|
@ -951,8 +950,8 @@
|
|||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-theme "group1" "token-theme-2"
|
||||
(fn [token-theme]
|
||||
(assoc token-theme :description "some description"))))
|
||||
(fn [token-theme]
|
||||
(assoc token-theme :description "some description"))))
|
||||
|
||||
themes-tree (ctob/get-theme-tree tokens-lib)
|
||||
themes-tree' (ctob/get-theme-tree tokens-lib')
|
||||
|
@ -986,9 +985,9 @@
|
|||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-theme "group1" "token-theme-2"
|
||||
(fn [token-theme]
|
||||
(assoc token-theme
|
||||
:name "updated-name"))))
|
||||
(fn [token-theme]
|
||||
(assoc token-theme
|
||||
:name "updated-name"))))
|
||||
|
||||
themes-tree (ctob/get-theme-tree tokens-lib)
|
||||
themes-tree' (ctob/get-theme-tree tokens-lib')
|
||||
|
@ -1013,10 +1012,10 @@
|
|||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-theme "group1" "token-theme-2"
|
||||
(fn [token-theme]
|
||||
(assoc token-theme
|
||||
:name "updated-name"
|
||||
:group "group2"))))
|
||||
(fn [token-theme]
|
||||
(assoc token-theme
|
||||
:name "updated-name"
|
||||
:group "group2"))))
|
||||
|
||||
themes-tree (ctob/get-theme-tree tokens-lib)
|
||||
themes-tree' (ctob/get-theme-tree tokens-lib')
|
||||
|
@ -1049,93 +1048,95 @@
|
|||
(t/is (= (count themes-tree') 1))
|
||||
(t/is (nil? token-theme'))))))
|
||||
|
||||
(t/testing "dtcg encoding/decoding"
|
||||
(t/deftest decode-dtcg-json
|
||||
(let [json (-> (slurp "test/common_tests/types/data/tokens-multi-set-example.json")
|
||||
(tr/decode-str))
|
||||
lib (ctob/decode-dtcg-json (ctob/ensure-tokens-lib nil) json)
|
||||
get-set-token (fn [set-name token-name]
|
||||
(some-> (ctob/get-set lib set-name)
|
||||
(ctob/get-token token-name)
|
||||
(dissoc :modified-at)))]
|
||||
(t/is (= '("core" "light" "dark" "theme") (ctob/get-ordered-set-names lib)))
|
||||
(t/testing "tokens exist in core set"
|
||||
(t/is (= (get-set-token "core" "colors.red.600")
|
||||
{:name "colors.red.600"
|
||||
:type :color
|
||||
:value "#e53e3e"
|
||||
:description nil}))
|
||||
(t/is (= (get-set-token "core" "spacing.multi-value")
|
||||
{:name "spacing.multi-value"
|
||||
:type :spacing
|
||||
:value "{dimension.sm} {dimension.xl}"
|
||||
:description "You can have multiple values in a single spacing token"}))
|
||||
(t/is (= (get-set-token "theme" "button.primary.background")
|
||||
{:name "button.primary.background"
|
||||
:type :color
|
||||
:value "{accent.default}"
|
||||
:description nil})))
|
||||
(t/testing "invalid tokens got discarded"
|
||||
(t/is (nil? (get-set-token "typography" "H1.Bold"))))))
|
||||
#?(:clj
|
||||
(t/testing "dtcg encoding/decoding"
|
||||
(t/deftest decode-dtcg-json
|
||||
(let [json (-> (slurp "test/common_tests/types/data/tokens-multi-set-example.json")
|
||||
(tr/decode-str))
|
||||
lib (ctob/decode-dtcg-json (ctob/ensure-tokens-lib nil) json)
|
||||
get-set-token (fn [set-name token-name]
|
||||
(some-> (ctob/get-set lib set-name)
|
||||
(ctob/get-token token-name)
|
||||
(dissoc :modified-at)))]
|
||||
(t/is (= '("core" "light" "dark" "theme") (ctob/get-ordered-set-names lib)))
|
||||
(t/testing "tokens exist in core set"
|
||||
(t/is (= (get-set-token "core" "colors.red.600")
|
||||
{:name "colors.red.600"
|
||||
:type :color
|
||||
:value "#e53e3e"
|
||||
:description nil}))
|
||||
(t/is (= (get-set-token "core" "spacing.multi-value")
|
||||
{:name "spacing.multi-value"
|
||||
:type :spacing
|
||||
:value "{dimension.sm} {dimension.xl}"
|
||||
:description "You can have multiple values in a single spacing token"}))
|
||||
(t/is (= (get-set-token "theme" "button.primary.background")
|
||||
{:name "button.primary.background"
|
||||
:type :color
|
||||
:value "{accent.default}"
|
||||
:description nil})))
|
||||
(t/testing "invalid tokens got discarded"
|
||||
(t/is (nil? (get-set-token "typography" "H1.Bold"))))))
|
||||
|
||||
(t/deftest encode-dtcg-json
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "core"
|
||||
:tokens {"colors.red.600"
|
||||
(ctob/make-token
|
||||
{:name "colors.red.600"
|
||||
:type :color
|
||||
:value "#e53e3e"})
|
||||
"spacing.multi-value"
|
||||
(ctob/make-token
|
||||
{:name "spacing.multi-value"
|
||||
:type :spacing
|
||||
:value "{dimension.sm} {dimension.xl}"
|
||||
:description "You can have multiple values in a single spacing token"})
|
||||
"button.primary.background"
|
||||
(ctob/make-token
|
||||
{:name "button.primary.background"
|
||||
:type :color
|
||||
:value "{accent.default}"})})))
|
||||
expected (ctob/encode-dtcg tokens-lib)]
|
||||
(t/is (= {"core"
|
||||
{"colors" {"red" {"600" {"$value" "#e53e3e"
|
||||
"$type" "color"}}}
|
||||
"spacing"
|
||||
{"multi-value"
|
||||
{"$value" "{dimension.sm} {dimension.xl}"
|
||||
"$type" "spacing"
|
||||
"$description" "You can have multiple values in a single spacing token"}}
|
||||
"button"
|
||||
{"primary" {"background" {"$value" "{accent.default}"
|
||||
"$type" "color"}}}}}
|
||||
expected))))
|
||||
(t/deftest encode-dtcg-json
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "core"
|
||||
:tokens {"colors.red.600"
|
||||
(ctob/make-token
|
||||
{:name "colors.red.600"
|
||||
:type :color
|
||||
:value "#e53e3e"})
|
||||
"spacing.multi-value"
|
||||
(ctob/make-token
|
||||
{:name "spacing.multi-value"
|
||||
:type :spacing
|
||||
:value "{dimension.sm} {dimension.xl}"
|
||||
:description "You can have multiple values in a single spacing token"})
|
||||
"button.primary.background"
|
||||
(ctob/make-token
|
||||
{:name "button.primary.background"
|
||||
:type :color
|
||||
:value "{accent.default}"})})))
|
||||
expected (ctob/encode-dtcg tokens-lib)]
|
||||
(t/is (= {"core"
|
||||
{"colors" {"red" {"600" {"$value" "#e53e3e"
|
||||
"$type" "color"}}}
|
||||
"spacing"
|
||||
{"multi-value"
|
||||
{"$value" "{dimension.sm} {dimension.xl}"
|
||||
"$type" "spacing"
|
||||
"$description" "You can have multiple values in a single spacing token"}}
|
||||
"button"
|
||||
{"primary" {"background" {"$value" "{accent.default}"
|
||||
"$type" "color"}}}}}
|
||||
expected))))
|
||||
|
||||
(t/deftest encode-decode-dtcg-json
|
||||
(with-redefs [dt/now (constantly #inst "2024-10-16T12:01:20.257840055-00:00")]
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "core"
|
||||
:tokens {"colors.red.600"
|
||||
(ctob/make-token
|
||||
{:name "colors.red.600"
|
||||
:type :color
|
||||
:value "#e53e3e"})
|
||||
"spacing.multi-value"
|
||||
(ctob/make-token
|
||||
{:name "spacing.multi-value"
|
||||
:type :spacing
|
||||
:value "{dimension.sm} {dimension.xl}"
|
||||
:description "You can have multiple values in a single spacing token"})
|
||||
"button.primary.background"
|
||||
(ctob/make-token
|
||||
{:name "button.primary.background"
|
||||
:type :color
|
||||
:value "{accent.default}"})})))
|
||||
encoded (ctob/encode-dtcg tokens-lib)
|
||||
with-prev-tokens-lib (ctob/decode-dtcg-json tokens-lib encoded)
|
||||
with-empty-tokens-lib (ctob/decode-dtcg-json (ctob/ensure-tokens-lib nil) encoded)]
|
||||
(t/testing "library got updated but data is equal"
|
||||
(t/is (not= with-prev-tokens-lib tokens-lib))
|
||||
(t/is (= @with-prev-tokens-lib @tokens-lib)))
|
||||
(t/testing "fresh tokens library is also equal"
|
||||
(= @with-empty-tokens-lib @tokens-lib)))))))
|
||||
|
||||
(t/deftest encode-decode-dtcg-json
|
||||
(with-redefs [dt/now (constantly #inst "2024-10-16T12:01:20.257840055-00:00")]
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "core"
|
||||
:tokens {"colors.red.600"
|
||||
(ctob/make-token
|
||||
{:name "colors.red.600"
|
||||
:type :color
|
||||
:value "#e53e3e"})
|
||||
"spacing.multi-value"
|
||||
(ctob/make-token
|
||||
{:name "spacing.multi-value"
|
||||
:type :spacing
|
||||
:value "{dimension.sm} {dimension.xl}"
|
||||
:description "You can have multiple values in a single spacing token"})
|
||||
"button.primary.background"
|
||||
(ctob/make-token
|
||||
{:name "button.primary.background"
|
||||
:type :color
|
||||
:value "{accent.default}"})})))
|
||||
encoded (ctob/encode-dtcg tokens-lib)
|
||||
with-prev-tokens-lib (ctob/decode-dtcg-json tokens-lib encoded)
|
||||
with-empty-tokens-lib (ctob/decode-dtcg-json (ctob/ensure-tokens-lib nil) encoded)]
|
||||
(t/testing "library got updated but data is equal"
|
||||
(t/is (not= with-prev-tokens-lib tokens-lib))
|
||||
(t/is (= @with-prev-tokens-lib @tokens-lib)))
|
||||
(t/testing "fresh tokens library is also equal"
|
||||
(= @with-empty-tokens-lib @tokens-lib))))))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue