0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-18 10:41:29 -05:00

♻️ Refactor and modularize all specs.

This commit is contained in:
Andrey Antukh 2022-01-25 00:07:08 +01:00 committed by Andrés Moya
parent b1d55348dc
commit 04f7169aef
48 changed files with 1112 additions and 1031 deletions

View file

@ -7,6 +7,7 @@
(ns app.rpc.mutations.comments
(:require
[app.common.exceptions :as ex]
[app.common.geom.point :as gpt]
[app.common.spec :as us]
[app.db :as db]
[app.rpc.queries.comments :as comments]
@ -26,7 +27,7 @@
(s/def ::page-id ::us/uuid)
(s/def ::file-id ::us/uuid)
(s/def ::profile-id ::us/uuid)
(s/def ::position ::us/point)
(s/def ::position ::gpt/point)
(s/def ::content ::us/string)
(s/def ::create-comment-thread

View file

@ -7,7 +7,7 @@
[app.common.logging :as l]
[app.common.pages :as cp]
[app.common.pages.migrations :as pmg]
[app.common.pages.spec :as spec]
[app.common.spec.file :as spec.file]
[app.common.uuid :as uuid]
[app.config :as cfg]
[app.db :as db]
@ -86,7 +86,7 @@
(validate-item [{:keys [id data modified-at] :as file}]
(let [data (blob/decode data)
valid? (s/valid? ::spec/data data)]
valid? (s/valid? ::spec.file/data data)]
(l/debug :hint "validated file"
:file-id id
@ -98,7 +98,7 @@
:valid valid?)
(when (and (not valid?) verbose?)
(let [edata (-> (s/explain-data ::spec/data data)
(let [edata (-> (s/explain-data ::spec.file/data data)
(update ::s/problems #(take 5 %)))]
(binding [s/*explain-out* expound/printer]
(l/warn ::l/raw (with-out-str (s/explain-out edata))))))

View file

@ -13,6 +13,7 @@
[app.common.pages.changes :as ch]
[app.common.pages.init :as init]
[app.common.spec :as us]
[app.common.spec.change :as spec.change]
[app.common.uuid :as uuid]
[cuerdas.core :as str]))
@ -38,9 +39,9 @@
:frame-id (:current-frame-id file)))]
(when fail-on-spec?
(us/verify :app.common.pages.spec/change change))
(us/verify ::spec.change/change change))
(let [valid? (us/valid? :app.common.pages.spec/change change)]
(let [valid? (us/valid? ::spec.change/change change)]
#?(:cljs
(when-not valid? (.warn js/console "Invalid shape" (clj->js change))))

View file

@ -10,7 +10,9 @@
:clj [clojure.pprint :as pp])
[app.common.data :as d]
[app.common.geom.point :as gpt]
[app.common.math :as mth]))
[app.common.math :as mth]
[app.common.spec :as us]
[clojure.spec.alpha :as s]))
;; --- Matrix Impl
@ -24,6 +26,21 @@
(toString [_]
(str "matrix(" a "," b "," c "," d "," e "," f ")")))
(defn ^boolean matrix?
"Return true if `v` is Matrix instance."
[v]
(instance? Matrix v))
(s/def ::a ::us/safe-number)
(s/def ::b ::us/safe-number)
(s/def ::c ::us/safe-number)
(s/def ::d ::us/safe-number)
(s/def ::e ::us/safe-number)
(s/def ::f ::us/safe-number)
(s/def ::matrix
(s/and (s/keys :req-un [::a ::b ::c ::d ::e ::f]) matrix?))
(defn matrix
"Create a new matrix instance."
([]
@ -84,11 +101,6 @@
(- m1a m2a) (- m1b m2b) (- m1c m2c)
(- m1d m2d) (- m1e m2e) (- m1f m2f)))
(defn ^boolean matrix?
"Return true if `v` is Matrix instance."
[v]
(instance? Matrix v))
(def base (matrix))
(defn base?

View file

@ -11,7 +11,9 @@
:clj [clojure.pprint :as pp])
#?(:cljs [cljs.core :as c]
:clj [clojure.core :as c])
[app.common.math :as mth]))
[app.common.math :as mth]
[app.common.spec :as us]
[clojure.spec.alpha :as s]))
;; --- Point Impl
@ -25,6 +27,13 @@
(or (instance? Point v)
(and (map? v) (contains? v :x) (contains? v :y))))
(s/def ::x ::us/safe-number)
(s/def ::y ::us/safe-number)
(s/def ::point
(s/and (s/keys :req-un [::x ::y]) point?))
(defn ^boolean point-like?
[{:keys [x y] :as v}]
(and (map? v)

View file

@ -185,3 +185,7 @@
;; Bool
(d/export gsb/update-bool-selrect)
(d/export gsb/calc-bool-content)
;; Constraints
(d/export gct/default-constraints-h)
(d/export gct/default-constraints-v)

View file

@ -11,7 +11,7 @@
[app.common.geom.shapes.common :as gco]
[app.common.geom.shapes.transforms :as gtr]
[app.common.math :as mth]
[app.common.pages.spec :as spec]))
[app.common.uuid :as uuid]))
;; Auxiliary methods to work in an specifica axis
(defn get-delta-start [axis rect tr-rect]
@ -117,7 +117,7 @@
(not (mth/close? (:y resize-vector-2) 1)))
(assoc :resize-origin (:resize-origin-2 modifiers)
:resize-vector (gpt/point 1 (:y resize-vector-2)))
(some? displacement)
(assoc :displacement
(get-displacement axis (-> (gpt/point 0 0)
@ -138,16 +138,32 @@
:center :center
:scale :scale})
(defn default-constraints-h
[shape]
(if (= (:parent-id shape) uuid/zero)
nil
(if (= (:parent-id shape) (:frame-id shape))
:left
:scale)))
(defn default-constraints-v
[shape]
(if (= (:parent-id shape) uuid/zero)
nil
(if (= (:parent-id shape) (:frame-id shape))
:top
:scale)))
(defn calc-child-modifiers
[parent child modifiers ignore-constraints transformed-parent-rect]
(let [constraints-h
(if-not ignore-constraints
(:constraints-h child (spec/default-constraints-h child))
(:constraints-h child (default-constraints-h child))
:scale)
constraints-v
(if-not ignore-constraints
(:constraints-v child (spec/default-constraints-v child))
(:constraints-v child (default-constraints-v child))
:scale)
modifiers-h (constraint-modifier (constraints-h const->type+axis) :x parent child modifiers transformed-parent-rect)

View file

@ -12,9 +12,7 @@
[app.common.pages.common :as common]
[app.common.pages.helpers :as helpers]
[app.common.pages.indices :as indices]
[app.common.pages.init :as init]
[app.common.pages.spec :as spec]
[clojure.spec.alpha :as s]))
[app.common.pages.init :as init]))
;; Common
(d/export common/root)
@ -88,15 +86,3 @@
(d/export init/make-minimal-shape)
(d/export init/make-minimal-group)
(d/export init/empty-file-data)
;; Specs
(s/def ::changes ::spec/changes)
(s/def ::color ::spec/color)
(s/def ::data ::spec/data)
(s/def ::media-object ::spec/media-object)
(s/def ::page ::spec/page)
(s/def ::recent-color ::spec/recent-color)
(s/def ::shape-attrs ::spec/shape-attrs)
(s/def ::typography ::spec/typography)

View file

@ -5,6 +5,7 @@
;; Copyright (c) UXBOX Labs SL
(ns app.common.pages.changes
#_:clj-kondo/ignore
(:require
[app.common.data :as d]
[app.common.exceptions :as ex]
@ -13,9 +14,9 @@
[app.common.pages.common :refer [component-sync-attrs]]
[app.common.pages.helpers :as cph]
[app.common.pages.init :as init]
[app.common.pages.spec :as spec]
[app.common.spec :as us]))
[app.common.spec :as us]
[app.common.spec.change :as spec.change]
[app.common.spec.shape :as spec.shape]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Specific helpers
@ -47,7 +48,7 @@
;; When verify? false we spec the schema validation. Currently used to make just
;; 1 validation even if the changes are applied twice
(when verify?
(us/assert ::spec/changes items))
(us/assert ::spec.change/changes items))
(let [result (reduce #(or (process-change %1 %2) %1) data items)]
;; Validate result shapes (only on the backend)
@ -57,7 +58,7 @@
(doseq [[id shape] (:objects page)]
(when-not (= shape (get-in data [:pages-index page-id :objects id]))
;; If object has change verify is correct
(us/verify ::spec/shape shape))))))
(us/verify ::spec.shape/shape shape))))))
result)))

View file

@ -9,7 +9,7 @@
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.spec :as us]
[app.common.types.interactions :as cti]
[app.common.spec.interactions :as cti]
[app.common.uuid :as uuid]
[cuerdas.core :as str]))
@ -464,3 +464,4 @@
(tree-seq #(d/not-empty? (get shape :shapes))
#(->> (get % :shapes) (map getter))
shape)))

View file

@ -1,623 +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) UXBOX Labs SL
(ns app.common.pages.spec
(:require
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.spec :as us]
[app.common.types.interactions :as cti]
[app.common.types.page-options :as cto]
[app.common.types.radius :as ctr]
[app.common.uuid :as uuid]
[clojure.set :as set]
[clojure.spec.alpha :as s]))
;; --- Specs
(s/def ::frame-id uuid?)
(s/def ::id uuid?)
(s/def ::name string?)
(s/def ::path (s/nilable string?))
(s/def ::page-id uuid?)
(s/def ::parent-id uuid?)
(s/def ::string string?)
(s/def ::type keyword?)
(s/def ::uuid uuid?)
(s/def ::component-id uuid?)
(s/def ::component-file uuid?)
(s/def ::component-root? boolean?)
(s/def ::shape-ref uuid?)
(s/def :internal.matrix/a ::us/safe-number)
(s/def :internal.matrix/b ::us/safe-number)
(s/def :internal.matrix/c ::us/safe-number)
(s/def :internal.matrix/d ::us/safe-number)
(s/def :internal.matrix/e ::us/safe-number)
(s/def :internal.matrix/f ::us/safe-number)
(s/def ::matrix
(s/and (s/keys :req-un [:internal.matrix/a
:internal.matrix/b
:internal.matrix/c
:internal.matrix/d
:internal.matrix/e
:internal.matrix/f])
gmt/matrix?))
(s/def :internal.point/x ::us/safe-number)
(s/def :internal.point/y ::us/safe-number)
(s/def ::point
(s/and (s/keys :req-un [:internal.point/x
:internal.point/y])
gpt/point?))
;; GRADIENTS
(s/def :internal.gradient.stop/color ::string)
(s/def :internal.gradient.stop/opacity ::us/safe-number)
(s/def :internal.gradient.stop/offset ::us/safe-number)
(s/def :internal.gradient/type #{:linear :radial})
(s/def :internal.gradient/start-x ::us/safe-number)
(s/def :internal.gradient/start-y ::us/safe-number)
(s/def :internal.gradient/end-x ::us/safe-number)
(s/def :internal.gradient/end-y ::us/safe-number)
(s/def :internal.gradient/width ::us/safe-number)
(s/def :internal.gradient/stop
(s/keys :req-un [:internal.gradient.stop/color
:internal.gradient.stop/opacity
:internal.gradient.stop/offset]))
(s/def :internal.gradient/stops
(s/coll-of :internal.gradient/stop :kind vector?))
(s/def ::gradient
(s/keys :req-un [:internal.gradient/type
:internal.gradient/start-x
:internal.gradient/start-y
:internal.gradient/end-x
:internal.gradient/end-y
:internal.gradient/width
:internal.gradient/stops]))
;;; COLORS
(s/def :internal.color/name ::string)
(s/def :internal.color/path (s/nilable ::string))
(s/def :internal.color/value (s/nilable ::string))
(s/def :internal.color/color (s/nilable ::string))
(s/def :internal.color/opacity (s/nilable ::us/safe-number))
(s/def :internal.color/gradient (s/nilable ::gradient))
(s/def ::color
(s/keys :opt-un [::id
:internal.color/name
:internal.color/path
:internal.color/value
:internal.color/color
:internal.color/opacity
:internal.color/gradient]))
;;; SHADOW EFFECT
(s/def :internal.shadow/id uuid?)
(s/def :internal.shadow/style #{:drop-shadow :inner-shadow})
(s/def :internal.shadow/color ::color)
(s/def :internal.shadow/offset-x ::us/safe-number)
(s/def :internal.shadow/offset-y ::us/safe-number)
(s/def :internal.shadow/blur ::us/safe-number)
(s/def :internal.shadow/spread ::us/safe-number)
(s/def :internal.shadow/hidden boolean?)
(s/def :internal.shadow/shadow
(s/keys :req-un [:internal.shadow/id
:internal.shadow/style
:internal.shadow/color
:internal.shadow/offset-x
:internal.shadow/offset-y
:internal.shadow/blur
:internal.shadow/spread
:internal.shadow/hidden]))
(s/def ::shadow
(s/coll-of :internal.shadow/shadow :kind vector?))
;;; BLUR EFFECT
(s/def :internal.blur/id uuid?)
(s/def :internal.blur/type #{:layer-blur})
(s/def :internal.blur/value ::us/safe-number)
(s/def :internal.blur/hidden boolean?)
(s/def ::blur
(s/keys :req-un [:internal.blur/id
:internal.blur/type
:internal.blur/value
:internal.blur/hidden]))
;; Size constraints
(s/def :internal.shape/constraints-h #{:left :right :leftright :center :scale})
(s/def :internal.shape/constraints-v #{:top :bottom :topbottom :center :scale})
(s/def :internal.shape/fixed-scroll boolean?)
; Shapes in the top frame have no constraints. Shapes directly below some
; frame are left-top constrained. Else (shapes in a group) are scaled.
(defn default-constraints-h
[shape]
(if (= (:parent-id shape) uuid/zero)
nil
(if (= (:parent-id shape) (:frame-id shape))
:left
:scale)))
(defn default-constraints-v
[shape]
(if (= (:parent-id shape) uuid/zero)
nil
(if (= (:parent-id shape) (:frame-id shape))
:top
:scale)))
;; Page Data related
(s/def :internal.shape/blocked boolean?)
(s/def :internal.shape/collapsed boolean?)
(s/def :internal.shape/fill-color string?)
(s/def :internal.shape/fill-opacity ::us/safe-number)
(s/def :internal.shape/fill-color-gradient (s/nilable ::gradient))
(s/def :internal.shape/fill-color-ref-file (s/nilable uuid?))
(s/def :internal.shape/fill-color-ref-id (s/nilable uuid?))
(s/def :internal.shape/hide-fill-on-export boolean?)
(s/def :internal.shape/font-family string?)
(s/def :internal.shape/font-size ::us/safe-integer)
(s/def :internal.shape/font-style string?)
(s/def :internal.shape/font-weight string?)
(s/def :internal.shape/hidden boolean?)
(s/def :internal.shape/letter-spacing ::us/safe-number)
(s/def :internal.shape/line-height ::us/safe-number)
(s/def :internal.shape/locked boolean?)
(s/def :internal.shape/page-id uuid?)
(s/def :internal.shape/proportion ::us/safe-number)
(s/def :internal.shape/proportion-lock boolean?)
(s/def :internal.shape/stroke-color string?)
(s/def :internal.shape/stroke-color-gradient (s/nilable ::gradient))
(s/def :internal.shape/stroke-color-ref-file (s/nilable uuid?))
(s/def :internal.shape/stroke-color-ref-id (s/nilable uuid?))
(s/def :internal.shape/stroke-opacity ::us/safe-number)
(s/def :internal.shape/stroke-style #{:solid :dotted :dashed :mixed :none :svg})
(def stroke-caps-line #{:round :square})
(def stroke-caps-marker #{:line-arrow :triangle-arrow :square-marker :circle-marker :diamond-marker})
(def stroke-caps (set/union stroke-caps-line stroke-caps-marker))
(s/def :internal.shape/stroke-cap-start stroke-caps)
(s/def :internal.shape/stroke-cap-end stroke-caps)
(defn has-caps?
[shape]
(= (:type shape) :path))
(s/def :internal.shape/stroke-width ::us/safe-number)
(s/def :internal.shape/stroke-alignment #{:center :inner :outer})
(s/def :internal.shape/text-align #{"left" "right" "center" "justify"})
(s/def :internal.shape/x ::us/safe-number)
(s/def :internal.shape/y ::us/safe-number)
(s/def :internal.shape/cx ::us/safe-number)
(s/def :internal.shape/cy ::us/safe-number)
(s/def :internal.shape/width ::us/safe-number)
(s/def :internal.shape/height ::us/safe-number)
(s/def :internal.shape/index integer?)
(s/def :internal.shape/shadow ::shadow)
(s/def :internal.shape/blur ::blur)
(s/def :internal.shape/x1 ::us/safe-number)
(s/def :internal.shape/y1 ::us/safe-number)
(s/def :internal.shape/x2 ::us/safe-number)
(s/def :internal.shape/y2 ::us/safe-number)
(s/def :internal.shape.export/suffix string?)
(s/def :internal.shape.export/scale ::us/safe-number)
(s/def :internal.shape/export
(s/keys :req-un [::type
:internal.shape.export/suffix
:internal.shape.export/scale]))
(s/def :internal.shape/exports
(s/coll-of :internal.shape/export :kind vector?))
(s/def :internal.shape/selrect
(s/keys :req-un [:internal.shape/x
:internal.shape/y
:internal.shape/x1
:internal.shape/y1
:internal.shape/x2
:internal.shape/y2
:internal.shape/width
:internal.shape/height]))
(s/def :internal.shape/points
(s/every ::point :kind vector?))
(s/def :internal.shape/shapes
(s/every uuid? :kind vector?))
(s/def :internal.shape/transform ::matrix)
(s/def :internal.shape/transform-inverse ::matrix)
(s/def :internal.shape/opacity ::us/safe-number)
(s/def :internal.shape/blend-mode
#{:normal
:darken
:multiply
:color-burn
:lighten
:screen
:color-dodge
:overlay
:soft-light
:hard-light
:difference
:exclusion
:hue
:saturation
:color
:luminosity})
(s/def ::shape-attrs
(s/keys :opt-un [::id
::type
::name
::component-id
::component-file
::component-root?
::shape-ref
:internal.shape/selrect
:internal.shape/points
:internal.shape/blocked
:internal.shape/collapsed
:internal.shape/fill-color
:internal.shape/fill-opacity
:internal.shape/fill-color-gradient
:internal.shape/fill-color-ref-file
:internal.shape/fill-color-ref-id
:internal.shape/font-family
:internal.shape/font-size
:internal.shape/font-style
:internal.shape/font-weight
:internal.shape/hidden
:internal.shape/letter-spacing
:internal.shape/line-height
:internal.shape/locked
:internal.shape/proportion
:internal.shape/proportion-lock
:internal.shape/constraints-h
:internal.shape/constraints-v
:internal.shape/fixed-scroll
::ctr/rx
::ctr/ry
::ctr/r1
::ctr/r2
::ctr/r3
::ctr/r4
:internal.shape/x
:internal.shape/y
:internal.shape/exports
:internal.shape/shapes
:internal.shape/stroke-color
:internal.shape/stroke-color-ref-file
:internal.shape/stroke-color-ref-id
:internal.shape/stroke-opacity
:internal.shape/stroke-style
:internal.shape/stroke-width
:internal.shape/stroke-alignment
:internal.shape/stroke-cap-start
:internal.shape/stroke-cap-end
:internal.shape/text-align
:internal.shape/transform
:internal.shape/transform-inverse
:internal.shape/width
:internal.shape/height
::cti/interactions
:internal.shape/masked-group?
:internal.shape/shadow
:internal.shape/blur
:internal.shape/opacity
:internal.shape/blend-mode]))
(s/def :internal.shape.text/type #{"root" "paragraph-set" "paragraph"})
(s/def :internal.shape.text/children
(s/coll-of :internal.shape.text/content
:kind vector?
:min-count 1))
(s/def :internal.shape.text/text string?)
(s/def :internal.shape.text/key string?)
(s/def :internal.shape.text/content
(s/nilable
(s/or :text-container
(s/keys :req-un [:internal.shape.text/type
:internal.shape.text/children]
:opt-un [:internal.shape.text/key])
:text-content
(s/keys :req-un [:internal.shape.text/text]))))
(s/def :internal.shape.path/command keyword?)
(s/def :internal.shape.path/params
(s/nilable (s/map-of keyword? any?)))
(s/def :internal.shape.path/command-item
(s/keys :req-un [:internal.shape.path/command]
:opt-un [:internal.shape.path/params]))
(s/def :internal.shape.path/content
(s/coll-of :internal.shape.path/command-item :kind vector?))
(defmulti shape-spec :type)
(defmethod shape-spec :default [_]
(s/spec ::shape-attrs))
(defmethod shape-spec :text [_]
(s/and ::shape-attrs
(s/keys :opt-un [:internal.shape.text/content])))
(defmethod shape-spec :path [_]
(s/and ::shape-attrs
(s/keys :opt-un [:internal.shape.path/content])))
(defmethod shape-spec :frame [_]
(s/and ::shape-attrs
(s/keys :opt-un [:internal.shape/hide-fill-on-export])))
(s/def ::shape
(s/and (s/multi-spec shape-spec :type)
#(contains? % :name)
#(contains? % :type)))
(s/def :internal.page/objects (s/map-of uuid? ::shape))
(s/def ::page
(s/keys :req-un [::id
::name
::cto/options
:internal.page/objects]))
(s/def ::recent-color
(s/keys :opt-un [:internal.color/value
:internal.color/color
:internal.color/opacity
:internal.color/gradient]))
(s/def :internal.media-object/name ::string)
(s/def :internal.media-object/width ::us/safe-integer)
(s/def :internal.media-object/height ::us/safe-integer)
(s/def :internal.media-object/mtype ::string)
(s/def ::media-object
(s/keys :req-un [::id
::name
:internal.media-object/width
:internal.media-object/height
:internal.media-object/mtype]))
(s/def ::media-object-update
(s/keys :req-un [::id]
:opt-un [::name
:internal.media-object/width
:internal.media-object/height
:internal.media-object/mtype]))
(s/def :internal.file/colors
(s/map-of ::uuid ::color))
(s/def :internal.file/recent-colors
(s/coll-of ::recent-color :kind vector?))
(s/def :internal.typography/id ::id)
(s/def :internal.typography/name ::string)
(s/def :internal.typography/path (s/nilable ::string))
(s/def :internal.typography/font-id ::string)
(s/def :internal.typography/font-family ::string)
(s/def :internal.typography/font-variant-id ::string)
(s/def :internal.typography/font-size ::string)
(s/def :internal.typography/font-weight ::string)
(s/def :internal.typography/font-style ::string)
(s/def :internal.typography/line-height ::string)
(s/def :internal.typography/letter-spacing ::string)
(s/def :internal.typography/text-transform ::string)
(s/def ::typography
(s/keys :req-un [:internal.typography/id
:internal.typography/name
:internal.typography/font-id
:internal.typography/font-family
:internal.typography/font-variant-id
:internal.typography/font-size
:internal.typography/font-weight
:internal.typography/font-style
:internal.typography/line-height
:internal.typography/letter-spacing
:internal.typography/text-transform]
:opt-un [:internal.typography/path]))
(s/def :internal.file/pages
(s/coll-of ::uuid :kind vector?))
(s/def :internal.file/media
(s/map-of ::uuid ::media-object))
(s/def :internal.file/pages-index
(s/map-of ::uuid ::page))
(s/def ::data
(s/keys :req-un [:internal.file/pages-index
:internal.file/pages]
:opt-un [:internal.file/colors
:internal.file/recent-colors
:internal.file/media]))
(s/def :internal.container/type #{:page :component})
(s/def ::container
(s/keys :req-un [:internal.container/type
::id
::name
:internal.page/objects]))
(defmulti operation-spec :type)
(s/def :internal.operations.set/attr keyword?)
(s/def :internal.operations.set/val any?)
(s/def :internal.operations.set/touched
(s/nilable (s/every keyword? :kind set?)))
(s/def :internal.operations.set/remote-synced?
(s/nilable boolean?))
(defmethod operation-spec :set [_]
(s/keys :req-un [:internal.operations.set/attr
:internal.operations.set/val]))
(defmethod operation-spec :set-touched [_]
(s/keys :req-un [:internal.operations.set/touched]))
(defmethod operation-spec :set-remote-synced [_]
(s/keys :req-un [:internal.operations.set/remote-synced?]))
(defmulti change-spec :type)
(s/def :internal.changes.set-option/option any?)
(s/def :internal.changes.set-option/value any?)
(defmethod change-spec :set-option [_]
(s/keys :req-un [:internal.changes.set-option/option
:internal.changes.set-option/value]))
(s/def :internal.changes.add-obj/obj ::shape)
(defn- valid-container-id-frame?
[o]
(or (and (contains? o :page-id)
(not (contains? o :component-id))
(some? (:frame-id o)))
(and (contains? o :component-id)
(not (contains? o :page-id))
(nil? (:frame-id o)))))
(defn- valid-container-id?
[o]
(or (and (contains? o :page-id)
(not (contains? o :component-id)))
(and (contains? o :component-id)
(not (contains? o :page-id)))))
(defmethod change-spec :add-obj [_]
(s/and (s/keys :req-un [::id :internal.changes.add-obj/obj]
:opt-un [::page-id ::component-id ::parent-id ::frame-id])
valid-container-id-frame?))
(s/def ::operation (s/multi-spec operation-spec :type))
(s/def ::operations (s/coll-of ::operation))
(defmethod change-spec :mod-obj [_]
(s/and (s/keys :req-un [::id ::operations]
:opt-un [::page-id ::component-id])
valid-container-id?))
(defmethod change-spec :del-obj [_]
(s/and (s/keys :req-un [::id]
:opt-un [::page-id ::component-id])
valid-container-id?))
(s/def :internal.changes.reg-objects/shapes
(s/coll-of uuid? :kind vector?))
(defmethod change-spec :reg-objects [_]
(s/and (s/keys :req-un [:internal.changes.reg-objects/shapes]
:opt-un [::page-id ::component-id])
valid-container-id?))
(defmethod change-spec :mov-objects [_]
(s/and (s/keys :req-un [::parent-id :internal.shape/shapes]
:opt-un [::page-id ::component-id ::index])
valid-container-id?))
(defmethod change-spec :add-page [_]
(s/or :empty (s/keys :req-un [::id ::name])
:complete (s/keys :req-un [::page])))
(defmethod change-spec :mod-page [_]
(s/keys :req-un [::id ::name]))
(defmethod change-spec :del-page [_]
(s/keys :req-un [::id]))
(defmethod change-spec :mov-page [_]
(s/keys :req-un [::id ::index]))
(defmethod change-spec :add-color [_]
(s/keys :req-un [::color]))
(defmethod change-spec :mod-color [_]
(s/keys :req-un [::color]))
(defmethod change-spec :del-color [_]
(s/keys :req-un [::id]))
(s/def :internal.changes.add-recent-color/color ::recent-color)
(defmethod change-spec :add-recent-color [_]
(s/keys :req-un [:internal.changes.add-recent-color/color]))
(s/def :internal.changes.media/object ::media-object)
(defmethod change-spec :add-media [_]
(s/keys :req-un [:internal.changes.media/object]))
(s/def :internal.changes.media.mod/object ::media-object-update)
(defmethod change-spec :mod-media [_]
(s/keys :req-un [:internal.changes.media.mod/object]))
(defmethod change-spec :del-media [_]
(s/keys :req-un [::id]))
(s/def :internal.changes.add-component/shapes
(s/coll-of ::shape))
(defmethod change-spec :add-component [_]
(s/keys :req-un [::id ::name :internal.changes.add-component/shapes]
:opt-un [::path]))
(defmethod change-spec :mod-component [_]
(s/keys :req-un [::id]
:opt-un [::name :internal.changes.add-component/shapes]))
(defmethod change-spec :del-component [_]
(s/keys :req-un [::id]))
(s/def :internal.changes.typography/typography ::typography)
(defmethod change-spec :add-typography [_]
(s/keys :req-un [:internal.changes.typography/typography]))
(defmethod change-spec :mod-typography [_]
(s/keys :req-un [:internal.changes.typography/typography]))
(defmethod change-spec :del-typography [_]
(s/keys :req-un [:internal.typography/id]))
(s/def ::change (s/multi-spec change-spec :type))
(s/def ::changes (s/coll-of ::change))

View file

@ -16,7 +16,6 @@
;; because of some strange interaction with cljs.spec.alpha and
;; modules splitting.
[app.common.exceptions :as ex]
[app.common.geom.point :as gpt]
[app.common.uuid :as uuid]
[cuerdas.core :as str]
[expound.alpha]))
@ -110,7 +109,6 @@
(s/def ::not-empty-string (s/and string? #(not (str/empty? %))))
(s/def ::url string?)
(s/def ::fn fn?)
(s/def ::point gpt/point?)
(s/def ::id ::uuid)
(defn bytes?

View file

@ -0,0 +1,19 @@
;; 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) UXBOX Labs SL
(ns app.common.spec.blur
(:require
[app.common.spec :as us]
[clojure.spec.alpha :as s]))
(s/def ::id uuid?)
(s/def ::type #{:layer-blur})
(s/def ::value ::us/safe-number)
(s/def ::hidden boolean?)
(s/def ::blur
(s/keys :req-un [::id ::type ::value ::hidden]))

View file

@ -0,0 +1,165 @@
;; 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) UXBOX Labs SL
(ns app.common.spec.change
(:require
[app.common.spec.color :as color]
[app.common.spec.file :as file]
[app.common.spec.page :as page]
[app.common.spec.shape :as shape]
[app.common.spec.typography :as typg]
[clojure.spec.alpha :as s]))
(s/def ::index integer?)
(s/def ::id uuid?)
(s/def ::parent-id uuid?)
(s/def ::frame-id uuid?)
(s/def ::page-id uuid?)
(s/def ::component-id uuid?)
(s/def ::name string?)
(defmulti operation-spec :type)
(s/def :internal.operations.set/attr keyword?)
(s/def :internal.operations.set/val any?)
(s/def :internal.operations.set/touched
(s/nilable (s/every keyword? :kind set?)))
(s/def :internal.operations.set/remote-synced?
(s/nilable boolean?))
(defmethod operation-spec :set [_]
(s/keys :req-un [:internal.operations.set/attr
:internal.operations.set/val]))
(defmethod operation-spec :set-touched [_]
(s/keys :req-un [:internal.operations.set/touched]))
(defmethod operation-spec :set-remote-synced [_]
(s/keys :req-un [:internal.operations.set/remote-synced?]))
(defmulti change-spec :type)
(s/def :internal.changes.set-option/option any?)
(s/def :internal.changes.set-option/value any?)
(defmethod change-spec :set-option [_]
(s/keys :req-un [:internal.changes.set-option/option
:internal.changes.set-option/value]))
(s/def :internal.changes.add-obj/obj ::shape/shape)
(defn- valid-container-id-frame?
[o]
(or (and (contains? o :page-id)
(not (contains? o :component-id))
(some? (:frame-id o)))
(and (contains? o :component-id)
(not (contains? o :page-id))
(nil? (:frame-id o)))))
(defn- valid-container-id?
[o]
(or (and (contains? o :page-id)
(not (contains? o :component-id)))
(and (contains? o :component-id)
(not (contains? o :page-id)))))
(defmethod change-spec :add-obj [_]
(s/and (s/keys :req-un [::id :internal.changes.add-obj/obj]
:opt-un [::page-id ::component-id ::parent-id ::frame-id])
valid-container-id-frame?))
(s/def ::operation (s/multi-spec operation-spec :type))
(s/def ::operations (s/coll-of ::operation))
(defmethod change-spec :mod-obj [_]
(s/and (s/keys :req-un [::id ::operations]
:opt-un [::page-id ::component-id])
valid-container-id?))
(defmethod change-spec :del-obj [_]
(s/and (s/keys :req-un [::id]
:opt-un [::page-id ::component-id])
valid-container-id?))
(defmethod change-spec :reg-objects [_]
(s/and (s/keys :req-un [::shape/shapes]
:opt-un [::page-id ::component-id])
valid-container-id?))
(defmethod change-spec :mov-objects [_]
(s/and (s/keys :req-un [::parent-id ::shape/shapes]
:opt-un [::page-id ::component-id ::index])
valid-container-id?))
(defmethod change-spec :add-page [_]
(s/or :empty (s/keys :req-un [::id ::name])
:complete (s/keys :req-un [::page/page])))
(defmethod change-spec :mod-page [_]
(s/keys :req-un [::id ::name]))
(defmethod change-spec :del-page [_]
(s/keys :req-un [::id]))
(defmethod change-spec :mov-page [_]
(s/keys :req-un [::id ::index]))
(defmethod change-spec :add-color [_]
(s/keys :req-un [::color/color]))
(defmethod change-spec :mod-color [_]
(s/keys :req-un [::color/color]))
(defmethod change-spec :del-color [_]
(s/keys :req-un [::id]))
(s/def :internal.changes.add-recent-color/color ::color/recent-color)
(defmethod change-spec :add-recent-color [_]
(s/keys :req-un [:internal.changes.add-recent-color/color]))
(s/def :internal.changes.media/object ::file/media-object)
(defmethod change-spec :add-media [_]
(s/keys :req-un [:internal.changes.media/object]))
(s/def :internal.changes.media.mod/object
(s/and ::file/media-object #(contains? % :id)))
(defmethod change-spec :mod-media [_]
(s/keys :req-un [:internal.changes.media.mod/object]))
(defmethod change-spec :del-media [_]
(s/keys :req-un [::id]))
(s/def :internal.changes.add-component/shapes
(s/coll-of ::shape/shape))
(defmethod change-spec :add-component [_]
(s/keys :req-un [::id ::name :internal.changes.add-component/shapes]
:opt-un [::path]))
(defmethod change-spec :mod-component [_]
(s/keys :req-un [::id]
:opt-un [::name :internal.changes.add-component/shapes]))
(defmethod change-spec :del-component [_]
(s/keys :req-un [::id]))
(defmethod change-spec :add-typography [_]
(s/keys :req-un [::typg/typography]))
(defmethod change-spec :mod-typography [_]
(s/keys :req-un [::typg/typography]))
(defmethod change-spec :del-typography [_]
(s/keys :req-un [::typg/id]))
(s/def ::change (s/multi-spec change-spec :type))
(s/def ::changes (s/coll-of ::change))

View file

@ -0,0 +1,75 @@
;; 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) UXBOX Labs SL
(ns app.common.spec.color
(:require
[app.common.spec :as us]
[clojure.spec.alpha :as s]))
;; TODO: waiting clojure 1.11 to rename this all :internal.stuff to a
;; more consistent name.
;; TODO: maybe define ::color-hex-string with proper hex color spec?
;; --- GRADIENTS
(s/def ::id uuid?)
(s/def :internal.gradient.stop/color string?)
(s/def :internal.gradient.stop/opacity ::us/safe-number)
(s/def :internal.gradient.stop/offset ::us/safe-number)
(s/def :internal.gradient/type #{:linear :radial})
(s/def :internal.gradient/start-x ::us/safe-number)
(s/def :internal.gradient/start-y ::us/safe-number)
(s/def :internal.gradient/end-x ::us/safe-number)
(s/def :internal.gradient/end-y ::us/safe-number)
(s/def :internal.gradient/width ::us/safe-number)
(s/def :internal.gradient/stop
(s/keys :req-un [:internal.gradient.stop/color
:internal.gradient.stop/opacity
:internal.gradient.stop/offset]))
(s/def :internal.gradient/stops
(s/coll-of :internal.gradient/stop :kind vector?))
(s/def ::gradient
(s/keys :req-un [:internal.gradient/type
:internal.gradient/start-x
:internal.gradient/start-y
:internal.gradient/end-x
:internal.gradient/end-y
:internal.gradient/width
:internal.gradient/stops]))
;;; --- COLORS
(s/def :internal.color/name string?)
(s/def :internal.color/path (s/nilable string?))
(s/def :internal.color/value (s/nilable string?))
(s/def :internal.color/color (s/nilable string?))
(s/def :internal.color/opacity (s/nilable ::us/safe-number))
(s/def :internal.color/gradient (s/nilable ::gradient))
(s/def ::color
(s/keys :opt-un [::id
:internal.color/name
:internal.color/path
:internal.color/value
:internal.color/color
:internal.color/opacity
:internal.color/gradient]))
(s/def ::recent-color
(s/keys :opt-un [:internal.color/value
:internal.color/color
:internal.color/opacity
:internal.color/gradient]))

View file

@ -0,0 +1,22 @@
;; 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) UXBOX Labs SL
(ns app.common.spec.export
(:require
[app.common.spec :as us]
[clojure.spec.alpha :as s]))
(s/def ::suffix string?)
(s/def ::scale ::us/safe-number)
(s/def ::type keyword?)
(s/def ::export
(s/keys :req-un [::type
::suffix
::scale]))

View file

@ -0,0 +1,54 @@
;; 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) UXBOX Labs SL
(ns app.common.spec.file
(:require
[app.common.spec :as us]
[app.common.spec.color :as color]
[app.common.spec.page :as page]
[app.common.spec.typography]
[clojure.spec.alpha :as s]))
(s/def :internal.media-object/name string?)
(s/def :internal.media-object/width ::us/safe-integer)
(s/def :internal.media-object/height ::us/safe-integer)
(s/def :internal.media-object/mtype string?)
(s/def ::media-object
(s/keys :req-un [::id
::name
:internal.media-object/width
:internal.media-object/height
:internal.media-object/mtype]))
(s/def ::colors
(s/map-of uuid? ::color/color))
(s/def ::recent-colors
(s/coll-of ::color/recent-color :kind vector?))
(s/def ::typographies
(s/map-of uuid? :app.common.spec.typography/typography))
(s/def ::pages
(s/coll-of uuid? :kind vector?))
(s/def ::media
(s/map-of uuid? ::media-object))
(s/def ::pages-index
(s/map-of uuid? ::page/page))
(s/def ::components
(s/map-of uuid? ::page/container))
(s/def ::data
(s/keys :req-un [::pages-index
::pages]
:opt-un [::colors
::recent-colors
::typographies
::media]))

View file

@ -4,7 +4,7 @@
;;
;; Copyright (c) UXBOX Labs SL
(ns app.common.types.interactions
(ns app.common.spec.interactions
(:require
[app.common.data :as d]
[app.common.geom.point :as gpt]
@ -100,7 +100,7 @@
:bottom-left
:bottom-right
:bottom-center})
(s/def ::overlay-position ::us/point)
(s/def ::overlay-position ::gpt/point)
(s/def ::url ::us/string)
(s/def ::close-click-outside ::us/boolean)
(s/def ::background-overlay ::us/boolean)

View file

@ -0,0 +1,129 @@
;; 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) UXBOX Labs SL
(ns app.common.spec.page
(:require
[app.common.data :as d]
[app.common.spec :as us]
[app.common.spec.shape :as shape]
[clojure.spec.alpha :as s]))
;; --- Grid options
(s/def :internal.grid.color/color string?)
(s/def :internal.grid.color/opacity ::us/safe-number)
(s/def :internal.grid/size (s/nilable ::us/safe-integer))
(s/def :internal.grid/item-length (s/nilable ::us/safe-number))
(s/def :internal.grid/color (s/keys :req-un [:internal.grid.color/color
:internal.grid.color/opacity]))
(s/def :internal.grid/type #{:stretch :left :center :right})
(s/def :internal.grid/gutter (s/nilable ::us/safe-integer))
(s/def :internal.grid/margin (s/nilable ::us/safe-integer))
(s/def :internal.grid/square
(s/keys :req-un [:internal.grid/size
:internal.grid/color]))
(s/def :internal.grid/column
(s/keys :req-un [:internal.grid/color]
:opt-un [:internal.grid/size
:internal.grid/type
:internal.grid/item-length
:internal.grid/margin
:internal.grid/gutter]))
(s/def :internal.grid/row :internal.grid/column)
(s/def ::saved-grids
(s/keys :opt-un [:internal.grid/square
:internal.grid/row
:internal.grid/column]))
;; --- Background options
(s/def ::background string?)
;; --- Flow options
(s/def :internal.flow/id uuid?)
(s/def :internal.flow/name string?)
(s/def :internal.flow/starting-frame uuid?)
(s/def ::flow
(s/keys :req-un [:internal.flow/id
:internal.flow/name
:internal.flow/starting-frame]))
(s/def ::flows
(s/coll-of ::flow :kind vector?))
;; --- Guides
(s/def :internal.guides/id uuid?)
(s/def :internal.guides/axis #{:x :y})
(s/def :internal.guides/position ::us/safe-number)
(s/def :internal.guides/frame-id (s/nilable uuid?))
(s/def ::guide
(s/keys :req-un [:internal.guides/id
:internal.guides/axis
:internal.guides/position]
:opt-un [:internal.guides/frame-id]))
(s/def ::guides
(s/map-of uuid? ::guide))
;; --- Page Options
(s/def ::options
(s/keys :opt-un [::background
::saved-grids
::flows
::guides]))
;; --- Page
(s/def ::id uuid?)
(s/def ::name string?)
(s/def ::objects (s/map-of uuid? ::shape/shape))
(s/def ::page
(s/keys :req-un [::id ::name ::objects ::options]))
(s/def ::type #{:page :component})
(s/def ::path (s/nilable string?))
(s/def ::container
(s/keys :req-un [::id ::name ::objects]
:opt-un [::type ::path]))
;; --- Helpers for flow
(defn rename-flow
[flow name]
(assoc flow :name name))
(defn add-flow
[flows flow]
(conj (or flows []) flow))
(defn remove-flow
[flows flow-id]
(d/removev #(= (:id %) flow-id) flows))
(defn update-flow
[flows flow-id update-fn]
(let [index (d/index-of-pred flows #(= (:id %) flow-id))]
(update flows index update-fn)))
(defn get-frame-flow
[flows frame-id]
(d/seek #(= (:starting-frame %) frame-id) flows))

View file

@ -4,7 +4,7 @@
;;
;; Copyright (c) UXBOX Labs SL
(ns app.common.types.radius
(ns app.common.spec.radius
(:require
[app.common.spec :as us]
[clojure.spec.alpha :as s]))

View file

@ -0,0 +1,37 @@
;; 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) UXBOX Labs SL
(ns app.common.spec.shadow
(:require
[app.common.spec :as us]
[app.common.spec.color :as color]
[clojure.spec.alpha :as s]))
;;; SHADOW EFFECT
(s/def ::id uuid?)
(s/def ::style #{:drop-shadow :inner-shadow})
(s/def ::color ::color/color)
(s/def ::offset-x ::us/safe-number)
(s/def ::offset-y ::us/safe-number)
(s/def ::blur ::us/safe-number)
(s/def ::spread ::us/safe-number)
(s/def ::hidden boolean?)
(s/def ::shadow-props
(s/keys :req-un [:internal.shadow/id
:internal.shadow/style
:internal.shadow/color
:internal.shadow/offset-x
:internal.shadow/offset-y
:internal.shadow/blur
:internal.shadow/spread
:internal.shadow/hidden]))
(s/def ::shadow
(s/coll-of ::shadow-props :kind vector?))

View file

@ -0,0 +1,241 @@
;; 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) UXBOX Labs SL
(ns app.common.spec.shape
(:require
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.spec :as us]
[app.common.spec.blur :as blur]
[app.common.spec.color :as color]
[app.common.spec.export :as export]
[app.common.spec.interactions :as cti]
[app.common.spec.radius :as radius]
[app.common.spec.shadow :as shadow]
[clojure.set :as set]
[clojure.spec.alpha :as s]))
;; --- Specs
(s/def ::frame-id uuid?)
(s/def ::id uuid?)
(s/def ::name string?)
(s/def ::path (s/nilable string?))
(s/def ::page-id uuid?)
(s/def ::parent-id uuid?)
(s/def ::string string?)
(s/def ::type keyword?)
(s/def ::uuid uuid?)
(s/def ::component-id uuid?)
(s/def ::component-file uuid?)
(s/def ::component-root? boolean?)
(s/def ::shape-ref uuid?)
;; Size constraints
(s/def ::constraints-h #{:left :right :leftright :center :scale})
(s/def ::constraints-v #{:top :bottom :topbottom :center :scale})
(s/def ::fixed-scroll boolean?)
;; Page Data related
(s/def ::blocked boolean?)
(s/def ::collapsed boolean?)
(s/def ::fill-color string?)
(s/def ::fill-opacity ::us/safe-number)
(s/def ::fill-color-gradient (s/nilable ::color/gradient))
(s/def ::fill-color-ref-file (s/nilable uuid?))
(s/def ::fill-color-ref-id (s/nilable uuid?))
(s/def ::hide-fill-on-export boolean?)
(s/def ::masked-group? boolean?)
(s/def ::font-family string?)
(s/def ::font-size ::us/safe-integer)
(s/def ::font-style string?)
(s/def ::font-weight string?)
(s/def ::hidden boolean?)
(s/def ::letter-spacing ::us/safe-number)
(s/def ::line-height ::us/safe-number)
(s/def ::locked boolean?)
(s/def ::page-id uuid?)
(s/def ::proportion ::us/safe-number)
(s/def ::proportion-lock boolean?)
(s/def ::stroke-color string?)
(s/def ::stroke-color-gradient (s/nilable ::color/gradient))
(s/def ::stroke-color-ref-file (s/nilable uuid?))
(s/def ::stroke-color-ref-id (s/nilable uuid?))
(s/def ::stroke-opacity ::us/safe-number)
(s/def ::stroke-style #{:solid :dotted :dashed :mixed :none :svg})
(def stroke-caps-line #{:round :square})
(def stroke-caps-marker #{:line-arrow :triangle-arrow :square-marker :circle-marker :diamond-marker})
(def stroke-caps (set/union stroke-caps-line stroke-caps-marker))
(s/def ::stroke-cap-start stroke-caps)
(s/def ::stroke-cap-end stroke-caps)
(s/def ::stroke-width ::us/safe-number)
(s/def ::stroke-alignment #{:center :inner :outer})
(s/def ::text-align #{"left" "right" "center" "justify"})
(s/def ::x ::us/safe-number)
(s/def ::y ::us/safe-number)
(s/def ::cx ::us/safe-number)
(s/def ::cy ::us/safe-number)
(s/def ::width ::us/safe-number)
(s/def ::height ::us/safe-number)
(s/def ::index integer?)
(s/def ::x1 ::us/safe-number)
(s/def ::y1 ::us/safe-number)
(s/def ::x2 ::us/safe-number)
(s/def ::y2 ::us/safe-number)
(s/def ::selrect
(s/keys :req-un [::x ::y ::x1 ::y1 ::x2 ::y2 ::width ::height]))
(s/def ::exports
(s/coll-of ::export/export :kind vector?))
(s/def ::points
(s/every ::gpt/point :kind vector?))
(s/def ::shapes
(s/every uuid? :kind vector?))
(s/def ::transform ::gmt/matrix)
(s/def ::transform-inverse ::gmt/matrix)
(s/def ::opacity ::us/safe-number)
(s/def ::blend-mode
#{:normal
:darken
:multiply
:color-burn
:lighten
:screen
:color-dodge
:overlay
:soft-light
:hard-light
:difference
:exclusion
:hue
:saturation
:color
:luminosity})
(s/def ::shape-attrs
(s/keys :opt-un [::id
::type
::name
::component-id
::component-file
::component-root?
::shape-ref
::selrect
::points
::blocked
::collapsed
::fill-color
::fill-opacity
::fill-color-gradient
::fill-color-ref-file
::fill-color-ref-id
::font-family
::font-size
::font-style
::font-weight
::hidden
::letter-spacing
::line-height
::locked
::proportion
::proportion-lock
::constraints-h
::constraints-v
::fixed-scroll
::radius/rx
::radius/ry
::radius/r1
::radius/r2
::radius/r3
::radius/r4
::x
::y
::exports
::shapes
::stroke-color
::stroke-color-ref-file
::stroke-color-ref-id
::stroke-opacity
::stroke-style
::stroke-width
::stroke-alignment
::stroke-cap-start
::stroke-cap-end
::text-align
::transform
::transform-inverse
::width
::height
::masked-group?
::cti/interactions
::shadow/shadow
::blur/blur
::opacity
::blend-mode]))
(s/def :internal.shape.text/type #{"root" "paragraph-set" "paragraph"})
(s/def :internal.shape.text/children
(s/coll-of :internal.shape.text/content
:kind vector?
:min-count 1))
(s/def :internal.shape.text/text string?)
(s/def :internal.shape.text/key string?)
(s/def :internal.shape.text/content
(s/nilable
(s/or :text-container
(s/keys :req-un [:internal.shape.text/type
:internal.shape.text/children]
:opt-un [:internal.shape.text/key])
:text-content
(s/keys :req-un [:internal.shape.text/text]))))
(s/def :internal.shape.path/command keyword?)
(s/def :internal.shape.path/params
(s/nilable (s/map-of keyword? any?)))
(s/def :internal.shape.path/command-item
(s/keys :req-un [:internal.shape.path/command]
:opt-un [:internal.shape.path/params]))
(s/def :internal.shape.path/content
(s/coll-of :internal.shape.path/command-item :kind vector?))
(defmulti shape-spec :type)
(defmethod shape-spec :default [_]
(s/spec ::shape-attrs))
(defmethod shape-spec :text [_]
(s/and ::shape-attrs
(s/keys :opt-un [:internal.shape.text/content])))
(defmethod shape-spec :path [_]
(s/and ::shape-attrs
(s/keys :opt-un [:internal.shape.path/content])))
(defmethod shape-spec :frame [_]
(s/and ::shape-attrs
(s/keys :opt-un [::hide-fill-on-export])))
(s/def ::shape
(s/and (s/multi-spec shape-spec :type)
#(contains? % :type)
#(contains? % :name)))

View file

@ -0,0 +1,38 @@
;; 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) UXBOX Labs SL
(ns app.common.spec.typography
(:require
[clojure.spec.alpha :as s]))
(s/def ::id uuid?)
(s/def ::name string?)
(s/def ::path (s/nilable string?))
(s/def ::font-id string?)
(s/def ::font-family string?)
(s/def ::font-variant-id string?)
(s/def ::font-size string?)
(s/def ::font-weight string?)
(s/def ::font-style string?)
(s/def ::line-height string?)
(s/def ::letter-spacing string?)
(s/def ::text-transform string?)
(s/def ::typography
(s/keys :req-un [::id
::name
::font-id
::font-family
::font-variant-id
::font-size
::font-weight
::font-style
::line-height
::letter-spacing
::text-transform]
:opt-un [::path]))

View file

@ -1,112 +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) UXBOX Labs SL
(ns app.common.types.page-options
(:require
[app.common.data :as d]
[app.common.spec :as us]
[clojure.spec.alpha :as s]))
;; --- Grid options
(s/def :artboard-grid.color/color ::us/string)
(s/def :artboard-grid.color/opacity ::us/safe-number)
(s/def :artboard-grid/size (s/nilable ::us/safe-integer))
(s/def :artboard-grid/item-length (s/nilable ::us/safe-number))
(s/def :artboard-grid/color (s/keys :req-un [:artboard-grid.color/color
:artboard-grid.color/opacity]))
(s/def :artboard-grid/type #{:stretch :left :center :right})
(s/def :artboard-grid/gutter (s/nilable ::us/safe-integer))
(s/def :artboard-grid/margin (s/nilable ::us/safe-integer))
(s/def :artboard-grid/square
(s/keys :req-un [:artboard-grid/size
:artboard-grid/color]))
(s/def :artboard-grid/column
(s/keys :req-un [:artboard-grid/color]
:opt-un [:artboard-grid/size
:artboard-grid/type
:artboard-grid/item-length
:artboard-grid/margin
:artboard-grid/gutter]))
(s/def :artboard-grid/row :artboard-grid/column)
(s/def ::saved-grids
(s/keys :opt-un [:artboard-grid/square
:artboard-grid/row
:artboard-grid/column]))
;; --- Background options
(s/def ::background string?)
;; --- Flow options
(s/def :interactions-flow/id ::us/uuid)
(s/def :interactions-flow/name ::us/string)
(s/def :interactions-flow/starting-frame ::us/uuid)
(s/def ::flow
(s/keys :req-un [:interactions-flow/id
:interactions-flow/name
:interactions-flow/starting-frame]))
(s/def ::flows
(s/coll-of ::flow :kind vector?))
;; --- Guides
(s/def :guides/id ::us/uuid)
(s/def :guides/axis #{:x :y})
(s/def :guides/position ::us/safe-number)
(s/def :guides/frame-id (s/nilable ::us/uuid))
(s/def ::guide
(s/keys :req-un [:guides/id
:guides/axis
:guides/position]
:opt-un [:guides/frame-id]))
(s/def ::guides
(s/map-of uuid? ::guide))
;; --- Options
(s/def ::options
(s/keys :opt-un [::background
::saved-grids
::flows
::guides]))
;; --- Helpers for flow
(defn rename-flow
[flow name]
(assoc flow :name name))
;; --- Helpers for flows
(defn add-flow
[flows flow]
(conj (or flows []) flow))
(defn remove-flow
[flows flow-id]
(d/removev #(= (:id %) flow-id) flows))
(defn update-flow
[flows flow-id update-fn]
(let [index (d/index-of-pred flows #(= (:id %) flow-id))]
(update flows index update-fn)))
(defn get-frame-flow
[flows frame-id]
(d/seek #(= (:starting-frame %) frame-id) flows))

View file

@ -4,68 +4,68 @@
;;
;; Copyright (c) UXBOX Labs SL
(ns app.common.types-interactions-test
(ns app.common.spec-interactions-test
(:require
[clojure.test :as t]
[clojure.pprint :refer [pprint]]
[app.common.exceptions :as ex]
[app.common.pages.init :as cpi]
[app.common.types.interactions :as cti]
[app.common.spec.interactions :as csi]
[app.common.uuid :as uuid]
[app.common.geom.point :as gpt]))
(t/deftest set-event-type
(let [interaction cti/default-interaction
(let [interaction csi/default-interaction
shape (cpi/make-minimal-shape :rect)
frame (cpi/make-minimal-shape :frame)]
(t/testing "Set event type unchanged"
(let [new-interaction
(cti/set-event-type interaction :click shape)]
(csi/set-event-type interaction :click shape)]
(t/is (= :click (:event-type new-interaction)))))
(t/testing "Set event type changed"
(let [new-interaction
(cti/set-event-type interaction :mouse-press shape)]
(csi/set-event-type interaction :mouse-press shape)]
(t/is (= :mouse-press (:event-type new-interaction)))))
(t/testing "Set after delay on non-frame"
(let [result (ex/try
(cti/set-event-type interaction :after-delay shape))]
(csi/set-event-type interaction :after-delay shape))]
(t/is (ex/exception? result))))
(t/testing "Set after delay on frame"
(let [new-interaction
(cti/set-event-type interaction :after-delay frame)]
(csi/set-event-type interaction :after-delay frame)]
(t/is (= :after-delay (:event-type new-interaction)))
(t/is (= 600 (:delay new-interaction)))))
(t/testing "Set after delay with previous data"
(let [interaction (assoc interaction :delay 300)
new-interaction
(cti/set-event-type interaction :after-delay frame)]
(csi/set-event-type interaction :after-delay frame)]
(t/is (= :after-delay (:event-type new-interaction)))
(t/is (= 300 (:delay new-interaction)))))))
(t/deftest set-action-type
(let [interaction cti/default-interaction]
(let [interaction csi/default-interaction]
(t/testing "Set action type unchanged"
(let [new-interaction
(cti/set-action-type interaction :navigate)]
(csi/set-action-type interaction :navigate)]
(t/is (= :navigate (:action-type new-interaction)))))
(t/testing "Set action type changed"
(let [new-interaction
(cti/set-action-type interaction :prev-screen)]
(csi/set-action-type interaction :prev-screen)]
(t/is (= :prev-screen (:action-type new-interaction)))))
(t/testing "Set action type navigate"
(let [interaction {:event-type :click
:action-type :prev-screen}
new-interaction
(cti/set-action-type interaction :navigate)]
(csi/set-action-type interaction :navigate)]
(t/is (= :navigate (:action-type new-interaction)))
(t/is (nil? (:destination new-interaction)))
(t/is (= false (:preserve-scroll new-interaction)))))
@ -77,14 +77,14 @@
:destination destination
:preserve-scroll true}
new-interaction
(cti/set-action-type interaction :navigate)]
(csi/set-action-type interaction :navigate)]
(t/is (= :navigate (:action-type new-interaction)))
(t/is (= destination (:destination new-interaction)))
(t/is (= true (:preserve-scroll new-interaction)))))
(t/testing "Set action type open-overlay"
(let [new-interaction
(cti/set-action-type interaction :open-overlay)]
(csi/set-action-type interaction :open-overlay)]
(t/is (= :open-overlay (:action-type new-interaction)))
(t/is (= :center (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 0 0) (:overlay-position new-interaction)))))
@ -93,14 +93,14 @@
(let [interaction (assoc interaction :overlay-pos-type :top-left
:overlay-position (gpt/point 100 200))
new-interaction
(cti/set-action-type interaction :open-overlay)]
(csi/set-action-type interaction :open-overlay)]
(t/is (= :open-overlay (:action-type new-interaction)))
(t/is (= :top-left (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 100 200) (:overlay-position new-interaction)))))
(t/testing "Set action type toggle-overlay"
(let [new-interaction
(cti/set-action-type interaction :toggle-overlay)]
(csi/set-action-type interaction :toggle-overlay)]
(t/is (= :toggle-overlay (:action-type new-interaction)))
(t/is (= :center (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 0 0) (:overlay-position new-interaction)))))
@ -109,14 +109,14 @@
(let [interaction (assoc interaction :overlay-pos-type :top-left
:overlay-position (gpt/point 100 200))
new-interaction
(cti/set-action-type interaction :toggle-overlay)]
(csi/set-action-type interaction :toggle-overlay)]
(t/is (= :toggle-overlay (:action-type new-interaction)))
(t/is (= :top-left (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 100 200) (:overlay-position new-interaction)))))
(t/testing "Set action type close-overlay"
(let [new-interaction
(cti/set-action-type interaction :close-overlay)]
(csi/set-action-type interaction :close-overlay)]
(t/is (= :close-overlay (:action-type new-interaction)))
(t/is (nil? (:destination new-interaction)))))
@ -124,89 +124,89 @@
(let [destination (uuid/next)
interaction (assoc interaction :destination destination)
new-interaction
(cti/set-action-type interaction :close-overlay)]
(csi/set-action-type interaction :close-overlay)]
(t/is (= :close-overlay (:action-type new-interaction)))
(t/is (= destination (:destination new-interaction)))))
(t/testing "Set action type prev-screen"
(let [new-interaction
(cti/set-action-type interaction :prev-screen)]
(csi/set-action-type interaction :prev-screen)]
(t/is (= :prev-screen (:action-type new-interaction)))))
(t/testing "Set action type open-url"
(let [new-interaction
(cti/set-action-type interaction :open-url)]
(csi/set-action-type interaction :open-url)]
(t/is (= :open-url (:action-type new-interaction)))
(t/is (= "" (:url new-interaction)))))
(t/testing "Set action type open-url with previous data"
(let [interaction (assoc interaction :url "https://example.com")
new-interaction
(cti/set-action-type interaction :open-url)]
(csi/set-action-type interaction :open-url)]
(t/is (= :open-url (:action-type new-interaction)))
(t/is (= "https://example.com" (:url new-interaction)))))))
(t/deftest option-delay
(let [frame (cpi/make-minimal-shape :frame)
i1 cti/default-interaction
i2 (cti/set-event-type i1 :after-delay frame)]
i1 csi/default-interaction
i2 (csi/set-event-type i1 :after-delay frame)]
(t/testing "Has delay"
(t/is (not (cti/has-delay i1)))
(t/is (cti/has-delay i2)))
(t/is (not (csi/has-delay i1)))
(t/is (csi/has-delay i2)))
(t/testing "Set delay"
(let [new-interaction (cti/set-delay i2 1000)]
(let [new-interaction (csi/set-delay i2 1000)]
(t/is (= 1000 (:delay new-interaction)))))))
(t/deftest option-destination
(let [destination (uuid/next)
i1 cti/default-interaction
i2 (cti/set-action-type i1 :prev-screen)
i3 (cti/set-action-type i1 :open-overlay)]
i1 csi/default-interaction
i2 (csi/set-action-type i1 :prev-screen)
i3 (csi/set-action-type i1 :open-overlay)]
(t/testing "Has destination"
(t/is (cti/has-destination i1))
(t/is (not (cti/has-destination i2))))
(t/is (csi/has-destination i1))
(t/is (not (csi/has-destination i2))))
(t/testing "Set destination"
(let [new-interaction (cti/set-destination i1 destination)]
(let [new-interaction (csi/set-destination i1 destination)]
(t/is (= destination (:destination new-interaction)))
(t/is (nil? (:overlay-pos-type new-interaction)))
(t/is (nil? (:overlay-position new-interaction)))))
(t/testing "Set destination of overlay"
(let [new-interaction (cti/set-destination i3 destination)]
(let [new-interaction (csi/set-destination i3 destination)]
(t/is (= destination (:destination new-interaction)))
(t/is (= :center (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 0 0) (:overlay-position new-interaction)))))))
(t/deftest option-preserve-scroll
(let [i1 cti/default-interaction
i2 (cti/set-action-type i1 :prev-screen)]
(let [i1 csi/default-interaction
i2 (csi/set-action-type i1 :prev-screen)]
(t/testing "Has preserve-scroll"
(t/is (cti/has-preserve-scroll i1))
(t/is (not (cti/has-preserve-scroll i2))))
(t/is (csi/has-preserve-scroll i1))
(t/is (not (csi/has-preserve-scroll i2))))
(t/testing "Set preserve-scroll"
(let [new-interaction (cti/set-preserve-scroll i1 true)]
(let [new-interaction (csi/set-preserve-scroll i1 true)]
(t/is (= true (:preserve-scroll new-interaction)))))))
(t/deftest option-url
(let [i1 cti/default-interaction
i2 (cti/set-action-type i1 :open-url)]
(let [i1 csi/default-interaction
i2 (csi/set-action-type i1 :open-url)]
(t/testing "Has url"
(t/is (not (cti/has-url i1)))
(t/is (cti/has-url i2)))
(t/is (not (csi/has-url i1)))
(t/is (csi/has-url i2)))
(t/testing "Set url"
(let [new-interaction (cti/set-url i2 "https://example.com")]
(let [new-interaction (csi/set-url i2 "https://example.com")]
(t/is (= "https://example.com" (:url new-interaction)))))))
@ -220,35 +220,35 @@
objects {(:id base-frame) base-frame
(:id overlay-frame) overlay-frame}
i1 cti/default-interaction
i2 (cti/set-action-type i1 :open-overlay)
i1 csi/default-interaction
i2 (csi/set-action-type i1 :open-overlay)
i3 (-> i1
(cti/set-action-type :open-overlay)
(cti/set-destination (:id overlay-frame)))]
(csi/set-action-type :open-overlay)
(csi/set-destination (:id overlay-frame)))]
(t/testing "Has overlay options"
(t/is (not (cti/has-overlay-opts i1)))
(t/is (cti/has-overlay-opts i2)))
(t/is (not (csi/has-overlay-opts i1)))
(t/is (csi/has-overlay-opts i2)))
(t/testing "Set overlay-pos-type without destination"
(let [new-interaction (cti/set-overlay-pos-type i2 :top-right base-frame objects)]
(let [new-interaction (csi/set-overlay-pos-type i2 :top-right base-frame objects)]
(t/is (= :top-right (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 0 0) (:overlay-position new-interaction)))))
(t/testing "Set overlay-pos-type with destination and auto"
(let [new-interaction (cti/set-overlay-pos-type i3 :bottom-right base-frame objects)]
(let [new-interaction (csi/set-overlay-pos-type i3 :bottom-right base-frame objects)]
(t/is (= :bottom-right (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 0 0) (:overlay-position new-interaction)))))
(t/testing "Set overlay-pos-type with destination and manual"
(let [new-interaction (cti/set-overlay-pos-type i3 :manual base-frame objects)]
(let [new-interaction (csi/set-overlay-pos-type i3 :manual base-frame objects)]
(t/is (= :manual (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 35 40) (:overlay-position new-interaction)))))
(t/testing "Toggle overlay-pos-type"
(let [new-interaction (cti/toggle-overlay-pos-type i3 :center base-frame objects)
new-interaction-2 (cti/toggle-overlay-pos-type new-interaction :center base-frame objects)
new-interaction-3 (cti/toggle-overlay-pos-type new-interaction-2 :top-right base-frame objects)]
(let [new-interaction (csi/toggle-overlay-pos-type i3 :center base-frame objects)
new-interaction-2 (csi/toggle-overlay-pos-type new-interaction :center base-frame objects)
new-interaction-3 (csi/toggle-overlay-pos-type new-interaction-2 :top-right base-frame objects)]
(t/is (= :manual (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 35 40) (:overlay-position new-interaction)))
(t/is (= :center (:overlay-pos-type new-interaction-2)))
@ -257,73 +257,73 @@
(t/is (= (gpt/point 0 0) (:overlay-position new-interaction-3)))))
(t/testing "Set overlay-position"
(let [new-interaction (cti/set-overlay-position i3 (gpt/point 50 60))]
(let [new-interaction (csi/set-overlay-position i3 (gpt/point 50 60))]
(t/is (= :manual (:overlay-pos-type new-interaction)))
(t/is (= (gpt/point 50 60) (:overlay-position new-interaction)))))
(t/testing "Set close-click-outside"
(let [new-interaction (cti/set-close-click-outside i3 true)]
(let [new-interaction (csi/set-close-click-outside i3 true)]
(t/is (not (:close-click-outside i3)))
(t/is (:close-click-outside new-interaction))))
(t/testing "Set background-overlay"
(let [new-interaction (cti/set-background-overlay i3 true)]
(let [new-interaction (csi/set-background-overlay i3 true)]
(t/is (not (:background-overlay i3)))
(t/is (:background-overlay new-interaction))))))
(t/deftest animation-checks
(let [i1 cti/default-interaction
i2 (cti/set-action-type i1 :open-overlay)
i3 (cti/set-action-type i1 :toggle-overlay)
i4 (cti/set-action-type i1 :close-overlay)
i5 (cti/set-action-type i1 :prev-screen)
i6 (cti/set-action-type i1 :open-url)]
(let [i1 csi/default-interaction
i2 (csi/set-action-type i1 :open-overlay)
i3 (csi/set-action-type i1 :toggle-overlay)
i4 (csi/set-action-type i1 :close-overlay)
i5 (csi/set-action-type i1 :prev-screen)
i6 (csi/set-action-type i1 :open-url)]
(t/testing "Has animation?"
(t/is (cti/has-animation? i1))
(t/is (cti/has-animation? i2))
(t/is (cti/has-animation? i3))
(t/is (cti/has-animation? i4))
(t/is (not (cti/has-animation? i5)))
(t/is (not (cti/has-animation? i6))))
(t/is (csi/has-animation? i1))
(t/is (csi/has-animation? i2))
(t/is (csi/has-animation? i3))
(t/is (csi/has-animation? i4))
(t/is (not (csi/has-animation? i5)))
(t/is (not (csi/has-animation? i6))))
(t/testing "Valid push?"
(t/is (cti/allow-push? (:action-type i1)))
(t/is (not (cti/allow-push? (:action-type i2))))
(t/is (not (cti/allow-push? (:action-type i3))))
(t/is (not (cti/allow-push? (:action-type i4))))
(t/is (not (cti/allow-push? (:action-type i5))))
(t/is (not (cti/allow-push? (:action-type i6)))))))
(t/is (csi/allow-push? (:action-type i1)))
(t/is (not (csi/allow-push? (:action-type i2))))
(t/is (not (csi/allow-push? (:action-type i3))))
(t/is (not (csi/allow-push? (:action-type i4))))
(t/is (not (csi/allow-push? (:action-type i5))))
(t/is (not (csi/allow-push? (:action-type i6)))))))
(t/deftest set-animation-type
(let [i1 cti/default-interaction
i2 (cti/set-animation-type i1 :dissolve)]
(let [i1 csi/default-interaction
i2 (csi/set-animation-type i1 :dissolve)]
(t/testing "Set animation type nil"
(let [new-interaction
(cti/set-animation-type i1 nil)]
(csi/set-animation-type i1 nil)]
(t/is (nil? (-> new-interaction :animation :animation-type)))))
(t/testing "Set animation type unchanged"
(let [new-interaction
(cti/set-animation-type i2 :dissolve)]
(csi/set-animation-type i2 :dissolve)]
(t/is (= :dissolve (-> new-interaction :animation :animation-type)))))
(t/testing "Set animation type changed"
(let [new-interaction
(cti/set-animation-type i2 :slide)]
(csi/set-animation-type i2 :slide)]
(t/is (= :slide (-> new-interaction :animation :animation-type)))))
(t/testing "Set animation type reset"
(let [new-interaction
(cti/set-animation-type i2 nil)]
(csi/set-animation-type i2 nil)]
(t/is (nil? (-> new-interaction :animation)))))
(t/testing "Set animation type dissolve"
(let [new-interaction
(cti/set-animation-type i1 :dissolve)]
(csi/set-animation-type i1 :dissolve)]
(t/is (= :dissolve (-> new-interaction :animation :animation-type)))
(t/is (= 300 (-> new-interaction :animation :duration)))
(t/is (= :linear (-> new-interaction :animation :easing)))))
@ -336,14 +336,14 @@
:direction :left
:offset-effect true})
new-interaction
(cti/set-animation-type interaction :dissolve)]
(csi/set-animation-type interaction :dissolve)]
(t/is (= :dissolve (-> new-interaction :animation :animation-type)))
(t/is (= 1000 (-> new-interaction :animation :duration)))
(t/is (= :ease-out (-> new-interaction :animation :easing)))))
(t/testing "Set animation type slide"
(let [new-interaction
(cti/set-animation-type i1 :slide)]
(csi/set-animation-type i1 :slide)]
(t/is (= :slide (-> new-interaction :animation :animation-type)))
(t/is (= 300 (-> new-interaction :animation :duration)))
(t/is (= :linear (-> new-interaction :animation :easing)))
@ -359,7 +359,7 @@
:direction :left
:offset-effect true})
new-interaction
(cti/set-animation-type interaction :slide)]
(csi/set-animation-type interaction :slide)]
(t/is (= :slide (-> new-interaction :animation :animation-type)))
(t/is (= 1000 (-> new-interaction :animation :duration)))
(t/is (= :ease-out (-> new-interaction :animation :easing)))
@ -369,7 +369,7 @@
(t/testing "Set animation type push"
(let [new-interaction
(cti/set-animation-type i1 :push)]
(csi/set-animation-type i1 :push)]
(t/is (= :push (-> new-interaction :animation :animation-type)))
(t/is (= 300 (-> new-interaction :animation :duration)))
(t/is (= :linear (-> new-interaction :animation :easing)))
@ -383,7 +383,7 @@
:direction :left
:offset-effect true})
new-interaction
(cti/set-animation-type interaction :push)]
(csi/set-animation-type interaction :push)]
(t/is (= :push (-> new-interaction :animation :animation-type)))
(t/is (= 1000 (-> new-interaction :animation :duration)))
(t/is (= :ease-out (-> new-interaction :animation :easing)))
@ -391,9 +391,9 @@
(t/deftest allowed-animation
(let [i1 (cti/set-action-type cti/default-interaction :open-overlay)
i2 (cti/set-action-type cti/default-interaction :close-overlay)
i3 (cti/set-action-type cti/default-interaction :toggle-overlay)]
(let [i1 (csi/set-action-type csi/default-interaction :open-overlay)
i2 (csi/set-action-type csi/default-interaction :close-overlay)
i3 (csi/set-action-type csi/default-interaction :toggle-overlay)]
(t/testing "Cannot use animation push for an overlay action"
(let [bad-interaction-1 (assoc i1 :animation {:animation-type :push
@ -408,72 +408,72 @@
:duration 1000
:easing :ease-out
:direction :left})]
(t/is (not (cti/allowed-animation? (:action-type bad-interaction-1)
(t/is (not (csi/allowed-animation? (:action-type bad-interaction-1)
(-> bad-interaction-1 :animation :animation-type))))
(t/is (not (cti/allowed-animation? (:action-type bad-interaction-2)
(t/is (not (csi/allowed-animation? (:action-type bad-interaction-2)
(-> bad-interaction-1 :animation :animation-type))))
(t/is (not (cti/allowed-animation? (:action-type bad-interaction-3)
(t/is (not (csi/allowed-animation? (:action-type bad-interaction-3)
(-> bad-interaction-1 :animation :animation-type))))))
(t/testing "Remove animation if moving to an forbidden state"
(let [interaction (cti/set-animation-type cti/default-interaction :push)
new-interaction (cti/set-action-type interaction :open-overlay)]
(let [interaction (csi/set-animation-type csi/default-interaction :push)
new-interaction (csi/set-action-type interaction :open-overlay)]
(t/is (nil? (:animation new-interaction)))))))
(t/deftest option-duration
(let [i1 cti/default-interaction
i2 (cti/set-animation-type cti/default-interaction :dissolve)]
(let [i1 csi/default-interaction
i2 (csi/set-animation-type csi/default-interaction :dissolve)]
(t/testing "Has duration?"
(t/is (not (cti/has-duration? i1)))
(t/is (cti/has-duration? i2)))
(t/is (not (csi/has-duration? i1)))
(t/is (csi/has-duration? i2)))
(t/testing "Set duration"
(let [new-interaction (cti/set-duration i2 1000)]
(let [new-interaction (csi/set-duration i2 1000)]
(t/is (= 1000 (-> new-interaction :animation :duration)))))))
(t/deftest option-easing
(let [i1 cti/default-interaction
i2 (cti/set-animation-type cti/default-interaction :dissolve)]
(let [i1 csi/default-interaction
i2 (csi/set-animation-type csi/default-interaction :dissolve)]
(t/testing "Has easing?"
(t/is (not (cti/has-easing? i1)))
(t/is (cti/has-easing? i2)))
(t/is (not (csi/has-easing? i1)))
(t/is (csi/has-easing? i2)))
(t/testing "Set easing"
(let [new-interaction (cti/set-easing i2 :ease-in)]
(let [new-interaction (csi/set-easing i2 :ease-in)]
(t/is (= :ease-in (-> new-interaction :animation :easing)))))))
(t/deftest option-way
(let [i1 cti/default-interaction
i2 (cti/set-animation-type cti/default-interaction :slide)
i3 (cti/set-action-type i2 :open-overlay)]
(let [i1 csi/default-interaction
i2 (csi/set-animation-type csi/default-interaction :slide)
i3 (csi/set-action-type i2 :open-overlay)]
(t/testing "Has way?"
(t/is (not (cti/has-way? i1)))
(t/is (cti/has-way? i2))
(t/is (not (cti/has-way? i3)))
(t/is (not (csi/has-way? i1)))
(t/is (csi/has-way? i2))
(t/is (not (csi/has-way? i3)))
(t/is (some? (-> i3 :animation :way)))) ; <- it exists but is ignored
(t/testing "Set way"
(let [new-interaction (cti/set-way i2 :out)]
(let [new-interaction (csi/set-way i2 :out)]
(t/is (= :out (-> new-interaction :animation :way)))))))
(t/deftest option-direction
(let [i1 cti/default-interaction
i2 (cti/set-animation-type cti/default-interaction :push)
i3 (cti/set-animation-type cti/default-interaction :dissolve)]
(let [i1 csi/default-interaction
i2 (csi/set-animation-type csi/default-interaction :push)
i3 (csi/set-animation-type csi/default-interaction :dissolve)]
(t/testing "Has direction?"
(t/is (not (cti/has-direction? i1)))
(t/is (cti/has-direction? i2)))
(t/is (not (csi/has-direction? i1)))
(t/is (csi/has-direction? i2)))
(t/testing "Set direction"
(let [new-interaction (cti/set-direction i2 :left)]
(let [new-interaction (csi/set-direction i2 :left)]
(t/is (= :left (-> new-interaction :animation :direction)))))
(t/testing "Invert direction"
@ -483,12 +483,12 @@
a-up (assoc a-right :direction :up)
a-down (assoc a-right :direction :down)
a-nil' (cti/invert-direction nil)
a-none' (cti/invert-direction a-none)
a-right' (cti/invert-direction a-right)
a-left' (cti/invert-direction a-left)
a-up' (cti/invert-direction a-up)
a-down' (cti/invert-direction a-down)]
a-nil' (csi/invert-direction nil)
a-none' (csi/invert-direction a-none)
a-right' (csi/invert-direction a-right)
a-left' (csi/invert-direction a-left)
a-up' (csi/invert-direction a-up)
a-down' (csi/invert-direction a-down)]
(t/is (nil? a-nil'))
(t/is (nil? (:direction a-none')))
@ -499,44 +499,44 @@
(t/deftest option-offset-effect
(let [i1 cti/default-interaction
i2 (cti/set-animation-type cti/default-interaction :slide)
i3 (cti/set-action-type i2 :open-overlay)]
(let [i1 csi/default-interaction
i2 (csi/set-animation-type csi/default-interaction :slide)
i3 (csi/set-action-type i2 :open-overlay)]
(t/testing "Has offset-effect"
(t/is (not (cti/has-offset-effect? i1)))
(t/is (cti/has-offset-effect? i2))
(t/is (not (cti/has-offset-effect? i3)))
(t/is (not (csi/has-offset-effect? i1)))
(t/is (csi/has-offset-effect? i2))
(t/is (not (csi/has-offset-effect? i3)))
(t/is (some? (-> i3 :animation :offset-effect)))) ; <- it exists but is ignored
(t/testing "Set offset-effect"
(let [new-interaction (cti/set-offset-effect i2 true)]
(let [new-interaction (csi/set-offset-effect i2 true)]
(t/is (= true (-> new-interaction :animation :offset-effect)))))))
(t/deftest modify-interactions
(let [i1 (cti/set-action-type cti/default-interaction :open-overlay)
i2 (cti/set-action-type cti/default-interaction :close-overlay)
i3 (cti/set-action-type cti/default-interaction :prev-screen)
(let [i1 (csi/set-action-type csi/default-interaction :open-overlay)
i2 (csi/set-action-type csi/default-interaction :close-overlay)
i3 (csi/set-action-type csi/default-interaction :prev-screen)
interactions [i1 i2]]
(t/testing "Add interaction to nil"
(let [new-interactions (cti/add-interaction nil i3)]
(let [new-interactions (csi/add-interaction nil i3)]
(t/is (= (count new-interactions) 1))
(t/is (= (:action-type (last new-interactions)) :prev-screen))))
(t/testing "Add interaction to normal"
(let [new-interactions (cti/add-interaction interactions i3)]
(let [new-interactions (csi/add-interaction interactions i3)]
(t/is (= (count new-interactions) 3))
(t/is (= (:action-type (last new-interactions)) :prev-screen))))
(t/testing "Remove interaction"
(let [new-interactions (cti/remove-interaction interactions 0)]
(let [new-interactions (csi/remove-interaction interactions 0)]
(t/is (= (count new-interactions) 1))
(t/is (= (:action-type (last new-interactions)) :close-overlay))))
(t/testing "Update interaction"
(let [new-interactions (cti/update-interaction interactions 1 #(cti/set-action-type % :open-url))]
(let [new-interactions (csi/update-interaction interactions 1 #(csi/set-action-type % :open-url))]
(t/is (= (count new-interactions) 2))
(t/is (= (:action-type (last new-interactions)) :open-url))))))
@ -556,16 +556,16 @@
ids-map {(:id frame1) (:id frame4)
(:id frame2) (:id frame5)}
i1 (cti/set-destination cti/default-interaction (:id frame1))
i2 (cti/set-destination cti/default-interaction (:id frame2))
i3 (cti/set-destination cti/default-interaction (:id frame3))
i4 (cti/set-destination cti/default-interaction nil)
i5 (cti/set-destination cti/default-interaction (:id frame6))
i1 (csi/set-destination csi/default-interaction (:id frame1))
i2 (csi/set-destination csi/default-interaction (:id frame2))
i3 (csi/set-destination csi/default-interaction (:id frame3))
i4 (csi/set-destination csi/default-interaction nil)
i5 (csi/set-destination csi/default-interaction (:id frame6))
interactions [i1 i2 i3 i4 i5]]
(t/testing "Remap interactions"
(let [new-interactions (cti/remap-interactions interactions ids-map objects)]
(let [new-interactions (csi/remap-interactions interactions ids-map objects)]
(t/is (= (count new-interactions) 4))
(t/is (= (:id frame4) (:destination (get new-interactions 0))))
(t/is (= (:id frame5) (:destination (get new-interactions 1))))

View file

@ -7,6 +7,7 @@
(ns app.main.data.comments
(:require
[app.common.data :as d]
[app.common.geom.point :as gpt]
[app.common.spec :as us]
[app.main.repo :as rp]
[beicon.core :as rx]
@ -24,7 +25,7 @@
(s/def ::page-id ::us/uuid)
(s/def ::page-name ::us/string)
(s/def ::participants (s/every ::us/uuid :kind set?))
(s/def ::position ::us/point)
(s/def ::position ::gpt/point)
(s/def ::project-id ::us/uuid)
(s/def ::seqn ::us/integer)
(s/def ::thread-id ::us/uuid)

View file

@ -7,9 +7,10 @@
(ns app.main.data.viewer
(:require
[app.common.data :as d]
[app.common.geom.point :as gpt]
[app.common.pages :as cp]
[app.common.spec :as us]
[app.common.types.interactions :as cti]
[app.common.spec.interactions :as cti]
[app.common.uuid :as uuid]
[app.main.data.comments :as dcm]
[app.main.data.fonts :as df]
@ -469,7 +470,7 @@
(defn open-overlay
[frame-id position close-click-outside background-overlay animation]
(us/verify ::us/uuid frame-id)
(us/verify ::us/point position)
(us/verify ::gpt/point position)
(us/verify (s/nilable ::us/boolean) close-click-outside)
(us/verify (s/nilable ::us/boolean) background-overlay)
(us/verify (s/nilable ::cti/animation) animation)
@ -494,7 +495,7 @@
(defn toggle-overlay
[frame-id position close-click-outside background-overlay animation]
(us/verify ::us/uuid frame-id)
(us/verify ::us/point position)
(us/verify ::gpt/point position)
(us/verify (s/nilable ::us/boolean) close-click-outside)
(us/verify (s/nilable ::us/boolean) background-overlay)
(us/verify (s/nilable ::cti/animation) animation)

View file

@ -17,8 +17,8 @@
[app.common.pages :as cp]
[app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph]
[app.common.pages.spec :as spec]
[app.common.spec :as us]
[app.common.spec.shape :as spec.shape]
[app.common.transit :as t]
[app.common.uuid :as uuid]
[app.config :as cfg]
@ -59,7 +59,7 @@
[cuerdas.core :as str]
[potok.core :as ptk]))
(s/def ::shape-attrs ::cp/shape-attrs)
(s/def ::shape-attrs ::spec.shape/shape)
(s/def ::set-of-string
(s/every string? :kind set?))
@ -925,13 +925,13 @@
:id id
:operations [{:type :set
:attr :constraints-h
:val (spec/default-constraints-h
(assoc obj :parent-id parent-id :frame-id frame-id))
:val (gsh/default-constraints-h
(assoc obj :parent-id parent-id :frame-id frame-id))
:ignore-touched true}
{:type :set
:attr :constraints-v
:val (spec/default-constraints-v
(assoc obj :parent-id parent-id :frame-id frame-id))
:val (gsh/default-constraints-v
(assoc obj :parent-id parent-id :frame-id frame-id))
:ignore-touched true}]}))
shapes-to-unconstraint)

View file

@ -9,8 +9,8 @@
[app.common.data :as d]
[app.common.logging :as log]
[app.common.pages :as cp]
[app.common.pages.spec :as spec]
[app.common.spec :as us]
[app.common.spec.change :as spec.change]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[app.main.store :as st]
@ -137,8 +137,8 @@
[:workspace-data]
[:workspace-libraries file-id :data])]
(try
(us/assert ::spec/changes redo-changes)
(us/assert ::spec/changes undo-changes)
(us/assert ::spec.change/changes redo-changes)
(us/assert ::spec.change/changes undo-changes)
;; (prn "====== commit-changes ======" path)
;; (cljs.pprint/pprint redo-changes)

View file

@ -12,8 +12,9 @@
[app.common.logging :as log]
[app.common.pages :as cp]
[app.common.spec :as us]
[app.common.types.interactions :as cti]
[app.common.types.page-options :as cto]
[app.common.spec.interactions :as csi]
[app.common.spec.page :as csp]
[app.common.spec.shape :as spec.shape]
[app.common.uuid :as uuid]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.state-helpers :as wsh]
@ -27,7 +28,7 @@
;; Change this to :info :debug or :trace to debug this module
(log/set-level! :warn)
(s/def ::shape-attrs ::cp/shape-attrs)
(s/def ::shape-attrs ::spec.shape/shape)
(s/def ::set-of-string (s/every string? :kind set?))
(s/def ::ordered-set-of-uuid (s/every uuid? :kind d/ordered-set?))
@ -409,7 +410,7 @@
interacting-shapes
(filter (fn [shape]
(let [interactions (:interactions shape)]
(some #(and (cti/has-destination %)
(some #(and (csi/has-destination %)
(contains? ids (:destination %)))
interactions)))
(vals objects))
@ -482,7 +483,7 @@
:operations [{:type :set
:attr :interactions
:val (vec (remove (fn [interaction]
(and (cti/has-destination interaction)
(and (csi/has-destination interaction)
(contains? ids (:destination interaction))))
(:interactions obj)))}]})))
mk-mod-int-add-xf
@ -501,7 +502,7 @@
{:type :set-option
:page-id page-id
:option :flows
:value (cto/remove-flow flows (:id flow))})))
:value (csp/remove-flow flows (:id flow))})))
mk-mod-add-flow-xf
(comp (filter some?)

View file

@ -10,7 +10,7 @@
[app.common.geom.shapes :as gsh]
[app.common.pages.changes-builder :as pcb]
[app.common.spec :as us]
[app.common.types.page-options :as tpo]
[app.common.spec.page :as csp]
[app.main.data.workspace.changes :as dwc]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.core :as rx]
@ -24,7 +24,7 @@
(merge guide))))
(defn update-guides [guide]
(us/verify ::tpo/guide guide)
(us/verify ::csp/guide guide)
(ptk/reify ::update-guides
ptk/WatchEvent
(watch [it state _]
@ -39,7 +39,7 @@
(rx/of (dwc/commit-changes changes))))))
(defn remove-guide [guide]
(us/verify ::tpo/guide guide)
(us/verify ::csp/guide guide)
(ptk/reify ::remove-guide
ptk/WatchEvent
(watch [it state _]

View file

@ -10,8 +10,8 @@
[app.common.geom.point :as gpt]
[app.common.pages.helpers :as cph]
[app.common.spec :as us]
[app.common.types.interactions :as cti]
[app.common.types.page-options :as cto]
[app.common.spec.interactions :as csi]
[app.common.spec.page :as csp]
[app.common.uuid :as uuid]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.common :as dwc]
@ -45,7 +45,7 @@
{:redo-changes [{:type :set-option
:page-id page-id
:option :flows
:value (cto/add-flow flows new-flow)}]
:value (csp/add-flow flows new-flow)}]
:undo-changes [{:type :set-option
:page-id page-id
:option :flows
@ -76,7 +76,7 @@
{:redo-changes [{:type :set-option
:page-id page-id
:option :flows
:value (cto/remove-flow flows flow-id)}]
:value (csp/remove-flow flows flow-id)}]
:undo-changes [{:type :set-option
:page-id page-id
:option :flows
@ -100,8 +100,8 @@
{:redo-changes [{:type :set-option
:page-id page-id
:option :flows
:value (cto/update-flow flows flow-id
#(cto/rename-flow % name))}]
:value (csp/update-flow flows flow-id
#(csp/rename-flow % name))}]
:undo-changes [{:type :set-option
:page-id page-id
:option :flows
@ -140,15 +140,15 @@
page-id
:options
:flows] [])
flow (cto/get-frame-flow flows (:id frame))]
flow (csp/get-frame-flow flows (:id frame))]
(rx/concat
(rx/of (dch/update-shapes [(:id shape)]
(fn [shape]
(let [new-interaction (cti/set-destination
cti/default-interaction
destination)]
(let [new-interaction (csi/set-destination
csi/default-interaction
destination)]
(update shape :interactions
cti/add-interaction new-interaction)))))
csi/add-interaction new-interaction)))))
(when (and (not (cph/connected-frame? (:id frame) objects))
(nil? flow))
(rx/of (add-flow (:id frame))))))))))
@ -161,7 +161,7 @@
(rx/of (dch/update-shapes [(:id shape)]
(fn [shape]
(update shape :interactions
cti/remove-interaction index)))))))
csi/remove-interaction index)))))))
(defn update-interaction
[shape index update-fn]
@ -171,7 +171,7 @@
(rx/of (dch/update-shapes [(:id shape)]
(fn [shape]
(update shape :interactions
cti/update-interaction index update-fn)))))))
csi/update-interaction index update-fn)))))))
(declare move-edit-interaction)
(declare finish-edit-interaction)
@ -244,11 +244,11 @@
(rx/of (update-interaction shape index
(fn [interaction]
(cond-> interaction
(not (cti/has-destination interaction))
(cti/set-action-type :navigate)
(not (csi/has-destination interaction))
(csi/set-action-type :navigate)
:always
(cti/set-destination (:id frame))))))))))))))
(csi/set-destination (:id frame))))))))))))))
;; --- Overlays
(declare move-overlay-pos)
@ -326,7 +326,7 @@
new-interactions
(update interactions index
#(cti/set-overlay-position % overlay-pos))]
#(csi/set-overlay-position % overlay-pos))]
(rx/of (dch/update-shapes [(:id shape)] #(merge % {:interactions new-interactions})))))))

View file

@ -12,6 +12,10 @@
[app.common.logging :as log]
[app.common.pages :as cp]
[app.common.spec :as us]
[app.common.spec.change :as spec.change]
[app.common.spec.color :as spec.color]
[app.common.spec.file :as spec.file]
[app.common.spec.typography :as spec.typography]
[app.common.uuid :as uuid]
[app.main.data.messages :as dm]
[app.main.data.workspace.changes :as dch]
@ -88,7 +92,7 @@
color (-> color
(assoc :id id)
(assoc :name (default-color-name color)))]
(us/assert ::cp/color color)
(us/assert ::spec.color/color color)
(ptk/reify ::add-color
IDeref
(-deref [_] color)
@ -105,7 +109,7 @@
:origin it})))))))
(defn add-recent-color
[color]
(us/assert ::cp/recent-color color)
(us/assert ::spec.color/recent-color color)
(ptk/reify ::add-recent-color
ptk/WatchEvent
(watch [it _ _]
@ -123,7 +127,7 @@
(defn update-color
[{:keys [id] :as color} file-id]
(us/assert ::cp/color color)
(us/assert ::spec.color/color color)
(us/assert ::us/uuid file-id)
(ptk/reify ::update-color
ptk/WatchEvent
@ -159,7 +163,7 @@
(defn add-media
[{:keys [id] :as media}]
(us/assert ::cp/media-object media)
(us/assert ::spec.file/media-object media)
(ptk/reify ::add-media
ptk/WatchEvent
(watch [it _ _]
@ -215,7 +219,7 @@
([typography] (add-typography typography true))
([typography edit?]
(let [typography (update typography :id #(or % (uuid/next)))]
(us/assert ::cp/typography typography)
(us/assert ::spec.typography/typography typography)
(ptk/reify ::add-typography
IDeref
(-deref [_] typography)
@ -235,7 +239,7 @@
(defn update-typography
[typography file-id]
(us/assert ::cp/typography typography)
(us/assert ::spec.typography/typography typography)
(us/assert ::us/uuid file-id)
(ptk/reify ::update-typography
ptk/WatchEvent
@ -396,7 +400,7 @@
[file-id component-id position]
(us/assert ::us/uuid file-id)
(us/assert ::us/uuid component-id)
(us/assert ::us/point position)
(us/assert ::gpt/point position)
(ptk/reify ::instantiate-component
ptk/WatchEvent
(watch [it state _]
@ -533,7 +537,7 @@
(defn ext-library-changed
[file-id modified-at revn changes]
(us/assert ::us/uuid file-id)
(us/assert ::cp/changes changes)
(us/assert ::spec.change/changes changes)
(ptk/reify ::ext-library-changed
ptk/UpdateEvent
(update [_ state]

View file

@ -8,8 +8,8 @@
(:require
[app.common.data :as d]
[app.common.geom.point :as gpt]
[app.common.pages :as cp]
[app.common.spec :as us]
[app.common.spec.change :as spec.change]
[app.common.transit :as t]
[app.common.uri :as u]
[app.config :as cf]
@ -201,7 +201,7 @@
(s/def ::file-id uuid?)
(s/def ::session-id uuid?)
(s/def ::revn integer?)
(s/def ::changes ::cp/changes)
(s/def ::changes ::spec.change/changes)
(s/def ::file-change-event
(s/keys :req-un [::type ::profile-id ::file-id ::session-id ::revn ::changes]))

View file

@ -10,6 +10,8 @@
[app.common.exceptions :as ex]
[app.common.pages :as cp]
[app.common.spec :as us]
[app.common.spec.change :as spec.change]
[app.common.spec.file :as spec.file]
[app.common.uuid :as uuid]
[app.main.data.dashboard :as dd]
[app.main.data.events :as ev]
@ -200,7 +202,7 @@
:updated-at (dt/now)))))))
(s/def ::shapes-changes-persisted
(s/keys :req-un [::revn ::cp/changes]))
(s/keys :req-un [::revn ::spec.change/changes]))
(defn shapes-persisted-event? [event]
(= (ptk/type event) ::changes-persisted))
@ -238,7 +240,7 @@
(s/def ::version ::us/integer)
(s/def ::revn ::us/integer)
(s/def ::ordering ::us/integer)
(s/def ::data ::cp/data)
(s/def ::data ::spec.file/data)
(s/def ::file ::dd/file)
(s/def ::project ::dd/project)

View file

@ -12,7 +12,7 @@
[app.common.math :as mth]
[app.common.pages :as cp]
[app.common.spec :as us]
[app.common.types.interactions :as cti]
[app.common.spec.interactions :as cti]
[app.common.uuid :as uuid]
[app.main.data.modal :as md]
[app.main.data.workspace.changes :as dch]

View file

@ -6,8 +6,8 @@
(ns app.main.data.workspace.undo
(:require
[app.common.pages.spec :as spec]
[app.common.spec :as us]
[app.common.spec.change :as spec.change]
[cljs.spec.alpha :as s]
[potok.core :as ptk]))
@ -15,8 +15,8 @@
;; Undo / Redo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::undo-changes ::spec/changes)
(s/def ::redo-changes ::spec/changes)
(s/def ::undo-changes ::spec.change/changes)
(s/def ::redo-changes ::spec.change/changes)
(s/def ::undo-entry
(s/keys :req-un [::undo-changes ::redo-changes]))

View file

@ -6,8 +6,8 @@
(ns app.main.ui.shapes.attrs
(:require
[app.common.pages.spec :as spec]
[app.common.types.radius :as ctr]
[app.common.spec.radius :as ctr]
[app.common.spec.shape :refer [stroke-caps-line stroke-caps-marker]]
[app.main.ui.context :as muc]
[app.util.object :as obj]
[app.util.svg :as usvg]
@ -131,7 +131,7 @@
;; For simple line caps we use svg stroke-line-cap attribute. This
;; only works if all caps are the same and we are not using the tricks
;; for inner or outer strokes.
(and (spec/stroke-caps-line (:stroke-cap-start shape))
(and (stroke-caps-line (:stroke-cap-start shape))
(= (:stroke-cap-start shape) (:stroke-cap-end shape))
(not (#{:inner :outer} (:stroke-alignment shape)))
(not= :dotted stroke-style))
@ -141,15 +141,15 @@
(assoc :strokeLinecap "round")
;; For other cap types we use markers.
(and (or (spec/stroke-caps-marker (:stroke-cap-start shape))
(and (spec/stroke-caps-line (:stroke-cap-start shape))
(and (or (stroke-caps-marker (:stroke-cap-start shape))
(and (stroke-caps-line (:stroke-cap-start shape))
(not= (:stroke-cap-start shape) (:stroke-cap-end shape))))
(not (#{:inner :outer} (:stroke-alignment shape))))
(assoc :markerStart
(str/format "url(#marker-%s-%s)" render-id (name (:stroke-cap-start shape))))
(and (or (spec/stroke-caps-marker (:stroke-cap-end shape))
(and (spec/stroke-caps-line (:stroke-cap-end shape))
(and (or (stroke-caps-marker (:stroke-cap-end shape))
(and (stroke-caps-line (:stroke-cap-end shape))
(not= (:stroke-cap-start shape) (:stroke-cap-end shape))))
(not (#{:inner :outer} (:stroke-alignment shape))))
(assoc :markerEnd

View file

@ -7,7 +7,7 @@
(ns app.main.ui.viewer.handoff.attributes.layout
(:require
[app.common.math :as mth]
[app.common.types.radius :as ctr]
[app.common.spec.radius :as ctr]
[app.main.ui.components.copy-button :refer [copy-button]]
[app.util.code-gen :as cg]
[app.util.i18n :refer [t]]

View file

@ -10,7 +10,7 @@
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.pages :as cp]
[app.common.types.page-options :as cto]
[app.common.spec.page :as csp]
[app.main.data.comments :as dcm]
[app.main.data.viewer :as dv]
[app.main.refs :as refs]
@ -107,7 +107,7 @@
frames (:frames page)
frame (get frames index)
current-flow (mf/use-state
(cto/get-frame-flow flows (:id frame)))
(csp/get-frame-flow flows (:id frame)))
show-dropdown? (mf/use-state false)
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))

View file

@ -11,7 +11,7 @@
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as geom]
[app.common.pages :as cp]
[app.common.types.interactions :as cti]
[app.common.spec.interactions :as cti]
[app.main.data.viewer :as dv]
[app.main.refs :as refs]
[app.main.store :as st]

View file

@ -8,7 +8,7 @@
"A workspace specific context menu (mouse right click)."
(:require
[app.common.data :as d]
[app.common.types.page-options :as cto]
[app.common.spec.page :as csp]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.data.workspace.interactions :as dwi]
@ -307,7 +307,7 @@
is-frame? (and single? has-frame?)]
(when (and prototype? is-frame?)
(let [flow (cto/get-frame-flow flows (-> shapes first :id))]
(let [flow (csp/get-frame-flow flows (-> shapes first :id))]
(if (some? flow)
[:& menu-entry {:title (tr "workspace.shape.menu.delete-flow-start")
:on-click (do-remove-flow flow)}]

View file

@ -8,7 +8,6 @@
(:require
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.pages.spec :as spec]
[app.common.uuid :as uuid]
[app.main.data.workspace.changes :as dch]
[app.main.refs :as refs]
@ -50,8 +49,8 @@
;; first-level? (and in-frame?
;; (= (:parent-id values) (:frame-id values)))
constraints-h (get values :constraints-h (spec/default-constraints-h values))
constraints-v (get values :constraints-v (spec/default-constraints-v values))
constraints-h (get values :constraints-h (gsh/default-constraints-h values))
constraints-v (get values :constraints-v (gsh/default-constraints-v values))
on-constraint-button-clicked
(mf/use-callback

View file

@ -8,8 +8,8 @@
(:require
[app.common.data :as d]
[app.common.pages :as cp]
[app.common.types.interactions :as cti]
[app.common.types.page-options :as cto]
[app.common.spec.interactions :as csi]
[app.common.spec.page :as csp]
[app.common.uuid :as uuid]
[app.main.data.workspace :as dw]
[app.main.data.workspace.interactions :as dwi]
@ -79,7 +79,7 @@
{:dissolve (tr "workspace.options.interaction-animation-dissolve")
:slide (tr "workspace.options.interaction-animation-slide")}
(cti/allow-push? (:action-type interaction))
(csi/allow-push? (:action-type interaction))
(assoc :push (tr "workspace.options.interaction-animation-push"))))
(defn- easing-names
@ -165,7 +165,7 @@
(mf/defc shape-flows
[{:keys [flows shape]}]
(when (= (:type shape) :frame)
(let [flow (cto/get-frame-flow flows (:id shape))]
(let [flow (csp/get-frame-flow flows (:id shape))]
[:div.element-set.interactions-options
[:div.element-set-title
[:span (tr "workspace.options.flows.flow-start")]]
@ -201,27 +201,27 @@
change-event-type
(fn [event]
(let [value (-> event dom/get-target dom/get-value d/read-string)]
(update-interaction index #(cti/set-event-type % value shape))))
(update-interaction index #(csi/set-event-type % value shape))))
change-action-type
(fn [event]
(let [value (-> event dom/get-target dom/get-value d/read-string)]
(update-interaction index #(cti/set-action-type % value))))
(update-interaction index #(csi/set-action-type % value))))
change-delay
(fn [value]
(update-interaction index #(cti/set-delay % value)))
(update-interaction index #(csi/set-delay % value)))
change-destination
(fn [event]
(let [value (-> event dom/get-target dom/get-value)
value (when (not= value "") (uuid/uuid value))]
(update-interaction index #(cti/set-destination % value))))
(update-interaction index #(csi/set-destination % value))))
change-preserve-scroll
(fn [event]
(let [value (-> event dom/get-target dom/checked?)]
(update-interaction index #(cti/set-preserve-scroll % value))))
(update-interaction index #(csi/set-preserve-scroll % value))))
change-url
(fn [event]
@ -237,55 +237,55 @@
(if (dom/valid? target)
(do
(dom/remove-class! target "error")
(update-interaction index #(cti/set-url % value)))
(update-interaction index #(csi/set-url % value)))
(dom/add-class! target "error"))))
change-overlay-pos-type
(fn [event]
(let [value (-> event dom/get-target dom/get-value d/read-string)]
(update-interaction index #(cti/set-overlay-pos-type % value shape objects))))
(update-interaction index #(csi/set-overlay-pos-type % value shape objects))))
toggle-overlay-pos-type
(fn [pos-type]
(update-interaction index #(cti/toggle-overlay-pos-type % pos-type shape objects)))
(update-interaction index #(csi/toggle-overlay-pos-type % pos-type shape objects)))
change-close-click-outside
(fn [event]
(let [value (-> event dom/get-target dom/checked?)]
(update-interaction index #(cti/set-close-click-outside % value))))
(update-interaction index #(csi/set-close-click-outside % value))))
change-background-overlay
(fn [event]
(let [value (-> event dom/get-target dom/checked?)]
(update-interaction index #(cti/set-background-overlay % value))))
(update-interaction index #(csi/set-background-overlay % value))))
change-animation-type
(fn [event]
(let [value (-> event dom/get-target dom/get-value d/read-string)]
(update-interaction index #(cti/set-animation-type % value))))
(update-interaction index #(csi/set-animation-type % value))))
change-duration
(fn [value]
(update-interaction index #(cti/set-duration % value)))
(update-interaction index #(csi/set-duration % value)))
change-easing
(fn [event]
(let [value (-> event dom/get-target dom/get-value d/read-string)]
(update-interaction index #(cti/set-easing % value))))
(update-interaction index #(csi/set-easing % value))))
change-way
(fn [event]
(let [value (-> event dom/get-target dom/get-value d/read-string)]
(update-interaction index #(cti/set-way % value))))
(update-interaction index #(csi/set-way % value))))
change-direction
(fn [value]
(update-interaction index #(cti/set-direction % value)))
(update-interaction index #(csi/set-direction % value)))
change-offset-effect
(fn [event]
(let [value (-> event dom/get-target dom/checked?)]
(update-interaction index #(cti/set-offset-effect % value))))
(update-interaction index #(csi/set-offset-effect % value))))
]
[:*
@ -316,7 +316,7 @@
[:option {:value (str value)} name]))]]
; Delay
(when (cti/has-delay interaction)
(when (csi/has-delay interaction)
[:div.interactions-element
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-delay")]
[:div.input-element {:title (tr "workspace.options.interaction-ms")}
@ -337,7 +337,7 @@
[:option {:value (str value)} name])]]
; Destination
(when (cti/has-destination interaction)
(when (csi/has-destination interaction)
[:div.interactions-element
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-destination")]
[:select.input-select
@ -352,7 +352,7 @@
[:option {:value (str (:id frame))} (:name frame)]))]])
; Preserve scroll
(when (cti/has-preserve-scroll interaction)
(when (csi/has-preserve-scroll interaction)
[:div.interactions-element
[:div.input-checkbox
[:input {:type "checkbox"
@ -363,7 +363,7 @@
(tr "workspace.options.interaction-preserve-scroll")]]])
; URL
(when (cti/has-url interaction)
(when (csi/has-url interaction)
[:div.interactions-element
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-url")]
[:input.input-text {:type "url"
@ -371,7 +371,7 @@
:default-value (str (:url interaction))
:on-blur change-url}]])
(when (cti/has-overlay-opts interaction)
(when (csi/has-overlay-opts interaction)
[:*
; Overlay position (select)
[:div.interactions-element
@ -433,7 +433,7 @@
[:label {:for (str "background-" index)}
(tr "workspace.options.interaction-background")]]]])
(when (cti/has-animation? interaction)
(when (csi/has-animation? interaction)
[:*
; Animation select
[:div.interactions-element.separator
@ -446,7 +446,7 @@
[:option {:value (str value)} name])]]
; Direction
(when (cti/has-way? interaction)
(when (csi/has-way? interaction)
[:div.interactions-element.interactions-way-buttons
[:div.input-radio
[:input {:type "radio"
@ -466,7 +466,7 @@
[:label {:for "way-out"} (tr "workspace.options.interaction-out")]]])
; Direction
(when (cti/has-direction? interaction)
(when (csi/has-direction? interaction)
[:div.interactions-element.interactions-direction-buttons
[:div.element-set-actions-button
{:class (dom/classnames :active (= direction :right))
@ -486,7 +486,7 @@
i/animate-up]])
; Duration
(when (cti/has-duration? interaction)
(when (csi/has-duration? interaction)
[:div.interactions-element
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-duration")]
[:div.input-element {:title (tr "workspace.options.interaction-ms")}
@ -498,7 +498,7 @@
[:span.after (tr "workspace.options.interaction-ms")]]])
; Easing
(when (cti/has-easing? interaction)
(when (csi/has-easing? interaction)
[:div.interactions-element
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-easing")]
[:select.input-select
@ -515,7 +515,7 @@
:ease-in-out i/easing-ease-in-out)]])
; Offset effect
(when (cti/has-offset-effect? interaction)
(when (csi/has-offset-effect? interaction)
[:div.interactions-element
[:div.input-checkbox
[:input {:type "checkbox"

View file

@ -9,7 +9,7 @@
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.math :as math]
[app.common.types.radius :as ctr]
[app.common.spec.radius :as ctr]
[app.main.data.workspace :as udw]
[app.main.data.workspace.changes :as dch]
[app.main.refs :as refs]

View file

@ -8,7 +8,6 @@
(:require
[app.common.colors :as clr]
[app.common.data :as d]
[app.common.pages.spec :as spec]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.colors :as dc]
[app.main.store :as st]
@ -127,7 +126,7 @@
update-cap-attr
(fn [& kvs]
#(if (spec/has-caps? %)
#(if (= :path (:type %))
(apply (partial assoc %) kvs)
%))

View file

@ -10,7 +10,7 @@
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.pages :as cp]
[app.common.types.interactions :as cti]
[app.common.spec.interactions :as cti]
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
[app.main.store :as st]

View file

@ -9,7 +9,7 @@
[app.common.data :as d]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.types.interactions :as cti]
[app.common.spec.interactions :as cti]
[app.common.uuid :as uuid]
[app.util.color :as uc]
[app.util.json :as json]