diff --git a/.github/workflows/commit-checker.yml b/.github/workflows/commit-checker.yml index 21a763e3a7..60988a4daa 100644 --- a/.github/workflows/commit-checker.yml +++ b/.github/workflows/commit-checker.yml @@ -26,7 +26,7 @@ jobs: - name: Check Commit Type uses: gsactions/commit-message-checker@v2 with: - pattern: '^(Merge|:(lipstick|globe_with_meridians|wrench|books|arrow_up|arrow_down|zap|ambulance|construction|boom|fire|whale|bug|sparkles|paperclip|tada|recycle):)\s[A-Z].*[^.]$' + pattern: '^(Merge|Revert|:(lipstick|globe_with_meridians|wrench|books|arrow_up|arrow_down|zap|ambulance|construction|boom|fire|whale|bug|sparkles|paperclip|tada|recycle):)\s[A-Z].*[^.]$' flags: 'gm' error: 'Commit should match CONTRIBUTING.md guideline' checkAllCommitMessages: 'true' # optional: this checks all commits associated with a pull request diff --git a/CHANGES.md b/CHANGES.md index 8cbc3c59f9..38451c31d4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -45,7 +45,6 @@ - Hide bounding box while editing visual effects [Taiga #11576](https://tree.taiga.io/project/penpot/issue/11576) - Improved text layer resizing: Allow double-click on text bounding box to set auto-width/auto-height [Taiga #11577](https://tree.taiga.io/project/penpot/issue/11577) - Improve text layer auto-resize: auto-width switches to auto-height on horizontal resize, and only switches to fixed on vertical resize [Taiga #11578](https://tree.taiga.io/project/penpot/issue/11578) -- Highlight first font in font selector search. Apply only on Enter or click. [Taiga #11579](https://tree.taiga.io/project/penpot/issue/11579) - Add the ability to show login dialog on profile settings [Github #6871](https://github.com/penpot/penpot/pull/6871) - Improve the application of tokens with object specific tokens [Taiga #10209](https://tree.taiga.io/project/penpot/us/10209) @@ -71,8 +70,8 @@ - Fix opacity on stroke gradients [Taiga #11646](https://tree.taiga.io/project/penpot/issue/11646) - Fix change from gradient to solid color [Taiga #11648](https://tree.taiga.io/project/penpot/issue/11648) - Fix the context menu always closes after any action [Taiga #11624](https://tree.taiga.io/project/penpot/issue/11624) -- Fix font selector highlight inconsistency when using keyboard navigation [Taiga #11668](https://tree.taiga.io/project/penpot/issue/11668) - Fix X & Y position do not sincronize with tokens [Taiga #11617](https://tree.taiga.io/project/penpot/issue/11617) +- Fix tooltip position after first time [Taiga #11688](https://tree.taiga.io/project/penpot/issue/11688) ## 2.8.1 (Unreleased) diff --git a/common/src/app/common/logic/shapes.cljc b/common/src/app/common/logic/shapes.cljc index 4e3e0e3924..a1b981a5b4 100644 --- a/common/src/app/common/logic/shapes.cljc +++ b/common/src/app/common/logic/shapes.cljc @@ -7,6 +7,7 @@ (ns app.common.logic.shapes (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] [app.common.files.helpers :as cfh] [app.common.geom.shapes :as gsh] @@ -25,7 +26,7 @@ (defn- generate-unapply-tokens "When updating attributes that have a token applied, we must unapply it, because the value - of the attribute now has been given directly, and does not come from the token. + of the attribute now has been given directly, and does not come from the token. When applying a typography asset style we also unapply any typographic tokens." [changes objects changed-sub-attr] (let [new-objects (pcb/get-objects changes) @@ -35,33 +36,38 @@ text-changed-attrs (fn [shape] (let [new-shape (get new-objects (:id shape)) - attrs (ctt/get-diff-attrs (:content shape) (:content new-shape)) + attrs (ctt/get-diff-attrs (:content shape) (:content new-shape)) + ;; Unapply token when applying typography asset style - attrs (if (set/intersection text-typography-attrs attrs) - (into attrs cto/typography-keys) - attrs)] + attrs (if (seq (set/intersection text-typography-attrs attrs)) + (into attrs cto/typography-keys) + attrs)] (apply set/union (map cto/shape-attr->token-attrs attrs)))) - check-attr (fn [shape changes attr] - (let [tokens (get shape :applied-tokens {}) - token-attrs (if (or (not= (:type shape) :text) (not= attr :content)) - (cto/shape-attr->token-attrs attr changed-sub-attr) - (text-changed-attrs shape))] - (if (some #(contains? tokens %) token-attrs) - (pcb/update-shapes changes [(:id shape)] #(cto/unapply-token-id % token-attrs)) - changes))) + check-attr + (fn [shape changes attr] + (let [shape-id (dm/get-prop shape :id) + tokens (get shape :applied-tokens {}) + token-attrs (if (and (cfh/text-shape? shape) (= attr :content)) + (text-changed-attrs shape) + (cto/shape-attr->token-attrs attr changed-sub-attr))] - check-shape (fn [changes mod-obj-change] - (let [shape (get objects (:id mod-obj-change)) - xf (comp (filter #(= (:type %) :set)) - (map :attr)) - attrs (into [] xf (:operations mod-obj-change))] - (reduce (partial check-attr shape) - changes - attrs)))] - (reduce check-shape - changes - mod-obj-changes))) + (if (some #(contains? tokens %) token-attrs) + (pcb/update-shapes changes [shape-id] #(cto/unapply-token-id % token-attrs)) + changes))) + + check-shape + (fn [changes mod-obj-change] + (let [shape (get objects (:id mod-obj-change)) + attrs (into [] + (comp (filter #(= (:type %) :set)) + (map :attr)) + (:operations mod-obj-change))] + (reduce (partial check-attr shape) + changes + attrs)))] + + (reduce check-shape changes mod-obj-changes))) (defn generate-update-shapes [changes ids update-fn objects {:keys [attrs changed-sub-attr ignore-tree ignore-touched with-objects?]}] diff --git a/common/src/app/common/text.cljc b/common/src/app/common/text.cljc index 30345ae801..bea80c9ebc 100644 --- a/common/src/app/common/text.cljc +++ b/common/src/app/common/text.cljc @@ -122,7 +122,7 @@ (fix-gradients) (assoc :text text)))) - (split-texts [text styles] + (split-texts [text styles data] (let [cpoints (text->code-points text) children (->> (parse-draft-styles styles) (build-style-index (count cpoints)) @@ -131,7 +131,7 @@ (mapv #(extract-text cpoints %)))] (cond-> children (empty? children) - (conj {:text ""})))) + (conj (assoc data :text ""))))) (build-paragraph [block] (let [key (get block :key) @@ -142,7 +142,7 @@ (-> data (assoc :key key) (assoc :type "paragraph") - (assoc :children (split-texts text styles)))))] + (assoc :children (split-texts text styles data)))))] {:type "root" :children diff --git a/frontend/src/app/main/data/workspace/tokens/application.cljs b/frontend/src/app/main/data/workspace/tokens/application.cljs index 78eb5da27b..747596ae7f 100644 --- a/frontend/src/app/main/data/workspace/tokens/application.cljs +++ b/frontend/src/app/main/data/workspace/tokens/application.cljs @@ -501,6 +501,7 @@ ctt/spacing-keys ctt/sizing-keys ctt/border-radius-keys + ctt/axis-keys ctt/stroke-width-keys) :on-update-shape update-shape-dimensions :modal {:key :tokens/dimensions diff --git a/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs b/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs index 59a96f8c4e..39995ab816 100644 --- a/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs +++ b/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs @@ -154,12 +154,17 @@ the dom with the result." [tooltip placement origin-brect offset] (show-popover tooltip) - (let [tooltip-brect (dom/get-bounding-rect tooltip) + (let [saved-height (dom/get-data tooltip "height") + saved-width (dom/get-data tooltip "width") + tooltip-brect (dom/get-bounding-rect tooltip) + tooltip-brect (assoc tooltip-brect :height (or saved-height (:height tooltip-brect)) :width (or saved-width (:width tooltip-brect))) window-size (dom/get-window-size)] (when-let [[placement placement-rect] (find-matching-placement placement tooltip-brect origin-brect window-size offset)] (let [height (if (or (= placement "right") (= placement "left")) (- (:height placement-rect) arrow-height) (:height placement-rect))] + (dom/set-data! tooltip "height" (:height tooltip-brect)) + (dom/set-data! tooltip "width" (:width tooltip-brect)) (dom/set-css-property! tooltip "block-size" (dm/str height "px")) (dom/set-css-property! tooltip "inset-block-start" (dm/str (:top placement-rect) "px")) (dom/set-css-property! tooltip "inset-inline-start" (dm/str (:left placement-rect) "px"))) diff --git a/frontend/src/app/main/ui/static.cljs b/frontend/src/app/main/ui/static.cljs index 980d8d4e4a..837c7c934b 100644 --- a/frontend/src/app/main/ui/static.cljs +++ b/frontend/src/app/main/ui/static.cljs @@ -181,7 +181,7 @@ [:div {:class (stl/css :form-container)} [:& recovery-sent-page {:email @user-email}]])]]])) -(mf/defc request-dialog +(mf/defc request-dialog* {::mf/props :obj} [{:keys [title content button-text on-button-click cancel-text on-close]}] (let [on-click (or on-button-click on-close)] @@ -235,45 +235,45 @@ (cond is-default - [:& request-dialog {:title (tr "not-found.no-permission.project") - :button-text (tr "not-found.no-permission.go-dashboard") - :on-close on-close}] + [:> request-dialog* {:title (tr "not-found.no-permission.project") + :button-text (tr "not-found.no-permission.go-dashboard") + :on-close on-close}] (and (some? file-id) (:already-requested requested)) - [:& request-dialog {:title (tr "not-found.no-permission.already-requested.file") - :content [(tr "not-found.no-permission.already-requested.or-others.file")] - :button-text (tr "not-found.no-permission.go-dashboard") - :on-close on-close}] + [:> request-dialog* {:title (tr "not-found.no-permission.already-requested.file") + :content [(tr "not-found.no-permission.already-requested.or-others.file")] + :button-text (tr "not-found.no-permission.go-dashboard") + :on-close on-close}] (:already-requested requested) - [:& request-dialog {:title (tr "not-found.no-permission.already-requested.project") - :content [(tr "not-found.no-permission.already-requested.or-others.project")] - :button-text (tr "not-found.no-permission.go-dashboard") - :on-close on-close}] + [:> request-dialog* {:title (tr "not-found.no-permission.already-requested.project") + :content [(tr "not-found.no-permission.already-requested.or-others.project")] + :button-text (tr "not-found.no-permission.go-dashboard") + :on-close on-close}] (:sent requested) - [:& request-dialog {:title (tr "not-found.no-permission.done.success") - :content [(tr "not-found.no-permission.done.remember")] - :button-text (tr "not-found.no-permission.go-dashboard") - :on-close on-close}] + [:> request-dialog* {:title (tr "not-found.no-permission.done.success") + :content [(tr "not-found.no-permission.done.remember")] + :button-text (tr "not-found.no-permission.go-dashboard") + :on-close on-close}] (some? file-id) - [:& request-dialog {:title (tr "not-found.no-permission.file") - :content [(tr "not-found.no-permission.you-can-ask.file") - (tr "not-found.no-permission.if-approves")] - :button-text (tr "not-found.no-permission.ask") - :on-button-click on-request-access - :cancel-text (tr "not-found.no-permission.go-dashboard") - :on-close on-close}] + [:> request-dialog* {:title (tr "not-found.no-permission.file") + :content [(tr "not-found.no-permission.you-can-ask.file") + (tr "not-found.no-permission.if-approves")] + :button-text (tr "not-found.no-permission.ask") + :on-button-click on-request-access + :cancel-text (tr "not-found.no-permission.go-dashboard") + :on-close on-close}] (some? team-id) - [:& request-dialog {:title (tr "not-found.no-permission.project") - :content [(tr "not-found.no-permission.you-can-ask.project") - (tr "not-found.no-permission.if-approves")] - :button-text (tr "not-found.no-permission.ask") - :on-button-click on-request-access - :cancel-text (tr "not-found.no-permission.go-dashboard") - :on-close on-close}]))) + [:> request-dialog* {:title (tr "not-found.no-permission.project") + :content [(tr "not-found.no-permission.you-can-ask.project") + (tr "not-found.no-permission.if-approves")] + :button-text (tr "not-found.no-permission.ask") + :on-button-click on-request-access + :cancel-text (tr "not-found.no-permission.go-dashboard") + :on-close on-close}]))) (mf/defc not-found* [] @@ -535,6 +535,7 @@ [:> request-access* {:file-id (:file-id info) :team-id (:team-id info) :is-default (:team-default info) + :profile profile :is-workspace workspace?}]] [:> exception-section* props]))))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs index 06987ffcaa..0e621db28a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs @@ -10,6 +10,7 @@ ["react-virtualized" :as rvt] [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.exceptions :as ex] [app.common.types.text :as txt] [app.main.constants :refer [max-input-length]] [app.main.data.common :as dcm] @@ -40,9 +41,25 @@ "" (ust/format-precision value 2))) +(defn- get-next-font + [{:keys [id] :as current} fonts] + (if (seq fonts) + (let [index (d/index-of-pred fonts #(= (:id %) id)) + index (or index -1) + next (ex/ignoring (nth fonts (inc index)))] + (or next (first fonts))) + current)) + +(defn- get-prev-font + [{:keys [id] :as current} fonts] + (if (seq fonts) + (let [index (d/index-of-pred fonts #(= (:id %) id)) + next (ex/ignoring (nth fonts (dec index)))] + (or next (peek fonts))) + current)) + (mf/defc font-item* - {::mf/wrap [mf/memo] - ::mf/private true} + {::mf/wrap [mf/memo]} [{:keys [font is-current on-click style]}] (let [item-ref (mf/use-ref) on-click (mf/use-fn (mf/deps font) #(on-click font))] @@ -66,7 +83,7 @@ (declare row-renderer) -(defn- filter-fonts +(defn filter-fonts [{:keys [term backends]} fonts] (let [term (str/lower term) xform (cond-> (map identity) @@ -79,7 +96,8 @@ (mf/defc font-selector* [{:keys [on-select on-close current-font show-recent full-size]}] - (let [state* (mf/use-state + (let [selected (mf/use-state current-font) + state* (mf/use-state #(do {:term "" :backends #{}})) state (deref state*) @@ -94,77 +112,59 @@ recent-fonts (mf/with-memo [state recent-fonts] (filter-fonts state recent-fonts)) - ;; Combine recent fonts with filtered fonts, avoiding duplicates - combined-fonts - (mf/with-memo [recent-fonts fonts] - (let [recent-ids (into #{} d/xf:map-id recent-fonts)] - (into recent-fonts (remove #(contains? recent-ids (:id %))) fonts))) - ;; Initialize selected with current font index - selected-index - (mf/use-state - (fn [] - (or (some (fn [[idx font]] - (when (= (:id current-font) (:id font)) idx)) - (map-indexed vector combined-fonts)) - 0))) - - full-size? - (boolean (and full-size show-recent)) + full-size? (boolean (and full-size show-recent)) select-next (mf/use-fn - (mf/deps combined-fonts) + (mf/deps fonts) (fn [event] (dom/stop-propagation event) (dom/prevent-default event) - (let [next-idx (mod (inc @selected-index) (count combined-fonts))] - (reset! selected-index next-idx)))) + (swap! selected get-next-font fonts))) select-prev (mf/use-fn - (mf/deps combined-fonts) + (mf/deps fonts) (fn [event] (dom/stop-propagation event) (dom/prevent-default event) - (let [prev-idx (mod (dec @selected-index) (count combined-fonts))] - (reset! selected-index prev-idx)))) + (swap! selected get-prev-font fonts))) + + on-key-down + (mf/use-fn + (mf/deps fonts) + (fn [event] + (cond + (kbd/up-arrow? event) (select-prev event) + (kbd/down-arrow? event) (select-next event) + (kbd/esc? event) (on-close) + (kbd/enter? event) (on-close) + :else (dom/focus! (mf/ref-val input))))) + + on-filter-change + (mf/use-fn + (fn [event] + (swap! state* assoc :term event))) on-select-and-close (mf/use-fn (mf/deps on-select on-close) (fn [font] (on-select font) - (on-close))) - - on-key-down - (mf/use-fn - (mf/deps combined-fonts) - (fn [event] - (cond - (kbd/up-arrow? event) (select-prev event) - (kbd/down-arrow? event) (select-next event) - (kbd/esc? event) (on-close) - (kbd/enter? event) (do - (let [selected-font (nth combined-fonts @selected-index)] - (on-select-and-close selected-font))) - :else (dom/focus! (mf/ref-val input))))) - - on-filter-change - (mf/use-fn - (fn [event] - (swap! state* assoc :term event) - ;; Reset selection to first item when filter changes - (reset! selected-index 0)))] + (on-close)))] (mf/with-effect [fonts] (let [key (events/listen js/document "keydown" on-key-down)] #(events/unlistenByKey key))) - (mf/with-effect [@selected-index] + (mf/with-effect [@selected] (when-let [inst (mf/ref-val flist)] - (when (and (>= @selected-index 0) (< @selected-index (count combined-fonts))) - (.scrollToRow ^js inst @selected-index)))) + (when-let [index (:index @selected)] + (.scrollToRow ^js inst index)))) + + (mf/with-effect [@selected] + (on-select @selected)) (mf/with-effect [] (st/emit! (dsc/push-shortcuts :typography {})) @@ -172,12 +172,11 @@ (st/emit! (dsc/pop-shortcuts :typography)))) (mf/with-effect [] - (let [index (d/index-of-pred combined-fonts #(= (:id %) (:id current-font))) + (let [index (d/index-of-pred fonts #(= (:id %) (:id current-font))) inst (mf/ref-val flist)] - (when (and index (>= index 0)) - (tm/schedule - #(let [offset (.getOffsetForRow ^js inst #js {:alignment "center" :index index})] - (.scrollToPosition ^js inst offset)))))) + (tm/schedule + #(let [offset (.getOffsetForRow ^js inst #js {:alignment "center" :index index})] + (.scrollToPosition ^js inst offset))))) [:div {:class (stl/css :font-selector)} [:div {:class (stl/css-case :font-selector-dropdown true :font-selector-dropdown-full-size full-size?)} @@ -194,7 +193,7 @@ :font font :style {} :on-click on-select-and-close - :is-current (= idx @selected-index)}])])] + :is-current (= (:id font) (:id @selected))}])])] [:div {:class (stl/css-case :fonts-list true :fonts-list-full-size full-size?)} @@ -202,17 +201,17 @@ (fn [props] (let [width (unchecked-get props "width") height (unchecked-get props "height") - render #(row-renderer combined-fonts @selected-index on-select-and-close %)] + render #(row-renderer fonts @selected on-select-and-close %)] (mf/html [:> rvt/List #js {:height height :ref flist :width width - :rowCount (count combined-fonts) + :rowCount (count fonts) :rowHeight 36 :rowRenderer render}])))]]]])) (defn row-renderer - [fonts selected-index on-select props] + [fonts selected on-select props] (let [index (unchecked-get props "index") key (unchecked-get props "key") style (unchecked-get props "style") @@ -222,7 +221,7 @@ :font font :style style :on-click on-select - :is-current (= index selected-index)}]))) + :is-current (= (:id font) (:id selected))}]))) (mf/defc font-options {::mf/wrap-props false}