diff --git a/docker/images/Dockerfile.exporter b/docker/images/Dockerfile.exporter index 28cc80c807..03be19d2f3 100644 --- a/docker/images/Dockerfile.exporter +++ b/docker/images/Dockerfile.exporter @@ -5,7 +5,8 @@ ENV LANG=en_US.UTF-8 \ LC_ALL=en_US.UTF-8 \ NODE_VERSION=v22.22.0 \ DEBIAN_FRONTEND=noninteractive \ - PATH=/opt/node/bin:/opt/imagick/bin:$PATH + PATH=/opt/node/bin:/opt/imagick/bin:$PATH \ + PLAYWRIGHT_BROWSERS_PATH=/opt/penpot/browsers RUN set -ex; \ useradd -U -M -u 1001 -s /bin/false -d /opt/penpot penpot; \ diff --git a/exporter/scripts/build b/exporter/scripts/build index 53a930f4b8..3daa2cf6f5 100755 --- a/exporter/scripts/build +++ b/exporter/scripts/build @@ -15,6 +15,7 @@ pnpm run build; cp pnpm-lock.yaml target/; cp package.json target/; +touch target/pnpm-workspace.yaml; cat <\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:r3\",0,\"~:layout-justify-content\",\"~:stretch\",\"~:r1\",0,\"^N\",\"~uaef184da-e9c1-80f8-8007-961cf253d534\",\"~:layout-justify-items\",\"^G\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:layout-align-content\",\"^19\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",322,\"~:proportion\",1,\"~:r4\",0,\"~:layout-grid-rows\",[[\"^ \",\"^2\",\"^3\",\"^4\",1],[\"^ \",\"^2\",\"^3\",\"^4\",1]],\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",322,\"~:y\",286,\"^H\",298,\"~:height\",266,\"~:x1\",322,\"~:y1\",286,\"~:x2\",620,\"~:y2\",552]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:layout-grid-dir\",\"^R\",\"~:flip-x\",null,\"^1E\",266,\"~:flip-y\",null,\"^T\",[]]]" + } + }, + "~:id": "~u0472abff-2573-8186-8007-961793e53f46", + "~:name": "Page 1" + } + }, + "~:id": "~u0472abff-2573-8186-8007-961793e53f45", + "~:options": { + "~:components-v2": true, + "~:base-font-size": "16px" + } + } +} \ No newline at end of file diff --git a/frontend/playwright/data/workspace/update-file-13415.json b/frontend/playwright/data/workspace/update-file-13415.json new file mode 100644 index 0000000000..866b4eb8eb --- /dev/null +++ b/frontend/playwright/data/workspace/update-file-13415.json @@ -0,0 +1,18 @@ +{ + "~:revn": 14, + "~:lagged": [ + { + "~:id": "~u0472abff-2573-8186-8007-96347d525f65", + "~:revn": 15, + "~:file-id": "~u0472abff-2573-8186-8007-961793e53f45", + "~:session-id": "~uf25e6d2f-d10c-8021-8007-96344433f08d", + "~:changes": [ + { + "~:type": "~:del-obj", + "~:page-id": "~u0472abff-2573-8186-8007-961793e53f46", + "~:id": "~uaef184da-e9c1-80f8-8007-961cf253d534" + } + ] + } + ] +} \ No newline at end of file diff --git a/frontend/playwright/ui/pages/WasmWorkspacePage.js b/frontend/playwright/ui/pages/WasmWorkspacePage.js index 405f3eb55e..a877f03dba 100644 --- a/frontend/playwright/ui/pages/WasmWorkspacePage.js +++ b/frontend/playwright/ui/pages/WasmWorkspacePage.js @@ -35,8 +35,8 @@ export class WasmWorkspacePage extends WorkspacePage { return WasmWorkspacePage.mockConfigFlags(this.page, flags); } - constructor(page) { - super(page); + constructor(page, options) { + super(page, options); this.canvas = page.getByTestId("canvas-wasm-shapes"); } diff --git a/frontend/playwright/ui/pages/WorkspacePage.js b/frontend/playwright/ui/pages/WorkspacePage.js index 46c975827a..18da0810bd 100644 --- a/frontend/playwright/ui/pages/WorkspacePage.js +++ b/frontend/playwright/ui/pages/WorkspacePage.js @@ -35,45 +35,9 @@ export class WorkspacePage extends BaseWebSocketPage { } async waitForEditor() { - return this.page.waitForSelector('[data-itype="editor"]'); - } - - async waitForRoot() { - return this.page.waitForSelector('[data-itype="root"]'); - } - - async waitForParagraph(nth) { - if (!nth) { - return this.page.waitForSelector('[data-itype="paragraph"]'); - } - return this.page.waitForSelector( - `[data-itype="paragraph"]:nth-child(${nth})`, - ); - } - - async waitForParagraphStyle(nth, styleName) { - const paragraph = await this.waitForParagraph(nth); - return this.waitForStyle(paragraph, styleName); - } - - async waitForTextSpan(nth = 0) { - if (!nth) { - return this.page.waitForSelector('[data-itype="span"]'); - } - return this.page.waitForSelector( - `[data-itype="span"]:nth-child(${nth})`, - ); - } - - async waitForTextSpanContent(nth = 0) { - const textSpan = await this.waitForTextSpan(nth); - const textContent = await textSpan.textContent(); - return textContent; - } - - async waitForTextSpanStyle(nth, styleName) { - const textSpan = await this.waitForTextSpan(nth); - return this.waitForStyle(textSpan, styleName); + const typographyInput = + this.workspacePage.rightSidebar.getByLabel("Font Size"); + await expect(typographyInput).toBeVisible(); } async startEditing() { @@ -98,7 +62,7 @@ export class WorkspacePage extends BaseWebSocketPage { } async moveFromStart(offset = 0) { - await this.page.keyboard.press("ArrowLeft"); + await this.page.keyboard.press("Home"); await this.moveToRight(offset); } @@ -125,7 +89,7 @@ export class WorkspacePage extends BaseWebSocketPage { await expect(locator).toBeVisible(); await locator.focus(); await locator.fill(`${newValue}`); - await locator.blur(); + await this.page.keyboard.press("Enter"); } changeFontSize(newValue) { @@ -198,10 +162,10 @@ export class WorkspacePage extends BaseWebSocketPage { `[id="shape-00000000-0000-0000-0000-000000000000"]`, ); this.toolbarOptions = page.getByTestId("toolbar-options"); - this.rectShapeButton = page.getByTestId("toolbar-options").getByRole("button", { name: "Rectangle" }); - this.ellipseShapeButton = page.getByTestId("toolbar-options").getByRole("button", { name: "Ellipse" }); - this.moveButton = page.getByTestId("toolbar-options").getByRole("button", { name: "Move" }); - this.boardButton = page.getByTestId("toolbar-options").getByRole("button", { name: "Board" }); + this.rectShapeButton = page.getByRole("button", { name: "Rectangle (R)" }); + this.ellipseShapeButton = page.getByRole("button", { name: "Ellipse (E)" }); + this.moveButton = page.getByRole("button", { name: "Move (V)" }); + this.boardButton = page.getByRole("button", { name: "Board (B)" }); this.toggleToolbarButton = page.getByRole("button", { name: "Toggle toolbar", }); @@ -390,10 +354,12 @@ export class WorkspacePage extends BaseWebSocketPage { const timeToWait = options?.timeToWait ?? 100; await this.page.keyboard.press("T"); await this.page.waitForTimeout(timeToWait); + + const layersCountBefore = await this.layers.getByTestId("layer-row").count(); await this.clickAndMove(x1, y1, x2, y2); - await expect(this.page.getByTestId("text-editor")).toBeVisible(); if (initialText) { + await this.waitForSelectedShapeName("Text"); await this.page.keyboard.type(initialText); } } @@ -493,10 +459,23 @@ export class WorkspacePage extends BaseWebSocketPage { async expectSelectedLayer(name) { await expect( - this.layers - .getByTestId("layer-row") - .filter({ has: this.page.getByText(name) }), - ).toHaveClass(/selected/); + this.layers.getByRole("checkbox", { name, checked: true }), + ).toBeVisible(); + } + + async getSelectedShapeName() { + const selectedLayer = this.layers + .getByRole("checkbox", { checked: true }) + .first(); + await selectedLayer.waitFor({ state: "visible" }); + return (await selectedLayer.innerText()).trim(); + } + + async waitForSelectedShapeName(expectedName) { + const selectedLayer = this.layers + .getByRole("checkbox", { checked: true }) + .first(); + await expect(selectedLayer).toHaveText(expectedName); } async expectHiddenToolbarOptions() { diff --git a/frontend/playwright/ui/specs/design-tab.spec.js b/frontend/playwright/ui/specs/design-tab.spec.js index df12cf9238..489579b844 100644 --- a/frontend/playwright/ui/specs/design-tab.spec.js +++ b/frontend/playwright/ui/specs/design-tab.spec.js @@ -189,8 +189,8 @@ test("BUG 7760 - Layout losing properties when changing parents", async ({ await workspacePage.clickLeafLayer("Flex Board"); // Move the first board into the second - const hAuto = await workspacePage.page.getByTestId("behaviour-h-auto"); - const vAuto = await workspacePage.page.getByTestId("behaviour-v-auto"); + const hAuto = await workspacePage.page.getByTitle("Fit content (Horizontal)"); + const vAuto = await workspacePage.page.getByTitle("Fit content (Vertical)"); await expect(vAuto.locator("input")).toBeChecked(); await expect(hAuto.locator("input")).toBeChecked(); diff --git a/frontend/playwright/ui/specs/text-editor-v2.spec.js b/frontend/playwright/ui/specs/text-editor-v2.spec.js index 299430fad1..e32e0536a3 100644 --- a/frontend/playwright/ui/specs/text-editor-v2.spec.js +++ b/frontend/playwright/ui/specs/text-editor-v2.spec.js @@ -1,14 +1,14 @@ import { test, expect } from "@playwright/test"; import { Clipboard } from "../../helpers/Clipboard"; -import { WorkspacePage } from "../pages/WorkspacePage"; +import { WasmWorkspacePage } from "../pages/WasmWorkspacePage"; const timeToWait = 100; test.beforeEach(async ({ page, context }) => { await Clipboard.enable(context, Clipboard.Permission.ALL); - await WorkspacePage.init(page); - await WorkspacePage.mockConfigFlags(page, ["enable-feature-text-editor-v2"]); + await WasmWorkspacePage.init(page); + await WasmWorkspacePage.mockConfigFlags(page, ["enable-feature-text-editor-v2"]); }); test.afterEach(async ({ context }) => { @@ -17,22 +17,21 @@ test.afterEach(async ({ context }) => { test("Create a new text shape", async ({ page }) => { const initialText = "Lorem ipsum"; - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); await workspace.goToWorkspace(); await workspace.createTextShape(190, 150, 300, 200, initialText); - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe(initialText); - await workspace.textEditor.stopEditing(); + + await workspace.waitForSelectedShapeName(initialText); }); test("Create a new text shape from pasting text", async ({ page, context }) => { const textToPaste = "Lorem ipsum"; - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -43,13 +42,9 @@ test("Create a new text shape from pasting text", async ({ page, context }) => { await workspace.clickAt(190, 150); await workspace.paste("keyboard"); - - await page.waitForTimeout(timeToWait); - - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe(textToPaste); - await workspace.textEditor.stopEditing(); + + await expect(workspace.layers.getByText(textToPaste)).toBeVisible(); }); test("Create a new text shape from pasting text using context menu", async ({ @@ -57,7 +52,7 @@ test("Create a new text shape from pasting text using context menu", async ({ context, }) => { const textToPaste = "Lorem ipsum"; - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -67,17 +62,15 @@ test("Create a new text shape from pasting text using context menu", async ({ await workspace.clickAt(190, 150); await workspace.paste("context-menu"); - - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe(textToPaste); - await workspace.textEditor.stopEditing(); + + await expect(workspace.layers.getByText(textToPaste)).toBeVisible(); }); test("Update an already created text shape by appending text", async ({ page, }) => { - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -87,15 +80,14 @@ test("Update an already created text shape by appending text", async ({ await workspace.textEditor.startEditing(); await workspace.textEditor.moveFromEnd(0); await page.keyboard.type(" dolor sit amet"); - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe("Lorem ipsum dolor sit amet"); await workspace.textEditor.stopEditing(); + await workspace.waitForSelectedShapeName("Lorem ipsum dolor sit amet"); }); test("Update an already created text shape by prepending text", async ({ page, }) => { - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -105,15 +97,14 @@ test("Update an already created text shape by prepending text", async ({ await workspace.textEditor.startEditing(); await workspace.textEditor.moveFromStart(0); await page.keyboard.type("Dolor sit amet "); - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe("Dolor sit amet Lorem ipsum"); await workspace.textEditor.stopEditing(); + await workspace.waitForSelectedShapeName("Dolor sit amet Lorem ipsum"); }); test.skip("Update an already created text shape by inserting text in between", async ({ page, }) => { - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -123,9 +114,8 @@ test.skip("Update an already created text shape by inserting text in between", a await workspace.textEditor.startEditing(); await workspace.textEditor.moveFromStart(5); await page.keyboard.type(" dolor sit amet"); - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe("Lorem dolor sit amet ipsum"); await workspace.textEditor.stopEditing(); + await workspace.waitForSelectedShapeName("Lorem dolor sit amet ipsum"); }); test("Update a new text shape appending text by pasting text", async ({ @@ -133,7 +123,7 @@ test("Update a new text shape appending text by pasting text", async ({ context, }) => { const textToPaste = " dolor sit amet"; - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -146,17 +136,16 @@ test("Update a new text shape appending text by pasting text", async ({ await workspace.textEditor.startEditing(); await workspace.textEditor.moveFromEnd(); await workspace.paste("keyboard"); - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe("Lorem ipsum dolor sit amet"); await workspace.textEditor.stopEditing(); -}); + await workspace.waitForSelectedShapeName("Lorem ipsum dolor sit amet"); + }); test.skip("Update a new text shape prepending text by pasting text", async ({ page, context, }) => { const textToPaste = "Dolor sit amet "; - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -169,16 +158,17 @@ test.skip("Update a new text shape prepending text by pasting text", async ({ await workspace.textEditor.startEditing(); await workspace.textEditor.moveFromStart(); await workspace.paste("keyboard"); - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe("Dolor sit amet Lorem ipsum"); await workspace.textEditor.stopEditing(); + + await workspace.hideUI(); + await expect(workspace.canvas).toHaveScreenshot(); }); test("Update a new text shape replacing (starting) text with pasted text", async ({ page, }) => { const textToPaste = "Dolor sit amet"; - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -192,17 +182,15 @@ test("Update a new text shape replacing (starting) text with pasted text", async await workspace.paste("keyboard"); - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe("Dolor sit amet ipsum"); - await workspace.textEditor.stopEditing(); + await workspace.waitForSelectedShapeName("Dolor sit amet ipsum"); }); test("Update a new text shape replacing (ending) text with pasted text", async ({ page, }) => { const textToPaste = "dolor sit amet"; - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -216,17 +204,15 @@ test("Update a new text shape replacing (ending) text with pasted text", async ( await workspace.paste("keyboard"); - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe("Lorem dolor sit amet"); - await workspace.textEditor.stopEditing(); + await workspace.waitForSelectedShapeName("Lorem dolor sit amet"); }); test("Update a new text shape replacing (in between) text with pasted text", async ({ page, }) => { const textToPaste = "dolor sit amet"; - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -240,16 +226,14 @@ test("Update a new text shape replacing (in between) text with pasted text", asy await workspace.paste("keyboard"); - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe("Lordolor sit ametsum"); - await workspace.textEditor.stopEditing(); + await workspace.waitForSelectedShapeName("Lordolor sit ametsum"); }); test("Update text font size selecting a part of it (starting)", async ({ page, }) => { - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -260,18 +244,16 @@ test("Update text font size selecting a part of it (starting)", async ({ await workspace.textEditor.startEditing(); await workspace.textEditor.selectFromStart(5); await workspace.textEditor.changeFontSize(36); - - const textContent1 = await workspace.textEditor.waitForTextSpanContent(1); - expect(textContent1).toBe("Lorem"); - const textContent2 = await workspace.textEditor.waitForTextSpanContent(2); - expect(textContent2).toBe(" ipsum"); await workspace.textEditor.stopEditing(); + + await workspace.hideUI(); + await expect(workspace.canvas).toHaveScreenshot(); }); -test.skip("Update text line height selecting a part of it (starting)", async ({ +test("Update text line height selecting a part of it (starting)", async ({ page, }) => { - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -281,24 +263,17 @@ test.skip("Update text line height selecting a part of it (starting)", async ({ await workspace.clickLeafLayer("Lorem ipsum"); await workspace.textEditor.startEditing(); await workspace.textEditor.selectFromStart(5); - await workspace.textEditor.changeLineHeight(1.4); - - const lineHeight = await workspace.textEditor.waitForParagraphStyle( - 1, - "line-height", - ); - expect(lineHeight).toBe("1.4"); - - const textContent = await workspace.textEditor.waitForTextSpanContent(); - expect(textContent).toBe("Lorem ipsum"); - + await workspace.textEditor.changeLineHeight(4.4); await workspace.textEditor.stopEditing(); + + await workspace.hideUI(); + await expect(workspace.canvas).toHaveScreenshot(); }); test.skip("Update text letter spacing selecting a part of it (starting)", async ({ page, }) => { - const workspace = new WorkspacePage(page, { + const workspace = new WasmWorkspacePage(page, { textEditor: true, }); await workspace.setupEmptyFile(); @@ -309,16 +284,14 @@ test.skip("Update text letter spacing selecting a part of it (starting)", async await workspace.textEditor.startEditing(); await workspace.textEditor.selectFromStart(5); await workspace.textEditor.changeLetterSpacing(10); - - const textContent1 = await workspace.textEditor.waitForTextSpanContent(1); - expect(textContent1).toBe("Lorem"); - const textContent2 = await workspace.textEditor.waitForTextSpanContent(2); - expect(textContent2).toBe(" ipsum"); await workspace.textEditor.stopEditing(); + + await workspace.hideUI(); + await expect(workspace.canvas).toHaveScreenshot(); }); test("BUG 11552 - Apply styles to the current caret", async ({ page }) => { - const workspace = new WorkspacePage(page); + const workspace = new WasmWorkspacePage(page); await workspace.setupEmptyFile(); await workspace.mockGetFile("text-editor/get-file-11552.json"); await workspace.mockRPC( diff --git a/frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-font-size-selecting-a-part-of-it-starting-1.png b/frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-font-size-selecting-a-part-of-it-starting-1.png new file mode 100644 index 0000000000..0d31872f79 Binary files /dev/null and b/frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-font-size-selecting-a-part-of-it-starting-1.png differ diff --git a/frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-letter-spacing-selecting-a-part-of-it-starting-1.png b/frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-letter-spacing-selecting-a-part-of-it-starting-1.png new file mode 100644 index 0000000000..4b091658c9 Binary files /dev/null and b/frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-letter-spacing-selecting-a-part-of-it-starting-1.png differ diff --git a/frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-line-height-selecting-a-part-of-it-starting-1.png b/frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-line-height-selecting-a-part-of-it-starting-1.png new file mode 100644 index 0000000000..1dc0a0dffa Binary files /dev/null and b/frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-line-height-selecting-a-part-of-it-starting-1.png differ diff --git a/frontend/playwright/ui/specs/tokens/crud.spec.js b/frontend/playwright/ui/specs/tokens/crud.spec.js index 66a3591ee4..b726db042d 100644 --- a/frontend/playwright/ui/specs/tokens/crud.spec.js +++ b/frontend/playwright/ui/specs/tokens/crud.spec.js @@ -1493,10 +1493,8 @@ test.describe("Tokens - creation", () => { const nameField = tokensUpdateCreateModal.getByLabel("Name"); await nameField.fill(newTokenTitle); - const referenceTabButton = tokensUpdateCreateModal.getByRole("button", { - name: "Use a reference", - }); - referenceTabButton.click(); + const referenceTabButton = tokensUpdateCreateModal.getByTestId("reference-opt"); + await referenceTabButton.click(); const referenceField = tokensUpdateCreateModal.getByRole("textbox", { name: "Reference", diff --git a/frontend/playwright/ui/specs/workspace-modifers.spec.js b/frontend/playwright/ui/specs/workspace-modifers.spec.js index 3eaa0e5e18..de1f4ef23f 100644 --- a/frontend/playwright/ui/specs/workspace-modifers.spec.js +++ b/frontend/playwright/ui/specs/workspace-modifers.spec.js @@ -23,4 +23,35 @@ test("BUG 13305 - Fix resize board to fit content", async ({ page }) => { await expect(workspacePage.rightSidebar.getByTitle("Height").getByRole("textbox")).toHaveValue("630"); await expect(workspacePage.rightSidebar.getByTitle("X axis").getByRole("textbox")).toHaveValue("110"); await expect(workspacePage.rightSidebar.getByTitle("Y axis").getByRole("textbox")).toHaveValue("110"); -}); \ No newline at end of file +}); + +test("BUG 13382 - Fix problem with flex layout", async ({ page }) => { + const workspacePage = new WasmWorkspacePage(page); + await workspacePage.setupEmptyFile(); + await workspacePage.mockGetFile("workspace/get-file-13382.json"); + + await workspacePage.mockRPC( + "get-file-fragment?file-id=*&fragment-id=*", + "workspace/get-file-13382-fragment.json", + ); + + await workspacePage.mockRPC("update-file?id=*", "workspace/update-file-empty.json"); + + await workspacePage.goToWorkspace({ + fileId: "52c4e771-3853-8190-8007-9506c70e8100", + pageId: "ecb0cfd0-0f0b-81f7-8007-950628f9665b", + }); + + await workspacePage.clickToggableLayer("A"); + await workspacePage.clickToggableLayer("B"); + await workspacePage.clickToggableLayer("C"); + await workspacePage.clickLeafLayer("R2"); + + const heightText = workspacePage.rightSidebar.getByTitle("Height").getByPlaceholder('--'); + await heightText.fill("200"); + await heightText.press("Enter"); + + await workspacePage.clickLeafLayer("B"); + await expect(workspacePage.rightSidebar.getByTitle("Height").getByRole("textbox")).toHaveValue("340"); + +}); diff --git a/frontend/playwright/ui/specs/workspace.spec.js b/frontend/playwright/ui/specs/workspace.spec.js index 8c20a9efbe..cb1e4f268b 100644 --- a/frontend/playwright/ui/specs/workspace.spec.js +++ b/frontend/playwright/ui/specs/workspace.spec.js @@ -353,33 +353,24 @@ test("Copy/paste properties", async ({ page, context }) => { await page.getByText("Copy/Paste as").hover(); await page.getByText("Paste properties").click(); - await page - .getByTestId("layer-item") - .getByText("Rectangle") - .first() - .click({ button: "right" }); + await page.getByText("Rectangle").first().click({ button: "right" }); + await page.getByText("Copy/Paste as").hover(); + await page.getByText("Paste properties").click(); + + await page.getByText("Board").nth(2).click({ button: "right" }); await page.getByText("Copy/Paste as").hover(); await page.getByText("Paste properties").click(); await page .getByTestId("layer-item") - .getByText("Board") + .locator("div") + .filter({ hasText: "Path" }) .nth(1) .click({ button: "right" }); await page.getByText("Copy/Paste as").hover(); await page.getByText("Paste properties").click(); - await page - .getByTestId("layer-item") - .getByText("Path") - .click({ button: "right" }); - await page.getByText("Copy/Paste as").hover(); - await page.getByText("Paste properties").click(); - - await page - .getByTestId("layer-item") - .getByText("Ellipse") - .click({ button: "right" }); + await page.getByText("Ellipse").click({ button: "right" }); await page.getByText("Copy/Paste as").hover(); await page.getByText("Paste properties").click(); }); @@ -492,3 +483,25 @@ test("Bug 8371 - Flatten option is not visible in context menu", async ({ .filter({ visible: true }), ).toBeVisible(); }); + +test("BUG 13415 - Grid layout overlay is not removed when deleting a board", async ({ + page, +}) => { + const workspacePage = new WasmWorkspacePage(page); + await workspacePage.setupEmptyFile(page); + await workspacePage.mockGetFile("workspace/get-file-13415.json"); + await workspacePage.mockRPC( + "update-file?id=*", + "workspace/update-file-13415.json", + ); + + await workspacePage.goToWorkspace(); + await workspacePage.clickLeafLayer("Board"); + + const currentRenderCount = await workspacePage.getRenderCount(); + await workspacePage.page.keyboard.press("Delete"); + + await workspacePage.waitForNextRender(currentRenderCount); + await workspacePage.hideUI(); + await expect(workspacePage.canvas).toHaveScreenshot(); +}); diff --git a/frontend/playwright/ui/specs/workspace.spec.js-snapshots/BUG-13415---Grid-layout-overlay-is-not-removed-when-deleting-a-board-1.png b/frontend/playwright/ui/specs/workspace.spec.js-snapshots/BUG-13415---Grid-layout-overlay-is-not-removed-when-deleting-a-board-1.png new file mode 100644 index 0000000000..199d021532 Binary files /dev/null and b/frontend/playwright/ui/specs/workspace.spec.js-snapshots/BUG-13415---Grid-layout-overlay-is-not-removed-when-deleting-a-board-1.png differ diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss index 37f6c546f1..2acb81398a 100644 --- a/frontend/resources/styles/common/refactor/design-tokens.scss +++ b/frontend/resources/styles/common/refactor/design-tokens.scss @@ -244,6 +244,13 @@ --assets-component-second-border-selected: var(--color-background-primary); --assets-component-hightlight: var(--color-accent-secondary); + --radio-btns-background-color: var(--color-background-tertiary); + --radio-btn-background-color-selected: var(--color-background-quaternary); + --radio-btn-foreground-color: var(--color-foreground-secondary); + --radio-btn-foreground-color-selected: var(--color-accent-primary); + --radio-btn-border-color: var(--color-background-tertiary); + --radio-btn-border-color-selected: var(--color-background-quaternary); + --library-name-foreground-color: var(--color-foreground-primary); --library-content-foreground-color: var(--color-foreground-secondary); @@ -416,6 +423,13 @@ --tab-border-color: var(--color-background-tertiary); --tab-border-color-selected: var(--color-background-secondary); + --radio-btns-background-color: var(--color-background-tertiary); + --radio-btn-background-color-selected: var(--color-background-primary); + --radio-btn-foreground-color: var(--color-foreground-secondary); + --radio-btn-foreground-color-selected: var(--color-accent-primary); + --radio-btn-border-color: var(--color-background-tertiary); + --radio-btn-border-color-selected: var(--color-background-secondary); + --button-icon-background-color-selected: var(--color-background-primary); --button-icon-border-color-selected: var(--color-background-secondary); diff --git a/frontend/src/app/main/ui/components/file_uploader.cljs b/frontend/src/app/main/ui/components/file_uploader.cljs index b381dc396a..8eebdff516 100644 --- a/frontend/src/app/main/ui/components/file_uploader.cljs +++ b/frontend/src/app/main/ui/components/file_uploader.cljs @@ -10,9 +10,9 @@ [app.util.dom :as dom] [rumext.v2 :as mf])) -(mf/defc file-uploader* +(mf/defc file-uploader {::mf/forward-ref true} - [{:keys [accept multi label-text label-class input-id on-selected data-testid]} input-ref] + [{:keys [accept multi label-text label-class input-id on-selected data-testid] :as props} input-ref] (let [opt-pick-one #(if multi % (first %)) on-files-selected diff --git a/frontend/src/app/main/ui/components/radio_buttons.cljs b/frontend/src/app/main/ui/components/radio_buttons.cljs new file mode 100644 index 0000000000..d8bc4c969e --- /dev/null +++ b/frontend/src/app/main/ui/components/radio_buttons.cljs @@ -0,0 +1,107 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.main.ui.components.radio-buttons + (:require-macros [app.main.style :as stl]) + (:require + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.main.ui.ds.foundations.assets.icon :refer [icon*]] + [app.main.ui.formats :as fmt] + [app.util.dom :as dom] + [rumext.v2 :as mf])) + +(def context + (mf/create-context nil)) + +(mf/defc radio-button + {::mf/props :obj} + [{:keys [icon id value disabled title icon-class type]}] + (let [context (mf/use-ctx context) + allow-empty (unchecked-get context "allow-empty") + type (if ^boolean type + type + (if ^boolean allow-empty + "checkbox" + "radio")) + + on-change (unchecked-get context "on-change") + selected (unchecked-get context "selected") + name (unchecked-get context "name") + + encode-fn (unchecked-get context "encode-fn") + checked? (= selected value) + + value (encode-fn value)] + + + [:label {:html-for id + :data-testid id + :title title + :class (stl/css-case + :radio-icon true + :checked checked? + :disabled disabled)} + + (if (some? icon) + [:> icon* {:icon-id icon :class icon-class :aria-hidden true}] + [:span {:class (stl/css :title-name)} value]) + + [:input {:id id + :on-change on-change + :type type + :name name + :disabled disabled + :value value + :default-checked checked?}]])) + +(mf/defc radio-buttons + {::mf/props :obj} + [{:keys [name children on-change selected class wide encode-fn decode-fn allow-empty] :as props}] + (let [encode-fn (d/nilv encode-fn identity) + decode-fn (d/nilv decode-fn identity) + nitems (if (array? children) + (count (keep identity children)) + 1) + ;; FIXME: we should handle this with CSS + width (mf/with-memo [nitems] + (if (= wide true) + "unset" + (fmt/format-pixels + (+ (* 4 (- nitems 1)) + (* 32 nitems))))) + + on-change' + (mf/use-fn + (mf/deps selected on-change) + (fn [event] + (let [input (dom/get-target event) + value (dom/get-target-val event) + + ;; Only allow null values when the "allow-empty" prop is true + value (when (or (not allow-empty) + (not= value selected)) value)] + (when (fn? on-change) + (on-change (decode-fn value) event)) + (dom/blur! input)))) + + context-value + (mf/spread-object props + ;; We pass a special metadata for disable + ;; key casing transformation in this + ;; concrete case, because this component + ;; uses legacy mode and props are in + ;; kebab-case style + ^{::mf/transform false} + {:on-change on-change' + :encode-fn encode-fn + :decode-fn decode-fn})] + + [:& (mf/provider context) {:value context-value} + [:div {:class (dm/str class " " (stl/css :radio-btn-wrapper)) + :style {:width width} + :key (dm/str name "-" selected)} + children]])) diff --git a/frontend/src/app/main/ui/components/radio_buttons.scss b/frontend/src/app/main/ui/components/radio_buttons.scss new file mode 100644 index 0000000000..6ef73339ad --- /dev/null +++ b/frontend/src/app/main/ui/components/radio_buttons.scss @@ -0,0 +1,79 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@use "refactor/common-refactor.scss" as deprecated; + +.radio-btn-wrapper { + @include deprecated.flexCenter; + border-radius: deprecated.$br-8; + height: deprecated.$s-32; + background-color: var(--input-background-color); + gap: deprecated.$s-4; +} + +.radio-icon { + --radio-icon-border-color: var(--radio-btn-border-color); + + @include deprecated.buttonStyle; + @include deprecated.flexCenter; + @include deprecated.focusRadio; + height: deprecated.$s-32; + flex-grow: 1; + border-radius: deprecated.$s-8; + box-sizing: border-box; + border: deprecated.$br-2 solid var(--radio-icon-border-color); + + input { + display: none; + } + svg { + @extend .button-icon; + stroke: var(--radio-btn-foreground-color); + } + .title-name { + @include deprecated.uppercaseTitleTipography; + color: var(--radio-btn-foreground-color); + } + &:hover { + svg { + stroke: var(--radio-btn-foreground-color-selected); + } + } +} + +.checked { + --radio-icon-border-color: var(--radio-btn-border-color-selected); + + background-color: var(--radio-btn-background-color-selected); + svg { + stroke: var(--radio-btn-foreground-color-selected); + } + .title-name { + color: var(--radio-btn-foreground-color-selected); + } +} + +.disabled { + cursor: default; + background-color: transparent; + border: deprecated.$s-2 solid transparent; + svg { + stroke: var(--button-foreground-color-disabled); + } + .title-name { + color: var(--button-foreground-color-disabled); + } + &:hover { + background-color: transparent; + border: deprecated.$s-2 solid transparent; + svg { + stroke: var(--button-foreground-color-disabled); + } + .title-name { + color: var(--button-foreground-color-disabled); + } + } +} diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs index fb40826a49..930b21ac5e 100644 --- a/frontend/src/app/main/ui/dashboard/fonts.cljs +++ b/frontend/src/app/main/ui/dashboard/fonts.cljs @@ -19,7 +19,7 @@ [app.main.repo :as rp] [app.main.store :as st] [app.main.ui.components.context-menu-a11y :refer [context-menu*]] - [app.main.ui.components.file-uploader :refer [file-uploader*]] + [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]] [app.main.ui.icons :as deprecated-icon] [app.main.ui.notifications.context-notification :refer [context-notification]] @@ -187,11 +187,11 @@ :on-click on-click :tab-index "0"} [:span (tr "labels.add-custom-font")] - [:> file-uploader* {:input-id "font-upload" - :accept accept-font-types - :multi true - :ref input-ref - :on-selected on-selected}]] + [:& file-uploader {:input-id "font-upload" + :accept accept-font-types + :multi true + :ref input-ref + :on-selected on-selected}]] (when-let [url cf/terms-of-service-uri] [:& context-notification {:content (tr "dashboard.fonts.hero-text2" url) diff --git a/frontend/src/app/main/ui/dashboard/import.cljs b/frontend/src/app/main/ui/dashboard/import.cljs index ea2db3bda2..1510af2455 100644 --- a/frontend/src/app/main/ui/dashboard/import.cljs +++ b/frontend/src/app/main/ui/dashboard/import.cljs @@ -16,7 +16,7 @@ [app.main.data.modal :as modal] [app.main.data.notifications :as ntf] [app.main.store :as st] - [app.main.ui.components.file-uploader :refer [file-uploader*]] + [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.ds.product.loader :refer [loader*]] [app.main.ui.icons :as deprecated-icon] [app.main.ui.notifications.context-notification :refer [context-notification]] @@ -58,10 +58,10 @@ [{:keys [project-id on-finish-import]} external-ref] (let [on-file-selected (use-import-file project-id on-finish-import)] [:form.import-file {:aria-hidden "true"} - [:> file-uploader* {:accept ".penpot,.zip" - :multi true - :ref external-ref - :on-selected on-file-selected}]])) + [:& file-uploader {:accept ".penpot,.zip" + :multi true + :ref external-ref + :on-selected on-file-selected}]])) (defn- update-entry-name [entries file-id new-name] diff --git a/frontend/src/app/main/ui/dashboard/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs index 51eab781b2..96afda2563 100644 --- a/frontend/src/app/main/ui/dashboard/team.cljs +++ b/frontend/src/app/main/ui/dashboard/team.cljs @@ -19,7 +19,7 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] - [app.main.ui.components.file-uploader :refer [file-uploader*]] + [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.forms :as fm] [app.main.ui.dashboard.change-owner] [app.main.ui.dashboard.subscription :refer [members-cta* @@ -1315,10 +1315,10 @@ [:img {:class (stl/css :team-image) :src (cfg/resolve-team-photo-url team)}] (when can-edit - [:> file-uploader* {:accept "image/jpeg,image/png" - :multi false - :ref finput - :on-selected on-file-selected}])] + [:& file-uploader {:accept "image/jpeg,image/png" + :multi false + :ref finput + :on-selected on-file-selected}])] [:div {:class (stl/css :block-label)} (tr "dashboard.team-info")] [:div {:class (stl/css :block-text)} diff --git a/frontend/src/app/main/ui/delete_shared.cljs b/frontend/src/app/main/ui/delete_shared.cljs index eb6ffcd35c..51fcb8225e 100644 --- a/frontend/src/app/main/ui/delete_shared.cljs +++ b/frontend/src/app/main/ui/delete_shared.cljs @@ -11,10 +11,8 @@ [app.main.data.modal :as modal] [app.main.repo :as rp] [app.main.store :as st] - [app.main.ui.ds.buttons.button :refer [button*]] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.ds.notifications.context-notification :refer [context-notification*]] + [app.main.ui.icons :as deprecated-icon] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as k] @@ -99,11 +97,8 @@ [:div {:class (stl/css :modal-container)} [:div {:class (stl/css :modal-header)} [:h2 {:class (stl/css :modal-title)} title] - [:> icon-button* {:variant "ghost" - :class (stl/css :modal-close-btn) - :icon i/close - :aria-label (tr "labels.close") - :on-click cancel-fn}]] + [:button {:class (stl/css :modal-close-btn) + :on-click cancel-fn} deprecated-icon/close]] [:div {:class (stl/css :modal-content)} (when (and (string? subtitle) (not= subtitle "")) @@ -129,10 +124,14 @@ [:div {:class (stl/css :modal-footer)} [:div {:class (stl/css :action-buttons)} (when-not (= cancel-label :omit) - [:> button* {:variant "secondary" - :on-click cancel-fn} - cancel-label]) + [:input {:class (stl/css :cancel-button) + :type "button" + :value cancel-label + :on-click cancel-fn}]) - [:> button* {:variant (if (= accept-style :danger) "destructive" "primary") - :on-click accept-fn} - accept-label]]]]])) + [:input {:class (stl/css-case :accept-btn true + :danger (= accept-style :danger) + :primary (= accept-style :primary)) + :type "button" + :value accept-label + :on-click accept-fn}]]]]])) diff --git a/frontend/src/app/main/ui/delete_shared.scss b/frontend/src/app/main/ui/delete_shared.scss index e9597009d1..d0f08a50e8 100644 --- a/frontend/src/app/main/ui/delete_shared.scss +++ b/frontend/src/app/main/ui/delete_shared.scss @@ -33,9 +33,7 @@ } .modal-close-btn { - position: absolute; - top: var(--sp-s); - right: var(--sp-s); + @extend .modal-close-btn-base; } .modal-content { @@ -55,6 +53,17 @@ @extend .modal-action-btns; } +.cancel-button { + @extend .modal-cancel-btn; +} + +.accept-btn { + @extend .modal-accept-btn; + &.danger { + @extend .modal-danger-btn; + } +} + .modal-scd-msg { margin-block: 0; } diff --git a/frontend/src/app/main/ui/ds/buttons/button.scss b/frontend/src/app/main/ui/ds/buttons/button.scss index a46f062c5d..dd8c720559 100644 --- a/frontend/src/app/main/ui/ds/buttons/button.scss +++ b/frontend/src/app/main/ui/ds/buttons/button.scss @@ -15,7 +15,6 @@ display: inline-flex; align-items: center; - justify-content: center; column-gap: var(--sp-xs); } diff --git a/frontend/src/app/main/ui/exports/assets.cljs b/frontend/src/app/main/ui/exports/assets.cljs index 7850050c7c..feb7f52906 100644 --- a/frontend/src/app/main/ui/exports/assets.cljs +++ b/frontend/src/app/main/ui/exports/assets.cljs @@ -208,7 +208,7 @@ ;; FIXME: deprecated, should be refactored in two components and use ;; the generic progress reporter -(mf/defc progress-widget* +(mf/defc progress-widget {::mf/wrap [mf/memo]} [] (let [state (mf/deref refs/export) diff --git a/frontend/src/app/main/ui/inspect/code.cljs b/frontend/src/app/main/ui/inspect/code.cljs index 605d8e38ee..661bee9075 100644 --- a/frontend/src/app/main/ui/inspect/code.cljs +++ b/frontend/src/app/main/ui/inspect/code.cljs @@ -19,10 +19,7 @@ [app.main.store :as st] [app.main.ui.components.code-block :refer [code-block]] [app.main.ui.components.copy-button :refer [copy-button*]] - [app.main.ui.ds.buttons.button :refer [button*]] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] - [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.hooks.resize :refer [use-resize-hook]] [app.main.ui.icons :as deprecated-icon] [app.main.ui.shapes.text.fontfaces :refer [shapes->fonts]] @@ -263,9 +260,8 @@ [:div {:class (stl/css-case :element-options true :viewer-code-block (= :viewer from))} [:div {:class (stl/css :attributes-block)} - [:> button* {:variant "secondary" - :class (stl/css :download-button) - :on-click handle-copy-all-code} + [:button {:class (stl/css :download-button) + :on-click handle-copy-all-code} "Copy all code"]] #_[:div.attributes-block @@ -292,10 +288,10 @@ ;; :options [{:label "CSS" :value "css"}]}] [:div {:class (stl/css :action-btns)} - [:> icon-button* {:variant "ghost" - :aria-label "Expand" - :on-click on-expand - :icon i/code}] + [:button {:class (stl/css :expand-button) + :on-click on-expand} + deprecated-icon/code] + [:> copy-button* {:data copy-css-fn :class (stl/css :css-copy-btn) :on-copied on-style-copied}]]] @@ -322,21 +318,21 @@ :rotated collapsed-markup?)} deprecated-icon/arrow]] - [:> radio-buttons* {:selected markup-type - :on-change set-markup - :name "listing-style" - :options [{:id "html" - :label "HTML" - :value "html"} - {:id "svg" - :label "SVG" - :value "svg"}]}] + [:& radio-buttons {:selected markup-type + :on-change set-markup + :class (stl/css :code-lang-options) + :wide true + :name "listing-style"} + [:& radio-button {:value "html" + :id :html}] + [:& radio-button {:value "svg" + :id :svg}]] [:div {:class (stl/css :action-btns)} - [:> icon-button* {:variant "ghost" - :aria-label "Expand" - :on-click on-expand - :icon i/code}] + [:button {:class (stl/css :expand-button) + :on-click on-expand} + deprecated-icon/code] + [:> copy-button* {:data copy-html-fn :class (stl/css :html-copy-btn) :on-copied on-markup-copied}]]] diff --git a/frontend/src/app/main/ui/inspect/code.scss b/frontend/src/app/main/ui/inspect/code.scss index 93bf3c88e5..7f88871edc 100644 --- a/frontend/src/app/main/ui/inspect/code.scss +++ b/frontend/src/app/main/ui/inspect/code.scss @@ -17,18 +17,16 @@ padding-inline: var(--sp-m); } -.attributes-block { - display: flex; - flex-direction: column; - row-gap: 12px; -} - .viewer-code-block { height: calc(100vh - #{deprecated.$s-108}); // TODO: Fix this hardcoded value } .download-button { - margin: var(--sp-s) 0; + @extend .button-secondary; + @include deprecated.uppercaseTitleTipography; + height: deprecated.$s-32; + width: 100%; + margin: deprecated.$s-8 0; } .code-block { @@ -75,6 +73,7 @@ gap: deprecated.$s-4; } +.expand-button, .css-copy-btn, .html-copy-btn { @extend .button-tertiary; @@ -86,6 +85,9 @@ } } +.code-lang-options { + max-width: deprecated.$s-108; +} .code-lang-select { @include deprecated.uppercaseTitleTipography; width: deprecated.$s-72; diff --git a/frontend/src/app/main/ui/settings/profile.cljs b/frontend/src/app/main/ui/settings/profile.cljs index 30855c2b00..763ee3c836 100644 --- a/frontend/src/app/main/ui/settings/profile.cljs +++ b/frontend/src/app/main/ui/settings/profile.cljs @@ -14,7 +14,7 @@ [app.main.data.profile :as du] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.components.file-uploader :refer [file-uploader*]] + [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.forms :as fm] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -110,11 +110,11 @@ [:span {:class (stl/css :update-overlay) :on-click on-image-click} (tr "labels.update")] [:img {:src photo}] - [:> file-uploader* {:accept "image/jpeg,image/png" - :multi false - :ref input-ref - :on-selected on-file-selected - :data-testid "profile-image-input"}]]])) + [:& file-uploader {:accept "image/jpeg,image/png" + :multi false + :ref input-ref + :on-selected on-file-selected + :data-testid "profile-image-input"}]]])) ;; --- Profile Page diff --git a/frontend/src/app/main/ui/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs index 5bc7e4a953..9646c81f8c 100644 --- a/frontend/src/app/main/ui/viewer/comments.cljs +++ b/frontend/src/app/main/ui/viewer/comments.cljs @@ -27,8 +27,9 @@ [okulary.core :as l] [rumext.v2 :as mf])) -(mf/defc comments-menu* - {::mf/memo true} +(mf/defc comments-menu + {::mf/props :obj + ::mf/memo true} [] (let [state (mf/deref refs/comments-local) cmode (:mode state) diff --git a/frontend/src/app/main/ui/viewer/header.cljs b/frontend/src/app/main/ui/viewer/header.cljs index 334c3ac9d2..270e30643b 100644 --- a/frontend/src/app/main/ui/viewer/header.cljs +++ b/frontend/src/app/main/ui/viewer/header.cljs @@ -14,13 +14,10 @@ [app.main.data.viewer.shortcuts :as sc] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] - [app.main.ui.ds.buttons.button :refer [button*]] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.foundations.assets.icon :as i] - [app.main.ui.exports.assets :refer [progress-widget*]] + [app.main.ui.exports.assets :refer [progress-widget]] [app.main.ui.formats :as fmt] [app.main.ui.icons :as deprecated-icon] - [app.main.ui.viewer.comments :refer [comments-menu*]] + [app.main.ui.viewer.comments :refer [comments-menu]] [app.main.ui.viewer.interactions :refer [flows-menu* interactions-menu*]] [app.util.dom :as dom] [app.util.i18n :refer [tr]] @@ -36,12 +33,20 @@ [] (modal/show! :login-register {})) -(mf/defc zoom-widget* - {::mf/memo true} - [{:keys [zoom on-increase on-decrease on-zoom-reset on-fullscreen on-zoom-fit on-zoom-fill]}] - (let [open* (mf/use-state false) - open? (deref open*) +(mf/defc zoom-widget + {::mf/memo true + ::mf/props :obj} + [{:keys [zoom + on-increase + on-decrease + on-zoom-reset + on-fullscreen + on-zoom-fit + on-zoom-fill] + :as props}] + (let [open* (mf/use-state false) + open? (deref open*) open-dropdown (mf/use-fn (fn [event] @@ -70,7 +75,7 @@ [:div {:class (stl/css-case :zoom-widget true :selected open?) - :on-click (if open? close-dropdown open-dropdown) + :on-click open-dropdown :title (tr "workspace.header.zoom")} [:span {:class (stl/css :label)} (fmt/format-percent zoom)] [:& dropdown {:show open? @@ -78,18 +83,18 @@ [:ul {:class (stl/css :dropdown)} [:li {:class (stl/css :basic-zoom-bar)} [:span {:class (stl/css :zoom-btns)} - [:> icon-button* {:variant "ghost" - :aria-label (tr "shortcuts.decrease-zoom") - :on-click on-decrease - :icon i/remove}] - [:p {:class (stl/css :zoom-text)} + [:button {:class (stl/css :zoom-btn) + :on-click on-decrease} + [:span {:class (stl/css :zoom-icon)} + deprecated-icon/remove-icon]] + [:p {:class (stl/css :zoom-text)} (fmt/format-percent zoom)] - [:> icon-button* {:variant "ghost" - :aria-label (tr "shortcuts.increase-zoom") - :on-click on-increase - :icon i/add}]] - [:> button* {:variant "ghost" - :on-click on-zoom-reset} + [:button {:class (stl/css :zoom-btn) + :on-click on-increase} + [:span {:class (stl/css :zoom-icon)} + deprecated-icon/add]]] + [:button {:class (stl/css :reset-btn) + :on-click on-zoom-reset} (tr "workspace.header.reset-zoom")]] [:li {:class (stl/css :zoom-option) @@ -114,7 +119,7 @@ [:span {:class (stl/css :shortcut-key) :key (dm/str "zoom-fullscreen-" sc)} sc])]]]]])) -(mf/defc header-options* +(mf/defc header-options [{:keys [section zoom page file index permissions interactions-mode share]}] (let [fullscreen? (mf/deref fullscreen-ref) @@ -154,7 +159,6 @@ handle-zoom-fit (mf/use-fn #(st/emit! dv/zoom-to-fit))] - (mf/with-effect [permissions share] (when (and (:in-team permissions) @@ -163,7 +167,7 @@ (open-share-dialog))) [:div {:class (stl/css :options-zone)} - [:> progress-widget*] + [:& progress-widget] (case section :interactions [:* @@ -171,41 +175,40 @@ [:> flows-menu* {:page page :index index}]) [:> interactions-menu* {:interactions-mode interactions-mode}]] - :comments [:> comments-menu*] + :comments [:& comments-menu] [:div {:class (stl/css :view-options)}]) - [:> zoom-widget* {:zoom zoom - :on-increase handle-increase - :on-decrease handle-decrease - :on-zoom-reset handle-zoom-reset - :on-zoom-fill handle-zoom-fill - :on-zoom-fit handle-zoom-fit - :on-fullscreen toggle-fullscreen}] + [:& zoom-widget + {:zoom zoom + :on-increase handle-increase + :on-decrease handle-decrease + :on-zoom-reset handle-zoom-reset + :on-zoom-fill handle-zoom-fill + :on-zoom-fit handle-zoom-fit + :on-fullscreen toggle-fullscreen}] (when (:in-team permissions) - [:> icon-button* {:variant "ghost" - :aria-label (tr "viewer.header.edit-in-workspace") - :on-click go-to-workspace - :icon i/curve}]) + [:span {:on-click go-to-workspace + :class (stl/css :edit-btn)} + deprecated-icon/curve]) - [:> icon-button* {:variant "ghost" - :aria-pressed fullscreen? - :aria-label (tr "viewer.header.fullscreen") - :on-click toggle-fullscreen - :icon i/expand}] + [:span {:title (tr "viewer.header.fullscreen") + :class (stl/css-case :fullscreen-btn true + :selected fullscreen?) + :on-click toggle-fullscreen} + deprecated-icon/expand] (when (:in-team permissions) - [:> button* {:variant "primary" - :class (stl/css :share-btn) - :on-click open-share-dialog} + [:button {:on-click open-share-dialog + :class (stl/css :share-btn)} (tr "labels.share")]) (when-not (:is-logged permissions) [:span {:on-click open-login-dialog :class (stl/css :go-log-btn)} (tr "labels.log-or-sign")])])) -(mf/defc header-sitemap* - [{:keys [project file page frame toggle-thumbnails]}] +(mf/defc header-sitemap + [{:keys [project file page frame toggle-thumbnails] :as props}] (let [project-name (:name project) file-name (:name file) page-name (:name page) @@ -314,44 +317,44 @@ :pointer-events (when-not (:in-team permissions) "none")}} penpot-logo-icon] - [:> header-sitemap* {:project project - :file file - :page page - :frame frame - :toggle-thumbnails toggle-thumbnails - :index index}]] + [:& header-sitemap {:project project + :file file + :page page + :frame frame + :toggle-thumbnails toggle-thumbnails + :index index}]] [:div {:class (stl/css :mode-zone)} - [:> icon-button* {:variant "ghost" - :aria-pressed (= section :interactions) - :aria-label (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions)) - :data-value "interactions" - :on-click navigate - :icon i/play}] + [:button {:on-click navigate + :data-value "interactions" + :class (stl/css-case :mode-zone-btn true + :selected (= section :interactions)) + :title (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))} + deprecated-icon/play] (when (or (:in-team permissions) (= (:who-comment permissions) "all")) - [:> icon-button* {:variant "ghost" - :aria-pressed (= section :comments) - :aria-label (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments)) - :data-value "comments" - :on-click navigate - :icon i/comments}]) + [:button {:on-click navigate + :data-value "comments" + :class (stl/css-case :mode-zone-btn true + :selected (= section :comments)) + :title (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))} + deprecated-icon/comments]) (when (or (:in-team permissions) (and (= (:type permissions) :share-link) (= (:who-inspect permissions) "all"))) - [:> icon-button* {:variant "ghost" - :aria-pressed (= section :inspect) - :aria-label (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect)) - :on-click go-to-inspect - :icon i/code}])] + [:button {:on-click go-to-inspect + :class (stl/css-case :mode-zone-btn true + :selected (= section :inspect)) + :title (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))} + deprecated-icon/code])] - [:> header-options* {:section section - :permissions permissions - :page page - :file file - :index index - :zoom zoom - :interactions-mode interactions-mode - :share share}]])) + [:& header-options {:section section + :permissions permissions + :page page + :file file + :index index + :zoom zoom + :interactions-mode interactions-mode + :share share}]])) diff --git a/frontend/src/app/main/ui/viewer/header.scss b/frontend/src/app/main/ui/viewer/header.scss index 83a1400033..f9814d3a44 100644 --- a/frontend/src/app/main/ui/viewer/header.scss +++ b/frontend/src/app/main/ui/viewer/header.scss @@ -12,7 +12,7 @@ grid-column: 1 / span 1; grid-row: 1 / span 1; display: grid; - grid-template-columns: 1fr auto 1fr; + grid-template-columns: 1fr deprecated.$s-92 1fr; justify-content: space-between; align-items: center; height: deprecated.$s-48; @@ -130,9 +130,23 @@ // SECTION BUTTONS .mode-zone { - display: flex; - flex-direction: row; - gap: var(--sp-xs); + @include deprecated.flexRow; + height: 100%; +} + +.mode-zone-btn { + @extend .button-tertiary; + @include deprecated.flexCenter; + height: deprecated.$s-32; + width: deprecated.$s-28; + padding: 0; + svg { + @extend .button-icon; + } +} + +.selected { + @extend .button-icon-selected; } // OPTION AREA @@ -151,8 +165,33 @@ cursor: pointer; } +.fullscreen-btn { + @extend .button-tertiary; + @include deprecated.flexCenter; + height: deprecated.$s-32; + width: deprecated.$s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } +} + .share-btn { - margin-left: var(--sp-xs); + @extend .button-primary; + height: deprecated.$s-32; + min-width: deprecated.$s-72; + margin-left: deprecated.$s-4; +} + +.edit-btn { + @extend .button-tertiary; + @include deprecated.flexCenter; + height: deprecated.$s-32; + width: deprecated.$s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } } .go-log-btn { @@ -206,15 +245,43 @@ display: flex; } +.zoom-btn { + @extend .button-tertiary; + height: deprecated.$s-28; + width: deprecated.$s-28; + border-radius: deprecated.$br-8; + .zoom-icon { + @include deprecated.flexCenter; + width: deprecated.$s-24; + height: deprecated.$s-32; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + } + &:hover { + .zoom-icon svg { + stroke: var(--button-tertiary-foreground-color-hover); + } + } +} + .zoom-text { @include deprecated.flexCenter; height: 100%; - min-width: deprecated.$s-48; + min-width: deprecated.$s-64; padding: 0; margin: 0 deprecated.$s-2; color: var(--modal-title-foreground-color); } +.reset-btn { + @extend .button-tertiary; + color: var(--button-tertiary-foreground-color-hover); + height: deprecated.$s-28; + border-radius: deprecated.$br-8; +} + .zoom-option { @extend .menu-item-base; .shortcuts { diff --git a/frontend/src/app/main/ui/viewer/share_link.cljs b/frontend/src/app/main/ui/viewer/share_link.cljs index 7867a3c200..646405676c 100644 --- a/frontend/src/app/main/ui/viewer/share_link.cljs +++ b/frontend/src/app/main/ui/viewer/share_link.cljs @@ -20,9 +20,6 @@ [app.main.router :as rt] [app.main.store :as st] [app.main.ui.components.select :refer [select]] - [app.main.ui.ds.buttons.button :refer [button*]] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.icons :as deprecated-icon] [app.util.clipboard :as clipboard] [app.util.dom :as dom] @@ -174,11 +171,10 @@ [:div {:class (stl/css :share-link-header)} [:h2 {:class (stl/css :share-link-title)} (tr "common.share-link.title")] - [:> icon-button* {:variant "ghost" - :class (stl/css :modal-close-button) - :aria-label (tr "labels.close") - :on-click on-close - :icon i/close}]] + [:button {:class (stl/css :modal-close-button) + :on-click on-close + :title (tr "labels.close")} + deprecated-icon/close]] [:div {:class (stl/css :modal-content)} [:div {:class (stl/css :share-link-section)} (when (and (not confirm?) (some? current-link)) @@ -189,10 +185,10 @@ :placeholder (tr "common.share-link.placeholder") :read-only true}] - [:> icon-button* {:variant "ghost" - :aria-label (tr "viewer.header.share.copy-link") - :on-click copy-link - :icon i/clipboard}]]) + [:button {:class (stl/css :copy-button) + :title (tr "viewer.header.share.copy-link") + :on-click copy-link} + deprecated-icon/clipboard]]) [:div {:class (stl/css :hint-wrapper)} (when (not ^boolean confirm?) @@ -203,22 +199,28 @@ [:div {:class (stl/css :description)} (tr "common.share-link.confirm-deletion-link-description")] [:div {:class (stl/css :actions)} - [:> button* {:variant "secondary" - :on-click #(reset! confirm* false)} - (tr "labels.cancel")] - [:> button* {:variant "destructive" - :on-click delete-link} - (tr "common.share-link.destroy-link")]]] + [:input {:type "button" + :class (stl/css :button-cancel) + :on-click #(reset! confirm* false) + :value (tr "labels.cancel")}] + [:input {:type "button" + :class (stl/css :button-danger) + :on-click delete-link + :value (tr "common.share-link.destroy-link")}]]] (some? current-link) - [:> button* {:variant "destructive" - :on-click try-delete-link} - (tr "common.share-link.destroy-link")] + [:input + {:type "button" + :class (stl/css :button-danger) + :on-click try-delete-link + :value (tr "common.share-link.destroy-link")}] :else - [:> button* {:variant "primary" - :on-click create-link} - (tr "common.share-link.get-link")])]] + [:input + {:type "button" + :class (stl/css :button-active) + :on-click create-link + :value (tr "common.share-link.get-link")}])]] (when (not ^boolean confirm?) @@ -303,7 +305,6 @@ :options [{:value "team" :label (tr "common.share-link.team-members")} {:value "all" :label (tr "common.share-link.all-users")}] :on-change on-comment-change}]]] - [:div {:class (stl/css :inspect-mode)} [:div {:class (stl/css :subtitle)} (tr "common.share-link.permissions-can-inspect")] @@ -314,3 +315,6 @@ :options [{:value "team" :label (tr "common.share-link.team-members")} {:value "all" :label (tr "common.share-link.all-users")}] :on-change on-inspect-change}]]]])])]]])) + + + diff --git a/frontend/src/app/main/ui/viewer/share_link.scss b/frontend/src/app/main/ui/viewer/share_link.scss index b877736d16..2c8bcc60b1 100644 --- a/frontend/src/app/main/ui/viewer/share_link.scss +++ b/frontend/src/app/main/ui/viewer/share_link.scss @@ -30,9 +30,7 @@ } .modal-close-button { - position: absolute; - top: var(--sp-s); - right: var(--sp-s); + @extend .modal-close-btn-base; } .modal-content { @@ -76,6 +74,18 @@ } } +.copy-button { + @extend .button-secondary; + @include deprecated.flexRow; + gap: deprecated.$s-8; + height: deprecated.$s-32; + width: deprecated.$s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground-hover); + } +} + .description { @include deprecated.bodySmallTypography; color: var(--modal-text-foreground-color); @@ -87,6 +97,18 @@ justify-content: flex-end; } +.button-active { + @extend .modal-accept-btn; +} + +.button-cancel { + @extend .modal-cancel-btn; +} + +.button-danger { + @extend .modal-danger-btn; +} + .permissions-section { @include deprecated.flexColumn; gap: deprecated.$s-8; diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 8abd50ba06..3e930e9f81 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -25,11 +25,10 @@ [app.main.features :as features] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.components.file-uploader :refer [file-uploader*]] + [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.components.radio-buttons :refer [radio-buttons radio-button]] [app.main.ui.components.select :refer [select]] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]] [app.main.ui.hooks :as hooks] @@ -416,25 +415,24 @@ :on-change handle-change-mode}]]) (when (and (= origin :sidebar) show-tokens? token-color) - [:> radio-buttons* {:selected color-style - :on-change toggle-token-color - :name "color-style" - :options [{:id "swap-opt-list" - :icon i/swatches - :label (tr "labels.color") - :value :direct-color} - {:id "swap-opt-grid" - :icon i/tokens - :label (tr "workspace.colorpicker.color-tokens") - :value :token-color}]}])] + [:& radio-buttons {:selected color-style + :on-change toggle-token-color + :name "color-style"} + [:& radio-button {:icon i/swatches + :value :direct-color + :title (tr "labels.color") + :id "opt-color"}] + [:& radio-button {:icon i/tokens + :value :token-color + :title (tr "workspace.colorpicker.color-tokens") + :id "opt-token-color"}]])] (when (and (not= selected-mode :image) (= color-style :direct-color)) - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.colorpicker.get-color") - :aria-pressed picking-color? - :on-click handle-click-picker - :icon i/picker}]) + [:button {:class (stl/css-case :picker-btn true + :selected picking-color?) + :on-click handle-click-picker} + deprecated-icon/picker]) (when (= color-style :token-color) [:div {:class (stl/css :token-color-title)} @@ -485,11 +483,12 @@ :aria-label (tr "media.choose-image") :on-click on-fill-image-click} (tr "media.choose-image") - [:> file-uploader* {:input-id "fill-image-upload" - :accept "image/jpeg,image/png" - :multi false - :ref fill-image-ref - :on-selected on-fill-image-selected}]]]) + [:& file-uploader + {:input-id "fill-image-upload" + :accept "image/jpeg,image/png" + :multi false + :ref fill-image-ref + :on-selected on-fill-image-selected}]]]) [:* [:div {:class (stl/css :colorpicker-tabs)} diff --git a/frontend/src/app/main/ui/workspace/colorpicker.scss b/frontend/src/app/main/ui/workspace/colorpicker.scss index d50ed0002c..1d7e303d41 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.scss +++ b/frontend/src/app/main/ui/workspace/colorpicker.scss @@ -46,6 +46,52 @@ width: px2rem(68); } +// TODO: change to DS button component +.picker-btn { + display: flex; + justify-content: center; + align-items: center; + border: none; + background: none; + cursor: pointer; + border-radius: $br-8; + background-color: transparent; + border: $b-1 solid transparent; + height: var(--sp-xl); + width: var(--sp-xl); + border-radius: $br-4; + padding: 0; + margin-top: var(--sp-xs); + svg { + @extend .button-icon; + stroke: var(--button-tertiary-foreground-color-rest); + } + &:hover { + svg { + stroke: var(--button-tertiary-foreground-color-focus); + } + } + &:focus, + &:focus-visible { + outline: none; + svg { + stroke: var(--button-secondary-foreground-color-hover); + } + } + &:active { + outline: none; + border: $b-1 solid transparent; + svg { + stroke: var(--button-tertiary-foreground-color-active); + } + } + &.selected { + svg { + stroke: var(--button-tertiary-foreground-color-active); + } + } +} + .gradient-buttons { display: flex; align-items: center; diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index bede05c92c..18fd87e7c8 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -30,7 +30,6 @@ [app.main.ui.components.search-bar :refer [search-bar*]] [app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.context :as ctx] - [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]] @@ -45,6 +44,12 @@ [cuerdas.core :as str] [rumext.v2 :as mf])) +(def ^:private close-icon + (deprecated-icon/icon-xref :close (stl/css :close-icon))) + +(def ^:private add-icon + (deprecated-icon/icon-xref :add (stl/css :add-icon))) + (defn- get-library-summary "Given a library data return a summary representation of this library" [data] @@ -163,10 +168,12 @@ [:div {:class (stl/css :sample-library-item) :key (dm/str id)} [:div {:class (stl/css :sample-library-item-name)} (:name library)] - [:> button* {:variant "secondary" - :on-click import-library - :disabled (some? importing?)} - (if (= importing? id) (tr "labels.adding") (tr "labels.add"))]])) + [:input {:class (stl/css-case :sample-library-button true + :sample-library-add (nil? importing?) + :sample-library-adding (some? importing?)) + :type "button" + :value (if (= importing? id) (tr "labels.adding") (tr "labels.add")) + :on-click import-library}]])) (defn- empty-library? "Check if currentt library summary has elements or not" @@ -315,12 +322,14 @@ [:> library-description* {:summary summary}]]] (if ^boolean is-shared - [:> button* {:variant "secondary" - :on-click unpublish} - (tr "common.unpublish")] - [:> button* {:variant "primary" - :on-click publish} - (tr "common.publish")])] + [:input {:class (stl/css :item-unpublish) + :type "button" + :value (tr "common.unpublish") + :on-click unpublish}] + [:input {:class (stl/css :item-publish) + :type "button" + :value (tr "common.publish") + :on-click publish}])] (for [{:keys [id name data connected-to connected-to-names] :as library} linked-libraries] (let [disabled? (some #(contains? linked-libraries-ids %) connected-to)] @@ -368,11 +377,12 @@ (let [summary (-> (:library-summary library) (adapt-backend-summary))] [:> library-description* {:summary summary}])]] - [:> icon-button* {:variant "secondary" - :aria-label (tr "workspace.libraries.shared-library-btn") - :icon i/add - :data-library-id (dm/str id) - :on-click link-library}]])] + + [:button {:class (stl/css :item-button-shared) + :data-library-id (dm/str id) + :title (tr "workspace.libraries.shared-library-btn") + :on-click link-library} + add-icon]])] (when (empty? shared-libraries) [:div {:class (stl/css :section-list-empty)} @@ -637,13 +647,11 @@ :on-click close-dialog-outside :data-testid "libraries-modal"} [:div {:class (stl/css :modal-dialog)} - [:> icon-button* {:variant "ghost" - :class (stl/css :close-btn) - :icon i/close - :aria-label (tr "labels.close") - :data-testid "close-libraries" - :on-click close-dialog}] - + [:button {:class (stl/css :close-btn) + :on-click close-dialog + :aria-label (tr "labels.close") + :data-testid "close-libraries"} + close-icon] [:div {:class (stl/css :modal-title)} (tr "workspace.libraries.libraries")] diff --git a/frontend/src/app/main/ui/workspace/libraries.scss b/frontend/src/app/main/ui/workspace/libraries.scss index 46a7edca7f..9776c08bad 100644 --- a/frontend/src/app/main/ui/workspace/libraries.scss +++ b/frontend/src/app/main/ui/workspace/libraries.scss @@ -33,7 +33,7 @@ background-color: var(--modal-background-color); border: $b-2 solid var(--modal-border-color); display: grid; - grid-template-rows: 0 auto 1fr; + grid-template-rows: auto 1fr; min-width: $sz-364; min-height: $sz-192; height: $sz-520; @@ -42,10 +42,21 @@ max-width: $sz-712; } +// TODO: Remove this extended creating modal component .close-btn { - position: absolute; - top: var(--sp-s); - right: var(--sp-s); + @extend .modal-close-btn-base; +} + +.close-icon { + display: flex; + justify-content: center; + align-items: center; + height: $sz-16; + width: $sz-16; + color: transparent; + fill: none; + stroke-width: $b-1; + stroke: var(--icon-foreground); } .modal-title { @@ -109,6 +120,46 @@ height: fit-content; } +.item-publish, +.item-unpublish { + // TODO: remove this extended by using DS button component + @extend .button-primary; + @include t.use-typography("headline-small"); + height: $sz-32; + min-width: px2rem(92); + padding: var(--sp-s) var(--sp-xxl); + margin: 0; + border-radius: $br-8; +} + +.item-unpublish { + // TODO: remove this extended by using DS button component + @extend .button-secondary; +} + +.item-button, +.item-button-shared { + // TODO: remove this extended by using DS button component + @extend .button-secondary; + height: $sz-32; + width: $sz-32; + margin-inline-start: var(--sp-xxs); + padding: var(--sp-s); +} + +.detach-icon, +.add-icon { + display: flex; + justify-content: center; + align-items: center; + height: $sz-16; + width: $sz-16; + color: transparent; + fill: none; + stroke-width: $b-1; + stroke: var(--icon-foreground); +} + .section-list-shared { max-height: px2rem(272); } @@ -119,6 +170,26 @@ color: var(--title-foreground-color); } +.search-icon { + display: flex; + justify-content: center; + align-items: center; + width: px2rem(20); + padding: 0 0 0 var(--sp-s); + + svg { + display: flex; + justify-content: center; + align-items: center; + color: transparent; + fill: none; + height: px2rem(12); + width: px2rem(12); + stroke-width: 1.33px; + stroke: var(--icon-foreground); + } +} + // empty state .section-list-empty { display: grid; @@ -357,3 +428,24 @@ text-overflow: ellipsis; max-width: px2rem(232); } + +// TODO: Remove this extended using a DS component +.sample-library-add { + @extend .button-secondary; +} + +// TODO: Remove this extended using a DS component +.sample-library-adding { + @extend .button-disabled; +} + +.sample-library-button { + @include t.use-typography("headline-small"); + height: $sz-32; + width: px2rem(80); + margin: 0; + border-radius: $br-8; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/frontend/src/app/main/ui/workspace/main_menu.cljs b/frontend/src/app/main/ui/workspace/main_menu.cljs index 226d0d0233..a964d27475 100644 --- a/frontend/src/app/main/ui/workspace/main_menu.cljs +++ b/frontend/src/app/main/ui/workspace/main_menu.cljs @@ -853,9 +853,8 @@ [:* [:> icon-button* {:variant "ghost" - :aria-pressed show-menu? :aria-label (tr "shortcut-subsection.main-menu") - :on-click (if show-menu? close-all-menus open-menu) + :on-click open-menu :icon i/menu}] [:> dropdown-menu* {:show show-menu? diff --git a/frontend/src/app/main/ui/workspace/palette.cljs b/frontend/src/app/main/ui/workspace/palette.cljs index dd219410a8..80c396989e 100644 --- a/frontend/src/app/main/ui/workspace/palette.cljs +++ b/frontend/src/app/main/ui/workspace/palette.cljs @@ -18,10 +18,9 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.context :as ctx] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.hooks :as h] [app.main.ui.hooks.resize :as r] + [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.color-palette :refer [color-palette*]] [app.main.ui.workspace.color-palette-ctx-menu :refer [color-palette-ctx-menu*]] [app.main.ui.workspace.text-palette :refer [text-palette]] @@ -179,27 +178,27 @@ [:ul {:class (dm/str size-classname " " (stl/css-case :palette-btn-list true :hidden-bts hide-palettes?))} [:li {:class (stl/css :palette-item)} - [:> icon-button* {:variant "ghost" - :aria-pressed (some? color-palette?) - :aria-label (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette)) - :on-click on-select-color-palette - :icon i/drop}]] + [:button {:title (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette)) + :aria-label (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette)) + :class (stl/css-case :palette-btn true + :selected color-palette?) + :on-click on-select-color-palette} + deprecated-icon/drop-icon]] + [:li {:class (stl/css :palette-item)} - [:> icon-button* {:variant "ghost" - :aria-pressed (some? text-palette?) - :aria-label (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette)) - :on-click on-select-text-palette - :icon i/text-palette}]]] + [:button {:title (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette)) + :aria-label (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette)) + :class (stl/css-case :palette-btn true + :selected text-palette?) + :on-click on-select-text-palette} + deprecated-icon/text-palette]]] + (if any-palette? [:* - [:div {:class (stl/css :menu-btn)} - [:> icon-button* {:variant "ghost" - :aria-pressed show-menu? - :aria-label (tr "labels.options") - :on-click #(swap! state* update :show-menu not) - :icon i/menu}]] - + [:button {:class (stl/css :palette-actions) + :on-click #(swap! state* update :show-menu not)} + deprecated-icon/menu] [:div {:class (stl/css :palette) :ref container} (when text-palette? diff --git a/frontend/src/app/main/ui/workspace/palette.scss b/frontend/src/app/main/ui/workspace/palette.scss index dbdef2a6b2..7dc42ffc37 100644 --- a/frontend/src/app/main/ui/workspace/palette.scss +++ b/frontend/src/app/main/ui/workspace/palette.scss @@ -49,6 +49,7 @@ &.wide { width: 100%; } + .resize-area { grid-area: resize; height: deprecated.$s-8; @@ -71,22 +72,49 @@ &.small-palette { display: flex; } + .palette-item { + @include deprecated.flexCenter; + border-radius: deprecated.$br-8; + opacity: deprecated.$op-10; + transition: opacity 1s ease; + .palette-btn { + @extend .button-tertiary; + height: deprecated.$s-32; + width: deprecated.$s-32; + border-radius: deprecated.$br-8; + background-clip: padding-box; + padding: 0; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } + &.selected { + @extend .button-icon-selected; + } + } + } + } + + .palette-actions { + @extend .button-tertiary; + grid-area: actions; + height: calc(var(--height) - deprecated.$s-16); + width: deprecated.$s-32; + padding: 0; + margin-left: deprecated.$s-4; + border-radius: deprecated.$br-8; + background-color: var(--palette-background-color); + z-index: deprecated.$z-index-2; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } } .palette { grid-area: palette; width: 100%; min-width: 0; } - .palette-item { - display: flex; - align-items: center; - } -} - -.menu-btn { - display: flex; - align-items: center; - margin-left: var(--sp-s); } .handler { diff --git a/frontend/src/app/main/ui/workspace/presence.cljs b/frontend/src/app/main/ui/workspace/presence.cljs index d7bcda046f..38302ed536 100644 --- a/frontend/src/app/main/ui/workspace/presence.cljs +++ b/frontend/src/app/main/ui/workspace/presence.cljs @@ -29,7 +29,7 @@ :style {:background-color color} :src (cfg/resolve-profile-photo-url profile)}]])) -(mf/defc active-sessions* +(mf/defc active-sessions {::mf/memo true} [] (let [profiles (mf/deref refs/profiles) diff --git a/frontend/src/app/main/ui/workspace/right_header.cljs b/frontend/src/app/main/ui/workspace/right_header.cljs index b9867ea6b2..ce10de99cf 100644 --- a/frontend/src/app/main/ui/workspace/right_header.cljs +++ b/frontend/src/app/main/ui/workspace/right_header.cljs @@ -20,19 +20,23 @@ [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.context :as ctx] [app.main.ui.dashboard.team] - [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :as i] - [app.main.ui.exports.assets :refer [progress-widget*]] + [app.main.ui.exports.assets :refer [progress-widget]] [app.main.ui.formats :as fmt] - [app.main.ui.workspace.presence :refer [active-sessions*]] + [app.main.ui.icons :as deprecated-icon] + [app.main.ui.workspace.presence :refer [active-sessions]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] + [okulary.core :as l] [rumext.v2 :as mf])) +(def ref:persistence-status + (l/derived :status refs/persistence)) + ;; --- Zoom Widget -(mf/defc zoom-widget-workspace* +(mf/defc zoom-widget-workspace {::mf/wrap [mf/memo] ::mf/wrap-props false} [{:keys [zoom on-increase on-decrease on-zoom-reset on-zoom-fit on-zoom-selected]}] @@ -68,12 +72,11 @@ zoom (fmt/format-percent zoom {:precision 0})] [:* - [:div {:on-click (if open? close-dropdown open-dropdown) + [:div {:on-click open-dropdown :class (stl/css-case :zoom-widget true :selected open?) :title (tr "workspace.header.zoom")} [:span {:class (stl/css :label)} zoom]] - [:& dropdown {:show open? :on-close close-dropdown} [:ul {:class (stl/css :dropdown)} [:li {:class (stl/css :basic-zoom-bar)} @@ -87,10 +90,9 @@ :aria-label (tr "shortcuts.increase-zoom") :on-click on-increase :icon i/add}]] - [:> button* {:variant "ghost" - :on-click on-zoom-reset} + [:button {:class (stl/css :reset-btn) + :on-click on-zoom-reset} (tr "workspace.header.reset-zoom")]] - [:li {:class (stl/css :zoom-option) :on-click on-zoom-fit} (tr "workspace.header.zoom-fit-all") @@ -98,7 +100,6 @@ (for [sc (scd/split-sc (sc/get-tooltip :fit-all))] [:span {:class (stl/css :shortcut-key) :key (str "zoom-fit-" sc)} sc])]] - [:li {:class (stl/css :zoom-option) :on-click on-zoom-selected} (tr "workspace.header.zoom-selected") @@ -197,43 +198,51 @@ [:div {:class (stl/css :workspace-header-right)} [:div {:class (stl/css :users-section)} - [:> active-sessions*]] + [:& active-sessions]] - [:> progress-widget*] + [:& progress-widget] [:div {:class (stl/css :separator)}] [:div {:class (stl/css :zoom-section)} - [:> zoom-widget-workspace* {:zoom zoom - :on-increase on-increase - :on-decrease on-decrease - :on-zoom-reset on-zoom-reset - :on-zoom-fit on-zoom-fit - :on-zoom-selected on-zoom-selected}]] + [:& zoom-widget-workspace + {:zoom zoom + :on-increase on-increase + :on-decrease on-decrease + :on-zoom-reset on-zoom-reset + :on-zoom-fit on-zoom-fit + :on-zoom-selected on-zoom-selected}]] - [:div {:class (stl/css :comments-button-wrapper)} - [:> icon-button* {:variant "ghost" - :aria-pressed (= selected-drawtool :comments) - :aria-label (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment)) - :on-click toggle-comments - :icon i/comments}] - (when ^boolean has-unread-comments? - [:div {:class (stl/css :unread)}])] + [:div {:class (stl/css :comments-section)} + [:button {:title (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment)) + :aria-label (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment)) + :class (stl/css-case :comments-btn true + :selected (= selected-drawtool :comments)) + :on-click toggle-comments + :data-tool "comments" + :style {:position "relative"}} + deprecated-icon/comments + (when ^boolean has-unread-comments? + [:div {:class (stl/css :unread)}])]] (when-not ^boolean read-only? - [:> icon-button* {:variant "ghost" - :aria-pressed (contains? layout :document-history) - :aria-label (tr "workspace.sidebar.history") - :on-click toggle-history - :icon i/history}]) + [:div {:class (stl/css :history-section)} + [:button + {:title (tr "workspace.sidebar.history") + :aria-label (tr "workspace.sidebar.history") + :class (stl/css-case :selected (contains? layout :document-history) + :history-button true) + :on-click toggle-history} + deprecated-icon/history]]) (when display-share-button? - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.header.share") - :on-click open-share-dialog - :icon i/to-corner}]) + [:a {:class (stl/css :viewer-btn) + :title (tr "workspace.header.share") + :on-click open-share-dialog} + deprecated-icon/share]) + + [:a {:class (stl/css :viewer-btn) + :title (tr "workspace.header.viewer" (sc/get-tooltip :open-viewer)) + :on-click nav-to-viewer} + deprecated-icon/play]])) - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.header.viewer" (sc/get-tooltip :open-viewer)) - :on-click nav-to-viewer - :icon i/play}]])) diff --git a/frontend/src/app/main/ui/workspace/right_header.scss b/frontend/src/app/main/ui/workspace/right_header.scss index e49c314ef6..e6d7ea2092 100644 --- a/frontend/src/app/main/ui/workspace/right_header.scss +++ b/frontend/src/app/main/ui/workspace/right_header.scss @@ -11,8 +11,8 @@ justify-content: space-between; align-items: center; min-width: deprecated.$s-256; - padding: deprecated.$s-8 deprecated.$s-12; - gap: deprecated.$s-4; + padding: deprecated.$s-8; + gap: deprecated.$s-8; background-color: var(--panel-background-color); } @@ -28,14 +28,19 @@ } .zoom-widget { + @include deprecated.buttonStyle; display: flex; align-items: center; justify-content: center; + height: deprecated.$s-28; + max-width: deprecated.$s-48; width: deprecated.$s-48; - height: deprecated.$s-32; + border-radius: deprecated.$br-8; .label { @include deprecated.bodySmallTypography; + height: 100%; + padding: deprecated.$s-8 0; color: var(--button-tertiary-foreground-color-rest); } @@ -79,6 +84,13 @@ color: var(--modal-title-foreground-color); } +.reset-btn { + @extend .button-tertiary; + color: var(--button-tertiary-foreground-color-hover); + height: deprecated.$s-28; + border-radius: deprecated.$br-8; +} + .zoom-option { @extend .menu-item-base; @@ -101,11 +113,127 @@ } } -.comments-button-wrapper { - position: relative; +.comments-btn { + @extend .button-tertiary; + border-radius: deprecated.$br-8; + margin: 0; + height: deprecated.$s-28; + width: deprecated.$s-28; + border: none; + + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + height: deprecated.$s-16; + width: deprecated.$s-16; + } + + &:hover { + background-color: transparent; + border: none; + } + + &.selected { + background-color: var(--button-tertiary-background-color-selected); + + svg { + stroke: var(--button-tertiary-foreground-color-active); + } + } } -.comments-button-unread { +.history-button { + @extend .button-tertiary; + border-radius: deprecated.$br-8; + margin: 0; + height: deprecated.$s-28; + width: deprecated.$s-28; + border: none; + + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + height: deprecated.$s-16; + width: deprecated.$s-16; + } + + &:hover { + background-color: transparent; + border: none; + } + + &.selected { + background-color: var(--button-tertiary-background-color-selected); + + svg { + stroke: var(--button-tertiary-foreground-color-active); + } + } +} + +.persistence-status-widget { + @include deprecated.flexCenter; + width: deprecated.$s-28; + height: deprecated.$s-28; +} + +.status-icon { + @include deprecated.flexCenter; + width: deprecated.$s-24; + height: deprecated.$s-24; + margin: 0; + border-radius: deprecated.$br-circle; + + svg { + @extend .button-icon; + stroke: var(--status-widget-icon-foreground-color); + } +} + +.pending-status { + background-color: var(--status-widget-background-color-warning); +} + +.saving-status { + background-color: var(--status-widget-background-color-pending); + + svg { + animation: spin-animation 1s infinite; + animation-timing-function: linear; + } +} + +.saved-status { + background-color: var(--status-widget-background-color-success); +} + +.error-status { + background-color: var(--status-widget-background-color-error); +} + +.share-btn, +.viewer-btn { + @extend .button-tertiary; + border-radius: deprecated.$br-8; + margin: 0; + width: deprecated.$s-28; + height: deprecated.$s-28; + border: none; + + svg { + @extend .button-icon; + height: deprecated.$s-16; + width: deprecated.$s-16; + stroke: var(--icon-foreground); + } + + &:hover { + background-color: transparent; + border: none; + } +} + +.unread { position: absolute; width: 8px; height: 8px; diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index 482393e286..d899f20d67 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -17,9 +17,8 @@ [app.main.ui.components.context-menu-a11y :refer [context-menu*]] [app.main.ui.components.search-bar :refer [search-bar*]] [app.main.ui.context :as ctx] - [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.sidebar.assets.common :as cmm] [app.main.ui.workspace.sidebar.assets.file-library :refer [file-library*]] [app.util.dom :as dom] @@ -162,40 +161,43 @@ :id "typographies" :handler on-section-filter-change}])] - [:article {:class (stl/css :assets-bar)} + [:article {:class (stl/css :assets-bar)} [:div {:class (stl/css :assets-header)} (when-not ^boolean read-only? (if (and (= num-libs 1) (empty? components)) - [:> button* {:variant "primary" - :on-click show-libraries-dialog - :data-testid "libraries"} + [:button {:class (stl/css :add-library-button) + :on-click show-libraries-dialog + :data-testid "libraries"} (tr "workspace.assets.add-library")] - [:> button* {:variant "secondary" - :on-click show-libraries-dialog - :data-testid "libraries"} + + [:button {:class (stl/css :libraries-button) + :on-click show-libraries-dialog + :data-testid "libraries"} (tr "workspace.assets.manage-library")])) + [:div {:class (stl/css :search-wrapper)} [:> search-bar* {:on-change on-search-term-change :value term :placeholder (tr "workspace.assets.search")} - [:> icon-button* {:variant "secondary" - :icon i/filter - :class (stl/css :filter-button) - :aria-pressed menu-open? - :aria-label (tr "workspace.assets.filter") - :on-click on-open-menu}]] + [:button + {:on-click on-open-menu + :title (tr "workspace.assets.filter") + :class (stl/css-case :section-button true + :opened menu-open?)} + deprecated-icon/filter-icon]] - [:> context-menu* {:on-close on-menu-close - :selectable true - :selected section - :show menu-open? - :fixed true - :min-width true - :width size - :top 158 - :left 18 - :options options}] + [:> context-menu* + {:on-close on-menu-close + :selectable true + :selected section + :show menu-open? + :fixed true + :min-width true + :width size + :top 158 + :left 18 + :options options}] [:> icon-button* {:variant "ghost" :aria-label (tr "workspace.assets.sort") diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.scss b/frontend/src/app/main/ui/workspace/sidebar/assets.scss index 53cbc98e0e..f89069cca5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.scss @@ -17,14 +17,89 @@ padding-top: deprecated.$s-8; } -.assets-header { - display: flex; - flex-direction: column; - gap: var(--sp-xxs); +.libraries-button { + @extend .button-secondary; + @include deprecated.uppercaseTitleTipography; + gap: deprecated.$s-2; + height: deprecated.$s-32; + width: 100%; + margin-bottom: deprecated.$s-4; + border-radius: deprecated.$s-8; + + &:hover { + background-color: var(--button-secondary-background-color-hover); + color: var(--button-secondary-foreground-color-hover); + border: deprecated.$s-1 solid var(--button-secondary-border-color-hover); + } + + &:focus { + background-color: var(--button-secondary-background-color-focus); + color: var(--button-secondary-foreground-color-focus); + border: deprecated.$s-1 solid var(--button-secondary-border-color-focus); + } } -.filter-button { - border-radius: deprecated.$br-8 0 0 deprecated.$br-8; +.add-library-button { + @extend .button-primary; + @include deprecated.uppercaseTitleTipography; + gap: deprecated.$s-2; + height: deprecated.$s-32; + width: 100%; + margin-bottom: deprecated.$s-4; + border-radius: deprecated.$s-8; +} + +.section-button { + @include deprecated.flexCenter; + @include deprecated.buttonStyle; + height: deprecated.$s-32; + width: deprecated.$s-32; + margin: 0; + border: deprecated.$s-1 solid var(--input-border-color-rest); + border-radius: deprecated.$br-8 deprecated.$br-2 deprecated.$br-2 deprecated.$br-8; + background-color: var(--input-background-color-rest); + + svg { + height: deprecated.$s-16; + width: deprecated.$s-16; + stroke: var(--icon-foreground); + } + + &:focus { + border: deprecated.$s-1 solid var(--input-border-color-focus); + outline: 0; + background-color: var(--input-background-color-focus); + color: var(--input-foreground-color-focus); + + svg { + background-color: var(--input-background-color-focus); + } + } + + &:hover { + border: deprecated.$s-1 solid var(--input-border-color-hover); + background-color: var(--input-background-color-hover); + + svg { + background-color: var(--input-background-color-hover); + stroke: var(--button-foreground-hover); + } + + &:focus { + border: deprecated.$s-1 solid var(--input-border-color-focus); + outline: 0; + background-color: var(--input-background-color-focus); + color: var(--input-foreground-color-focus); + + svg { + background-color: var(--input-background-color-focus); + } + } + } + + &.opened { + @extend .button-icon-selected; + } } .sections-container { @@ -50,6 +125,10 @@ border-radius: deprecated.$br-8; } +.section-btn { + @include deprecated.buttonStyle; +} + .assets-header { padding: 0 0 deprecated.$s-24 deprecated.$s-12; } diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs index 9aa485d5eb..077742d71d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs @@ -22,10 +22,10 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.editable-label :refer [editable-label*]] - [app.main.ui.components.file-uploader :refer [file-uploader*]] + [app.main.ui.components.file-uploader :refer [file-uploader]] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.context :as ctx] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.hooks :as h] [app.main.ui.workspace.sidebar.assets.common :as cmm] @@ -563,27 +563,27 @@ [:> cmm/asset-section-block* {:role :title-button} (when ^boolean is-open [:div - [:> radio-buttons* {:selected (if is-listing-thumbs "grid" "list") - :on-change toggle-list-style - :name "listing-style" - :options [{:id "opt-list" - :icon i/view-as-list - :label (tr "workspace.assets.list-view") - :value "list"} - {:id "opt-grid" - :icon i/flex-grid - :label (tr "workspace.assets.grid-view") - :value "grid"}]}]]) + [:& radio-buttons {:selected (if is-listing-thumbs "grid" "list") + :on-change toggle-list-style + :name "listing-style"} + [:& radio-button {:icon i/view-as-list + :value "list" + :title (tr "workspace.assets.list-view") + :id "opt-list"}] + [:& radio-button {:icon i/flex-grid + :value "grid" + :title (tr "workspace.assets.grid-view") + :id "opt-grid"}]]]) (when (and (not read-only?) is-local) [:> icon-button* {:variant "ghost" :aria-label (tr "workspace.assets.components.add-component") :on-click add-component :icon i/add} - [:> file-uploader* {:accept dwm/accept-image-types - :multi true - :ref input-ref - :on-selected on-file-selected}]])] + [:& file-uploader {:accept dwm/accept-image-types + :multi true + :ref input-ref + :on-selected on-file-selected}]])] [:> cmm/asset-section-block* {:role :content} (when ^boolean is-open diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs index 5d29117036..8ad40c2f4e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs @@ -23,7 +23,7 @@ [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.workspace.sidebar.assets.common :as cmm] [app.main.ui.workspace.sidebar.assets.groups :as grp] - [app.main.ui.workspace.sidebar.options.menus.typography :refer [typography-entry*]] + [app.main.ui.workspace.sidebar.options.menus.typography :refer [typography-entry]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] @@ -113,17 +113,18 @@ :on-drag-over dom/prevent-default :on-drop on-drop} - [:> typography-entry* {:file-id file-id - :typography typography - :local? local? - :selected? (contains? selected typography-id) - :on-click on-asset-click - :on-change handle-change - :on-context-menu on-context-menu - :editing? editing? - :renaming? renaming? - :focus-name? rename? - :external-open* open*}] + [:& typography-entry + {:file-id file-id + :typography typography + :local? local? + :selected? (contains? selected typography-id) + :on-click on-asset-click + :on-change handle-change + :on-context-menu on-context-menu + :editing? editing? + :renaming? renaming? + :focus-name? rename? + :external-open* open*}] (when ^boolean dragging? [:div {:class (stl/css :dragging)}])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs index 8c22f87fc5..550e072d07 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -84,6 +84,8 @@ :on-click on-select-shape :on-context-menu on-context-menu :data-testid "layer-row" + :role "checkbox" + :aria-checked selected? :class (stl/css-case :layer-row true :highlight highlighted? diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 282eca00e8..dabe7aae77 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -291,12 +291,13 @@ :value current-search :on-clear clear-search-text :placeholder (tr "workspace.sidebar.layers.search")} - [:> icon-button* {:variant "secondary" - :class (stl/css :filter-button) - :aria-pressed show-menu? - :aria-label (tr "workspace.sidebar.layers.filter") - :on-click on-toggle-filters-click - :icon i/filter}]] + [:button {:on-click on-toggle-filters-click + :class (stl/css-case + :filter-button true + :opened show-menu? + :active active?)} + [:> icon* {:icon-id i/filter}]]] + [:> icon-button* {:variant "ghost" :aria-label (tr "labels.close") :on-click toggle-search diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.scss b/frontend/src/app/main/ui/workspace/sidebar/layers.scss index 9a008fb94a..e89f730323 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.scss @@ -19,7 +19,39 @@ padding: 0 deprecated.$s-12 0 deprecated.$s-8; gap: deprecated.$s-4; .filter-button { - border-radius: deprecated.$br-8 0 0 deprecated.$br-8; + @include deprecated.flexCenter; + @include deprecated.buttonStyle; + height: deprecated.$s-32; + width: deprecated.$s-32; + margin: 0; + border: deprecated.$s-1 solid var(--color-background-tertiary); + border-radius: deprecated.$br-8 deprecated.$br-2 deprecated.$br-2 deprecated.$br-8; + background-color: var(--color-background-tertiary); + svg { + height: deprecated.$s-16; + width: deprecated.$s-16; + stroke: var(--icon-foreground); + } + &:focus { + border: deprecated.$s-1 solid var(--input-border-color-focus); + outline: 0; + background-color: var(--input-background-color-active); + color: var(--input-foreground-color-active); + svg { + background-color: var(--input-background-color-active); + } + } + &:hover { + border: deprecated.$s-1 solid var(--input-border-color-hover); + background-color: var(--input-background-color-hover); + svg { + background-color: var(--input-background-color-hover); + stroke: var(--button-foreground-hover); + } + } + &.opened { + @extend .button-icon-selected; + } } } } @@ -111,7 +143,7 @@ .filters-container { @extend .menu-dropdown; position: absolute; - left: deprecated.$s-16; + left: deprecated.$s-20; width: deprecated.$s-192; .filter-menu-item { @include deprecated.bodySmallTypography; diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/drawing/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/drawing/frame.cljs index 7bebe451b3..275ad11e8d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/drawing/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/drawing/frame.cljs @@ -12,7 +12,7 @@ [app.main.data.workspace.drawing :as dwd] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.icons :as deprecated-icon] [app.util.dom :as dom] @@ -95,15 +95,15 @@ (when preset-match [:span {:class (stl/css :check-icon)} deprecated-icon/tick])])))]]] - [:> radio-buttons* {:class (stl/css :radio-buttons) - :selected (or (d/name orientation) "") - :on-change on-orientation-change - :name "frame-orientation" - :options [{:id "size-vertical" - :icon i/size-vertical - :label (tr "workspace.options.orientation.vertical") - :value "vertical"} - {:id "size-horizontal" - :icon i/size-horizontal - :label (tr "workspace.options.orientation.horizontal") - :value "horizontal"}]}]])) + [:& radio-buttons {:selected (or (d/name orientation) "") + :on-change on-orientation-change + :name "frame-orientation" + :wide true + :class (stl/css :radio-buttons)} + [:& radio-button {:icon i/size-vertical + :value "vertical" + :id "size-vertical"}] + [:& radio-button {:icon i/size-horizontal + :value "horizontal" + :id "size-horizontal"}]]])) + diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs index aeb1fb8c60..4cf1c6efc4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs @@ -10,8 +10,7 @@ [app.main.data.workspace :as dw] [app.main.data.workspace.shortcuts :as sc] [app.main.store :as st] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.icons :as deprecated-icon] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -43,59 +42,68 @@ (when-not (and disabled-align disabled-distribute) [:div {:class (stl/css :align-options)} [:div {:class (stl/css :align-group-horizontal)} - [:> icon-button* {:variant "ghost" - :icon i/align-left - :aria-label (tr "workspace.align.hleft" (sc/get-tooltip :align-left)) - :on-click align-objects - :data-value "hleft" - :disabled disabled-align}] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.hleft" (sc/get-tooltip :align-left)) + :data-value "hleft" + :on-click align-objects} + deprecated-icon/align-left] - [:> icon-button* {:variant "ghost" - :icon i/align-horizontal-center - :aria-label (tr "workspace.align.hcenter" (sc/get-tooltip :align-hcenter)) - :on-click align-objects - :data-value "hcenter" - :disabled disabled-align}] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.hcenter" (sc/get-tooltip :align-hcenter)) + :data-value "hcenter" + :on-click align-objects} + deprecated-icon/align-horizontal-center] - [:> icon-button* {:variant "ghost" - :icon i/align-right - :aria-label (tr "workspace.align.hright" (sc/get-tooltip :align-right)) - :on-click align-objects - :data-value "hright" - :disabled disabled-align}] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.hright" (sc/get-tooltip :align-right)) + :data-value "hright" + :on-click align-objects} + deprecated-icon/align-right] - [:> icon-button* {:variant "ghost" - :icon i/distribute-horizontally - :aria-label (tr "workspace.align.hdistribute" (sc/get-tooltip :h-distribute)) - :on-click distribute-objects - :data-value "horizontal" - :disabled disabled-distribute}]] + [:button {:class (stl/css-case :align-button true + :disabled disabled-distribute) + :disabled disabled-distribute + :title (tr "workspace.align.hdistribute" (sc/get-tooltip :h-distribute)) + :data-value "horizontal" + :on-click distribute-objects} + deprecated-icon/distribute-horizontally]] [:div {:class (stl/css :align-group-vertical)} - [:> icon-button* {:variant "ghost" - :icon i/align-top - :aria-label (tr "workspace.align.vtop" (sc/get-tooltip :align-top)) - :on-click align-objects - :data-value "vtop" - :disabled disabled-align}] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.vtop" (sc/get-tooltip :align-top)) + :data-value "vtop" + :on-click align-objects} + deprecated-icon/align-top] - [:> icon-button* {:variant "ghost" - :icon i/align-vertical-center - :aria-label (tr "workspace.align.vcenter" (sc/get-tooltip :align-vcenter)) - :on-click align-objects - :data-value "vcenter" - :disabled disabled-align}] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.vcenter" (sc/get-tooltip :align-vcenter)) + :data-value "vcenter" + :on-click align-objects} + deprecated-icon/align-vertical-center] - [:> icon-button* {:variant "ghost" - :icon i/align-bottom - :aria-label (tr "workspace.align.vbottom" (sc/get-tooltip :align-bottom)) - :on-click align-objects - :data-value "vbottom" - :disabled disabled-align}] + [:button {:class (stl/css-case :align-button true + :disabled disabled-align) + :disabled disabled-align + :title (tr "workspace.align.vbottom" (sc/get-tooltip :align-bottom)) + :data-value "vbottom" + :on-click align-objects} + deprecated-icon/align-bottom] + + [:button {:title (tr "workspace.align.vdistribute" (sc/get-tooltip :v-distribute)) + :class (stl/css-case :align-button true + :disabled disabled-distribute) + :disabled disabled-distribute + :data-value "vertical" + :on-click distribute-objects} + deprecated-icon/distribute-vertical-spacing]]]))) - [:> icon-button* {:variant "ghost" - :icon i/distribute-vertical-spacing - :aria-label (tr "workspace.align.vdistribute" (sc/get-tooltip :v-distribute)) - :on-click distribute-objects - :data-value "vertical" - :disabled disabled-distribute}]]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.scss index 6b3f27b621..6535f728b4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.scss @@ -4,10 +4,12 @@ // // Copyright (c) KALEIDOS INC +@use "refactor/common-refactor.scss" as deprecated; @use "../../../sidebar/common/sidebar.scss" as sidebar; .align-options { @include sidebar.option-grid-structure; + height: deprecated.$s-32; } .align-group-horizontal, .align-group-vertical { @@ -24,3 +26,27 @@ .align-group-vertical { grid-column: 5 / span 4; } + +.align-button { + @extend .button-tertiary; + height: deprecated.$s-32; + width: deprecated.$s-32; + padding: 0; + border-radius: deprecated.$br-8; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + &.disabled { + cursor: default; + svg { + stroke: var(--button-foreground-color-disabled); + } + &:hover { + background-color: var(--panel-background-color); + svg { + stroke: var(--button-foreground-color-disabled); + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs index 7c27041728..52a5570614 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs @@ -15,6 +15,7 @@ [app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.icons :as deprecated-icon] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -102,12 +103,10 @@ [:div {:class (stl/css-case :first-row true :hidden hidden?)} [:div {:class (stl/css :blur-info)} - [:> icon-button* {:variant "secondary" - :class (stl/css :show-more) - :aria-label (tr "labels.options") - :aria-pressed more-options? - :on-click toggle-more-options - :icon i/menu}] + [:button {:class (stl/css-case :show-more true + :selected more-options?) + :on-click toggle-more-options} + deprecated-icon/menu] [:span {:class (stl/css :label)} (tr "workspace.options.blur-options.title")]] [:div {:class (stl/css :actions)} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss index 7623012431..e15a50c83e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss @@ -37,7 +37,21 @@ border-radius: deprecated.$br-8; background-color: var(--input-details-color); .show-more { + @extend .button-secondary; + height: deprecated.$s-32; + width: deprecated.$s-28; border-radius: deprecated.$br-8 0 0 deprecated.$br-8; + box-sizing: border-box; + border: deprecated.$s-1 solid var(--button-secondary-background-color-rest); + svg { + @extend .button-icon; + } + &.selected { + background-color: var(--button-radio-background-color-active); + svg { + stroke: var(--button-radio-foreground-color-active); + } + } } .label { @include deprecated.bodySmallTypography; diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs index 9fc8fdc6bb..b2ffa16cb8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs @@ -15,12 +15,15 @@ [app.main.data.workspace.shortcuts :as sc] [app.main.features :as features] [app.main.store :as st] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.icons :as deprecated-icon] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) +(def ^:private flatten-icon + (deprecated-icon/icon-xref :boolean-flatten (stl/css :flatten-icon))) + (mf/defc bool-options* [{:keys [total-selected shapes shapes-with-children]}] (let [head (first shapes) @@ -67,40 +70,41 @@ (st/emit! (dwb/change-bool-type head-id bool-type))))))) flatten-objects - (mf/use-fn - #(st/emit! (dwps/convert-selected-to-path)))] + (mf/use-fn #(st/emit! (dwps/convert-selected-to-path)))] (when (not (and disabled-bool-btns disabled-flatten)) [:div {:class (stl/css :boolean-options)} - [:div {:class (stl/css :boolean-group)} - [:> radio-buttons* {:class (stl/css :boolean-radio-btn) - :variant "ghost" - :selected (d/name head-bool-type) - :on-change on-change - :name "bool-options" - :options [{:id "bool-opt-union" - :icon i/boolean-union - :label (str (tr "workspace.shape.menu.union") " (" (sc/get-tooltip :bool-union) ")") - :value "union" - :disabled disabled-bool-btns} - {:id "bool-opt-differente" - :icon i/boolean-difference - :label (str (tr "workspace.shape.menu.difference") " (" (sc/get-tooltip :bool-difference) ")") - :value "difference" - :disabled disabled-bool-btns} - {:id "bool-opt-intersection" - :icon i/boolean-intersection - :label (str (tr "workspace.shape.menu.intersection") " (" (sc/get-tooltip :bool-intersection) ")") - :value "intersection" - :disabled disabled-bool-btns} - {:id "bool-opt-exclude" - :icon i/boolean-exclude - :label (str (tr "workspace.shape.menu.exclude") " (" (sc/get-tooltip :bool-exclude) ")") - :value "exclude" - :disabled disabled-bool-btns}]}]] + [:div {:class (stl/css :bool-group)} + [:& radio-buttons {:selected (d/name head-bool-type) + :class (stl/css :boolean-radio-btn) + :on-change on-change + :name "bool-options"} + [:& radio-button {:icon i/boolean-union + :value "union" + :disabled disabled-bool-btns + :title (str (tr "workspace.shape.menu.union") " (" (sc/get-tooltip :bool-union) ")") + :id "bool-opt-union"}] + [:& radio-button {:icon i/boolean-difference + :value "difference" + :disabled disabled-bool-btns + :title (str (tr "workspace.shape.menu.difference") " (" (sc/get-tooltip :bool-difference) ")") + :id "bool-opt-differente"}] + [:& radio-button {:icon i/boolean-intersection + :value "intersection" + :disabled disabled-bool-btns + :title (str (tr "workspace.shape.menu.intersection") " (" (sc/get-tooltip :bool-intersection) ")") + :id "bool-opt-intersection"}] + [:& radio-button {:icon i/boolean-exclude + :value "exclude" + :disabled disabled-bool-btns + :title (str (tr "workspace.shape.menu.exclude") " (" (sc/get-tooltip :bool-exclude) ")") + :id "bool-opt-exclude"}]]] - [:> icon-button* {:variant "ghost" - :icon i/boolean-flatten - :aria-label (tr "workspace.shape.menu.flatten") - :on-click flatten-objects - :disabled disabled-flatten}]]))) + [:button + {:title (tr "workspace.shape.menu.flatten") + :class (stl/css-case + :flatten-button true + :disabled disabled-flatten) + :disabled disabled-flatten + :on-click flatten-objects} + flatten-icon]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.scss index babf5564bd..ef69c2dd4e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.scss @@ -4,18 +4,45 @@ // // Copyright (c) KALEIDOS INC +@use "refactor/common-refactor.scss" as deprecated; @use "../../../sidebar/common/sidebar.scss" as sidebar; .boolean-options { @include sidebar.option-grid-structure; + height: var(--sp-xxxl); } -.boolean-group { +.bool-group { display: grid; grid-template-columns: subgrid; grid-column: 1 / span 4; } +.flatten-button { + @extend .button-tertiary; + height: deprecated.$s-32; + width: deprecated.$s-32; + border-radius: deprecated.$br-8; + grid-column: 5 / span 1; + --flatten-icon-foreground-color: var(--icon-foreground); + + &.disabled { + cursor: default; + --flatten-icon-foreground-color: var(--button-foreground-color-disabled); + + &:hover { + background-color: var(--panel-background-color); + --flatten-icon-foreground-color: var(--button-foreground-color-disabled); + } + } +} + +.flatten-icon { + @extend .button-icon; + stroke: var(--flatten-icon-foreground-color); +} + .boolean-radio-btn { background-color: transparent; + gap: var(--sp-xs); } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs index 7daff9923a..d1d7a55fc5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs @@ -333,9 +333,9 @@ :on-change on-radius-r3-change :value (:r3 values)}]]])) - [:> icon-button* {:variant "ghost" + [:> icon-button* {:class (stl/css-case :selected radius-expanded) + :variant "ghost" :on-click toggle-radius-mode - :aria-pressed radius-expanded :aria-label (if radius-expanded (tr "workspace.options.radius.hide-all-corners") (tr "workspace.options.radius.show-single-corners")) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.scss index db4cf8f11e..5473314c67 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.scss @@ -36,6 +36,12 @@ color: var(--color-accent-primary); } +.selected { + border-color: var(--button-icon-border-color-selected); + background-color: var(--button-icon-background-color-selected); + color: var(--button-icon-foreground-color-selected); +} + .icon { margin-inline: var(--sp-xs); } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs index 6a0862379a..eac46af116 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs @@ -13,7 +13,6 @@ [app.main.data.workspace.tokens.application :as dwta] [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar*]] - [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -50,16 +49,16 @@ • :prop → the property type (:fill, :stroke, :shadow, etc.) • :shape-id → the UUID of the shape using this color • :index → index of the color in the shape's fill/stroke list - + Example of groups: { {:color \"#9f2929\", :opacity 0.3, :token-name \"asd2\" :has-token-applied true} [{:prop :fill, :shape-id #uuid \"d0231035-25c9-80d5-8006-eae4c3dff32e\", :index 0}] - + {:color \"#1b54b6\", :opacity 1} [{:prop :fill, :shape-id #uuid \"aab34f9a-98c1-801a-8006-eae5e8236f1b\", :index 0}] } - + This structure allows fast lookups of all shapes using the same visual color, regardless of whether it comes from local fills, strokes or shadow-colors." @@ -218,8 +217,8 @@ :origin :color-selection :on-close on-close}])) (when (and (false? @expand-lib-color) (< 3 (count library-colors))) - [:> button* {:variant "secondary" - :on-click #(reset! expand-lib-color true)} + [:button {:class (stl/css :more-colors-btn) + :on-click #(reset! expand-lib-color true)} (tr "workspace.options.more-lib-colors")])] [:div {:class (stl/css :selected-color-group)} @@ -236,8 +235,8 @@ :on-close on-close}]) (when (and (false? @expand-color) (< 3 (count colors))) - [:> button* {:variant "secondary" - :on-click #(reset! expand-color true)} + [:button {:class (stl/css :more-colors-btn) + :on-click #(reset! expand-color true)} (tr "workspace.options.more-colors")])] [:div {:class (stl/css :selected-color-group)} @@ -260,6 +259,6 @@ (when (and (false? @expand-token-color) (< 3 (count token-colors))) - [:> button* {:variant "secondary" - :on-click #(reset! expand-token-color true)} + [:button {:class (stl/css :more-colors-btn) + :on-click #(reset! expand-token-color true)} (tr "workspace.options.more-token-colors")])]])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss index f84a46c2a2..7519bcb568 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss @@ -40,5 +40,7 @@ } .more-colors-btn { - justify-content: center; + @extend .button-secondary; + @include deprecated.uppercaseTitleTipography; + height: deprecated.$s-32; } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs index 1a6c61425e..401b01d67b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs @@ -28,6 +28,7 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.reorder-handler :refer [reorder-handler*]] [app.main.ui.components.search-bar :refer [search-bar*]] [app.main.ui.components.select :refer [select]] @@ -36,7 +37,6 @@ [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.controls.combobox :refer [combobox*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.controls.select :refer [select*]] [app.main.ui.ds.controls.switch :refer [switch*]] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] @@ -794,17 +794,15 @@ [:div {:class (stl/css :swap-library)} [:div {:class (stl/css :swap-library-title)} [:div {:class (stl/css :swap-library-name)} current-lib-name] - [:> radio-buttons* {:selected (if (:listing-thumbs? filters) "grid" "list") - :on-change toggle-list-style - :name "swap-listing-style" - :options [{:id "swap-opt-list" - :icon i/view-as-list - :label (tr "workspace.assets.list-view") - :value "list"} - {:id "swap-opt-grid" - :icon i/flex-grid - :label (tr "workspace.assets.grid-view") - :value "grid"}]}]] + [:& radio-buttons {:selected (if (:listing-thumbs? filters) "grid" "list") + :on-change toggle-list-style + :name "swap-listing-style"} + [:& radio-button {:icon i/view-as-list + :value "list" + :id "swap-opt-list"}] + [:& radio-button {:icon i/flex-grid + :value "grid" + :id "swap-opt-grid"}]]] (when-not (or search? (str/empty? (:path filters))) [:button {:class (stl/css :swap-library-back) @@ -899,13 +897,11 @@ (when menu-entries? [:div {:class (stl/css :pill-actions)} - [:> icon-button* {:variant "secondary" - :class (stl/css-case :pill-actions-btn true - :extended subtext) - :aria-pressed menu-open? - :aria-label (tr "labels.options") - :on-click on-menu-click - :icon i/menu}] + [:button {:class (stl/css-case :pill-actions-btn true + :selected menu-open?) + :on-click on-menu-click} + [:> icon* {:icon-id i/menu}]] + [:& dropdown {:show menu-open? :on-close on-menu-close} [:ul {:class (stl/css-case :pill-actions-dropdown true diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss index e8838fdb77..88ca5dd5b6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss @@ -587,9 +587,14 @@ } .pill-actions-btn { + @extend .button-secondary; + cursor: unset; + block-size: 100%; + inline-size: 100%; border-radius: 0 $br-8 $br-8 0; - &.extended { - block-size: $sz-48; + + &.selected { + @extend .button-icon-selected; } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs index f9368c9a4f..a56843dce2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs @@ -16,7 +16,7 @@ [app.main.store :as st] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar*]] - [app.main.ui.ds.controls.checkbox :refer [checkbox*]] + [app.main.ui.icons :as deprecated-icon] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] @@ -61,7 +61,6 @@ constraints-h (or (get values :constraints-h) (gsh/default-constraints-h values)) constraints-v (or (get values :constraints-v) (gsh/default-constraints-v values)) - fixed-scroll? (d/nilv (:fixed-scroll values) false) on-constraint-button-clicked (mf/use-fn @@ -219,8 +218,16 @@ :options options-v :on-change on-constraint-v-select-changed}]] (when first-level? - [:> checkbox* {:id "fixed-on-scroll" - :class (stl/css :checkbox) - :label (tr "workspace.options.constraints.fix-when-scrolling") - :checked fixed-scroll? - :on-change on-fixed-scroll-clicked}])]])]))) + [:div {:class (stl/css :checkbox)} + + [:label {:for "fixed-on-scroll" + :class (stl/css-case :checked (:fixed-scroll values))} + [:span {:class (stl/css-case :check-mark true + :checked (:fixed-scroll values))} + (when (:fixed-scroll values) + deprecated-icon/status-tick)] + (tr "workspace.options.constraints.fix-when-scrolling") + [:input {:type "checkbox" + :id "fixed-on-scroll" + :checked (:fixed-scroll values) + :on-change on-fixed-scroll-clicked}]]])]])]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss index 3f3fdc5dc1..5f7578afe1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss @@ -137,4 +137,36 @@ margin-bottom: deprecated.$s-8; margin-top: deprecated.$s-8; padding-left: 0; + input { + margin: 0; + } + + label { + @include deprecated.bodySmallTypography; + display: flex; + align-items: center; + gap: deprecated.$s-2; + cursor: pointer; + color: var(--input-checkbox-text-foreground-color); + .check-mark { + @include deprecated.flexCenter; + width: deprecated.$s-16; + height: deprecated.$s-16; + border-radius: deprecated.$br-6; + background-color: var(--input-checkbox-inactive-background-color); + &.checked { + background-color: var(--input-checkbox-background-color-active); + svg { + @extend .button-icon-small; + stroke: var(--input-details-color); + } + } + &:hover { + border-color: var(--input-checkbox-border-color-hover); + } + &:focus { + border-color: var(--input-checkbox-border-color-focus); + } + } + } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs index 88eca7dcfe..5e7d5c9127 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs @@ -14,7 +14,6 @@ [app.main.store :as st] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar*]] - [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.exports.assets] @@ -264,10 +263,12 @@ :icon i/remove}]])]) (when (or (= :multiple exports) (seq exports)) - [:> button* {:variant "secondary" - :class (stl/css :export-btn) - :on-click (when-not in-progress? on-download) - :disabled in-progress?} + [:button + {:on-click (when-not in-progress? on-download) + :class (stl/css-case + :export-btn true + :btn-disabled in-progress?) + :disabled in-progress?} (if in-progress? (tr "workspace.options.exporting-object") (tr "workspace.options.export-object" (c (count shapes-with-exports))))])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss index a9a4963921..487e4805bc 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss @@ -27,7 +27,7 @@ .multiple-exports { @include deprecated.flexRow; - grid-column: 1 / span 8; + grid-column: 1 / span 9; .label { @extend .mixed-bar; } @@ -76,6 +76,8 @@ } .export-btn { - grid-column: 1 / span 8; - justify-content: center; + @extend .button-secondary; + @include deprecated.uppercaseTitleTipography; + grid-column: 1 / span 9; + height: deprecated.$s-32; } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs index 190c53645f..ba6ea893f2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs @@ -17,9 +17,9 @@ [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.checkbox :refer [checkbox*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.hooks :as h] + [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -252,9 +252,16 @@ (when (or (= type :frame) (and (= type :multiple) (some? hide-on-export))) - [:> checkbox* {:ref checkbox-ref - :id "show-fill-on-export" - :class (stl/css :fill-checkbox) - :label (tr "workspace.options.show-fill-on-export") - :checked (not hide-on-export) - :on-change on-change-show-on-export}])])])) + [:div {:class (stl/css :fill-checkbox)} + [:label {:for "show-fill-on-export" + :class (stl/css-case :global/checked (not hide-on-export))} + [:span {:class (stl/css-case :check-mark true + :checked (not hide-on-export))} + (when (not hide-on-export) + deprecated-icon/status-tick)] + (tr "workspace.options.show-fill-on-export") + [:input {:type "checkbox" + :id "show-fill-on-export" + :ref checkbox-ref + :checked (not hide-on-export) + :on-change on-change-show-on-export}]]])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss index 3ca90bb806..28a159b4de 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss @@ -50,5 +50,14 @@ } .fill-checkbox { + // TODO create a checkbox component in the DS + @extend .input-checkbox; padding-inline-start: var(--sp-s); + span.checked { + background-color: var(--color-accent-primary); + svg { + @extend .button-icon-small; + stroke: var(--color-background-primary); + } + } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs index 6cb6665d56..326b5efa4a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs @@ -148,13 +148,10 @@ [:div {:class (stl/css :grid-title)} [:div {:class (stl/css-case :option-row true :hidden is-hidden?)} - [:> icon-button* {:variant "secondary" - :icon i/menu - :class (stl/css :show-options) - :aria-pressed open? - :aria-label (tr "labels.options") - :on-click toggle-advanced-options - :disabled is-hidden?}] + [:button {:class (stl/css-case :show-options true + :selected open?) + :on-click toggle-advanced-options} + deprecated-icon/menu] [:div {:class (stl/css :type-select-wrapper)} [:& select {:class (stl/css :grid-type-select) @@ -207,11 +204,10 @@ :origin :guides :on-change handle-change-color :on-detach handle-detach-color}] - [:> icon-button* {:variant "ghost" - :icon i/menu - :aria-pressed show-more-options? - :aria-label (tr "labels.options") - :on-click toggle-more-options}]] + [:button {:class (stl/css-case :show-more-options true + :selected show-more-options?) + :on-click toggle-more-options} + deprecated-icon/menu]] (when show-more-options? [:div {:class (stl/css :second-row)} [:button {:class (stl/css-case :btn-options true @@ -288,12 +284,11 @@ :className (stl/css :numeric-input) :value (or (:margin params) 0)}]] - [:> icon-button* {:variant "ghost" - :icon i/menu - :aria-pressed show-more-options? - :aria-label (tr "labels.options") - :on-click toggle-more-options - :disabled is-default}] + [:button {:class (stl/css-case :show-more-options true + :selected show-more-options?) + :on-click toggle-more-options + :disabled is-default} + deprecated-icon/menu] (when show-more-options? [:div {:class (stl/css :more-options)} [:button {:class (stl/css :option-btn) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss index f6ab50dba3..51b82c5434 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss @@ -38,7 +38,18 @@ border-radius: deprecated.$br-8; background-color: var(--input-details-color); .show-options { + @extend .button-secondary; + height: deprecated.$s-32; + width: deprecated.$s-28; border-radius: deprecated.$br-8 0 0 deprecated.$br-8; + box-sizing: border-box; + border: deprecated.$s-1 solid var(--input-border-color); + svg { + @extend .button-icon; + } + &.selected { + @extend .button-icon-selected; + } } .type-select-wrapper { flex-grow: 1; @@ -97,6 +108,7 @@ &.hidden { .show-options { + @include deprecated.hiddenElement; border: deprecated.$s-1 solid var(--input-border-color-disabled); } .type-select-wrapper, @@ -164,7 +176,17 @@ .color-wrapper { width: deprecated.$s-156; } - + .show-more-options { + @extend .button-tertiary; + height: deprecated.$s-32; + width: deprecated.$s-32; + svg { + @extend .button-icon; + } + &.selected { + @extend .button-icon-selected; + } + } .height { @extend .input-element; @include deprecated.bodySmallTypography; diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs index 5e9295fe75..8308bae61e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs @@ -16,9 +16,8 @@ [app.main.data.workspace.shape-layout :as dwsl] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.title-bar :refer [title-bar*]] - [app.main.ui.ds.buttons.button :refer [button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.hooks :as hooks] [app.main.ui.icons :as deprecated-icon] @@ -36,10 +35,10 @@ :justify-self :area-name]) -(mf/defc set-self-alignment* - [{:keys [is-col alignment set-alignment]}] +(mf/defc set-self-alignment + [{:keys [is-col? alignment set-alignment] :as props}] (let [alignment (or alignment :auto) - type (if is-col "col" "row") + type (if is-col? "col" "row") handle-set-alignment (mf/use-callback @@ -47,35 +46,39 @@ (fn [value] (set-alignment (-> value keyword))))] - [:> radio-buttons* {:class (stl/css :self-align-menu) - :selected (d/name alignment) - :name (dm/str "flex-align-items-" type) - :allow-empty true + [:div {:class (stl/css :self-align-menu)} + [:& radio-buttons {:selected (d/name alignment) :on-change handle-set-alignment - :options [{:id (dm/str "align-self-start-" type) - :icon (if is-col - i/align-self-row-left - i/align-self-column-top) - :label "Align self start" - :value "start"} - {:id (dm/str "align-self-center-" type) - :icon (if is-col - i/align-self-row-center - i/align-self-column-center) - :label "Align self center" - :value "center"} - {:id (dm/str "align-self-end-" type) - :icon (if is-col - i/align-self-row-right - i/align-self-column-bottom) - :label "Align self end" - :value "end"} - {:id (dm/str "align-self-stretch-" type) - :icon (if is-col - i/align-self-row-stretch - i/align-self-column-stretch) - :label "Align self stretch" - :value "stretch"}]}])) + :allow-empty true + :name (dm/str "flex-align-items-" type)} + [:& radio-button {:value "start" + :icon (if is-col? + i/align-self-row-left + i/align-self-column-top) + :title "Align self start" + :id (dm/str "align-self-start-" type)}] + + [:& radio-button {:value "center" + :icon (if is-col? + i/align-self-row-center + i/align-self-column-center) + :title "Align self center" + :id (dm/str "align-self-center-" type)}] + + [:& radio-button {:value "end" + :icon (if is-col? + i/align-self-row-right + i/align-self-column-bottom) + :title "Align self end" + :id (dm/str "align-self-end-" type)}] + + [:& radio-button {:value "stretch" + :icon (if is-col? + i/align-self-row-stretch + i/align-self-column-stretch) + :title "Align self stretch" + :id (dm/str "align-self-stretch-" type)}]]])) + (mf/defc options {::mf/wrap [mf/memo]} @@ -179,19 +182,16 @@ (when open? [:div {:class (stl/css :grid-cell-menu-container)} - [:> radio-buttons* {:selected (d/name cell-mode) - :name "cell-mode" + [:div {:class (stl/css :cell-mode :row)} + [:& radio-buttons {:selected (d/name cell-mode) :on-change set-cell-mode - :options [{:id "auto" - :label "Auto" - :value "auto"} - {:id "manual" - :label "Manual" - :value "manual"} - {:id "area" - :label "Area" - :value "area" - :disabled (not valid-area-cells?)}]}] + :name "cell-mode" + :wide true} + [:& radio-button {:value "auto" :id :auto}] + [:& radio-button {:value "manual" :id :manual}] + [:& radio-button {:value "area" + :id :area + :disabled (not valid-area-cells?)}]]] (when (= :area cell-mode) [:div {:class (stl/css :row)} @@ -261,15 +261,16 @@ :value row-end}]]]]) [:div {:class (stl/css :row)} - [:> set-self-alignment* {:is-col false - :alignment align-self - :set-alignment set-alignment}] - [:> set-self-alignment* {:is-col true - :alignment justify-self - :set-alignment set-justify-self}]] + [:& set-self-alignment {:is-col? false + :alignment align-self + :set-alignment set-alignment}] + [:& set-self-alignment {:is-col? true + :alignment justify-self + :set-alignment set-justify-self}]] [:div {:class (stl/css :row)} - [:> button* {:variant "secondary" - :class (stl/css :edit-grid-btn) - :on-click toggle-edit-mode} + [:button + {:class (stl/css :edit-grid-btn) + :alt (tr "workspace.layout-grid.editor.options.edit-grid") + :on-click toggle-edit-mode} (tr "workspace.layout-grid.editor.options.edit-grid")]]])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss index a9c9814683..5b61b4dabf 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss @@ -30,6 +30,17 @@ @include deprecated.flexRow; } +.cell-mode :global(label) { + padding: 0 deprecated.$s-12; +} + +.edit-grid-btn { + @extend .button-secondary; + @include deprecated.uppercaseTitleTipography; + width: 100%; + padding: deprecated.$s-8; +} + .area-input { @extend .input-element; @include deprecated.bodySmallTypography; @@ -55,7 +66,3 @@ border-radius: 0 deprecated.$br-8 deprecated.$br-8 0; border-left: deprecated.$s-1 solid var(--panel-background-color); } - -.edit-grid-btn { - flex-grow: 1; -} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs index 9c2846a614..ac8fdc23cf 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs @@ -17,13 +17,13 @@ [app.main.data.workspace.interactions :as dwi] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.controls.checkbox :refer [checkbox*]] [app.main.ui.ds.controls.input :refer [input*]] [app.main.ui.ds.controls.numeric-input :refer [numeric-input*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.ds.product.empty-state :refer [empty-state*]] [app.util.dom :as dom] @@ -582,43 +582,41 @@ :options animation-opts :on-change change-animation-type}]]] - ;; Way + ;; Direction (when (ctsi/has-way? interaction) [:div {:class (stl/css :interaction-row)} [:div {:class (stl/css :interaction-row-radio)} - [:> radio-buttons* {:selected (d/name way) - :on-change change-way - :name "animation-way" - :options [{:id "animation-way-in" - :label (tr "workspace.options.interaction-animation-direction-in") - :value "in"} - {:id "animation-way-out" - :label (tr "workspace.options.interaction-animation-direction-out") - :value "out"}]}]]]) + [:& radio-buttons {:selected (d/name way) + :on-change change-way + :name "animation-way"} + [:& radio-button {:value "in" + :id "animation-way-in"}] + [:& radio-button {:id "animation-way-out" + :value "out"}]]]]) ;; Direction (when (ctsi/has-direction? interaction) [:div {:class (stl/css :interaction-row)} [:div {:class (stl/css :interaction-row-radio)} - [:> radio-buttons* {:selected (d/name direction) - :on-change change-direction - :name "animation-direction" - :options [{:id "animation-right" - :icon i/row - :label (tr "workspace.options.interaction-animation-direction-right") - :value "right"} - {:id "animation-left" - :icon i/row-reverse - :label (tr "workspace.options.interaction-animation-direction-left") - :value "left"} - {:id "animation-down" - :icon i/column - :label (tr "workspace.options.interaction-animation-direction-down") - :value "down"} - {:id "animation-up" - :icon i/column-reverse - :label (tr "workspace.options.interaction-animation-direction-up") - :value "up"}]}]]]) + [:& radio-buttons {:selected (d/name direction) + :on-change change-direction + :name "animation-direction"} + [:& radio-button {:icon i/row + :icon-class (stl/css :right) + :value "right" + :id "animation-right"}] + [:& radio-button {:icon i/row-reverse + :icon-class (stl/css :left) + :id "animation-left" + :value "left"}] + [:& radio-button {:icon i/column + :icon-class (stl/css :down) + :id "animation-down" + :value "down"}] + [:& radio-button {:icon i/column-reverse + :icon-class (stl/css :up) + :id "animation-up" + :value "up"}]]]]) ;; Duration (when (ctsi/has-duration? interaction) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 655c00867d..e07c3cd958 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -22,11 +22,10 @@ [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.numeric-input :as deprecated-input] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar*]] - [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.formats :as fmt] [app.main.ui.hooks :as h] @@ -163,118 +162,128 @@ :space-between i/align-content-row-between :stretch i/align-content-row-stretch)))) -(mf/defc direction-row-flex* - {::mf/private true} +(mf/defc direction-row-flex + {::mf/props :obj + ::mf/private true} [{:keys [value on-change]}] - [:> radio-buttons* {:class (stl/css :direction-row-flex) - :selected (d/name value) - :on-change on-change - :name "flex-direction" - :options [{:id "flex-direction-row" - :icon (dir-icons-refactor :row) - :label "Row" - :value "row"} - {:id "flex-direction-row-reverse" - :icon (dir-icons-refactor :row-reverse) - :label "Row reverse" - :value "row-reverse"} - {:id "flex-direction-column" - :icon (dir-icons-refactor :column) - :label "Column" - :value "column"} - {:id "flex-direction-column-reverse" - :icon (dir-icons-refactor :column-reverse) - :label "Column reverse" - :value "column-reverse"}]}]) + [:& radio-buttons {:class (stl/css :direction-row-flex) + :selected (d/name value) + :decode-fn keyword + :on-change on-change + :name "flex-direction"} + [:& radio-button {:value "row" + :id "flex-direction-row" + :title "Row" + :icon (dir-icons-refactor :row)}] + [:& radio-button {:value "row-reverse" + :id "flex-direction-row-reverse" + :title "Row reverse" + :icon (dir-icons-refactor :row-reverse)}] + [:& radio-button {:value "column" + :id "flex-direction-column" + :title "Column" + :icon (dir-icons-refactor :column)}] + [:& radio-button {:value "column-reverse" + :id "flex-direction-column-reverse" + :title "Column reverse" + :icon (dir-icons-refactor :column-reverse)}]]) -(mf/defc wrap-row* +(mf/defc wrap-row + {::mf/props :obj} [{:keys [wrap-type on-click]}] - [:> icon-button* {:variant "ghost" - :aria-label (if (= :wrap wrap-type) "No wrap" "Wrap") - :aria-pressed (= wrap-type :wrap) - :on-click on-click - :icon i/wrap}]) + [:button {:class (stl/css-case :wrap-button true + :selected (= wrap-type :wrap)) + :title (if (= :wrap wrap-type) + "No wrap" + "Wrap") + :on-click on-click} + deprecated-icon/wrap]) -(mf/defc align-row* +(mf/defc align-row + {::mf/props :obj} [{:keys [is-column value on-change]}] - [:> radio-buttons* {:class (stl/css :align-row) - :selected (d/name value) - :on-change on-change - :name "flex-align-items" - :options [{:id "align-items-start" - :icon (get-layout-flex-icon :align-items :start is-column) - :label "Align items start" - :value "start"} - {:id "align-items-center" - :icon (get-layout-flex-icon :align-items :center is-column) - :label "Align items center" - :value "center"} - {:id "align-items-end" - :icon (get-layout-flex-icon :align-items :end is-column) - :label "Align items end" - :value "end"}]}]) + [:& radio-buttons {:class (stl/css :align-row) + :selected (d/name value) + :decode-fn keyword + :on-change on-change + :name "flex-align-items"} + [:& radio-button {:value "start" + :icon (get-layout-flex-icon :align-items :start is-column) + :title "Align items start" + :id "align-items-start"}] + [:& radio-button {:value "center" + :icon (get-layout-flex-icon :align-items :center is-column) + :title "Align items center" + :id "align-items-center"}] + [:& radio-button {:value "end" + :icon (get-layout-flex-icon :align-items :end is-column) + :title "Align items end" + :id "align-items-end"}]]) -(mf/defc align-content-row* +(mf/defc align-content-row + {::mf/props :obj} [{:keys [is-column value on-change]}] - [:> radio-buttons* {:class (stl/css :align-content-row) - :selected (d/name value) - :on-change on-change - :name "flex-align-content" - :options [{:id "align-content-start" - :icon (get-layout-flex-icon :align-content :start is-column) - :label "Align content start" - :value "start"} - {:id "align-content-center" - :icon (get-layout-flex-icon :align-content :center is-column) - :label "Align content center" - :value "center"} - {:id "align-content-end" - :icon (get-layout-flex-icon :align-content :end is-column) - :label "Align content end" - :value "end"} - {:id "align-content-space-between" - :icon (get-layout-flex-icon :align-content :space-between is-column) - :label "Align content space-between" - :value "space-between"} - {:id "align-content-space-around" - :icon (get-layout-flex-icon :align-content :space-around is-column) - :label "Align content space-around" - :value "space-around"} - {:id "align-content-space-evenly" - :icon (get-layout-flex-icon :align-content :space-evenly is-column) - :label "Align content space-evenly" - :value "space-evenly"}]}]) + [:& radio-buttons {:class (stl/css :align-content-row) + :selected (d/name value) + :decode-fn keyword + :on-change on-change + :name "flex-align-content"} + [:& radio-button {:value "start" + :icon (get-layout-flex-icon :align-content :start is-column) + :title "Align content start" + :id "align-content-start"}] + [:& radio-button {:value "center" + :icon (get-layout-flex-icon :align-content :center is-column) + :title "Align content center" + :id "align-content-center"}] + [:& radio-button {:value "end" + :icon (get-layout-flex-icon :align-content :end is-column) + :title "Align content end" + :id "align-content-end"}] + [:& radio-button {:value "space-between" + :icon (get-layout-flex-icon :align-content :space-between is-column) + :title "Align content space-between" + :id "align-content-space-between"}] + [:& radio-button {:value "space-around" + :icon (get-layout-flex-icon :align-content :space-around is-column) + :title "Align content space-around" + :id "align-content-space-around"}] + [:& radio-button {:value "space-evenly" + :icon (get-layout-flex-icon :align-content :space-evenly is-column) + :title "Align content space-evenly" + :id "align-content-space-evenly"}]]) -(mf/defc justify-content-row* +(mf/defc justify-content-row + {::mf/props :obj} [{:keys [is-column justify-content on-change]}] - [:> radio-buttons* {:class (stl/css :justify-content-row) - :selected (d/name justify-content) - :on-change on-change - :name "flex-justify" - :options [{:id "justify-content-start" - :icon (get-layout-flex-icon :justify-content :start is-column) - :label "Justify content start" - :value "start"} - {:id "justify-content-center" - :icon (get-layout-flex-icon :justify-content :center is-column) - :label "Justify content center" - :value "center"} - {:id "justify-content-end" - :icon (get-layout-flex-icon :justify-content :end is-column) - :label "Justify content end" - :value "end"} - {:id "justify-content-space-between" - :icon (get-layout-flex-icon :justify-content :space-between is-column) - :label "Justify content space-between" - :value "space-between"} - {:id "justify-content-space-around" - :icon (get-layout-flex-icon :justify-content :space-around is-column) - :label "Justify content space-around" - :value "space-around"} - {:id "justify-content-space-evenly" - :icon (get-layout-flex-icon :justify-content :space-evenly is-column) - :label "Justify content space-evenly" - :value "space-evenly"}]}]) + [:& radio-buttons {:class (stl/css :justify-content-row) + :selected (d/name justify-content) + :on-change on-change + :name "flex-justify"} + [:& radio-button {:value "start" + :icon (get-layout-flex-icon :justify-content :start is-column) + :title "Justify content start" + :id "justify-content-start"}] + [:& radio-button {:value "center" + :icon (get-layout-flex-icon :justify-content :center is-column) + :title "Justify content center" + :id "justify-content-center"}] + [:& radio-button {:value "end" + :icon (get-layout-flex-icon :justify-content :end is-column) + :title "Justify content end" + :id "justify-content-end"}] + [:& radio-button {:value "space-between" + :icon (get-layout-flex-icon :justify-content :space-between is-column) + :title "Justify content space-between" + :id "justify-content-space-between"}] + [:& radio-button {:value "space-around" + :icon (get-layout-flex-icon :justify-content :space-around is-column) + :title "Justify content space-around" + :id "justify-content-space-around"}] + [:& radio-button {:value "space-evenly" + :icon (get-layout-flex-icon :justify-content :space-evenly is-column) + :title "Justify content space-evenly" + :id "justify-content-space-evenly"}]]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; PADDING @@ -665,12 +674,14 @@ (= type :multiple) [:> multiple-padding-selection* props])] - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.layout-grid.editor.padding.expand") - :aria-pressed (= type :multiple) - :data-type (d/name type) - :on-click on-type-change' - :icon i/padding-extended}]])) + [:button {:class (stl/css-case + :padding-toggle true + :selected (= type :multiple)) + :title (tr "workspace.layout-grid.editor.padding.expand") + :aria-label (tr "workspace.layout-grid.editor.padding.expand") + :data-type (d/name type) + :on-click on-type-change'} + deprecated-icon/padding-extended]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; GAP @@ -825,22 +836,25 @@ ;; GRID COMPONENTS -(mf/defc direction-row-grid* +(mf/defc direction-row-grid + {::mf/props :obj} [{:keys [value on-change] :as props}] - [:> radio-buttons* {:class (stl/css :direction-row-grid) - :selected (d/name value) - :on-change on-change - :name "grid-direction" - :options [{:id "grid-direction-row" - :icon (dir-icons-refactor :row) - :label "Row" - :value "row"} - {:id "grid-direction-column" - :icon (dir-icons-refactor :column) - :label "Column" - :value "column"}]}]) + [:& radio-buttons {:class (stl/css :direction-row-grid) + :selected (d/name value) + :decode-fn keyword + :on-change on-change + :name "grid-direction"} + [:& radio-button {:value "row" + :id "grid-direction-row" + :title "Row" + :icon (dir-icons-refactor :row)}] + [:& radio-button {:value "column" + :id "grid-direction-column" + :title "Column" + :icon (dir-icons-refactor :column)}]]) -(mf/defc grid-edit-mode* +(mf/defc grid-edit-mode + {::mf/props :obj} [{:keys [id]}] (let [edition (mf/deref refs/selected-edition) active? (= id edition) @@ -852,65 +866,81 @@ (if-not active? (st/emit! (udw/start-edition-mode id)) (st/emit! :interrupt))))] - - [:> button* {:variant "secondary" - :class (stl/css :edit-mode-btn) - :on-click toggle-edit-mode} + [:button + {:class (stl/css :edit-mode-btn) + :alt "Grid edit mode" + :on-click toggle-edit-mode} (tr "workspace.layout-grid.editor.options.edit-grid")])) -(mf/defc align-grid-row* - {::mf/private true} +(mf/defc align-grid-row + {::mf/props :obj + ::mf/private true} [{:keys [is-column value on-change]}] (let [type (if ^boolean is-column "column" "row")] - [:> radio-buttons* {:class (stl/css :align-grid-row) - :selected (d/name value) - :on-change on-change - :name (dm/str "flex-align-items-" type) - :options [{:id (dm/str "align-items-start-" type) - :icon (get-layout-grid-icon :align-items :start is-column) - :label "Align items start" - :value "start"} - {:id (dm/str "align-items-center-" type) - :icon (get-layout-grid-icon :align-items :center is-column) - :label "Align items center" - :value "center"} - {:id (dm/str "align-items-end-" type) - :icon (get-layout-grid-icon :align-items :end is-column) - :label "Align items end" - :value "end"}]}])) + [:& radio-buttons {:class (stl/css :align-grid-row) + :selected (d/name value) + :decode-fn keyword + :on-change on-change + :name (dm/str "flex-align-items-" type)} + [:& radio-button {:value "start" + :icon (get-layout-grid-icon :align-items :start is-column) + :title "Align items start" + :id (dm/str "align-items-start-" type)}] + [:& radio-button {:value "center" + :icon (get-layout-grid-icon :align-items :center is-column) + :title "Align items center" + :id (dm/str "align-items-center-" type)}] + [:& radio-button {:value "end" + :icon (get-layout-grid-icon :align-items :end is-column) + :title "Align items end" + :id (dm/str "align-items-end-" type)}]])) -(mf/defc justify-grid-row* - {::mf/private true} +(mf/defc justify-grid-row + {::mf/props :obj + ::mf/private :obj} [{:keys [is-column value on-change]}] (let [type (if ^boolean is-column "column" "row")] - [:> radio-buttons* {:class (stl/css :justify-grid-row) - :selected (d/name value) - :on-change on-change - :name (dm/str "grid-justify-items-" type) - :options [{:id (dm/str "justify-items-start-" type) - :icon (get-layout-grid-icon :justify-items :start is-column) - :label "Justify items start" - :value "start"} - {:id (dm/str "justify-items-center-" type) - :icon (get-layout-grid-icon :justify-items :center is-column) - :label "Justify items center" - :value "center"} - {:id (dm/str "justify-items-end-" type) - :icon (get-layout-grid-icon :justify-items :end is-column) - :label "Justify items end" - :value "end"} - {:id (dm/str "justify-items-space-around-" type) - :icon (get-layout-grid-icon :justify-items :space-around is-column) - :label "Justify items space-around" - :value "space-around"} - {:id (dm/str "justify-items-space-between-" type) - :icon (get-layout-grid-icon :justify-items :space-between is-column) - :label "Justify items space-between" - :value "space-between"} - {:id (dm/str "justify-items-stretch-" type) - :icon (get-layout-grid-icon :justify-items :stretch is-column) - :label "Justify items stretch" - :value "stretch"}]}])) + [:& radio-buttons {:class (stl/css :justify-grid-row) + :selected (d/name value) + :on-change on-change + :decode-fn keyword + :name (dm/str "grid-justify-items-" type)} + + [:& radio-button {:key "justify-item-start" + :value "start" + :icon (get-layout-grid-icon :justify-items :start is-column) + :title "Justify items start" + :id (dm/str "justify-items-start-" type)}] + + [:& radio-button {:key "justify-item-center" + :value "center" + :icon (get-layout-grid-icon :justify-items :center is-column) + :title "Justify items center" + :id (dm/str "justify-items-center-" type)}] + + [:& radio-button {:key "justify-item-end" + :value "end" + :icon (get-layout-grid-icon :justify-items :end is-column) + :title "Justify items end" + :id (dm/str "justify-items-end-" type)}] + + [:& radio-button {:key "justify-item-space-around" + :value "space-around" + :icon (get-layout-grid-icon :justify-items :space-around is-column) + :title "Justify items space-around" + :id (dm/str "justify-items-space-around-" type)}] + + [:& radio-button {:key "justify-item-space-between" + :value "space-between" + :icon (get-layout-grid-icon :justify-items :space-between is-column) + :title "Justify items space-between" + :id (dm/str "justify-items-space-between-" type)}] + + [:& radio-button {:key "justify-item-stretch" + :value "stretch" + :icon (get-layout-grid-icon :justify-items :stretch is-column) + :title "Justify items stretch" + :id (dm/str "justify-items-stretch-" type)}]])) (defn- manage-values [{:keys [type value]}] @@ -921,7 +951,8 @@ :fixed (fmt/format-pixels value) value)) -(mf/defc grid-track-info* +(mf/defc grid-track-info + {::mf/props :obj} [{:keys [is-column type index @@ -1004,7 +1035,8 @@ :data-index index :icon i/remove}]])) -(mf/defc grid-columns-row* +(mf/defc grid-columns-row + {::mf/props :obj} [{:keys [is-column expanded? column-values toggle add-new-element set-column-value set-column-type remove-element reorder-track hover-track on-select-track]}] (let [column-num (count column-values) @@ -1025,38 +1057,27 @@ [:div {:class (stl/css :grid-tracks) :data-testid testid} [:div {:class (stl/css :grid-track-header)} - [:> icon-button* {:variant "secondary" - :class (stl/css :expand-icon) - :aria-pressed expanded? - :aria-label (tr "labels.options") - :on-click toggle - :icon i/menu}] - #_[:button {:class (stl/css :expand-icon) :on-click toggle} deprecated-icon/menu] + [:button {:class (stl/css :expand-icon) :on-click toggle} deprecated-icon/menu] [:div {:class (stl/css :track-title) :on-click toggle} [:div {:class (stl/css :track-name) :title track-name} track-name] [:div {:class (stl/css :track-detail) :title track-detail} track-detail]] - [:> icon-button* {:variant "secondary" - :class (stl/css :add-column) - :aria-label (tr "labels.add") - :on-click add-track - :icon i/add}] - #_[:button {:class (stl/css :add-column) :on-click add-track} deprecated-icon/add]] + [:button {:class (stl/css :add-column) :on-click add-track} deprecated-icon/add]] (when expanded? [:> h/sortable-container* {} [:div {:class (stl/css :grid-tracks-info-container)} (for [[index column] (d/enumerate column-values)] - [:> grid-track-info* {:key (dm/str index "-" (d/name type)) - :type type - :is-column is-column - :index index - :column column - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track - :on-select-track on-select-track}])]])])) + [:& grid-track-info {:key (dm/str index "-" (d/name type)) + :type type + :is-column is-column + :index index + :column column + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track + :on-select-track on-select-track}])]])])) ;; LAYOUT COMPONENT @@ -1192,8 +1213,8 @@ (mf/deps layout-type ids) (fn [dir] (if (= :flex layout-type) - (st/emit! (dwsl/update-layout ids {:layout-flex-dir (keyword dir)})) - (st/emit! (dwsl/update-layout ids {:layout-grid-dir (keyword dir)}))))) + (st/emit! (dwsl/update-layout ids {:layout-flex-dir dir})) + (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir}))))) ;; Align grid align-items-row (:layout-align-items values) @@ -1203,13 +1224,13 @@ (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout ids {:layout-justify-items (keyword value)})))) + (st/emit! (dwsl/update-layout ids {:layout-justify-items value})))) on-row-align-change (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout ids {:layout-align-items (keyword value)})))) + (st/emit! (dwsl/update-layout ids {:layout-align-items value})))) ;; Justify grid grid-justify-content-row (:layout-justify-content values) @@ -1219,13 +1240,13 @@ (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout ids {:layout-align-content (keyword value)})))) + (st/emit! (dwsl/update-layout ids {:layout-align-content value})))) on-row-justify-change (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout ids {:layout-justify-content (keyword value)})))) + (st/emit! (dwsl/update-layout ids {:layout-justify-content value})))) on-toggle-dropdown-visibility (mf/use-fn #(swap! show-dropdown* not)) @@ -1298,31 +1319,31 @@ :flex [:div {:class (stl/css :flex-layout-menu)} [:div {:class (stl/css :first-row)} - [:> align-row* {:is-column is-column - :value align-items - :on-change set-align-items}] + [:& align-row {:is-column is-column + :value align-items + :on-change set-align-items}] - [:> direction-row-flex* {:on-change on-direction-change - :value saved-dir}] + [:& direction-row-flex {:on-change on-direction-change + :value saved-dir}] - [:> wrap-row* {:wrap-type wrap-type - :on-click toggle-wrap}]] + [:& wrap-row {:wrap-type wrap-type + :on-click toggle-wrap}]] - [:div {:class (stl/css :middle-row)} - [:div {:class (stl/css :help-button-wrapper)} - [:> justify-content-row* {:is-column is-column - :justify-content justify-content - :on-change set-justify-content}] - [:> icon-button* {:variant "ghost" - :aria-label (tr "labels.help-center") - :on-click open-flex-help - :icon i/help}]] - (when (= :wrap wrap-type) - [:> align-content-row* {:is-column is-column - :value align-content - :on-change on-align-content-change}])] + [:div {:class (stl/css :second-row :help-button-wrapper)} + [:& justify-content-row {:is-column is-column + :justify-content justify-content + :on-change set-justify-content}] - [:div {:class (stl/css :last-row)} + [:> icon-button* {:variant "ghost" + :aria-label (tr "labels.help-center") + :on-click open-flex-help + :icon i/help}]] + (when (= :wrap wrap-type) + [:div {:class (stl/css :third-row)} + [:& align-content-row {:is-column is-column + :value align-content + :on-change on-align-content-change}]]) + [:div {:class (stl/css :forth-row)} [:> gap-section* {:is-column is-column :wrap-type wrap-type :on-change on-gap-change @@ -1340,7 +1361,7 @@ [:div {:class (stl/css :grid-layout-menu)} (when (= 1 (count ids)) [:div {:class (stl/css :edit-grid-wrapper)} - [:> grid-edit-mode* {:id (first ids)}] + [:& grid-edit-mode {:id (first ids)}] [:> icon-button* {:variant "ghost" :aria-label (tr "labels.help-center") :on-click open-grid-help @@ -1349,23 +1370,23 @@ [:div {:class (stl/css :first-row)} [:div {:class (stl/css :direction-edit)} [:div {:class (stl/css :direction)} - [:> direction-row-grid* {:value saved-grid-dir - :on-change on-direction-change}]]] + [:& direction-row-grid {:value saved-grid-dir + :on-change on-direction-change}]]] - [:> align-grid-row* {:is-column false - :value align-items-row - :on-change on-row-align-change}] - [:> align-grid-row* {:is-column true - :value align-items-column - :on-change on-column-align-change}]] + [:& align-grid-row {:is-column false + :value align-items-row + :on-change on-row-align-change}] + [:& align-grid-row {:is-column true + :value align-items-column + :on-change on-column-align-change}]] [:div {:class (stl/css :row :grid-layout-align)} - [:> justify-grid-row* {:is-column true - :value grid-justify-content-column - :on-change on-column-justify-change}] - [:> justify-grid-row* {:is-column false - :value grid-justify-content-row - :on-change on-row-justify-change}]] + [:& justify-grid-row {:is-column true + :value grid-justify-content-column + :on-change on-column-justify-change}] + [:& justify-grid-row {:is-column false + :value grid-justify-content-row + :on-change on-row-justify-change}]] [:div {:class (stl/css :gap-row)} [:> gap-section* {:on-change on-gap-change @@ -1391,7 +1412,7 @@ (mf/use-fn (mf/deps ids) (fn [dir] - (st/emit! (dwsl/update-layout ids {:layout-grid-dir (keyword dir)})))) + (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir})))) on-gap-change (mf/use-fn @@ -1430,13 +1451,13 @@ (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout ids {:layout-justify-items (keyword value)})))) + (st/emit! (dwsl/update-layout ids {:layout-justify-items value})))) on-row-align-change (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout ids {:layout-align-items (keyword value)})))) + (st/emit! (dwsl/update-layout ids {:layout-align-items value})))) ;; Justify grid grid-justify-content-row (:layout-justify-content values) @@ -1446,13 +1467,13 @@ (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout ids {:layout-align-content (keyword value)})))) + (st/emit! (dwsl/update-layout ids {:layout-align-content value})))) on-row-justify-change (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout ids {:layout-justify-content (keyword value)})))) + (st/emit! (dwsl/update-layout ids {:layout-justify-content value})))) columns-open? (mf/use-state false) rows-open? (mf/use-state false) @@ -1533,32 +1554,31 @@ :aria-label (tr "labels.help-center") :on-click open-grid-help :icon i/help}] - [:> button* {:variant "secondary" - :class (stl/css :exit-btn) - :on-click #(st/emit! (udw/clear-edition-mode))} + [:button {:class (stl/css :exit-btn) + :on-click #(st/emit! (udw/clear-edition-mode))} (tr "workspace.layout-grid.editor.options.exit")]] [:div {:class (stl/css :row :first-row)} [:div {:class (stl/css :direction-edit)} [:div {:class (stl/css :direction)} - [:> direction-row-grid* {:value saved-grid-dir - :on-change on-direction-change}]]] + [:& direction-row-grid {:value saved-grid-dir + :on-change on-direction-change}]]] - [:> align-grid-row* {:is-column false - :value align-items-row - :on-change on-row-align-change}] + [:& align-grid-row {:is-column false + :value align-items-row + :on-change on-row-align-change}] - [:> align-grid-row* {:is-column true - :value align-items-column - :on-change on-column-align-change}]] + [:& align-grid-row {:is-column true + :value align-items-column + :on-change on-column-align-change}]] [:div {:class (stl/css :row :grid-layout-align)} - [:> justify-grid-row* {:is-column true - :value grid-justify-content-column - :on-change on-column-justify-change}] - [:> justify-grid-row* {:is-column false - :value grid-justify-content-row - :on-change on-row-justify-change}] + [:& justify-grid-row {:is-column true + :value grid-justify-content-column + :on-change on-column-justify-change}] + [:& justify-grid-row {:is-column false + :value grid-justify-content-row + :on-change on-row-justify-change}] [:> icon-button* {:variant "ghost" :class (stl/css :locate-button) @@ -1572,33 +1592,33 @@ :applied-tokens applied-tokens :value (:layout-gap values)}]] - [:div {:class (stl/css :padding-row)} + [:div {:class (stl/css :padding-row :padding-section)} [:> padding-section* {:value (:layout-padding values) :type (:layout-padding-type values) :on-type-change on-padding-type-change :on-change on-padding-change}]] [:div {:class (stl/css :grid-tracks-row)} - [:> grid-columns-row* {:is-column true - :expanded? @columns-open? - :toggle toggle-columns-open - :column-values column-values - :add-new-element add-new-element - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track - :on-select-track handle-select-track}] + [:& grid-columns-row {:is-column true + :expanded? @columns-open? + :toggle toggle-columns-open + :column-values column-values + :add-new-element add-new-element + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track + :on-select-track handle-select-track}] - [:> grid-columns-row* {:is-column false - :expanded? @rows-open? - :toggle toggle-rows-open - :column-values rows-values - :add-new-element add-new-element - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track - :on-select-track handle-select-track}]]])) + [:& grid-columns-row {:is-column false + :expanded? @rows-open? + :toggle toggle-rows-open + :column-values rows-values + :add-new-element add-new-element + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track + :on-select-track handle-select-track}]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss index c835494e8a..10247a86b1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss @@ -42,7 +42,6 @@ .flex-layout-menu { @include sidebar.option-grid-structure; - row-gap: var(--sp-s); margin-block-end: var(--sp-s); } @@ -50,6 +49,8 @@ grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; + margin-block-end: var(--sp-m); + margin-block-start: var(--sp-xs); } .align-row { @@ -60,11 +61,27 @@ grid-column: span 4; } -.middle-row { - grid-column: span 8; - display: flex; - flex-direction: column; - row-gap: var(--sp-xs); +// TODO: Replace this buttons with DS buttons +.wrap-button { + @extend .button-tertiary; + border-radius: $br-8; + block-size: $sz-32; + inline-size: $sz-32; + svg { + @extend .button-icon; + stroke: var(--color-foreground-secondary); + } + &.selected { + @extend .button-icon-selected; + } +} + +.second-row, +.third-row { + grid-column: 1 / -1; + display: grid; + grid-template-columns: subgrid; + margin-block-end: var(--sp-m); } .align-content-row, @@ -72,7 +89,7 @@ grid-column: span 6; } -.last-row { +.forth-row { display: grid; grid-template-columns: var(--grid-exception-input-width) /* first input block */ @@ -83,7 +100,9 @@ } .help-button-wrapper { + grid-column: 1 / -1; display: flex; + flex-direction: row; justify-content: space-between; } @@ -130,10 +149,23 @@ gap: var(--sp-xs); } +// TODO: Replace this buttons with DS buttons +.padding-toggle { + @extend .button-tertiary; + block-size: $sz-32; + inline-size: $sz-32; + border-radius: $br-8; + svg { + @extend .button-icon; + stroke: var(--color-foreground-secondary); + } + &.selected { + @extend .button-icon-selected; + } +} + .grid-layout-menu { @include sidebar.option-grid-structure; - margin-top: var(--sp-xs); - row-gap: var(--sp-s); } .edit-grid-wrapper, @@ -145,6 +177,7 @@ } .first-row { + margin-block-end: var(--sp-s); display: grid; grid-template-columns: subgrid; } @@ -169,12 +202,20 @@ grid-column: span 5; } +// TODO: Replace this buttons with DS buttons .edit-mode-btn { - justify-content: center; + @extend .button-secondary; + @include t.use-typography("headline-small"); + inline-size: 100%; + padding: var(--sp-s); grid-column: span 7; } +// TODO: Replace this buttons with DS buttons .exit-btn { + @extend .button-secondary; + @include t.use-typography("headline-small"); + padding: var(--sp-s) var(--sp-xl); grid-column: span 2; } @@ -186,11 +227,14 @@ margin-block-start: var(--sp-xs); } +.padding-section { + margin-block-start: var(--sp-s); +} + .grid-tracks-row { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; - row-gap: var(--sp-s); } .edit-grid-wrapper { @@ -249,6 +293,7 @@ display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; + margin-block-start: var(--sp-s); } .grid-track-header { @@ -259,7 +304,7 @@ border-radius: $br-8; overflow: hidden; background: var(--color-background-tertiary); - block-size: $sz-48; + block-size: px2rem(52); grid-column: 1 / -1; } @@ -283,14 +328,44 @@ color: var(--color-foreground-secondary); } +// TODO: Replace this buttons with DS buttons .expand-icon { - block-size: $sz-48; + @extend .button-secondary; + block-size: px2rem(52); + border-radius: $br-8 0 0 $br-8; + border-inline-end: $b-1 solid var(--color-background-primary); + svg { + @extend .button-icon; + stroke: var(--color-foreground-secondary); + fill: var(--color-foreground-secondary); + } + &:hover, + &:active { + svg { + stroke: var(--color-accent-primary); + fill: var(--color-accent-primary); + } + } } +// TODO: Replace this buttons with DS buttons .add-column { - block-size: $sz-48; - border-radius: 0 $br-8 $br-8 0; + @extend .button-tertiary; + block-size: px2rem(52); + + svg { + display: flex; + justify-content: center; + align-items: center; + color: transparent; + fill: none; + stroke-width: px2rem(1); + block-size: $sz-12; + inline-size: $sz-12; + stroke: var(--color-foreground-secondary); + fill: var(--color-foreground-secondary); + } } .layout-options { diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index c7c2bd9193..dd6c661030 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -17,9 +17,8 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.numeric-input :as deprecated-input] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.title-bar :refer [title-bar*]] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]] @@ -417,85 +416,104 @@ (= type :multiple) [:> margin-multiple* props])] - [:> icon-button* {:variant "ghost" - :aria-pressed (= type :multiple) - :aria-label (tr "workspace.layout-grid.editor.margin.expand") - :on-click on-type-change' - :icon i/margin}]])) + [:button {:class (stl/css-case + :margin-mode true + :selected (= type :multiple)) + :title "Margin - multiple" + :on-click on-type-change'} + deprecated-icon/margin]])) -(mf/defc element-behaviour-horizontal* - {::mf/private true} +(mf/defc element-behaviour-horizontal + {::mf/props :obj + ::mf/private true} [{:keys [^boolean is-auto ^boolean has-fill value on-change]}] - [:div {:class (stl/css-case :horizontal-behaviour true - :one-element (and (not has-fill) (not is-auto)) - :two-element (or has-fill is-auto) - :three-element (and has-fill is-auto))} - [:> radio-buttons* {:selected (d/name value) - :on-change on-change - :name "flex-behaviour-h" - :options (remove nil? - [{:id "behaviour-h-fix" - :icon i/fixed-width - :label (tr "workspace.layout-item.fix-width") - :value "fix"} - (when has-fill - {:id "behaviour-h-fill" - :icon i/fill-content - :label (tr "workspace.layout-item.width-100") - :value "fill"}) - (when is-auto - {:id "behaviour-h-auto" - :icon i/hug-content - :label (tr "workspace.layout-item.fit-content-horizontal") - :value "auto"})])}]]) + [:div {:class (stl/css-case + :horizontal-behaviour true + :one-element (and (not has-fill) (not is-auto)) + :two-element (or has-fill is-auto) + :three-element (and has-fill is-auto))} + [:& radio-buttons + {:selected (d/name value) + :decode-fn keyword + :on-change on-change + :name "flex-behaviour-h"} -(mf/defc element-behaviour-vertical* - {::mf/private true} + [:& radio-button + {:value "fix" + :icon i/fixed-width + :title "Fix width" + :id "behaviour-h-fix"}] + + (when has-fill + [:& radio-button + {:value "fill" + :icon i/fill-content + :title "Width 100%" + :id "behaviour-h-fill"}]) + (when is-auto + [:& radio-button + {:value "auto" + :icon i/hug-content + :title "Fit content (Horizontal)" + :id "behaviour-h-auto"}])]]) + +(mf/defc element-behaviour-vertical + {::mf/props :obj + ::mf/private true} [{:keys [^boolean is-auto ^boolean has-fill value on-change]}] - [:div {:class (stl/css-case :vertical-behaviour true - :one-element (and (not has-fill) (not is-auto)) - :two-element (or has-fill is-auto) - :three-element (and has-fill is-auto))} - [:> radio-buttons* {:selected (d/name value) - :on-change on-change - :name "flex-behaviour-v" - :options (remove nil? - [{:id "behaviour-v-fix" - :icon i/fixed-width - :label (tr "workspace.layout-item.fix-height") - :class (stl/css :rotated) - :value "fix"} - (when has-fill - {:id "behaviour-v-fill" - :icon i/fill-content - :label (tr "workspace.layout-item.height-100") - :class (stl/css :rotated) - :value "fill"}) - (when is-auto - {:id "behaviour-v-auto" - :icon i/hug-content - :label (tr "workspace.layout-item.fit-content-vertical") - :class (stl/css :rotated) - :value "auto"})])}]]) + [:div {:class (stl/css-case + :vertical-behaviour true + :one-element (and (not has-fill) (not is-auto)) + :two-element (or has-fill is-auto) + :three-element (and has-fill is-auto))} + [:& radio-buttons + {:selected (d/name value) + :decode-fn keyword + :on-change on-change + :name "flex-behaviour-v"} + [:& radio-button + {:value "fix" + :icon i/fixed-width + :icon-class (stl/css :rotated) + :title "Fix height" + :id "behaviour-v-fix"}] -(mf/defc align-self-row* + (when has-fill + [:& radio-button + {:value "fill" + :icon i/fill-content + :icon-class (stl/css :rotated) + :title "Height 100%" + :id "behaviour-v-fill"}]) + (when is-auto + [:& radio-button + {:value "auto" + :icon i/hug-content + :icon-class (stl/css :rotated) + :title "Fit content (Vertical)" + :id "behaviour-v-auto"}])]]) + +(mf/defc align-self-row + {::mf/props :obj} [{:keys [^boolean is-col value on-change]}] - [:> radio-buttons* {:selected (d/name value) - :name "flex-align-self" - :on-change on-change - :allow-empty true - :options [{:id "align-self-start" - :icon (get-layout-flex-icon :align-self :start is-col) - :label "Align self start" - :value "start"} - {:id "align-self-center" - :icon (get-layout-flex-icon :align-self :center is-col) - :label "Align self center" - :value "center"} - {:id "align-self-end" - :icon (get-layout-flex-icon :align-self :end is-col) - :label "Align self end" - :value "end"}]}]) + [:& radio-buttons {:selected (d/name value) + :decode-fn keyword + :on-change on-change + :name "flex-align-self" + :allow-empty true} + [:& radio-button {:value "start" + :icon (get-layout-flex-icon :align-self :start is-col) + :title "Align self start" + :id "align-self-start"}] + [:& radio-button {:value "center" + :icon (get-layout-flex-icon :align-self :center is-col) + :title "Align self center" + :id "align-self-center"}] + [:& radio-button {:value "end" + :icon (get-layout-flex-icon :align-self :end is-col) + :title "Align self end" + :id "align-self-end"}]]) + (def ^:private schema:layout-item-props-schema [:map @@ -772,10 +790,9 @@ (mf/use-fn (mf/deps ids align-self) (fn [value] - (let [value (keyword value)] - (if (= align-self value) - (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil})) - (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value})))))) + (if (= align-self value) + (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil})) + (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value}))))) ;; Margin on-margin-type-change @@ -803,23 +820,22 @@ (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout-child ids {:layout-item-h-sizing (keyword value)})))) + (st/emit! (dwsl/update-layout-child ids {:layout-item-h-sizing value})))) on-behaviour-v-change (mf/use-fn (mf/deps ids) (fn [value] - (st/emit! (dwsl/update-layout-child ids {:layout-item-v-sizing (keyword value)})))) + (st/emit! (dwsl/update-layout-child ids {:layout-item-v-sizing value})))) ;; Position on-change-position (mf/use-fn (mf/deps ids) (fn [value] - (let [value (keyword value)] - (when (= value :static) - (st/emit! (dwsl/update-layout-child ids {:layout-item-z-index nil}))) - (st/emit! (dwsl/update-layout-child ids {:layout-item-absolute (= value :absolute)}))))) + (when (= value :static) + (st/emit! (dwsl/update-layout-child ids {:layout-item-z-index nil}))) + (st/emit! (dwsl/update-layout-child ids {:layout-item-absolute (= value :absolute)})))) ;; Z Index on-change-z-index @@ -841,17 +857,16 @@ [:div {:class (stl/css :flex-element-menu)} (when (or is-layout-child? is-absolute?) [:div {:class (stl/css :position-row)} - [:> radio-buttons* {:class (stl/css :position-options) - :selected (if is-absolute? "absolute" "static") + [:div {:class (stl/css :position-options)} + [:& radio-buttons {:selected (if is-absolute? "absolute" "static") + :decode-fn keyword :on-change on-change-position :name "layout-style" - :extended true - :options [{:id "static-position" - :label "Static" - :value "static"} - {:id "absolute-position" - :label "Absolute" - :value "absolute"}]}] + :wide true} + [:& radio-button {:value "static" + :id :static-position}] + [:& radio-button {:value "absolute" + :id :absolute-position}]]] [:div {:class (stl/css :z-index-wrapper) :title "z-index"} @@ -870,20 +885,22 @@ :behaviour-menu true :wrap (and ^boolean is-layout-child? ^boolean is-layout-container?))} - [:> element-behaviour-horizontal* {:is-auto is-layout-container? - :has-fill is-layout-child? - :value (:layout-item-h-sizing values) - :on-change on-behaviour-h-change}] - [:> element-behaviour-vertical* {:is-auto is-layout-container? - :has-fill is-layout-child? - :value (:layout-item-v-sizing values) - :on-change on-behaviour-v-change}]]] + [:& element-behaviour-horizontal + {:is-auto is-layout-container? + :has-fill is-layout-child? + :value (:layout-item-h-sizing values) + :on-change on-behaviour-h-change}] + [:& element-behaviour-vertical + {:is-auto is-layout-container? + :has-fill is-layout-child? + :value (:layout-item-v-sizing values) + :on-change on-behaviour-v-change}]]] (when (and is-layout-child? is-flex-parent?) [:div {:class (stl/css :align-row)} - [:> align-self-row* {:is-col is-col? - :value align-self - :on-change on-align-self-change}]]) + [:& align-self-row {:is-col is-col? + :value align-self + :on-change on-align-self-change}]]) (when is-layout-child? [:> margin-section* {:value (:layout-item-margin values) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss index de7d7e542e..d54b68e918 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss @@ -34,8 +34,10 @@ grid-template-columns: auto auto; } -.rotated { - transform: rotate(90deg); +.vertical-behaviour { + .rotated { + transform: rotate(90deg); + } } .z-index-wrapper { @@ -72,6 +74,18 @@ gap: var(--sp-xs); } +.margin-mode { + @extend .button-tertiary; + grid-column: 3; + height: deprecated.$s-32; + svg { + @extend .button-icon; + } + &.selected { + @extend .button-icon-selected; + } +} + .margin-simple { display: grid; gap: var(--sp-xs); diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 85000c49e9..769f7910f1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -25,9 +25,9 @@ [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.numeric-input :as deprecated-input] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] - [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.sidebar.options.menus.border-radius :refer [border-radius-menu*]] [app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]] @@ -209,6 +209,12 @@ proportion-lock (get values :proportion-lock) + clip-content-ref + (mf/use-ref nil) + + show-in-viewer-ref + (mf/use-ref nil) + ;; PRESETS preset-state* (mf/use-state false) @@ -327,19 +333,19 @@ ;; CLIP CONTENT AND SHOW IN VIEWER on-change-clip-content (mf/use-fn - (mf/deps ids values) - (fn [] - (let [value (not (:show-content values))] - (st/emit! (dwsh/update-shapes ids (fn [shape] (assoc shape :show-content value))))))) + (mf/deps ids) + (fn [event] + (let [value (-> event dom/get-target dom/checked?)] + (st/emit! (dwsh/update-shapes ids (fn [shape] (assoc shape :show-content (not value)))))))) on-change-show-in-viewer (mf/use-fn - (mf/deps ids values) - (fn [] - (let [value (not (:hide-in-viewer values)) + (mf/deps ids) + (fn [event] + (let [value (-> event dom/get-target dom/checked?) undo-id (js/Symbol)] (st/emit! (dwu/start-undo-transaction undo-id) - (dwsh/update-shapes ids (fn [shape] (cls/change-show-in-viewer shape value)))) + (dwsh/update-shapes ids (fn [shape] (cls/change-show-in-viewer shape (not value))))) (when-not value ;; when a frame is no longer shown in view mode, cannot @@ -388,23 +394,22 @@ (when preset-match [:span {:class (stl/css :check-icon)} deprecated-icon/tick])])))]]] - [:> radio-buttons* {:class (stl/css :radio-buttons) - :selected (or (d/name orientation) "") - :on-change on-orientation-change - :name "frame-orientation" - :options [{:id "size-vertical" - :icon i/size-vertical - :label (tr "workspace.options.orientation.vertical") - :value "vert"} - {:id "size-horizontal" - :icon i/size-horizontal - :label (tr "workspace.options.orientation.horizontal") - :value "horiz"}]}] - - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.options.fit-content") - :on-pointer-down handle-fit-content - :icon i/fit-content}]]) + [:& radio-buttons {:selected (or (d/name orientation) "") + :on-change on-orientation-change + :name "frame-orientation" + :wide true + :class (stl/css :radio-buttons)} + [:& radio-button {:icon i/size-vertical + :value "vert" + :id "size-vertical"}] + [:& radio-button {:icon i/size-horizontal + :value "horiz" + :id "size-horizontal"}]] + [:> icon-button* + {:variant "ghost" + :aria-label (tr "workspace.options.fit-content") + :on-pointer-down handle-fit-content + :icon i/fit-content}]]) (when (options :size) [:div {:class (stl/css :size)} @@ -464,8 +469,8 @@ [:> icon-button* {:variant "ghost" :tooltip-placement "top-left" :icon (if proportion-lock "lock" "unlock") + :class (stl/css-case :selected (true? proportion-lock)) :disabled (= proportion-lock :multiple) - :aria-pressed (true? proportion-lock) :aria-label (if proportion-lock (tr "workspace.options.size.unlock") (tr "workspace.options.size.lock")) :on-click on-proportion-lock-change}]]) @@ -553,24 +558,41 @@ :on-change on-rotation-change :class (stl/css :numeric-input) :value (:rotation values)}]])) + (when (options :radius) [:> border-radius-menu* {:class (stl/css :border-radius) :ids ids :values values :applied-tokens applied-tokens}])]) - (when (or (options :clip-content) - (options :show-in-viewer)) + + (when (or (options :clip-content) (options :show-in-viewer)) [:div {:class (stl/css :clip-show)} (when (options :clip-content) - [:> icon-button* {:variant "ghost" - :aria-pressed (not (:show-content values)) - :aria-label (tr "workspace.options.clip-content") - :on-click on-change-clip-content - :icon i/clip-content}]) + [:div {:class (stl/css :clip-content)} + [:input {:type "checkbox" + :id "clip-content" + :ref clip-content-ref + :class (stl/css :clip-content-input) + :checked (not (:show-content values)) + :on-change on-change-clip-content}] + [:label {:for "clip-content" + :title (tr "workspace.options.clip-content") + :class (stl/css-case :clip-content-label true + :selected (not (:show-content values)))} + + [:> icon* {:icon-id i/clip-content}]]]) (when (options :show-in-viewer) - [:> icon-button* {:variant "ghost" - :aria-pressed (not (:hide-in-viewer values)) - :aria-label (tr "workspace.options.show-in-viewer") - :on-click on-change-show-in-viewer - :icon i/play}])])])) + [:div {:class (stl/css :show-in-viewer)} + [:input {:type "checkbox" + :id "show-in-viewer" + :ref show-in-viewer-ref + :class (stl/css :clip-content-input) + :checked (not (:hide-in-viewer values)) + :on-change on-change-show-in-viewer}] + + [:label {:for "show-in-viewer" + :title (tr "workspace.options.show-in-viewer") + :class (stl/css-case :clip-content-label true + :selected (not (:hide-in-viewer values)))} + [:> icon* {:icon-id i/play}]]])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss index dbc3074281..e214e0f636 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss @@ -145,6 +145,16 @@ grid-column: 2/-1; } +.lock-size-btn { + @extend .button-tertiary; + border-radius: deprecated.$br-8; + height: deprecated.$s-32; + width: deprecated.$s-28; + &.selected { + @extend .button-icon-selected; + } +} + .lock-ratio-icon { @extend .button-icon; stroke: var(--icon-foreground); @@ -156,3 +166,30 @@ justify-content: flex-start; gap: deprecated.$s-4; } + +.clip-content, +.show-in-viewer { + .clip-content-input { + display: none; + } +} + +.clip-content-label { + @extend .button-tertiary; + height: var(--sp-xxxl); + width: var(--sp-xxxl); + border-radius: deprecated.$br-8; +} + +.selected { + @extend .button-icon-selected; +} + +.checkbox-button { + @extend .button-icon; +} + +// TODO: Add a proper variable to this sizing +.numeric-input-measures { + --dropdown-width: var(--7-columns-dropdown-width); +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs index bdb948cc22..3135a815bc 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs @@ -19,15 +19,15 @@ [app.main.features :as features] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.context :as ctx] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.hooks :as hooks] [app.main.ui.icons :as deprecated-icon] - [app.main.ui.workspace.sidebar.options.menus.typography :refer [text-options* - typography-entry*]] + [app.main.ui.workspace.sidebar.options.menus.typography :refer [text-options + typography-entry]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.text.content :as content] @@ -37,99 +37,96 @@ [potok.v2.core :as ptk] [rumext.v2 :as mf])) -(mf/defc text-align-options* - [{:keys [values on-change on-blur]}] +(mf/defc text-align-options + [{:keys [values on-change on-blur] :as props}] (let [{:keys [text-align]} values - handle-change (mf/use-fn (mf/deps on-change on-blur) (fn [value] (on-change {:text-align value}) - (when (some? on-blur) - (on-blur))))] + (when (some? on-blur) (on-blur))))] - [:> radio-buttons* {:class (stl/css :align-options) - :selected text-align + ;; --- Align + [:div {:class (stl/css :align-options)} + [:& radio-buttons {:selected text-align :on-change handle-change - :name "align-text-options" - :options [{:id "text-align-left" - :icon i/text-align-left - :label (tr "workspace.options.text-options.text-align-left") - :value "left"} - {:id "text-align-center" - :icon i/text-align-center - :label (tr "workspace.options.text-options.text-align-center") - :value "center"} - {:id "text-align-right" - :icon i/text-align-right - :label (tr "workspace.options.text-options.text-align-right") - :value "right"} - {:id "text-align-justify" - :icon i/text-justify - :label (tr "workspace.options.text-options.text-align-justify") - :value "justify"}]}])) + :name "align-text-options"} + [:& radio-button {:value "left" + :id "text-align-left" + :title (tr "workspace.options.text-options.text-align-left") + :icon i/text-align-left}] + [:& radio-button {:value "center" + :id "text-align-center" + :title (tr "workspace.options.text-options.text-align-center") + :icon i/text-align-center}] + [:& radio-button {:value "right" + :id "text-align-right" + :title (tr "workspace.options.text-options.text-align-right") + :icon i/text-align-right}] + [:& radio-button {:value "justify" + :id "text-align-justify" + :title (tr "workspace.options.text-options.text-align-justify") + :icon i/text-justify}]]])) -(mf/defc text-direction-options* - [{:keys [values on-change on-blur]}] +(mf/defc text-direction-options + [{:keys [values on-change on-blur] :as props}] (let [direction (:text-direction values) - handle-change (mf/use-fn (mf/deps on-change on-blur direction) (fn [value] - (let [dir (if (= value direction) "none" value)] + (let [dir (if (= value direction) + "none" + value)] (on-change {:text-direction dir}) - (when (some? on-blur) - (on-blur)))))] + (when (some? on-blur) (on-blur)))))] - [:> radio-buttons* {:class (stl/css :text-direction-options) - :selected direction + [:div {:class (stl/css :text-direction-options)} + [:& radio-buttons {:selected direction :on-change handle-change - :allow-empty true - :name "text-direction-options" - :options [{:id "ltr-text-direction" - :icon i/text-ltr - :label (tr "workspace.options.text-options.direction-ltr") - :value "ltr"} - {:id "rtl-text-direction" - :icon i/text-rtl - :label (tr "workspace.options.text-options.direction-rtl") - :value "rtl"}]}])) + :name "text-direction-options"} + [:& radio-button {:value "ltr" + :type "checkbox" + :id "ltr-text-direction" + :title (tr "workspace.options.text-options.direction-ltr") + :icon i/text-ltr}] + [:& radio-button {:value "rtl" + :type "checkbox" + :id "rtl-text-direction" + :title (tr "workspace.options.text-options.direction-rtl") + :icon i/text-rtl}]]])) -(mf/defc vertical-align* - [{:keys [values on-change on-blur]}] +(mf/defc vertical-align + [{:keys [values on-change on-blur] :as props}] (let [{:keys [vertical-align]} values - vertical-align (or vertical-align "top") - handle-change (mf/use-fn (mf/deps on-change on-blur) (fn [value] (on-change {:vertical-align value}) - (when (some? on-blur) - (on-blur))))] + (when (some? on-blur) (on-blur))))] - [:> radio-buttons* {:class (stl/css :vertical-align-options) - :selected vertical-align + [:div {:class (stl/css :vertical-align-options)} + [:& radio-buttons {:selected vertical-align :on-change handle-change - :name "vertical-align-text-options" - :options [{:id "vertical-text-align-top" - :icon i/text-top - :label (tr "workspace.options.text-options.align-top") - :value "top"} - {:id "vertical-text-align-center" - :icon i/text-middle - :label (tr "workspace.options.text-options.align-middle") - :value "center"} - {:id "vertical-text-align-bottom" - :icon i/text-bottom - :label (tr "workspace.options.text-options.align-bottom") - :value "bottom"}]}])) + :name "vertical-align-text-options"} + [:& radio-button {:value "top" + :id "vertical-text-align-top" + :title (tr "workspace.options.text-options.align-top") + :icon i/text-top}] + [:& radio-button {:value "center" + :id "vertical-text-align-center" + :title (tr "workspace.options.text-options.align-middle") + :icon i/text-middle}] + [:& radio-button {:value "bottom" + :id "vertical-text-align-bottom" + :title (tr "workspace.options.text-options.align-bottom") + :icon i/text-bottom}]]])) -(mf/defc grow-options* - [{:keys [ids values on-blur]}] +(mf/defc grow-options + [{:keys [ids values on-blur] :as props}] (let [grow-type (:grow-type values) editor-instance (mf/deref refs/workspace-editor) @@ -152,56 +149,55 @@ (st/emit! (dwwt/resize-wasm-text-all ids))) ;; We asynchronously commit so every sychronous event is resolved first and inside the transaction (ts/schedule #(st/emit! (dwu/commit-undo-transaction uid)))) - (when (some? on-blur) - (on-blur))))] + (when (some? on-blur) (on-blur))))] - [:> radio-buttons* {:class (stl/css :grow-options) - :selected (d/name grow-type) + [:div {:class (stl/css :grow-options)} + [:& radio-buttons {:selected (d/name grow-type) :on-change handle-change-grow - :name "grow-text-options" - :options [{:id "text-fixed-grow" - :icon i/text-fixed - :label (tr "workspace.options.text-options.grow-fixed") - :value "fixed"} - {:id "text-auto-width-grow" - :icon i/text-auto-width - :label (tr "workspace.options.text-options.grow-auto-width") - :value "auto-width"} - {:id "text-auto-height-grow" - :icon i/text-auto-height - :label (tr "workspace.options.text-options.grow-auto-height") - :value "auto-height"}]}])) + :name "grow-text-options"} + [:& radio-button {:value "fixed" + :id "text-fixed-grow" + :title (tr "workspace.options.text-options.grow-fixed") + :icon i/text-fixed}] + [:& radio-button {:value "auto-width" + :id "text-auto-width-grow" + :title (tr "workspace.options.text-options.grow-auto-width") + :icon i/text-auto-width}] + [:& radio-button {:value "auto-height" + :id "text-auto-height-grow" + :title (tr "workspace.options.text-options.grow-auto-height") + :icon i/text-auto-height}]]])) -(mf/defc text-decoration-options* - [{:keys [values on-change on-blur]}] +(mf/defc text-decoration-options + [{:keys [values on-change on-blur] :as props}] (let [text-decoration (or (:text-decoration values) "none") - handle-change (mf/use-fn (mf/deps on-change on-blur text-decoration) (fn [value] - (let [decoration (if (= value text-decoration) "none" value)] + (let [decoration (if (= value text-decoration) + "none" + value)] (on-change {:text-decoration decoration}) - (when (some? on-blur) - (on-blur)))))] - - [:> radio-buttons* {:class (stl/css :text-decoration-options) - :selected text-decoration + (when (some? on-blur) (on-blur)))))] + [:div {:class (stl/css :text-decoration-options)} + [:& radio-buttons {:selected text-decoration :on-change handle-change - :name "grow-text-options" - :allow-empty true - :options [{:id "underline-text-decoration" - :icon i/text-underlined - :label (tr "workspace.options.text-options.underline" (sc/get-tooltip :underline)) - :value "underline"} - {:id "line-through-text-decoration" - :icon i/text-stroked - :label (tr "workspace.options.text-options.strikethrough" (sc/get-tooltip :line-through)) - :value "line-through"}]}])) + :name "text-decoration-options"} + [:& radio-button {:value "underline" + :type "checkbox" + :id "underline-text-decoration" + :title (tr "workspace.options.text-options.underline" (sc/get-tooltip :underline)) + :icon i/text-underlined}] + [:& radio-button {:value "line-through" + :type "checkbox" + :id "line-through-text-decoration" + :title (tr "workspace.options.text-options.strikethrough" (sc/get-tooltip :line-through)) + :icon i/text-stroked}]]])) -(mf/defc text-menu* +(mf/defc text-menu {::mf/wrap [mf/memo]} - [{:keys [ids type values]}] + [{:keys [ids type values] :as props}] (let [file-id (mf/use-ctx ctx/current-file-id) typographies (mf/deref refs/workspace-file-typography) @@ -294,19 +290,18 @@ multiple? (->> values vals (d/seek #(= % :multiple))) - props - (mf/props {:ids ids - :values values - :on-change on-change - :show-recent true - :on-blur - (fn [] - (ts/schedule - 100 - (fn [] - (when (not= "INPUT" (-> (dom/get-active) (dom/get-tag-name))) - (let [node (txu/get-text-editor-content)] - (dom/focus! node))))))})] + opts #js {:ids ids + :values values + :on-change on-change + :show-recent true + :on-blur + (fn [] + (ts/schedule + 100 + (fn [] + (when (not= "INPUT" (-> (dom/get-active) (dom/get-tag-name))) + (let [node (txu/get-text-editor-content)] + (dom/focus! node))))))}] (hooks/use-stream expand-stream #(swap! state* assoc-in [:more-options] true)) @@ -328,11 +323,11 @@ [:div {:class (stl/css :element-content)} (cond typography - [:> typography-entry* {:file-id typography-file-id - :typography typography - :local? (= typography-file-id file-id) - :on-detach handle-detach-typography - :on-change handle-change-typography}] + [:& typography-entry {:file-id typography-file-id + :typography typography + :local? (= typography-file-id file-id) + :on-detach handle-detach-typography + :on-change handle-change-typography}] (= typography-id :multiple) [:div {:class (stl/css :multiple-typography)} @@ -343,20 +338,19 @@ deprecated-icon/detach]] :else - [:> text-options* props]) + [:> text-options opts]) [:div {:class (stl/css :text-align-options)} - [:> text-align-options* props] - [:> grow-options* props] + [:> text-align-options opts] + [:> grow-options opts] [:> icon-button* {:variant "ghost" :aria-label (tr "labels.options") - :aria-pressed more-options-open? :data-testid "text-align-options-button" :on-click toggle-more-options :icon i/menu}]] (when more-options-open? - [:div {:class (stl/css :text-decoration-options)} - [:> vertical-align* props] - [:> text-decoration-options* props] - [:> text-direction-options* props]])])])) + [:div {:class (stl/css :text-decoration-options)} + [:> vertical-align opts] + [:> text-decoration-options opts] + [:> text-direction-options opts]])])])) 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 fc1d60c34a..940682be89 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 @@ -22,10 +22,10 @@ [app.main.store :as st] [app.main.ui.components.editable-select :refer [editable-select]] [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.search-bar :refer [search-bar*]] [app.main.ui.components.select :refer [select]] [app.main.ui.context :as ctx] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.icons :as deprecated-icon] [app.util.dom :as dom] @@ -424,24 +424,27 @@ (on-change {:text-transform type})) (when (some? on-blur) (on-blur)))] - [:> radio-buttons* {:selected text-transform + [:div {:class (stl/css :text-transform)} + [:& radio-buttons {:selected text-transform :on-change handle-change - :name "text-transform" - :allow-empty true - :options [{:id "text-transform-uppercase" - :icon i/text-uppercase - :label (tr "inspect.attributes.typography.text-transform.uppercase") - :value "uppercase"} - {:id "text-transform-capitalize" - :icon i/text-mixed - :label (tr "inspect.attributes.typography.text-transform.capitalize") - :value "capitalize"} - {:id "text-transform-lowercase" - :icon i/text-lowercase - :label (tr "inspect.attributes.typography.text-transform.lowercase") - :value "lowercase"}]}])) + :name "text-transform"} + [:& radio-button {:icon i/text-uppercase + :type "checkbox" + :title (tr "inspect.attributes.typography.text-transform.uppercase") + :value "uppercase" + :id "text-transform-uppercase"}] + [:& radio-button {:icon i/text-mixed + :type "checkbox" + :value "capitalize" + :title (tr "inspect.attributes.typography.text-transform.capitalize") + :id "text-transform-capitalize"}] + [:& radio-button {:icon i/text-lowercase + :type "checkbox" + :title (tr "inspect.attributes.typography.text-transform.lowercase") + :value "lowercase" + :id "text-transform-lowercase"}]]])) -(mf/defc text-options* +(mf/defc text-options {::mf/wrap-props false} [{:keys [ids editor values on-change on-blur show-recent]}] (let [full-size-selector? (and show-recent (= (mf/use-ctx ctx/sidebar) :right)) @@ -499,13 +502,14 @@ :on-click on-close} deprecated-icon/tick]] - [:> text-options* {:values typography - :on-change on-change - :show-recent false}]] + [:& text-options {:values typography + :on-change on-change + :show-recent false}]] [:div {:class (stl/css :typography-info-wrapper)} [:div {:class (stl/css :typography-name-wrapper)} [:div {:class (stl/css :typography-sample) + :style {:font-family (:font-family typography) :font-weight (:font-weight typography) :font-style (:font-style typography)}} @@ -545,7 +549,7 @@ :on-click navigate-to-library} (tr "workspace.assets.typography.go-to-edit")])])]))) -(mf/defc typography-entry* +(mf/defc typography-entry {::mf/wrap-props false} [{:keys [file-id typography local? selected? on-click on-change on-detach on-context-menu editing? renaming? focus-name? external-open*]}] (let [name-input-ref (mf/use-ref) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss index b5c5ebaa62..506fb58b34 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss @@ -324,6 +324,15 @@ } } } + .text-transform { + @extend .asset-element; + width: fit-content; + padding: 0; + background-color: var(--radio-btns-background-color); + &:hover { + background-color: var(--radio-btns-background-color); + } + } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.cljs index 4b2fb0f4f7..48a8b8ca0d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.cljs @@ -141,9 +141,8 @@ [:> icon-button* {:variant "secondary" :icon i/menu :class (stl/css-case :shadow-basic-button true - :hidden hidden?) - :aria-pressed is-open - :aria-label (tr "labels.options") + :selected is-open) + :aria-label "open more options" :disabled hidden? :on-click on-toggle-open}] [:& select {:class (stl/css :shadow-basic-select) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.scss b/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.scss index b4355228d9..f13404d03e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.scss @@ -43,8 +43,14 @@ .shadow-basic-button { border-radius: $br-8 0 0 $br-8; - &.hidden { - border: deprecated.$s-1 solid var(--input-border-color-disabled); + + &.selected { + --button-bg-color: var(--color-background-quaternary); + --button-fg-color: var(--color-accent-primary); + } + + &:disabled { + border: $b-1 solid var(--color-background-quaternary); } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs index 8b7cc718a4..eaab775a8e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs @@ -171,7 +171,7 @@ [:& blur-menu {:type type :ids blur-ids :values blur-values}]) (when-not (empty? text-ids) - [:> ot/text-menu* {:type type :ids text-ids :values text-values}]) + [:& ot/text-menu {:type type :ids text-ids :values text-values}]) (when-not (empty? svg-values) [:& svg-attrs-menu {:ids ids :values svg-values}]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index d2a8b25720..f3c6ee2b1e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -478,7 +478,7 @@ [:& constraints-menu {:ids constraint-ids :values constraint-values}]) (when-not (empty? text-ids) - [:> ot/text-menu* {:type type :ids text-ids :values text-values}]) + [:& ot/text-menu {:type type :ids text-ids :values text-values}]) (when-not (empty? fill-ids) [:> fill/fill-menu* {:type type diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs index 8b3f66dd51..21cd88b881 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs @@ -25,7 +25,7 @@ [app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]] [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] - [app.main.ui.workspace.sidebar.options.menus.text :refer [text-menu*]] + [app.main.ui.workspace.sidebar.options.menus.text :refer [text-menu]] [rumext.v2 :as mf])) (mf/defc options* @@ -162,9 +162,10 @@ {:ids ids :values (select-keys shape constraint-attrs)}]) - [:> text-menu* {:ids ids - :type type - :values text-values}] + [:& text-menu + {:ids ids + :type type + :values text-values}] [:> fill/fill-menu* {:ids ids diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/shadow.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/shadow.cljs index 99579abab1..9bf6fa32a2 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/shadow.cljs @@ -12,15 +12,14 @@ [app.common.types.token :as cto] [app.common.types.tokens-lib :as ctob] [app.main.data.workspace.tokens.errors :as wte] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.forms :as forms] [app.main.ui.hooks :as hooks] [app.main.ui.workspace.tokens.management.forms.controls :as token.controls] [app.main.ui.workspace.tokens.management.forms.generic-form :as generic] - [app.main.ui.workspace.tokens.management.forms.validators :refer [check-self-reference - default-validate-token]] + [app.main.ui.workspace.tokens.management.forms.validators :refer [check-self-reference default-validate-token]] [app.util.dom :as dom] [app.util.i18n :refer [tr]] [beicon.v2.core :as rx] @@ -232,17 +231,18 @@ :aria-label (tr "workspace.tokens.shadow-add-shadow") :on-click on-add-shadow-block :icon i/add}] - [:> radio-buttons* {:selected (d/name tab) - :on-change handle-toggle - :name "reference-composite-tab" - :options [{:id "composite-opt" - :icon i/layers - :label (tr "workspace.tokens.individual-tokens") - :value "composite"} - {:id "reference-opt" - :icon i/tokens - :label (tr "workspace.tokens.use-reference") - :value "reference"}]}]] + [:& radio-buttons {:class (stl/css :listing-options) + :selected (d/name tab) + :on-change handle-toggle + :name "reference-composite-tab"} + [:& radio-button {:icon i/layers + :value "composite" + :title (tr "workspace.tokens.individual-tokens") + :id "composite-opt"}] + [:& radio-button {:icon i/tokens + :value "reference" + :title (tr "workspace.tokens.use-reference") + :id "reference-opt"}]]] (if (= tab :composite) [:> composite-form* {:token token diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/typography.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/typography.cljs index 26a50a2f50..37a7fda7ca 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/typography.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/typography.cljs @@ -12,13 +12,11 @@ [app.common.types.token :as cto] [app.common.types.tokens-lib :as ctob] [app.main.data.workspace.tokens.errors :as wte] - [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.workspace.tokens.management.forms.controls :as token.controls] [app.main.ui.workspace.tokens.management.forms.generic-form :as generic] - [app.main.ui.workspace.tokens.management.forms.validators :refer [check-coll-self-reference - check-self-reference - default-validate-token]] + [app.main.ui.workspace.tokens.management.forms.validators :refer [check-coll-self-reference check-self-reference default-validate-token]] [app.util.i18n :refer [tr]] [beicon.v2.core :as rx] [cuerdas.core :as str] @@ -187,17 +185,18 @@ [:* [:div {:class (stl/css :title-bar)} [:div {:class (stl/css :title)} (tr "labels.typography")] - [:> radio-buttons* {:selected (d/name tab) - :on-change handle-toggle - :name "reference-composite-tab" - :options [{:id "composite-opt" - :icon i/layers - :label (tr "workspace.tokens.individual-tokens") - :value "composite"} - {:id "reference-opt" - :icon i/tokens - :label (tr "workspace.tokens.use-reference") - :value "reference"}]}]] + [:& radio-buttons {:class (stl/css :listing-options) + :selected (d/name tab) + :on-change handle-toggle + :name "reference-composite-tab"} + [:& radio-button {:icon i/layers + :value "composite" + :title (tr "workspace.tokens.individual-tokens") + :id "composite-opt"}] + [:& radio-button {:icon i/tokens + :value "reference" + :title (tr "workspace.tokens.use-reference") + :id "reference-opt"}]]] [:div {:class (stl/css :inputs-wrapper)} (if (= tab :composite) [:> composite-form* {:token token diff --git a/frontend/src/app/main/ui/workspace/tokens/themes/create_modal.cljs b/frontend/src/app/main/ui/workspace/tokens/themes/create_modal.cljs index 597d4a681e..a9fa7e5998 100644 --- a/frontend/src/app/main/ui/workspace/tokens/themes/create_modal.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/themes/create_modal.cljs @@ -119,7 +119,6 @@ :on-change on-switch-theme :default-checked selected?}]] - [:div {:class (stl/css :theme-actions-row)} (let [sets-count (some-> theme :sets seq count)] [:> button* {:class (stl/css-case :sets-count-button sets-count diff --git a/frontend/src/app/main/ui/workspace/top_toolbar.cljs b/frontend/src/app/main/ui/workspace/top_toolbar.cljs index 6fc3a09d4e..54a6bca3e0 100644 --- a/frontend/src/app/main/ui/workspace/top_toolbar.cljs +++ b/frontend/src/app/main/ui/workspace/top_toolbar.cljs @@ -17,10 +17,9 @@ [app.main.features :as features] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.components.file-uploader :refer [file-uploader*]] + [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.context :as ctx] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.icons :as deprecated-icon] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.timers :as ts] @@ -28,7 +27,7 @@ [potok.v2.core :as ptk] [rumext.v2 :as mf])) -(mf/defc image-upload* +(mf/defc image-upload {::mf/wrap [mf/memo]} [] (let [ref (mf/use-ref nil) @@ -54,17 +53,18 @@ :position (gpt/point x y)}] (st/emit! (dwm/upload-media-workspace params)))))] [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/img - :aria-label (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image)) - :tooltip-placement "bottom" - :on-click on-click} - [:> file-uploader* {:input-id "image-upload" - :accept dwm/accept-image-types - :multi true - :ref ref - :on-selected on-selected}]]])) + [:button + {:title (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image)) + :aria-label (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image)) + :on-click on-click + :class (stl/css :main-toolbar-options-button)} + deprecated-icon/img + [:& file-uploader + {:input-id "image-upload" + :accept dwm/accept-image-types + :multi true + :ref ref + :on-selected on-selected}]]])) (def ^:private toolbar-hidden-ref (l/derived (fn [state] @@ -136,104 +136,98 @@ [:ul {:class (stl/css :main-toolbar-options) :data-testid "toolbar-options"} [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/move - :aria-pressed (and (nil? drawtool) (not edition)) - :aria-label (tr "workspace.toolbar.move" (sc/get-tooltip :move)) - :tooltip-placement "bottom" - :on-click interrupt}]] + [:button + {:title (tr "workspace.toolbar.move" (sc/get-tooltip :move)) + :aria-label (tr "workspace.toolbar.move" (sc/get-tooltip :move)) + :class (stl/css-case :main-toolbar-options-button true + :selected (and (nil? drawtool) + (not edition))) + :on-click interrupt} + deprecated-icon/move]] [:* [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/board - :aria-pressed (= drawtool :frame) - :aria-label test-tooltip-board-text - :tooltip-placement "bottom" - :on-click select-drawtool - :data-tool "frame" - :data-testid "artboard-btn"}]] + [:button + {:title test-tooltip-board-text + :aria-label (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :frame)) + :on-click select-drawtool + :data-tool "frame" + :data-testid "artboard-btn"} + deprecated-icon/board]] [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/rectangle - :aria-pressed (= drawtool :rect) - :aria-label (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) - :tooltip-placement "bottom" - :on-click select-drawtool - :data-tool "rect" - :data-testid "rect-btn"}]] + [:button + {:title (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) + :aria-label (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :rect)) + :on-click select-drawtool + :data-tool "rect" + :data-testid "rect-btn"} + deprecated-icon/rectangle]] [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/elipse - :aria-pressed (= drawtool :circle) - :aria-label (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) - :tooltip-placement "bottom" - :on-click select-drawtool - :data-tool "circle" - :data-testid "ellipse-btn"}]] + [:button + {:title (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) + :aria-label (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :circle)) + :on-click select-drawtool + :data-tool "circle" + :data-testid "ellipse-btn"} + deprecated-icon/elipse]] [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/text - :aria-pressed (= drawtool :text) - :aria-label (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) - :tooltip-placement "bottom" - :on-click select-drawtool - :data-tool "text" - :data-testid "text-btn"}]] + [:button + {:title (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) + :aria-label (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :text)) + :on-click select-drawtool + :data-tool "text"} + deprecated-icon/text]] - [:> image-upload*] + [:& image-upload] [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/curve - :aria-pressed (= drawtool :curve) - :aria-label (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) - :tooltip-placement "bottom" - :on-click select-drawtool - :data-tool "curve" - :data-testid "curve-btn"}]] + [:button + {:title (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) + :aria-label (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :curve)) + :on-click select-drawtool + :data-tool "curve" + :data-testid "curve-btn"} + deprecated-icon/curve]] [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/path - :aria-pressed (= drawtool :path) - :aria-label (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) - :tooltip-placement "bottom" - :on-click select-drawtool - :data-tool "path" - :data-testid "path-btn"}]] + [:button + {:title (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) + :aria-label (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) + :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :path)) + :on-click select-drawtool + :data-tool "path" + :data-testid "path-btn"} + deprecated-icon/path]] (when (features/active-feature? @st/state "plugins/runtime") [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/puzzle - :aria-label (tr "workspace.toolbar.plugins" (sc/get-tooltip :plugins)) - :tooltip-placement "bottom" - :on-click #(st/emit! - (ptk/data-event ::ev/event {::ev/name "open-plugins-manager" - ::ev/origin "workspace:toolbar"}) - (modal/show :plugin-management {})) - :data-tool "plugins" - :data-testid "plugins-btn"}]]) + [:button + {:title (tr "workspace.toolbar.plugins" (sc/get-tooltip :plugins)) + :aria-label (tr "workspace.toolbar.plugins" (sc/get-tooltip :plugins)) + :class (stl/css :main-toolbar-options-button) + :on-click #(st/emit! + (ptk/data-event ::ev/event {::ev/name "open-plugins-manager" + ::ev/origin "workspace:toolbar"}) + (modal/show :plugin-management {})) + :data-tool "plugins" + :data-testid "plugins-btn"} + deprecated-icon/puzzle]]) (when *assert* [:li - [:> icon-button* {:variant "ghost" - :class (stl/css :main-toolbar-options-button) - :icon i/bug - :aria-pressed (contains? layout :debug-panel) - :aria-label (tr "workspace.toolbar.debug") - :tooltip-placement "bottom" - :on-click toggle-debug-panel}]])]] + [:button + {:title "Debugging tool" + :class (stl/css-case :main-toolbar-options-button true :selected (contains? layout :debug-panel)) + :on-click toggle-debug-panel} + deprecated-icon/bug]])]] [:button {:title (tr "workspace.toolbar.toggle-toolbar") :aria-label (tr "workspace.toolbar.toggle-toolbar") :class (stl/css :toolbar-handler) :on-click toggle-toolbar} [:div {:class (stl/css :toolbar-handler-btn)}]]]))) + + diff --git a/frontend/src/app/main/ui/workspace/top_toolbar.scss b/frontend/src/app/main/ui/workspace/top_toolbar.scss index a2837cc433..d005682878 100644 --- a/frontend/src/app/main/ui/workspace/top_toolbar.scss +++ b/frontend/src/app/main/ui/workspace/top_toolbar.scss @@ -54,7 +54,6 @@ align-items: center; margin: 0; opacity: deprecated.$op-10; - gap: var(--sp-xs); transition: opacity 0.3s ease; li { @@ -63,8 +62,21 @@ } .main-toolbar-options-button { + @extend .button-tertiary; height: deprecated.$s-36; width: deprecated.$s-36; + flex-shrink: 0; + border-radius: deprecated.$s-8; + margin: 0 deprecated.$s-2; + + svg { + @extend .button-icon; + stroke: var(--color-foreground-secondary); + } + + &.selected { + @extend .button-icon-selected; + } } .toolbar-handler { @@ -85,3 +97,7 @@ background-color: var(--palette-handler-background-color); } } + +ul.main-toolbar-panels { + display: none; +} diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index df81896e75..1fd44b32f0 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -28,7 +28,6 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.css-cursors :as cur] - [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.formats :as fmt] [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.viewport.viewport-ref :as uwvv] @@ -60,13 +59,11 @@ [:div {:class (stl/css :grid-actions-container)} [:div {:class (stl/css :grid-actions-title)} (tr "workspace.layout-grid.editor.title") " " [:span {:stl/css :board-name} (:name shape)]] - [:> button* {:variant "secondary" - :class (stl/css :action-btn) - :on-click #(st/emit! (dwge/locate-board (:id shape)))} + [:button {:class (stl/css :locate-btn) + :on-click #(st/emit! (dwge/locate-board (:id shape)))} (tr "workspace.layout-grid.editor.top-bar.locate")] - [:> button* {:variant "primary" - :class (stl/css :action-btn) - :on-click #(st/emit! (dw/clear-edition-mode))} + [:button {:class (stl/css :done-btn) + :on-click #(st/emit! (dw/clear-edition-mode))} (tr "workspace.layout-grid.editor.top-bar.done")]]]) (mf/defc grid-editor-frame diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss index 76859a85ff..d0f1549cb1 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss @@ -138,8 +138,18 @@ padding-left: deprecated.$s-8; } -.action-btn { - padding: 0 var(--sp-xl); +.locate-btn { + @extend .button-secondary; + text-transform: uppercase; + padding: deprecated.$s-8 deprecated.$s-20; + font-size: deprecated.$fs-11; +} + +.done-btn { + @extend .button-primary; + text-transform: uppercase; + padding: deprecated.$s-8 deprecated.$s-20; + font-size: deprecated.$fs-11; } .close-btn { diff --git a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs index b9be870c15..f496c4ec9b 100644 --- a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs @@ -11,11 +11,40 @@ [app.main.data.workspace.path :as drp] [app.main.data.workspace.path.shortcuts :as sc] [app.main.store :as st] - [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.icons :as deprecated-icon] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) +(def ^:private pentool-icon + (deprecated-icon/icon-xref :pentool (stl/css :pentool-icon :pathbar-icon))) + +(def ^:private move-icon + (deprecated-icon/icon-xref :move (stl/css :move-icon :pathbar-icon))) + +(def ^:private add-icon + (deprecated-icon/icon-xref :add (stl/css :add-icon :pathbar-icon))) + +(def ^:private remove-icon + (deprecated-icon/icon-xref :remove (stl/css :remove :pathbar-icon))) + +(def ^:private merge-nodes-icon + (deprecated-icon/icon-xref :merge-nodes (stl/css :merge-nodes-icon :pathbar-icon))) + +(def ^:private join-nodes-icon + (deprecated-icon/icon-xref :join-nodes (stl/css :join-nodes-icon :pathbar-icon))) + +(def ^:private separate-nodes-icon + (deprecated-icon/icon-xref :separate-nodes (stl/css :separate-nodes-icon :pathbar-icon))) + +(def ^:private to-corner-icon + (deprecated-icon/icon-xref :to-corner (stl/css :to-corner-icon :pathbar-icon))) + +(def ^:private to-curve-icon + (deprecated-icon/icon-xref :to-curve (stl/css :to-curve-icon :pathbar-icon))) + +(def ^:private snap-nodes-icon + (deprecated-icon/icon-xref :snap-nodes (stl/css :snap-nodes-icon :pathbar-icon))) + (defn check-enabled [content selected-points] (when content (let [segments (path.segm/get-segments-with-points content selected-points) @@ -115,91 +144,76 @@ [:div {:class (stl/css :sub-actions) :data-dont-clear-path true} [:div {:class (stl/css :sub-actions-group)} + ;; Draw Mode - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/pentool - :aria-pressed (= edit-mode :draw) - :aria-label (tr "workspace.path.actions.draw-nodes" (sc/get-tooltip :draw-nodes)) - :tooltip-placement "bottom" - :on-click on-select-draw-mode}] + [:button {:class (stl/css-case :is-toggled (= edit-mode :draw) + :topbar-btn true) + :title (tr "workspace.path.actions.draw-nodes" (sc/get-tooltip :draw-nodes)) + :on-click on-select-draw-mode} + pentool-icon] + ;; Edit mode - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/move - :aria-pressed (= edit-mode :move) - :aria-label (tr "workspace.path.actions.move-nodes" (sc/get-tooltip :move-nodes)) - :tooltip-placement "bottom" - :on-click on-select-edit-mode}]] + [:button {:class (stl/css-case :is-toggled (= edit-mode :move) + :topbar-btn true) + :title (tr "workspace.path.actions.move-nodes" (sc/get-tooltip :move-nodes)) + :on-click on-select-edit-mode} + move-icon]] [:div {:class (stl/css :sub-actions-group)} ;; Add Node - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/add - :aria-label (tr "workspace.path.actions.add-node" (sc/get-tooltip :add-node)) - :tooltip-placement "bottom" - :on-click on-add-node - :disabled (not (:add-node enabled-buttons))}] + [:button {:disabled (not (:add-node enabled-buttons)) + :class (stl/css :topbar-btn) + :title (tr "workspace.path.actions.add-node" (sc/get-tooltip :add-node)) + :on-click on-add-node} + add-icon] + ;; Remove node - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/remove - :aria-label (tr "workspace.path.actions.delete-node" (sc/get-tooltip :delete-node)) - :tooltip-placement "bottom" - :on-click on-remove-node - :disabled (not (:remove-node enabled-buttons))}]] + [:button {:disabled (not (:remove-node enabled-buttons)) + :class (stl/css :topbar-btn) + :title (tr "workspace.path.actions.delete-node" (sc/get-tooltip :delete-node)) + :on-click on-remove-node} + remove-icon]] [:div {:class (stl/css :sub-actions-group)} ;; Merge Nodes - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/merge-nodes - :aria-label (tr "workspace.path.actions.merge-nodes" (sc/get-tooltip :merge-nodes)) - :tooltip-placement "bottom" - :on-click on-merge-nodes - :disabled (not (:merge-nodes enabled-buttons))}] + [:button {:disabled (not (:merge-nodes enabled-buttons)) + :class (stl/css :topbar-btn) + :title (tr "workspace.path.actions.merge-nodes" (sc/get-tooltip :merge-nodes)) + :on-click on-merge-nodes} + merge-nodes-icon] + ;; Join Nodes - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/join-nodes - :aria-label (tr "workspace.path.actions.join-nodes" (sc/get-tooltip :join-nodes)) - :tooltip-placement "bottom" - :on-click on-join-nodes - :disabled (not (:join-nodes enabled-buttons))}] + [:button {:disabled (not (:join-nodes enabled-buttons)) + :class (stl/css :topbar-btn) + :title (tr "workspace.path.actions.join-nodes" (sc/get-tooltip :join-nodes)) + :on-click on-join-nodes} + join-nodes-icon] + ;; Separate Nodes - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/separate-nodes - :aria-label (tr "workspace.path.actions.separate-nodes" (sc/get-tooltip :separate-nodes)) - :tooltip-placement "bottom" - :on-click on-separate-nodes - :disabled (not (:separate-nodes enabled-buttons))}]] + [:button {:disabled (not (:separate-nodes enabled-buttons)) + :class (stl/css :topbar-btn) + :title (tr "workspace.path.actions.separate-nodes" (sc/get-tooltip :separate-nodes)) + :on-click on-separate-nodes} + separate-nodes-icon]] [:div {:class (stl/css :sub-actions-group)} ; Make Corner - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/to-corner - :aria-label (tr "workspace.path.actions.make-corner" (sc/get-tooltip :make-corner)) - :tooltip-placement "bottom" - :on-click on-make-corner - :disabled (not (:make-corner enabled-buttons))}] - ;; Make Curve - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/to-curve - :aria-label (tr "workspace.path.actions.make-curve" (sc/get-tooltip :make-curve)) - :tooltip-placement "bottom" - :on-click on-make-curve - :disabled (not (:make-curve enabled-buttons))}]] + [:button {:disabled (not (:make-corner enabled-buttons)) + :class (stl/css :topbar-btn) + :title (tr "workspace.path.actions.make-corner" (sc/get-tooltip :make-corner)) + :on-click on-make-corner} + to-corner-icon] + ;; Make Curve + [:button {:disabled (not (:make-curve enabled-buttons)) + :class (stl/css :topbar-btn) + :title (tr "workspace.path.actions.make-curve" (sc/get-tooltip :make-curve)) + :on-click on-make-curve} + to-curve-icon]] [:div {:class (stl/css :sub-actions-group)} ;; Toggle snap - [:> icon-button* {:variant "ghost" - :class (stl/css :topbar-btn) - :icon i/snap-nodes - :aria-pressed snap-toggled - :aria-label (tr "workspace.path.actions.snap-nodes" (sc/get-tooltip :snap-nodes)) - :tooltip-placement "bottom" - :on-click on-toggle-snap}]]])) + [:button {:class (stl/css-case :is-toggled snap-toggled + :topbar-btn true) + :title (tr "workspace.path.actions.snap-nodes" (sc/get-tooltip :snap-nodes)) + :on-click on-toggle-snap} + snap-nodes-icon]]])) diff --git a/frontend/src/app/main/ui/workspace/viewport/path_actions.scss b/frontend/src/app/main/ui/workspace/viewport/path_actions.scss index d6fa360618..94c86e6a8d 100644 --- a/frontend/src/app/main/ui/workspace/viewport/path_actions.scss +++ b/frontend/src/app/main/ui/workspace/viewport/path_actions.scss @@ -34,11 +34,27 @@ align-items: center; margin: 0; opacity: deprecated.$op-10; - gap: var(--sp-xs); transition: opacity 0.3s ease; } .topbar-btn { + --pathbar-icon-color: var(--color-foreground-secondary); + @extend .button-tertiary; height: deprecated.$s-36; width: deprecated.$s-36; + flex-shrink: 0; + background-color: transparent; + border-radius: deprecated.$s-8; + border: none; + margin: 0 deprecated.$s-2; + + &.is-toggled { + --pathbar-icon-color: var(--button-radio-foreground-color-active); + background-color: var(--button-radio-background-color-active); + } + + .pathbar-icon { + @extend .button-icon; + stroke: var(--pathbar-icon-color); + } } diff --git a/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs b/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs index 8aeaf5db3d..b9f4f69cb4 100644 --- a/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs @@ -10,7 +10,6 @@ [app.main.data.workspace :as dw] [app.main.data.workspace.common :as dwc] [app.main.store :as st] - [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.workspace.viewport.grid-layout-editor :refer [grid-edition-actions]] [app.main.ui.workspace.viewport.path-actions :refer [path-actions*]] [app.util.i18n :as i18n :refer [tr]] @@ -35,9 +34,8 @@ [:> i18n/tr-html* {:tag-name "span" :content (tr "workspace.top-bar.view-only")}]] - [:> button* {:variant "primary" - :class (stl/css :done-btn) - :on-click handle-close-view-mode} + [:button {:class (stl/css :done-btn) + :on-click handle-close-view-mode} (tr "workspace.top-bar.read-only.done")]]])) (mf/defc path-edition-bar* diff --git a/frontend/src/app/main/ui/workspace/viewport/top_bar.scss b/frontend/src/app/main/ui/workspace/viewport/top_bar.scss index d9dd78f4fd..802dc32ab7 100644 --- a/frontend/src/app/main/ui/workspace/viewport/top_bar.scss +++ b/frontend/src/app/main/ui/workspace/viewport/top_bar.scss @@ -45,7 +45,10 @@ } .done-btn { - padding: 0 var(--sp-xl); + @extend .button-primary; + text-transform: uppercase; + padding: deprecated.$s-8 deprecated.$s-20; + font-size: deprecated.$fs-11; } .viewport-actions-no-rulers { diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 7c3a5c8834..ff088bd743 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5529,10 +5529,6 @@ msgstr "Ungroup" msgid "workspace.colorpicker.color-tokens" msgstr "Color tokens" -#: src/app/main/ui/workspace/colorpicker.cljs:434 -msgid "workspace.colorpicker.get-color" -msgstr "Get color" - #: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:506 msgid "workspace.component.swap.loop-error" msgstr "Components can't be nested inside themselves." @@ -5823,10 +5819,6 @@ msgstr "Full screen" msgid "workspace.header.zoom-selected" msgstr "Zoom to selected" -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:422 -msgid "workspace.layout-grid.editor.margin.expand" -msgstr "Show 4 sided margin options" - #: src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs:275, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:859 msgid "workspace.layout-grid.editor.options.edit-grid" msgstr "Edit grid" @@ -5879,30 +5871,6 @@ msgstr "Locate" msgid "workspace.layout-grid.editor.top-bar.locate.tooltip" msgstr "Locate grid layout" -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:449 -msgid "workspace.layout-item.fit-content-horizontal" -msgstr "Fit content (Horizontal)" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:477 -msgid "workspace.layout-item.fit-content-vertical" -msgstr "Fit content (Vertical)" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:465 -msgid "workspace.layout-item.fix-height" -msgstr "Fix height" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:439 -msgid "workspace.layout-item.fix-width" -msgstr "Fix width" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:471 -msgid "workspace.layout-item.height-100" -msgstr "Height 100%" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:444 -msgid "workspace.layout-item.width-100" -msgstr "Width 100%" - #: src/app/main/ui/workspace/libraries.cljs #, unused msgid "workspace.libraries.add" @@ -6503,30 +6471,6 @@ msgstr "After delay" msgid "workspace.options.interaction-animation" msgstr "Animation" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:616 -msgid "workspace.options.interaction-animation-direction-down" -msgstr "Down" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:593 -msgid "workspace.options.interaction-animation-direction-in" -msgstr "In" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:612 -msgid "workspace.options.interaction-animation-direction-left" -msgstr "Left" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:596 -msgid "workspace.options.interaction-animation-direction-out" -msgstr "Out" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:608 -msgid "workspace.options.interaction-animation-direction-right" -msgstr "Right" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:620 -msgid "workspace.options.interaction-animation-direction-up" -msgstr "Up" - #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:383 msgid "workspace.options.interaction-animation-dissolve" msgstr "Dissolve" @@ -6972,14 +6916,6 @@ msgstr "More color tokens" msgid "workspace.options.opacity" msgstr "Opacity" -#: src/app/main/ui/workspace/sidebar/options/drawing/frame.cljs:108, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:401 -msgid "workspace.options.orientation.horizontal" -msgstr "Horizontal" - -#: src/app/main/ui/workspace/sidebar/options/drawing/frame.cljs:104, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:397 -msgid "workspace.options.orientation.vertical" -msgstr "Vertical" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs #, unused msgid "workspace.options.position" @@ -7830,7 +7766,7 @@ msgstr "Components" msgid "workspace.sidebar.layers.filter" msgstr "Filter" -#: src/app/main/ui/workspace/sidebar/layers.cljs:310, src/app/main/ui/workspace/sidebar/layers.cljs:338 +#: src/app/main/ui/workspace/sidebar/layers.cljs:311, src/app/main/ui/workspace/sidebar/layers.cljs:339 msgid "workspace.sidebar.layers.frames" msgstr "Boards" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index b4bc62124d..33a89f18a6 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -5510,10 +5510,6 @@ msgstr "Desagrupar" msgid "workspace.colorpicker.color-tokens" msgstr "Tokens de color" -#: src/app/main/ui/workspace/colorpicker.cljs:434 -msgid "workspace.colorpicker.get-color" -msgstr "Absorber color" - #: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:506 msgid "workspace.component.swap.loop-error" msgstr "Los componentes no pueden anidarse dentro de sí mismos." @@ -5799,12 +5795,8 @@ msgstr "Pantalla completa" msgid "workspace.header.zoom-selected" msgstr "Zoom a selección" -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:422 -msgid "workspace.layout-grid.editor.margin.expand" -msgstr "Mostrar el margen a 4 lados" - -#: src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs:275, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:859 -msgid "workspace.layout-grid.editor.options.edit-grid" +#: src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs:274, src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs:276, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:868 +msgid "workspace.layout_grid.editor.options.edit-grid" msgstr "Editar rejilla" #: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1539 @@ -5855,30 +5847,6 @@ msgstr "Mostrar" msgid "workspace.layout-grid.editor.top-bar.locate.tooltip" msgstr "Mostrar grid layout" -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:449 -msgid "workspace.layout-item.fit-content-horizontal" -msgstr "Ajustar contenido (horizontal)" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:477 -msgid "workspace.layout-item.fit-content-vertical" -msgstr "Ajustar contenido (vertical)" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:465 -msgid "workspace.layout-item.fix-height" -msgstr "Fijar altura" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:439 -msgid "workspace.layout-item.fix-width" -msgstr "Fijar anchura" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:471 -msgid "workspace.layout-item.height-100" -msgstr "Altura 100%" - -#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:444 -msgid "workspace.layout-item.width-100" -msgstr "Anchura 100%" - #: src/app/main/ui/workspace/libraries.cljs #, unused msgid "workspace.libraries.add" @@ -6443,30 +6411,6 @@ msgstr "Tiempo" msgid "workspace.options.interaction-animation" msgstr "Animación" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:616 -msgid "workspace.options.interaction-animation-direction-down" -msgstr "Abajo" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:593 -msgid "workspace.options.interaction-animation-direction-in" -msgstr "Dentro" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:612 -msgid "workspace.options.interaction-animation-direction-left" -msgstr "Izquierda" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:596 -msgid "workspace.options.interaction-animation-direction-out" -msgstr "Fuera" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:608 -msgid "workspace.options.interaction-animation-direction-right" -msgstr "Derecha" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:620 -msgid "workspace.options.interaction-animation-direction-up" -msgstr "Arriba" - #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:383 msgid "workspace.options.interaction-animation-dissolve" msgstr "Disolver" @@ -6912,14 +6856,6 @@ msgstr "Más tokens de color" msgid "workspace.options.opacity" msgstr "Opacidad" -#: src/app/main/ui/workspace/sidebar/options/drawing/frame.cljs:108, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:401 -msgid "workspace.options.orientation.horizontal" -msgstr "Horizontal" - -#: src/app/main/ui/workspace/sidebar/options/drawing/frame.cljs:104, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:397 -msgid "workspace.options.orientation.vertical" -msgstr "Vertical" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs #, unused msgid "workspace.options.position" @@ -7770,11 +7706,7 @@ msgstr "Capas" msgid "workspace.sidebar.layers.components" msgstr "Componentes" -#: src/app/main/ui/workspace/sidebar/layers.cljs:297 -msgid "workspace.sidebar.layers.filter" -msgstr "Filtrar" - -#: src/app/main/ui/workspace/sidebar/layers.cljs:310, src/app/main/ui/workspace/sidebar/layers.cljs:338 +#: src/app/main/ui/workspace/sidebar/layers.cljs:311, src/app/main/ui/workspace/sidebar/layers.cljs:339 msgid "workspace.sidebar.layers.frames" msgstr "Paneles" @@ -8331,7 +8263,6 @@ msgid "workspace.tokens.text-decoration-value-enter" msgstr "none | underline | strike-through o {alias}" #: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:154 -#, unused msgid "workspace.tokens.theme-name" msgstr "Tema %s" diff --git a/mcp/packages/server/data/api_types.yml b/mcp/packages/server/data/api_types.yml index 912adaa95a..18079c5c3d 100644 --- a/mcp/packages/server/data/api_types.yml +++ b/mcp/packages/server/data/api_types.yml @@ -1064,7 +1064,44 @@ Board: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -1425,7 +1462,44 @@ Board: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -2099,7 +2173,44 @@ VariantContainer: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -2463,7 +2574,44 @@ VariantContainer: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -3124,7 +3272,44 @@ Boolean: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -3450,7 +3635,44 @@ Boolean: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -5630,7 +5852,44 @@ Ellipse: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -5926,7 +6185,44 @@ Ellipse: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -7985,7 +8281,44 @@ Group: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -8287,7 +8620,44 @@ Group: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -9155,7 +9525,44 @@ Image: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -9451,7 +9858,44 @@ Image: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -12544,7 +12988,44 @@ Path: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -12864,7 +13345,44 @@ Path: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -13797,7 +14315,44 @@ Rectangle: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -14095,7 +14650,44 @@ Rectangle: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -14759,7 +15351,44 @@ ShapeBase: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -15056,7 +15685,44 @@ ShapeBase: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -15751,7 +16417,44 @@ SvgRaw: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -16042,7 +16745,44 @@ SvgRaw: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -16596,7 +17336,44 @@ Text: layoutChild?: LayoutChildProperties; layoutCell?: LayoutChildProperties; setParentIndex(index: number): void; - tokens: { [property: string]: string }; + tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + }; isComponentInstance(): boolean; isComponentMainInstance(): boolean; isComponentCopyInstance(): boolean; @@ -16904,7 +17681,44 @@ Text: Layout properties for cells in a grid layout. tokens: |- ``` - readonly tokens: { [property: string]: string } + readonly tokens: { + width: string; + height: string; + fill: string; + x: string; + y: string; + all: string; + r1: string; + r2: string; + r3: string; + r4: string; + shadow: string; + strokeColor: string; + strokeWidth: string; + fontFamilies: string; + fontSize: string; + fontWeight: string; + letterSpacing: string; + rotation: string; + opacity: string; + layoutItemMinW: string; + layoutItemMaxW: string; + layoutItemMinH: string; + layoutItemMaxH: string; + rowGap: string; + columnGap: string; + p1: string; + p2: string; + p3: string; + p4: string; + m1: string; + m2: string; + m3: string; + m4: string; + textCase: string; + textDecoration: string; + typography: string; + } ``` The design tokens applied to this shape. @@ -17841,6 +18655,7 @@ TokenBase: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -17890,6 +18705,16 @@ TokenBase: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. Methods: duplicate: |- ``` @@ -17963,6 +18788,7 @@ TokenBorderRadius: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -18001,6 +18827,16 @@ TokenBorderRadius: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "borderRadius" @@ -18212,6 +19048,7 @@ TokenShadow: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -18250,6 +19087,16 @@ TokenShadow: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "shadow" @@ -18347,6 +19194,7 @@ TokenColor: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -18385,6 +19233,16 @@ TokenColor: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "color" @@ -18478,6 +19336,7 @@ TokenDimension: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -18516,6 +19375,16 @@ TokenDimension: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "dimension" @@ -18611,6 +19480,7 @@ TokenFontFamilies: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -18649,6 +19519,16 @@ TokenFontFamilies: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "fontFamilies" @@ -18747,6 +19627,7 @@ TokenFontSizes: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -18785,6 +19666,16 @@ TokenFontSizes: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "fontSizes" @@ -18880,6 +19771,7 @@ TokenFontWeights: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -18918,6 +19810,16 @@ TokenFontWeights: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "fontWeights" @@ -19014,6 +19916,7 @@ TokenLetterSpacing: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -19052,6 +19955,16 @@ TokenLetterSpacing: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "letterSpacing" @@ -19147,6 +20060,7 @@ TokenNumber: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -19185,6 +20099,16 @@ TokenNumber: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "number" @@ -19280,6 +20204,7 @@ TokenOpacity: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -19318,6 +20243,16 @@ TokenOpacity: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "opacity" @@ -19414,6 +20349,7 @@ TokenRotation: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -19452,6 +20388,16 @@ TokenRotation: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "rotation" @@ -19548,6 +20494,7 @@ TokenSizing: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -19586,6 +20533,16 @@ TokenSizing: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "sizing" @@ -19681,6 +20638,7 @@ TokenSpacing: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -19719,6 +20677,16 @@ TokenSpacing: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "spacing" @@ -19814,6 +20782,7 @@ TokenBorderWidth: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -19852,6 +20821,16 @@ TokenBorderWidth: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "borderWidth" @@ -19947,6 +20926,7 @@ TokenTextCase: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -19985,6 +20965,16 @@ TokenTextCase: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "textCase" @@ -20081,6 +21071,7 @@ TokenTextDecoration: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -20119,6 +21110,16 @@ TokenTextDecoration: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "textDecoration" @@ -20344,6 +21345,7 @@ TokenTypography: description: string; duplicate(): Token; remove(): void; + resolvedValueString: string | undefined; applyToShapes( shapes: Shape[], properties: TokenProperty[] | undefined, @@ -20382,6 +21384,16 @@ TokenTypography: ``` An optional description text. + resolvedValueString: |- + ``` + readonly resolvedValueString: string | undefined + ``` + + The value calculated by finding all tokens with the same name in active sets + and resolving the references. + + It's converted to string, regardless of the data type of the value depending + on the token type. It can be undefined if no value has been found in active sets. type: |- ``` readonly type: "typography" @@ -21635,7 +22647,7 @@ TokenDimensionProps: ============================== ``` - TokenDimensionProps: "x" | "y" | "stroke-width" + TokenDimensionProps: "x" | "y" | "strokeWidth" ``` The properties that a Dimension token can be applied to. @@ -21648,7 +22660,7 @@ TokenFontFamiliesProps: ================================= ``` - TokenFontFamiliesProps: "font-families" + TokenFontFamiliesProps: "fontFamilies" ``` The properties that a FontFamilies token can be applied to. @@ -21661,7 +22673,7 @@ TokenFontSizesProps: ============================== ``` - TokenFontSizesProps: "font-size" + TokenFontSizesProps: "fontSize" ``` The properties that a FontSizes token can be applied to. @@ -21674,7 +22686,7 @@ TokenFontWeightProps: =============================== ``` - TokenFontWeightProps: "font-weight" + TokenFontWeightProps: "fontWeight" ``` The properties that a FontWeight token can be applied to. @@ -21687,7 +22699,7 @@ TokenLetterSpacingProps: ================================== ``` - TokenLetterSpacingProps: "letter-spacing" + TokenLetterSpacingProps: "letterSpacing" ``` The properties that a LetterSpacing token can be applied to. @@ -21700,7 +22712,7 @@ TokenNumberProps: =========================== ``` - TokenNumberProps: "rotation" | "line-height" + TokenNumberProps: "rotation" ``` The properties that a Number token can be applied to. @@ -21729,10 +22741,10 @@ TokenSizingProps: TokenSizingProps: | "width" | "height" - | "layout-item-min-w" - | "layout-item-max-w" - | "layout-item-min-h" - | "layout-item-max-h" + | "layoutItemMinW" + | "layoutItemMaxW" + | "layoutItemMinH" + | "layoutItemMaxH" ``` The properties that a Sizing token can be applied to. @@ -21746,8 +22758,8 @@ TokenSpacingProps: ``` TokenSpacingProps: - | "row-gap" - | "column-gap" + | "rowGap" + | "columnGap" | "p1" | "p2" | "p3" @@ -21768,7 +22780,7 @@ TokenBorderWidthProps: ================================ ``` - TokenBorderWidthProps: "stroke-width" + TokenBorderWidthProps: "strokeWidth" ``` The properties that a BorderWidth token can be applied to. @@ -21781,7 +22793,7 @@ TokenTextCaseProps: ============================= ``` - TokenTextCaseProps: "text-case" + TokenTextCaseProps: "textCase" ``` The properties that a TextCase token can be applied to. @@ -21794,7 +22806,7 @@ TokenTextDecorationProps: =================================== ``` - TokenTextDecorationProps: "text-decoration" + TokenTextDecorationProps: "textDecoration" ``` The properties that a TextDecoration token can be applied to. diff --git a/mcp/scripts/build-types b/mcp/scripts/build-types index 1833e9ee35..f1c0130e89 100755 --- a/mcp/scripts/build-types +++ b/mcp/scripts/build-types @@ -7,6 +7,7 @@ pushd $SCRIPT_DIR; if [[ "$URL" = "http://localhost:9090" ]]; then pushd ../../plugins + rm -rf node_modules; pnpm install pnpm run build:doc popd diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 005bf31781..c435e03ded 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -412,6 +412,9 @@ fn set_children_set(entries: Vec) { for id in entries { state.touch_shape(id); + if let Some(children_shape) = state.shapes.get_mut(&id) { + children_shape.set_deleted(false); + } } }); diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index 52880f14a1..35e0e78721 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -831,6 +831,8 @@ impl RenderState { let text_content = text_content.new_bounds(shape.selrect()); let count_inner_strokes = shape.count_visible_inner_strokes(); + let text_stroke_blur_outset = + Stroke::max_bounds_width(shape.visible_strokes(), false); let mut paragraph_builders = text_content.paragraph_builder_group_from_text(None); let mut stroke_paragraphs_list = shape .visible_strokes() @@ -858,7 +860,7 @@ impl RenderState { ); for stroke_paragraphs in stroke_paragraphs_list.iter_mut() { - text::render( + text::render_with_bounds_outset( Some(self), None, &shape, @@ -866,6 +868,7 @@ impl RenderState { Some(strokes_surface_id), None, None, + text_stroke_blur_outset, ); } } else { @@ -957,7 +960,7 @@ impl RenderState { // 4. Stroke fills for stroke_paragraphs in stroke_paragraphs_list.iter_mut() { - text::render( + text::render_with_bounds_outset( Some(self), None, &shape, @@ -965,6 +968,7 @@ impl RenderState { Some(strokes_surface_id), None, blur_filter.as_ref(), + text_stroke_blur_outset, ); } diff --git a/render-wasm/src/render/text.rs b/render-wasm/src/render/text.rs index ba14112921..2761962071 100644 --- a/render-wasm/src/render/text.rs +++ b/render-wasm/src/render/text.rs @@ -156,7 +156,8 @@ fn get_text_stroke_paints( paints } -pub fn render( +#[allow(clippy::too_many_arguments)] +pub fn render_with_bounds_outset( render_state: Option<&mut RenderState>, canvas: Option<&Canvas>, shape: &Shape, @@ -164,12 +165,20 @@ pub fn render( surface_id: Option, shadow: Option<&Paint>, blur: Option<&ImageFilter>, + stroke_bounds_outset: f32, ) { if let Some(render_state) = render_state { let target_surface = surface_id.unwrap_or(SurfaceId::Fills); if let Some(blur_filter) = blur { - let bounds = blur_filter.compute_fast_bounds(shape.selrect); + let mut text_bounds = shape + .get_text_content() + .calculate_bounds(shape, false) + .to_rect(); + if stroke_bounds_outset > 0.0 { + text_bounds.inset((-stroke_bounds_outset, -stroke_bounds_outset)); + } + let bounds = blur_filter.compute_fast_bounds(text_bounds); if bounds.is_finite() && bounds.width() > 0.0 && bounds.height() > 0.0 { let blur_filter_clone = blur_filter.clone(); if filters::render_with_filter_surface( @@ -202,6 +211,27 @@ pub fn render( } } +pub fn render( + render_state: Option<&mut RenderState>, + canvas: Option<&Canvas>, + shape: &Shape, + paragraph_builders: &mut [Vec], + surface_id: Option, + shadow: Option<&Paint>, + blur: Option<&ImageFilter>, +) { + render_with_bounds_outset( + render_state, + canvas, + shape, + paragraph_builders, + surface_id, + shadow, + blur, + 0.0, + ); +} + fn render_text_on_canvas( canvas: &Canvas, shape: &Shape, diff --git a/render-wasm/src/render/ui.rs b/render-wasm/src/render/ui.rs index 97c8dd4867..7d6436fbc8 100644 --- a/render-wasm/src/render/ui.rs +++ b/render-wasm/src/render/ui.rs @@ -45,6 +45,10 @@ pub fn render(render_state: &mut RenderState, shapes: ShapesPoolRef) { continue; } + if shape.deleted() { + continue; + } + if let Some(shape) = shapes.get(&shape.id) { grid_layout::render_overlay(zoom, canvas, shape, shapes); } diff --git a/render-wasm/src/shapes.rs b/render-wasm/src/shapes.rs index 2eed111226..8967b6ee49 100644 --- a/render-wasm/src/shapes.rs +++ b/render-wasm/src/shapes.rs @@ -196,6 +196,7 @@ pub struct Shape { pub extrect_cache: RefCell>, pub svg_transform: Option, pub ignore_constraints: bool, + deleted: bool, } // Returns all ancestor shapes of this shape, traversing up the parent hierarchy @@ -284,6 +285,7 @@ impl Shape { extrect_cache: RefCell::new(None), svg_transform: None, ignore_constraints: false, + deleted: false, } } @@ -441,6 +443,14 @@ impl Shape { self.svg_transform } + pub fn set_deleted(&mut self, value: bool) { + self.deleted = value; + } + + pub fn deleted(&self) -> bool { + self.deleted + } + // FIXME: These arguments could be grouped or simplified #[allow(clippy::too_many_arguments)] pub fn set_flex_layout_child_data( diff --git a/render-wasm/src/shapes/modifiers.rs b/render-wasm/src/shapes/modifiers.rs index df2da87b3a..36cde42bf0 100644 --- a/render-wasm/src/shapes/modifiers.rs +++ b/render-wasm/src/shapes/modifiers.rs @@ -441,12 +441,18 @@ pub fn propagate_modifiers( db.cmp(&da) }); + // This temporary bounds is necesary so the layouts can be calculated + // correctly but will be discarded before the next iteration for the + // bounds to be calculated properly with the modifiers. + let mut bounds_temp = bounds.clone(); + for id in &layout_reflows_vec { if reflown.contains(id) { continue; } - reflow_shape(id, state, &mut reflown, &mut entries, &mut bounds); + reflow_shape(id, state, &mut reflown, &mut entries, &mut bounds_temp); } + layout_reflows = HashSet::new(); } #[allow(dead_code)] diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index 7762d4b5aa..b99b768334 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -157,6 +157,10 @@ impl State { self.render_state.tiles.remove_shape_at(tile, shape.id); } } + + if let Some(shape_to_delete) = self.shapes.get_mut(&id) { + shape_to_delete.set_deleted(true); + } } } diff --git a/render-wasm/watch b/render-wasm/watch index 59139ec2cb..5ead50c188 100755 --- a/render-wasm/watch +++ b/render-wasm/watch @@ -13,6 +13,8 @@ copy_shared_artifact; pushd $_SCRIPT_DIR; cargo watch \ + --why \ + -i "_tmp*" -x "build $CARGO_PARAMS" \ -s "./build" \ -s "echo 'DONE\n'";