mirror of
https://github.com/penpot/penpot.git
synced 2026-01-14 09:20:01 -05:00
Compare commits
1 Commits
develop
...
palba-fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb88a4e407 |
@@ -16,7 +16,7 @@
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
### :bug: Bugs fixed
|
||||
- Fix prototype connections lost when switching between variants [Taiga #12812](https://tree.taiga.io/project/penpot/issue/12812)
|
||||
|
||||
## 2.13.0 (Unreleased)
|
||||
|
||||
|
||||
@@ -2497,7 +2497,7 @@
|
||||
(-> changes
|
||||
(cls/generate-delete-shapes
|
||||
file page objects (d/ordered-set (:id shape))
|
||||
{:allow-altering-copies true :ignore-children-fn ignore-swapped-fn :ignore-mask true}))
|
||||
{:allow-altering-copies true :ignore-children-fn ignore-swapped-fn :ignore-mask true :ignore-flows-for #{(:id shape)}}))
|
||||
[new-shape changes]
|
||||
(-> changes
|
||||
(generate-new-shape-for-swap shape file page libraries id-new-component index target-cell keep-props-values))]
|
||||
|
||||
@@ -124,9 +124,11 @@
|
||||
;; on the deletion process. It should receive a shape and
|
||||
;; return a boolean
|
||||
ignore-children-fn
|
||||
ignore-mask]
|
||||
ignore-mask
|
||||
ignore-flows-for]
|
||||
:or {ignore-children-fn (constantly false)
|
||||
ignore-mask false}}]
|
||||
ignore-mask false
|
||||
ignore-flows-for #{}}}]
|
||||
(let [objects (pcb/get-objects changes)
|
||||
data (pcb/get-library-data changes)
|
||||
page-id (pcb/get-page-id changes)
|
||||
@@ -194,7 +196,8 @@
|
||||
(->> (:flows page)
|
||||
(reduce
|
||||
(fn [changes [id flow]]
|
||||
(if (id-to-delete? (:starting-frame flow))
|
||||
(if (and (id-to-delete? (:starting-frame flow))
|
||||
(not (contains? ignore-flows-for (:starting-frame flow))))
|
||||
(-> changes
|
||||
(pcb/with-page page)
|
||||
(pcb/set-flow id nil))
|
||||
|
||||
@@ -140,7 +140,8 @@
|
||||
:layout-item-min-w
|
||||
:layout-item-absolute
|
||||
:layout-item-z-index
|
||||
:layout-item-align-self})
|
||||
:layout-item-align-self
|
||||
:interactions})
|
||||
|
||||
(defn component-attr?
|
||||
"Check if some attribute is one that is involved in component syncrhonization.
|
||||
|
||||
@@ -50,7 +50,7 @@ const setupTokensFile = async (page, options = {}) => {
|
||||
const {
|
||||
file = "workspace/get-file-tokens.json",
|
||||
fileFragment = "workspace/get-file-fragment-tokens.json",
|
||||
flags = ["enable-feature-token-input"],
|
||||
flags = [],
|
||||
} = options;
|
||||
|
||||
const workspacePage = new WorkspacePage(page);
|
||||
@@ -2242,56 +2242,6 @@ test.describe("Tokens: Apply token", () => {
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("User applies border-radius token to a shape from sidebar", async ({ page }) => {
|
||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
||||
await setupTokensFile(page);
|
||||
|
||||
await page.getByRole("tab", { name: "Layers" }).click();
|
||||
|
||||
|
||||
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
||||
|
||||
// Open tokens sections on left sidebar
|
||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
||||
await tokensTabButton.click();
|
||||
|
||||
// Unfold border radius tokens
|
||||
await page.getByRole("button", { name: "Border Radius 3" }).click();
|
||||
await expect(
|
||||
tokensSidebar.getByRole("button", { name: "borderRadius" }),
|
||||
).toBeVisible();
|
||||
await tokensSidebar.getByRole("button", { name: "borderRadius" }).click();
|
||||
await expect(
|
||||
tokensSidebar.getByRole("button", { name: "borderRadius.sm" }),
|
||||
).toBeVisible();
|
||||
|
||||
// Apply border radius token from token panels
|
||||
await tokensSidebar.getByRole("button", { name: "borderRadius.sm" }).click();
|
||||
|
||||
// Check if border radius sections is visible on right sidebar
|
||||
const borderRadiusSection = page.getByRole("region", {name: "border-radius-section"});
|
||||
await expect(borderRadiusSection).toBeVisible();
|
||||
|
||||
// Check if token pill is visible on design tab on right sidebar
|
||||
const brTokenPillSM = borderRadiusSection.getByRole('button', { name: 'borderRadius.sm' });
|
||||
await expect(brTokenPillSM).toBeVisible();
|
||||
await brTokenPillSM.click();
|
||||
|
||||
// Change token from dropdown
|
||||
const brTokenOptionXl = borderRadiusSection.getByLabel('borderRadius.xl')
|
||||
await expect(brTokenOptionXl).toBeVisible();
|
||||
await brTokenOptionXl.click();
|
||||
|
||||
await expect(brTokenPillSM).not.toBeVisible();
|
||||
const brTokenPillXL = borderRadiusSection.getByRole('button', { name: 'borderRadius.xl' });
|
||||
await expect(brTokenPillXL).toBeVisible();
|
||||
|
||||
// Detach token from design tab on right sidebar
|
||||
const detachButton = borderRadiusSection.getByRole('button', { name: 'Detach token' });
|
||||
await detachButton.click();
|
||||
await expect(brTokenPillXL).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("User applies typography token to a text shape", async ({ page }) => {
|
||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
||||
await setupTypographyTokensFile(page);
|
||||
@@ -2467,13 +2417,12 @@ test.describe("Tokens: Apply token", () => {
|
||||
const nameField = tokensUpdateCreateModal.getByLabel("Name");
|
||||
await nameField.fill(newTokenTitle);
|
||||
|
||||
const referenceTabButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
name: "Use a reference",
|
||||
});
|
||||
const referenceTabButton =
|
||||
tokensUpdateCreateModal.getByRole('button', { name: 'Use a reference' });
|
||||
referenceTabButton.click();
|
||||
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||
name: "Reference",
|
||||
const referenceField = tokensUpdateCreateModal.getByRole('textbox', {
|
||||
name: 'Reference'
|
||||
});
|
||||
await referenceField.fill("{Full}");
|
||||
|
||||
@@ -2833,18 +2782,14 @@ test.describe("Tokens: Remapping Feature", () => {
|
||||
.click();
|
||||
await expect(tokensUpdateCreateModal).toBeVisible();
|
||||
|
||||
nameField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||
name: "Name",
|
||||
});
|
||||
nameField = tokensUpdateCreateModal.getByRole("textbox", {name: "Name"});
|
||||
await nameField.fill("derived-shadow");
|
||||
|
||||
const referenceToggle =
|
||||
tokensUpdateCreateModal.getByTestId("reference-opt");
|
||||
await referenceToggle.click();
|
||||
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||
name: "Reference",
|
||||
});
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {name: "Reference"});
|
||||
await referenceField.fill("{base-shadow}");
|
||||
|
||||
submitButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
@@ -2933,9 +2878,7 @@ test.describe("Tokens: Remapping Feature", () => {
|
||||
tokensUpdateCreateModal.getByTestId("reference-opt");
|
||||
await referenceToggle.click();
|
||||
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||
name: "Reference",
|
||||
});
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {name: "Reference"});
|
||||
await referenceField.fill("{primary-shadow}");
|
||||
|
||||
submitButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
@@ -3007,8 +2950,7 @@ test.describe("Tokens: Remapping Feature", () => {
|
||||
|
||||
// Verify the shape still has the shadow applied with the UPDATED color value
|
||||
// Expand the shadow section to access the color field
|
||||
const shadowSection =
|
||||
workspacePage.rightSidebar.getByTestId("shadow-section");
|
||||
const shadowSection = workspacePage.rightSidebar.getByTestId("shadow-section");
|
||||
await expect(shadowSection).toBeVisible();
|
||||
|
||||
// Click to expand the shadow options (the menu button)
|
||||
@@ -3066,18 +3008,14 @@ test.describe("Tokens: Remapping Feature", () => {
|
||||
.click();
|
||||
await expect(tokensUpdateCreateModal).toBeVisible();
|
||||
|
||||
nameField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||
name: "Name",
|
||||
});
|
||||
nameField = tokensUpdateCreateModal.getByRole("textbox", {name: "Name"});
|
||||
await nameField.fill("body-text");
|
||||
|
||||
const referenceToggle =
|
||||
tokensUpdateCreateModal.getByTestId("reference-opt");
|
||||
await referenceToggle.click();
|
||||
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||
name: "Reference",
|
||||
});
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {name: "Reference"})
|
||||
await referenceField.fill("{base-text}");
|
||||
|
||||
submitButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
@@ -3158,18 +3096,14 @@ test.describe("Tokens: Remapping Feature", () => {
|
||||
.click();
|
||||
await expect(tokensUpdateCreateModal).toBeVisible();
|
||||
|
||||
nameField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||
name: "Name",
|
||||
});
|
||||
nameField = tokensUpdateCreateModal.getByRole("textbox", {name: "Name"});
|
||||
await nameField.fill("paragraph-style");
|
||||
|
||||
const referenceToggle =
|
||||
tokensUpdateCreateModal.getByTestId("reference-opt");
|
||||
await referenceToggle.click();
|
||||
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||
name: "Reference",
|
||||
});
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {name: "Reference"});
|
||||
await referenceField.fill("{body-style}");
|
||||
|
||||
submitButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
|
||||
@@ -633,43 +633,6 @@
|
||||
:shape-ids shape-ids
|
||||
:on-update-shape on-update-shape}))))))))
|
||||
|
||||
(defn toggle-border-radius-token
|
||||
[{:keys [token attrs shape-ids expand-with-children]}]
|
||||
(ptk/reify ::on-toggle-border-radius-token
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
shapes (into [] (keep (d/getf objects)) shape-ids)
|
||||
|
||||
shapes
|
||||
(if expand-with-children
|
||||
(into []
|
||||
(mapcat (fn [shape]
|
||||
(if (= (:type shape) :group)
|
||||
(keep objects (:shapes shape))
|
||||
[shape])))
|
||||
shapes)
|
||||
shapes)
|
||||
|
||||
{:keys [attributes all-attributes]}
|
||||
(get token-properties (:type token))
|
||||
|
||||
unapply-tokens?
|
||||
(cft/shapes-token-applied? token shapes (or attrs all-attributes attributes))
|
||||
|
||||
shape-ids (map :id shapes)]
|
||||
|
||||
(if unapply-tokens?
|
||||
(rx/of
|
||||
(unapply-token {:attributes (or attrs all-attributes attributes)
|
||||
:token token
|
||||
:shape-ids shape-ids}))
|
||||
(rx/of
|
||||
(apply-token {:attributes attrs
|
||||
:token token
|
||||
:shape-ids shape-ids
|
||||
:on-update-shape update-shape-radius-for-corners})))))))
|
||||
|
||||
|
||||
(defn apply-token-on-selected
|
||||
[color-operations token]
|
||||
|
||||
@@ -183,7 +183,6 @@
|
||||
[:map
|
||||
[:id {:optional true} :string]
|
||||
[:class {:optional true} :string]
|
||||
[:inner-class {:optional true} :string]
|
||||
[:value {:optional true} [:maybe [:or
|
||||
:int
|
||||
:float
|
||||
@@ -210,8 +209,7 @@
|
||||
|
||||
(mf/defc numeric-input*
|
||||
{::mf/schema schema:numeric-input}
|
||||
[{:keys [id class value default placeholder
|
||||
icon disabled inner-class
|
||||
[{:keys [id class value default placeholder icon disabled
|
||||
min max max-length step
|
||||
is-selected-on-focus nillable
|
||||
tokens applied-token empty-to-end
|
||||
@@ -626,7 +624,6 @@
|
||||
(mf/spread-props props {:ref ref
|
||||
:type "text"
|
||||
:id id
|
||||
:class inner-class
|
||||
:placeholder (if is-multiple?
|
||||
(tr "labels.mixed-values")
|
||||
placeholder)
|
||||
@@ -647,7 +644,7 @@
|
||||
:class (stl/css :icon)}]]))
|
||||
:slot-end (when-not disabled
|
||||
(when (some? tokens)
|
||||
(mf/html [:> icon-button* {:variant "ghost"
|
||||
(mf/html [:> icon-button* {:variant "action"
|
||||
:icon i/tokens
|
||||
:class (stl/css :invisible-button)
|
||||
:aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown")
|
||||
@@ -672,7 +669,6 @@
|
||||
:on-token-key-down on-token-key-down
|
||||
:disabled disabled
|
||||
:on-blur on-blur
|
||||
:class inner-class
|
||||
:slot-start (when icon
|
||||
(mf/html [:> tooltip*
|
||||
{:content property
|
||||
|
||||
@@ -33,17 +33,12 @@
|
||||
}
|
||||
|
||||
.invisible-button {
|
||||
position: absolute;
|
||||
inset-inline-end: 0;
|
||||
inset-block-start: 0;
|
||||
opacity: var(--opacity-button);
|
||||
background-color: var(--color-background-quaternary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-background-quaternary);
|
||||
--opacity-button: 1;
|
||||
}
|
||||
&:focus {
|
||||
background-color: var(--color-background-quaternary);
|
||||
--opacity-button: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
[:map
|
||||
[:id {:optional true} :string]
|
||||
[:resolved-value {:optional true}
|
||||
[:or :int :string :float]]
|
||||
[:or :int :string]]
|
||||
[:name {:optional true} :string]
|
||||
[:icon {:optional true} schema:icon-list]
|
||||
[:label {:optional true} :string]
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
}
|
||||
|
||||
.left-align {
|
||||
left: var(--dropdown-offset, 0);
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.right-align {
|
||||
right: var(--dropdown-offset, 0);
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.option-separator {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
[:map
|
||||
[:id {:optiona true} :string]
|
||||
[:ref some?]
|
||||
[:resolved {:optional true} [:or :int :string :float]]
|
||||
[:resolved {:optional true} [:or :int :string]]
|
||||
[:name {:optional true} :string]
|
||||
[:on-click {:optional true} fn?]
|
||||
[:selected {:optional true} :boolean]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
(def ^:private schema:input-field
|
||||
[:map
|
||||
[:class {:optional true} [:maybe :string]]
|
||||
[:class {:optional true} :string]
|
||||
[:aria-label {:optional true} [:maybe :string]]
|
||||
[:id :string]
|
||||
[:icon {:optional true}
|
||||
@@ -44,10 +44,9 @@
|
||||
tooltip-id (mf/use-id)
|
||||
|
||||
props (mf/spread-props props
|
||||
{:class [class
|
||||
(stl/css-case
|
||||
:input true
|
||||
:input-with-icon (some? icon))]
|
||||
{:class (stl/css-case
|
||||
:input true
|
||||
:input-with-icon (some? icon))
|
||||
:ref (or ref input-ref)
|
||||
:aria-invalid (when (and has-hint
|
||||
(= hint-type "error"))
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
(def ^:private schema:token-field
|
||||
[:map
|
||||
[:class {:optional true} [:maybe :string]]
|
||||
[:id {:optional true} [:maybe :string]]
|
||||
[:label {:optional true} [:maybe :string]]
|
||||
[:value :any]
|
||||
@@ -33,7 +32,7 @@
|
||||
|
||||
(mf/defc token-field*
|
||||
{::mf/schema schema:token-field}
|
||||
[{:keys [id label value slot-start disabled class
|
||||
[{:keys [id label value slot-start disabled
|
||||
on-click on-token-key-down on-blur detach-token
|
||||
token-wrapper-ref token-detach-btn-ref on-focus]}]
|
||||
(let [set-active? (some? id)
|
||||
@@ -49,11 +48,14 @@
|
||||
(fn [event]
|
||||
(when-not ^boolean disabled
|
||||
(dom/prevent-default event)
|
||||
(dom/focus! (mf/ref-val token-wrapper-ref)))))]
|
||||
(dom/focus! (mf/ref-val token-wrapper-ref)))))
|
||||
|
||||
[:div {:class [class (stl/css-case :token-field true
|
||||
:with-icon (some? slot-start)
|
||||
:token-field-disabled disabled)]
|
||||
class
|
||||
(stl/css-case :token-field true
|
||||
:with-icon (some? slot-start)
|
||||
:token-field-disabled disabled)]
|
||||
|
||||
[:div {:class class
|
||||
:on-click focus-wrapper
|
||||
:disabled disabled
|
||||
:on-key-down on-token-key-down
|
||||
@@ -78,7 +80,7 @@
|
||||
[:div {:class (stl/css :pill-dot)}])]]
|
||||
|
||||
(when-not ^boolean disabled
|
||||
[:> icon-button* {:variant "ghost"
|
||||
[:> icon-button* {:variant "action"
|
||||
:class (stl/css :invisible-button)
|
||||
:icon i/broken-link
|
||||
:ref token-detach-btn-ref
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
@use "ds/_sizes.scss" as *;
|
||||
@use "ds/typography.scss" as t;
|
||||
@use "ds/colors.scss" as *;
|
||||
@use "ds/mixins.scss" as *;
|
||||
|
||||
.token-field {
|
||||
--token-field-bg-color: var(--color-background-tertiary);
|
||||
@@ -17,7 +16,9 @@
|
||||
--token-field-outline-color: none;
|
||||
--token-field-height: var(--sp-xxxl);
|
||||
--token-field-margin: unset;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
column-gap: var(--sp-xs);
|
||||
align-items: center;
|
||||
position: relative;
|
||||
@@ -26,7 +27,6 @@
|
||||
border-radius: $br-8;
|
||||
padding: var(--sp-xs);
|
||||
outline: $b-1 solid var(--token-field-outline-color);
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
--token-field-bg-color: var(--color-background-quaternary);
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
|
||||
.with-icon {
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
}
|
||||
|
||||
.token-field-disabled {
|
||||
@@ -57,17 +57,14 @@
|
||||
--pill-bg-color: var(--color-background-tertiary);
|
||||
--pill-fg-color: var(--color-token-foreground);
|
||||
@include t.use-typography("code-font");
|
||||
@include textEllipsis;
|
||||
display: block;
|
||||
block-size: var(--sp-xxl);
|
||||
inline-size: fit-content;
|
||||
height: var(--sp-xxl);
|
||||
width: fit-content;
|
||||
background: var(--pill-bg-color);
|
||||
cursor: pointer;
|
||||
border: $b-1 solid var(--pill-border-color);
|
||||
color: var(--pill-fg-color);
|
||||
border-radius: $br-6;
|
||||
padding-inline: $sz-6;
|
||||
max-inline-size: 100%;
|
||||
&:hover {
|
||||
--pill-bg-color: var(--color-token-background);
|
||||
--pill-fg-color: var(--color-foreground-primary);
|
||||
@@ -106,29 +103,24 @@
|
||||
}
|
||||
|
||||
.pill-dot {
|
||||
inline-size: $sz-6;
|
||||
block-size: $sz-6;
|
||||
width: $sz-6;
|
||||
height: $sz-6;
|
||||
outline: var(--sp-xxs) solid var(--color-background-primary);
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-foreground-error);
|
||||
margin-inline-start: var(--sp-xs);
|
||||
margin-left: var(--sp-xs);
|
||||
position: absolute;
|
||||
inset-inline-end: 0;
|
||||
inset-block-start: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.invisible-button {
|
||||
position: absolute;
|
||||
inset-inline-end: 0;
|
||||
inset-block-start: 0;
|
||||
opacity: var(--opacity-button);
|
||||
background-color: var(--color-background-quaternary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-background-quaternary);
|
||||
--opacity-button: 1;
|
||||
}
|
||||
&:focus {
|
||||
background-color: var(--color-background-quaternary);
|
||||
--opacity-button: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +159,4 @@ $arrow-side: 12px;
|
||||
block-size: fit-content;
|
||||
inline-size: fit-content;
|
||||
line-height: 0;
|
||||
display: grid;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@@ -3,15 +3,10 @@
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.shape.radius :as ctsr]
|
||||
[app.common.types.token :as tk]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
[app.main.features :as features]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.numeric-input :as deprecated-input]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
@@ -26,17 +21,11 @@
|
||||
(defn- check-border-radius-menu-props
|
||||
[old-props new-props]
|
||||
(let [old-values (unchecked-get old-props "values")
|
||||
new-values (unchecked-get new-props "values")
|
||||
old-applied-tokens (unchecked-get old-props "appliedTokens")
|
||||
new-applied-tokens (unchecked-get new-props "appliedTokens")]
|
||||
new-values (unchecked-get new-props "values")]
|
||||
(and (identical? (unchecked-get old-props "class")
|
||||
(unchecked-get new-props "class"))
|
||||
(identical? (unchecked-get old-props "ids")
|
||||
(unchecked-get new-props "ids"))
|
||||
(identical? (unchecked-get old-props "shapes")
|
||||
(unchecked-get new-props "shapes"))
|
||||
(identical? old-applied-tokens
|
||||
new-applied-tokens)
|
||||
(identical? (get old-values :r1)
|
||||
(get new-values :r1))
|
||||
(identical? (get old-values :r2)
|
||||
@@ -46,114 +35,13 @@
|
||||
(identical? (get old-values :r4)
|
||||
(get new-values :r4)))))
|
||||
|
||||
(mf/defc numeric-input-wrapper*
|
||||
{::mf/private true}
|
||||
[{:keys [values name applied-tokens align on-detach radius] :rest props}]
|
||||
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
|
||||
tokens (mf/with-memo [tokens name]
|
||||
(delay
|
||||
(-> (deref tokens)
|
||||
(select-keys (get tk/tokens-by-input name))
|
||||
(not-empty))))
|
||||
|
||||
on-detach-attr
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach name)
|
||||
#(on-detach % name))
|
||||
|
||||
r1-value (get applied-tokens :r1)
|
||||
all-token-equal? (and (seq applied-tokens) (all-equal? applied-tokens))
|
||||
all-values-equal? (all-equal? values)
|
||||
|
||||
applied-token (cond
|
||||
(not (seq applied-tokens))
|
||||
nil
|
||||
|
||||
(and (= radius :all) (or (not all-values-equal?) (not all-token-equal?)))
|
||||
:multiple
|
||||
|
||||
(and all-token-equal? all-values-equal? (= radius :all))
|
||||
r1-value
|
||||
|
||||
:else
|
||||
(get applied-tokens radius))
|
||||
|
||||
|
||||
placeholder (if (= radius :all)
|
||||
(cond
|
||||
(or (not all-values-equal?)
|
||||
(not all-token-equal?))
|
||||
(tr "settings.multiple")
|
||||
:else
|
||||
"--")
|
||||
|
||||
(cond
|
||||
(or (= :multiple (:applied-tokens values))
|
||||
(= :multiple (get values name)))
|
||||
(tr "settings.multiple")
|
||||
:else
|
||||
"--"))
|
||||
|
||||
|
||||
props (mf/spread-props props
|
||||
{:placeholder placeholder
|
||||
:applied-token applied-token
|
||||
:tokens (if (delay? tokens) @tokens tokens)
|
||||
:align align
|
||||
:on-detach on-detach-attr
|
||||
:value values})]
|
||||
[:> numeric-input* props]))
|
||||
|
||||
(mf/defc border-radius-menu*
|
||||
{::mf/wrap [#(mf/memo' % check-border-radius-menu-props)]}
|
||||
[{:keys [class ids values applied-tokens]}]
|
||||
(let [token-numeric-inputs
|
||||
(features/use-feature "tokens/numeric-input")
|
||||
|
||||
all-values-equal? (all-equal? values)
|
||||
|
||||
[{:keys [class ids values]}]
|
||||
(let [all-equal? (all-equal? values)
|
||||
radius-expanded* (mf/use-state false)
|
||||
radius-expanded (deref radius-expanded*)
|
||||
|
||||
;; DETACH
|
||||
on-detach-token
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [token attr]
|
||||
(st/emit! (dwta/unapply-token {:token (first token)
|
||||
:attributes #{attr}
|
||||
:shape-ids ids}))))
|
||||
|
||||
on-detach-all
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach-token)
|
||||
(fn [token]
|
||||
(run! #(on-detach-token token %) [:r1 :r2 :r3 :r4])))
|
||||
|
||||
on-detach-r1
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach-token)
|
||||
(fn [token]
|
||||
(on-detach-token token :r1)))
|
||||
|
||||
on-detach-r2
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach-token)
|
||||
(fn [token]
|
||||
(on-detach-token token :r2)))
|
||||
|
||||
on-detach-r3
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach-token)
|
||||
(fn [token]
|
||||
(on-detach-token token :r3)))
|
||||
|
||||
on-detach-r4
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach-token)
|
||||
(fn [token]
|
||||
(on-detach-token token :r4)))
|
||||
|
||||
change-radius
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
@@ -166,54 +54,31 @@
|
||||
{:reg-objects? true
|
||||
:attrs [:r1 :r2 :r3 :r4]})))
|
||||
|
||||
change-one-radius
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [update-fn attr]
|
||||
(dwsh/update-shapes ids
|
||||
(fn [shape]
|
||||
(if (ctsr/has-radius? shape)
|
||||
(update-fn shape)
|
||||
shape))
|
||||
{:reg-objects? true
|
||||
:attrs [attr]})))
|
||||
|
||||
toggle-radius-mode
|
||||
(mf/use-fn
|
||||
(mf/deps radius-expanded)
|
||||
(fn []
|
||||
(swap! radius-expanded* not)))
|
||||
|
||||
|
||||
on-all-radius-change
|
||||
(mf/use-fn
|
||||
(mf/deps change-radius ids)
|
||||
(fn [value]
|
||||
(if (or (string? value) (number? value))
|
||||
(st/emit!
|
||||
(change-radius (fn [shape]
|
||||
(ctsr/set-radius-to-all-corners shape value))))
|
||||
(doseq [attr [:r1 :r2 :r3 :r4]]
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids}))))))
|
||||
|
||||
|
||||
on-single-radius-change
|
||||
(mf/use-fn
|
||||
(mf/deps change-one-radius ids)
|
||||
(fn [value attr]
|
||||
(if (or (string? value) (number? value))
|
||||
(st/emit! (change-one-radius #(ctsr/set-radius-to-single-corner % attr value) attr))
|
||||
(st/emit! (dwta/toggle-border-radius-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids})))))
|
||||
(mf/deps ids change-radius)
|
||||
(fn [value]
|
||||
(st/emit!
|
||||
(change-radius (fn [shape]
|
||||
(ctsr/set-radius-to-all-corners shape value))))))
|
||||
|
||||
on-radius-r1-change #(on-single-radius-change % :r1)
|
||||
on-radius-r2-change #(on-single-radius-change % :r2)
|
||||
on-radius-r3-change #(on-single-radius-change % :r3)
|
||||
on-radius-r4-change #(on-single-radius-change % :r4)
|
||||
|
||||
on-radius-4-change
|
||||
(mf/use-fn
|
||||
(mf/deps ids change-radius)
|
||||
(fn [value attr]
|
||||
(st/emit! (change-radius #(ctsr/set-radius-to-single-corner % attr value)))))
|
||||
|
||||
on-radius-r1-change #(on-radius-4-change % :r1)
|
||||
on-radius-r2-change #(on-radius-4-change % :r2)
|
||||
on-radius-r3-change #(on-radius-4-change % :r3)
|
||||
on-radius-r4-change #(on-radius-4-change % :r4)
|
||||
|
||||
expand-stream
|
||||
(mf/with-memo []
|
||||
@@ -227,139 +92,58 @@
|
||||
(mf/with-effect [ids]
|
||||
(reset! radius-expanded* false))
|
||||
|
||||
[:section {:class (dm/str class " " (stl/css :radius))
|
||||
:aria-label "border-radius-section"}
|
||||
[:div {:class (dm/str class " " (stl/css :radius))}
|
||||
(if (not radius-expanded)
|
||||
(if token-numeric-inputs
|
||||
[:> numeric-input-wrapper*
|
||||
{:on-change on-all-radius-change
|
||||
:on-detach on-detach-all
|
||||
:icon i/corner-radius
|
||||
[:div {:class (stl/css :radius-1)
|
||||
:title (tr "workspace.options.radius")}
|
||||
[:> icon* {:icon-id i/corner-radius
|
||||
:size "s"
|
||||
:class (stl/css :icon)}]
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder (cond
|
||||
(not all-equal?)
|
||||
(tr "settings.multiple")
|
||||
(= :multiple (:r1 values))
|
||||
(tr "settings.multiple")
|
||||
:else
|
||||
"--")
|
||||
:min 0
|
||||
:nillable true
|
||||
:on-change on-single-radius-change
|
||||
:value (if all-equal? (:r1 values) nil)}]]
|
||||
|
||||
[:div {:class (stl/css :radius-4)}
|
||||
[:div {:class (stl/css :small-input)}
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder "--"
|
||||
:title (tr "workspace.options.radius-top-left")
|
||||
:min 0
|
||||
:name :border-radius
|
||||
:nillable true
|
||||
:property (tr "workspace.options.radius")
|
||||
:class (stl/css :radius-wrapper)
|
||||
:applied-tokens applied-tokens
|
||||
:radius :all
|
||||
:align :right
|
||||
:values (if all-values-equal?
|
||||
(if (nil? (:r1 values))
|
||||
0
|
||||
(:r1 values))
|
||||
nil)}]
|
||||
:on-change on-radius-r1-change
|
||||
:value (:r1 values)}]]
|
||||
|
||||
[:div {:class (stl/css :radius-1)
|
||||
:title (tr "workspace.options.radius")}
|
||||
[:> icon* {:icon-id i/corner-radius
|
||||
:size "s"
|
||||
:class (stl/css :icon)}]
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder (cond
|
||||
(not all-values-equal?)
|
||||
(tr "settings.multiple")
|
||||
(= :multiple (:r1 values))
|
||||
(tr "settings.multiple")
|
||||
:else
|
||||
"--")
|
||||
:min 0
|
||||
:nillable true
|
||||
:on-change on-all-radius-change
|
||||
:value (if all-values-equal?
|
||||
(if (nil? (:r1 values))
|
||||
0
|
||||
(:r1 values))
|
||||
nil)}]])
|
||||
[:div {:class (stl/css :small-input)}
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder "--"
|
||||
:title (tr "workspace.options.radius-top-right")
|
||||
:min 0
|
||||
:on-change on-radius-r2-change
|
||||
:value (:r2 values)}]]
|
||||
|
||||
(if token-numeric-inputs
|
||||
[:div {:class (stl/css :radius-4)}
|
||||
[:> numeric-input-wrapper*
|
||||
{:on-change on-radius-r1-change
|
||||
:on-detach on-detach-r1
|
||||
:min 0
|
||||
:name :border-radius
|
||||
:property (tr "workspace.options.radius-top-left")
|
||||
:applied-tokens applied-tokens
|
||||
:radius :r1
|
||||
:align :right
|
||||
:class (stl/css :radius-wrapper :dropdown-offset)
|
||||
:inner-class (stl/css :no-icon-input)
|
||||
:values (:r1 values)}]
|
||||
[:div {:class (stl/css :small-input)}
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder "--"
|
||||
:title (tr "workspace.options.radius-bottom-left")
|
||||
:min 0
|
||||
:on-change on-radius-r4-change
|
||||
:value (:r4 values)}]]
|
||||
|
||||
[:> numeric-input-wrapper*
|
||||
{:on-change on-radius-r2-change
|
||||
:on-detach on-detach-r2
|
||||
:min 0
|
||||
:name :border-radius
|
||||
:nillable true
|
||||
:property (tr "workspace.options.radius-top-right")
|
||||
:applied-tokens applied-tokens
|
||||
:align :right
|
||||
:class (stl/css :radius-wrapper)
|
||||
:inner-class (stl/css :no-icon-input)
|
||||
:radius :r2
|
||||
:values (:r2 values)}]
|
||||
|
||||
[:> numeric-input-wrapper*
|
||||
{:on-change on-radius-r4-change
|
||||
:on-detach on-detach-r4
|
||||
:min 0
|
||||
:name :border-radius
|
||||
:nillable true
|
||||
:property (tr "workspace.options.radius-bottom-left")
|
||||
:applied-tokens applied-tokens
|
||||
:class (stl/css :radius-wrapper :dropdown-offset)
|
||||
:inner-class (stl/css :no-icon-input)
|
||||
:radius :r4
|
||||
:align :right
|
||||
:values (:r4 values)}]
|
||||
|
||||
[:> numeric-input-wrapper*
|
||||
{:on-change on-radius-r3-change
|
||||
:on-detach on-detach-r3
|
||||
:min 0
|
||||
:name :border-radius
|
||||
:nillable true
|
||||
:property (tr "workspace.options.radius-bottom-right")
|
||||
:applied-tokens applied-tokens
|
||||
:radius :r3
|
||||
:align :right
|
||||
:class (stl/css :radius-wrapper)
|
||||
:inner-class (stl/css :no-icon-input)
|
||||
:values (:r3 values)}]]
|
||||
|
||||
[:div {:class (stl/css :radius-4)}
|
||||
[:div {:class (stl/css :small-input)}
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder "--"
|
||||
:title (tr "workspace.options.radius-top-left")
|
||||
:min 0
|
||||
:on-change on-radius-r1-change
|
||||
:value (:r1 values)}]]
|
||||
|
||||
[:div {:class (stl/css :small-input)}
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder "--"
|
||||
:title (tr "workspace.options.radius-top-right")
|
||||
:min 0
|
||||
:on-change on-radius-r2-change
|
||||
:value (:r2 values)}]]
|
||||
|
||||
[:div {:class (stl/css :small-input)}
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder "--"
|
||||
:title (tr "workspace.options.radius-bottom-left")
|
||||
:min 0
|
||||
:on-change on-radius-r4-change
|
||||
:value (:r4 values)}]]
|
||||
|
||||
[:div {:class (stl/css :small-input)}
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder "--"
|
||||
:title (tr "workspace.options.radius-bottom-right")
|
||||
:min 0
|
||||
:on-change on-radius-r3-change
|
||||
:value (:r3 values)}]]]))
|
||||
[:div {:class (stl/css :small-input)}
|
||||
[:> deprecated-input/numeric-input*
|
||||
{:placeholder "--"
|
||||
:title (tr "workspace.options.radius-bottom-right")
|
||||
:min 0
|
||||
:on-change on-radius-r3-change
|
||||
:value (:r3 values)}]]])
|
||||
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:on-click toggle-radius-mode
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
// Copyright (c) KALEIDOS INC
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "ds/typography" as t;
|
||||
@use "ds/_utils.scss" as *;
|
||||
|
||||
.radius {
|
||||
display: grid;
|
||||
@@ -16,7 +14,7 @@
|
||||
|
||||
.radius-1 {
|
||||
@extend .input-element;
|
||||
@include t.use-typography("body-small");
|
||||
@include deprecated.bodySmallTypography;
|
||||
}
|
||||
|
||||
.radius-4 {
|
||||
@@ -27,27 +25,9 @@
|
||||
|
||||
.small-input {
|
||||
@extend .input-element;
|
||||
@include t.use-typography("body-small");
|
||||
}
|
||||
|
||||
.selected {
|
||||
border-color: var(--button-icon-border-color-selected);
|
||||
background-color: var(--button-icon-background-color-selected);
|
||||
color: var(--color-accent-primary);
|
||||
@include deprecated.bodySmallTypography;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-inline: var(--sp-xs);
|
||||
}
|
||||
|
||||
.radius-wrapper {
|
||||
--dropdown-width: var(--7-columns-dropdown-width);
|
||||
}
|
||||
|
||||
.no-icon-input {
|
||||
padding-inline-start: px2rem(6);
|
||||
}
|
||||
|
||||
.dropdown-offset {
|
||||
--dropdown-offset: #{px2rem(-65)};
|
||||
margin-inline: deprecated.$s-4;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
(nil? (get values name)))
|
||||
(tr "settings.multiple")
|
||||
"--")
|
||||
:class (stl/css :numeric-input-layout)
|
||||
:class (stl/css :numeric-input-measures)
|
||||
:applied-token (get applied-tokens name)
|
||||
:tokens tokens
|
||||
:align align
|
||||
|
||||
@@ -358,6 +358,6 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.numeric-input-layout {
|
||||
.numeric-input-measures {
|
||||
--dropdown-width: var(--7-columns-dropdown-width);
|
||||
}
|
||||
|
||||
@@ -600,7 +600,10 @@
|
||||
[:> border-radius-menu* {:class (stl/css :border-radius)
|
||||
:ids ids
|
||||
:values values
|
||||
:applied-tokens applied-tokens}])])
|
||||
:applied-tokens applied-tokens
|
||||
:shapes shapes
|
||||
:shape shape}])])
|
||||
|
||||
(when (or (options :clip-content)
|
||||
(options :show-in-viewer))
|
||||
[:div {:class (stl/css :clip-show)}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "../../../sidebar/common/sidebar.scss" as sidebar;
|
||||
@use "ds/_utils.scss" as *;
|
||||
|
||||
.element-set {
|
||||
display: grid;
|
||||
@@ -157,6 +156,7 @@
|
||||
gap: deprecated.$s-4;
|
||||
}
|
||||
|
||||
// TODO: Add a proper variable to this sizing
|
||||
.numeric-input-measures {
|
||||
--dropdown-width: var(--7-columns-dropdown-width);
|
||||
}
|
||||
|
||||
@@ -223,6 +223,7 @@
|
||||
(cond
|
||||
(= existing ::not-found) (assoc acc t-attr new-val)
|
||||
(= existing new-val) acc
|
||||
(nil? new-val) acc
|
||||
:else (assoc acc t-attr :multiple))))
|
||||
|
||||
merge-shape-attr
|
||||
@@ -236,8 +237,10 @@
|
||||
(fn [acc shape-attrs applied-tokens]
|
||||
"Merges token values across all shape attributes.
|
||||
For each shape attribute, its corresponding token attributes are merged
|
||||
into the accumulator."
|
||||
(reduce #(merge-shape-attr %1 applied-tokens %2) acc shape-attrs))
|
||||
into the accumulator. If applied tokens are empty, the accumulator is returned unchanged."
|
||||
(if (seq applied-tokens)
|
||||
(reduce #(merge-shape-attr %1 applied-tokens %2) acc shape-attrs)
|
||||
acc))
|
||||
|
||||
extract-attrs
|
||||
(fn [[ids values token-acc] {:keys [id type applied-tokens] :as shape}]
|
||||
|
||||
Reference in New Issue
Block a user