0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-12 15:01:28 -05:00

Improved text handling in plugins

This commit is contained in:
alonso.torres 2024-06-27 15:17:32 +02:00
parent ac58a5b8fa
commit fbce59e81f
4 changed files with 175 additions and 91 deletions

View file

@ -71,6 +71,13 @@
(defn get-font-data [id]
(get @fontsdb id))
(defn find-font-data [data]
(d/seek
(fn [font]
(= (select-keys font (keys data))
data))
(vals @fontsdb)))
(defn resolve-variants
[id]
(get-in @fontsdb [id :variants]))
@ -249,6 +256,11 @@
(or (d/seek #(= (:id %) font-variant-id) variants)
(get-default-variant font)))
(defn find-variant
[{:keys [variants] :as font} variant-data]
(let [props (keys variant-data)]
(d/seek #(= (select-keys % props) variant-data) variants)))
;; Font embedding functions
(defn get-node-fonts
"Extracts the fonts used by some node"

View file

@ -19,6 +19,9 @@
(deftype PenpotFontVariant [name fontVariantId fontWeight fontStyle])
(defn variant-proxy? [p]
(instance? PenpotFontVariant p))
(deftype PenpotFont [name fontId fontFamily fontStyle fontVariantId fontWeight variants]
Object
@ -60,13 +63,13 @@
(instance? PenpotFont p))
(defn font-proxy
[{:keys [id name variants] :as font}]
[{:keys [id family name variants] :as font}]
(when (some? font)
(let [default-variant (fonts/get-default-variant font)]
(PenpotFont.
name
id
id
family
(:style default-variant)
(:id default-variant)
(:weight default-variant)

View file

@ -23,6 +23,12 @@
(when (some? coll)
(apply array (keep format-fn coll))))
(defn format-mixed
[value]
(if (= value :multiple)
"mixed"
value))
;; export type PenpotPoint = { x: number; y: number };
(defn format-point
[{:keys [x y] :as point}]
@ -183,7 +189,14 @@
(defn format-fills
[fills]
(when (some? fills)
(cond
(= fills :multiple)
"mixed"
(= fills "mixed")
"mixed"
(some? fills)
(format-array format-fill fills)))
;; export interface PenpotStroke {
@ -393,7 +406,7 @@
(format-array format-command content)))
;; export type PenpotTrackType = 'flex' | 'fixed' | 'percent' | 'auto';
;;
;;
;; export interface PenpotTrack {
;; type: PenpotTrackType;
;; value: number | null;

View file

@ -7,12 +7,14 @@
(ns app.plugins.text
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.record :as crc]
[app.common.schema :as sm]
[app.common.text :as txt]
[app.common.types.shape :as cts]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.texts :as dwt]
[app.main.fonts :as fonts]
[app.main.store :as st]
[app.plugins.format :as format]
[app.plugins.parser :as parser]
@ -21,11 +23,39 @@
[app.util.text-editor :as ted]
[cuerdas.core :as str]))
;; This regex seems duplicated but probably in the future when we support diferent units
;; this will need to reflect changes for each property
(def font-size-re #"^\d*\.?\d*$")
(def line-height-re #"^\d*\.?\d*$")
(def letter-spacing-re #"^\d*\.?\d*$")
(def text-transform-re #"uppercase|capitalize|lowercase|none")
(def text-decoration-re #"underline|line-through|none")
(def text-direction-re #"ltr|rtl")
(def text-align-re #"left|center|right|justify")
(def vertical-align-re #"top|center|bottom")
(defn mixed-value
[values]
(let [s (set values)]
(if (= (count s) 1) (first s) "mixed")))
(defn font-data
[font variant]
(d/without-nils
{:font-id (:id font)
:font-family (:family font)
:font-variant-id (:id variant)
:font-style (:style variant)
:font-weight (:weight variant)}))
(defn variant-data
[variant]
(d/without-nils
{:font-variant-id (:id variant)
:font-style (:style variant)
:font-weight (:weight variant)}))
(deftype TextRange [$plugin $file $page $id start end]
Object
(applyTypography [_ typography]
@ -71,12 +101,14 @@
:set
(fn [_ value]
(cond
(not (string? value))
(u/display-not-valid :fontId value)
(let [font (when (string? value) (fonts/get-font-data value))
variant (fonts/get-default-variant font)]
(cond
(not (some? font))
(u/display-not-valid :fontId value)
:else
(st/emit! (dwt/update-text-range id start end {:font-id value}))))}
:else
(st/emit! (dwt/update-text-range id start end (font-data font variant))))))}
{:name "fontFamily"
:get #(let [range-data
@ -85,25 +117,29 @@
:set
(fn [_ value]
(cond
(not (string? value))
(u/display-not-valid :fontFamily value)
(let [font (fonts/find-font-data {:font-family value})
variant (fonts/get-default-variant font)]
(cond
(not (string? value))
(u/display-not-valid :fontFamily value)
:else
(st/emit! (dwt/update-text-range id start end {:font-family value}))))}
:else
(st/emit! (dwt/update-text-range id start end (font-data font variant))))))}
{:name "fontVariantId"
:get #(let [range-data
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
(->> range-data (map :font-variant-id) mixed-value))
:set
(fn [_ value]
(cond
(not (string? value))
(u/display-not-valid :fontVariantId value)
(fn [self value]
(let [font (fonts/get-font-data (obj/get self "fontId"))
variant (fonts/get-variant font value)]
(cond
(not (string? value))
(u/display-not-valid :fontVariantId value)
:else
(st/emit! (dwt/update-text-range id start end {:font-variant-id value}))))}
:else
(st/emit! (dwt/update-text-range id start end (variant-data variant))))))}
{:name "fontSize"
:get #(let [range-data
@ -111,38 +147,43 @@
(->> range-data (map :font-size) mixed-value))
:set
(fn [_ value]
(cond
(not (string? value))
(u/display-not-valid :fontSize value)
(let [value (str/trim (dm/str value))]
(cond
(or (empty? value) (not (re-matches font-size-re value)))
(u/display-not-valid :fontSize value)
:else
(st/emit! (dwt/update-text-range id start end {:font-size value}))))}
:else
(st/emit! (dwt/update-text-range id start end {:font-size value})))))}
{:name "fontWeight"
:get #(let [range-data
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
(->> range-data (map :font-weight) mixed-value))
:set
(fn [_ value]
(cond
(not (string? value))
(u/display-not-valid :fontWeight value)
(fn [self value]
(let [font (fonts/get-font-data (obj/get self "fontId"))
variant (fonts/find-variant font {:weight (dm/str value)})]
(cond
(nil? variant)
(u/display-not-valid :fontWeight (dm/str "Font weight '" value "' not supported for the current font"))
:else
(st/emit! (dwt/update-text-range id start end {:font-weight value}))))}
:else
(st/emit! (dwt/update-text-range id start end (variant-data variant))))))}
{:name "fontStyle"
:get #(let [range-data
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
(->> range-data (map :font-style) mixed-value))
:set
(fn [_ value]
(cond
(not (string? value))
(u/display-not-valid :fontStyle value)
(fn [self value]
(let [font (fonts/get-font-data (obj/get self "fontId"))
variant (fonts/find-variant font {:weight (dm/str value)})]
(cond
(nil? variant)
(u/display-not-valid :fontStyle (dm/str "Font style '" value "' not supported for the current font"))
:else
(st/emit! (dwt/update-text-range id start end {:font-style value}))))}
:else
(st/emit! (dwt/update-text-range id start end (variant-data variant))))))}
{:name "lineHeight"
:get #(let [range-data
@ -150,12 +191,13 @@
(->> range-data (map :line-height) mixed-value))
:set
(fn [_ value]
(cond
(not (string? value))
(u/display-not-valid :lineHeight value)
(let [value (str/trim (dm/str value))]
(cond
(or (empty? value) (not (re-matches line-height-re value)))
(u/display-not-valid :lineHeight value)
:else
(st/emit! (dwt/update-text-range id start end {:line-height value}))))}
:else
(st/emit! (dwt/update-text-range id start end {:line-height value})))))}
{:name "letterSpacing"
:get #(let [range-data
@ -163,12 +205,13 @@
(->> range-data (map :letter-spacing) mixed-value))
:set
(fn [_ value]
(cond
(not (string? value))
(u/display-not-valid :letterSpacing value)
(let [value (str/trim (dm/str value))]
(cond
(or (empty? value) (re-matches letter-spacing-re value))
(u/display-not-valid :letterSpacing value)
:else
(st/emit! (dwt/update-text-range id start end {:letter-spacing value}))))}
:else
(st/emit! (dwt/update-text-range id start end {:letter-spacing value})))))}
{:name "textTransform"
:get #(let [range-data
@ -177,7 +220,7 @@
:set
(fn [_ value]
(cond
(not (string? value))
(and (string? value) (re-matches text-transform-re value))
(u/display-not-valid :textTransform value)
:else
@ -190,7 +233,7 @@
:set
(fn [_ value]
(cond
(not (string? value))
(and (string? value) (re-matches text-decoration-re value))
(u/display-not-valid :textDecoration value)
:else
@ -203,7 +246,7 @@
:set
(fn [_ value]
(cond
(not (string? value))
(and (string? value) (re-matches text-direction-re value))
(u/display-not-valid :direction value)
:else
@ -216,7 +259,7 @@
:set
(fn [_ value]
(cond
(not (string? value))
(and (string? value) (re-matches text-align-re value))
(u/display-not-valid :text-align value)
:else
@ -278,144 +321,157 @@
(st/emit! (dwsh/update-shapes [id] #(assoc % :grow-type value))))))}
{:name "fontId"
:get #(-> % u/proxy->shape text-props :font-id)
:get #(-> % u/proxy->shape text-props :font-id format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(let [id (obj/get self "$id")
font (when (string? value) (fonts/get-font-data value))
variant (fonts/get-default-variant font)]
(cond
(not (string? value))
(not (some? font))
(u/display-not-valid :fontId value)
:else
(st/emit! (dwt/update-attrs id {:font-id value})))))}
(st/emit! (dwt/update-attrs id (font-data font variant))))))}
{:name "fontFamily"
:get #(-> % u/proxy->shape text-props :font-family)
:get #(-> % u/proxy->shape text-props :font-family format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(let [id (obj/get self "$id")
font (fonts/find-font-data {:font-family value})
variant (fonts/get-default-variant font)]
(cond
(not (string? value))
(not (some? font))
(u/display-not-valid :fontFamily value)
:else
(st/emit! (dwt/update-attrs id {:font-family value})))))}
(st/emit! (dwt/update-attrs id (font-data font variant))))))}
{:name "fontVariantId"
:get #(-> % u/proxy->shape text-props :font-variant-id)
:get #(-> % u/proxy->shape text-props :font-variant-id format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(let [id (obj/get self "$id")
font (fonts/get-font-data (obj/get self "fontId"))
variant (fonts/get-variant font value)]
(cond
(not (string? value))
(not (some? variant))
(u/display-not-valid :fontVariantId value)
:else
(st/emit! (dwt/update-attrs id {:font-variant-id value})))))}
(st/emit! (dwt/update-attrs id (variant-data variant))))))}
{:name "fontSize"
:get #(-> % u/proxy->shape text-props :font-size)
:get #(-> % u/proxy->shape text-props :font-size format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(let [id (obj/get self "$id")
value (str/trim (dm/str value))]
(cond
(not (string? value))
(or (empty? value) (not (re-matches font-size-re value)))
(u/display-not-valid :fontSize value)
:else
(st/emit! (dwt/update-attrs id {:font-size value})))))}
{:name "fontWeight"
:get #(-> % u/proxy->shape text-props :font-weight)
:get #(-> % u/proxy->shape text-props :font-weight format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(let [id (obj/get self "$id")
font (fonts/get-font-data (obj/get self "fontId"))
variant (fonts/find-variant font {:weight (dm/str value)})]
(cond
(not (string? value))
(u/display-not-valid :fontWeight value)
(nil? variant)
(u/display-not-valid :fontWeight (dm/str "Font weight '" value "' not supported for the current font"))
:else
(st/emit! (dwt/update-attrs id {:font-weight value})))))}
(st/emit! (dwt/update-attrs id (variant-data variant))))))}
{:name "fontStyle"
:get #(-> % u/proxy->shape text-props :font-style)
:get #(-> % u/proxy->shape text-props :font-style format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(let [id (obj/get self "$id")
font (fonts/get-font-data (obj/get self "fontId"))
variant (fonts/find-variant font {:weight (dm/str value)})]
(cond
(not (string? value))
(u/display-not-valid :fontStyle value)
(nil? variant)
(u/display-not-valid :fontStyle (dm/str "Font style '" value "' not supported for the current font"))
:else
(st/emit! (dwt/update-attrs id {:font-style value})))))}
(st/emit! (dwt/update-attrs id (variant-data variant))))))}
{:name "lineHeight"
:get #(-> % u/proxy->shape text-props :line-height)
:get #(-> % u/proxy->shape text-props :line-height format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(let [id (obj/get self "$id")
value (str/trim (dm/str value))]
(cond
(not (string? value))
(or (empty? value) (not (re-matches line-height-re value)))
(u/display-not-valid :lineHeight value)
:else
(st/emit! (dwt/update-attrs id {:line-height value})))))}
{:name "letterSpacing"
:get #(-> % u/proxy->shape text-props :letter-spacing)
:get #(-> % u/proxy->shape text-props :letter-spacing format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(let [id (obj/get self "$id")
value (str/trim (dm/str value))]
(cond
(not (string? value))
(or (empty? value) (re-matches letter-spacing-re value))
(u/display-not-valid :letterSpacing value)
:else
(st/emit! (dwt/update-attrs id {:letter-spacing value})))))}
{:name "textTransform"
:get #(-> % u/proxy->shape text-props :text-transform)
:get #(-> % u/proxy->shape text-props :text-transform format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(cond
(not (string? value))
(and (string? value) (re-matches text-transform-re value))
(u/display-not-valid :textTransform value)
:else
(st/emit! (dwt/update-attrs id {:text-transform value})))))}
{:name "textDecoration"
:get #(-> % u/proxy->shape text-props :text-decoration)
:get #(-> % u/proxy->shape text-props :text-decoration format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(cond
(not (string? value))
(and (string? value) (re-matches text-decoration-re value))
(u/display-not-valid :textDecoration value)
:else
(st/emit! (dwt/update-attrs id {:text-decoration value})))))}
{:name "direction"
:get #(-> % u/proxy->shape text-props :text-direction)
:get #(-> % u/proxy->shape text-props :text-direction format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(cond
(not (string? value))
(and (string? value) (re-matches text-direction-re value))
(u/display-not-valid :textDecoration value)
:else
(st/emit! (dwt/update-attrs id {:text-decoration value})))))}
{:name "align"
:get #(-> % u/proxy->shape text-props :text-align)
:get #(-> % u/proxy->shape text-props :text-align format/format-mixed)
:set
(fn [self value]
(let [id (obj/get self "$id")]
(cond
(not (string? value))
(and (string? value) (re-matches text-align-re value))
(u/display-not-valid :align value)
:else
@ -427,7 +483,7 @@
(fn [self value]
(let [id (obj/get self "$id")]
(cond
(not (string? value))
(and (string? value) (re-matches vertical-align-re value))
(u/display-not-valid :verticalAlign value)
:else