From 0dda7bd9ee3671cb2685cea5e9bfc11b75a48dfc Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 17 Feb 2026 10:54:19 +0100 Subject: [PATCH 01/12] :bug: Fix text stroke bounds --- render-wasm/src/render.rs | 8 ++++++-- render-wasm/src/render/text.rs | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) 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, From 4185a7a6f357b8a73189497c5b9073f98469b138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Tue, 17 Feb 2026 12:58:15 +0100 Subject: [PATCH 02/12] :bug: Fix grid layout lines persisted after board is deleted --- render-wasm/src/main.rs | 3 +++ render-wasm/src/render/ui.rs | 4 ++++ render-wasm/src/shapes.rs | 10 ++++++++++ render-wasm/src/state.rs | 4 ++++ 4 files changed, 21 insertions(+) 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/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/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); + } } } From afb252f42e27bc5e97b9b3fc145d29019f4bf59f Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Fri, 13 Feb 2026 15:03:08 +0100 Subject: [PATCH 03/12] :wrench: Migrate text editor v2 tests to wasm viewport --- .../playwright/ui/pages/WasmWorkspacePage.js | 4 +- frontend/playwright/ui/pages/WorkspacePage.js | 71 ++++------- .../ui/specs/text-editor-v2.spec.js | 119 +++++++----------- ...size-selecting-a-part-of-it-starting-1.png | Bin 0 -> 12662 bytes ...cing-selecting-a-part-of-it-starting-1.png | Bin 0 -> 11392 bytes ...ight-selecting-a-part-of-it-starting-1.png | Bin 0 -> 11399 bytes .../main/ui/workspace/sidebar/layer_item.cljs | 2 + 7 files changed, 75 insertions(+), 121 deletions(-) create mode 100644 frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-font-size-selecting-a-part-of-it-starting-1.png create mode 100644 frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-letter-spacing-selecting-a-part-of-it-starting-1.png create mode 100644 frontend/playwright/ui/specs/text-editor-v2.spec.js-snapshots/Update-text-line-height-selecting-a-part-of-it-starting-1.png 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..c9f6fd97c7 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) { @@ -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/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 0000000000000000000000000000000000000000..0d31872f790e465f9b142dd57bfc6dd711998558 GIT binary patch literal 12662 zcmeI3Sy)q9w#ScBiX{qVTQ)6Y*|t)OfC_>TL$DmEx(G<2B7_hXnTIeXVG2=DDM3X` z1py_L7BUHlj3JW~q67%@5JJKX0wE?L31qw{RQLVv!+p3<{oVR*_RBh7a?Z)#Yp?ZN z|FieW&C_nqn>QM41OQ<3Pd^_28344e0Kiv=H>?Fe393H#EdYE2{B->2nfS*GBS{Z( z&{tdd+SkXruSAWX%e}j?d6&iM+6(BueW;@$7tBb(*GX3q`+GL^e0AW>#xU2d-OT$X z*X{OitNPyWw6FdAW{*w$)U{6!+N@dYARFy9%HF=OL1AOvK94?36F%VyaRr?H92I-U zp3#%o+vuBI zCdie7)ZMSC0Pym*F}QjXeC|#%`ja%H-)^zVtKEd~J#3&M1kv%Wjje1g;DoC<_rmuq zSfZ>ClqM#4+ZNNXqy6`v5%9H&5ABN$5y!>rfGg{XS_Z(C>C62$4ox(P*nu&=1MI2f zqZ8Fu0ATacx^N8;>{c)$_fcUU4xh@lo=RqH)6p?th{Z(!P`GaE>i3wC5lq*Oxd@*i zd(RH5S%<>Hdz-u!ga157xIq^H^6qcpI=CY!;rX9Rtt`xEbPTd^YkJDQ|H1}$nIuf!gG_f&cuHBpd2(Zt#6%&Jn2N35={n5% z8$&SRQHopJb5dmQw`%K|Br7)CWy8*$J&Ul9o#w`(Xkl!!C89|_kft+S8{*jz-}Bsc zO3ot2nkLTDknv;JN3a|mkCJW_-+9$k`K6GHNXUXp$Sc$ER?~qBI9Awh*G`P?c$VeZ z{Va%~rz;=za5fgbfr?AuDpo85ffJpTv=eBTKmDq=G>;u!qn)jTnPU+F;L7e}YPVkZ zAz`>g&*!HIjuny9D>DRSPVwV&eoWw)oa|>uHD?p__`6Nxf2*e@kx-r-Tpn zaA4fpm}u^#r#lqQ7{RK>_4Sq0-7b2L%M(*xi~?x+i$1WSy{MvWc%@8%)<@V>BuN&* zMLCN&LV=*v6g|KSdi+YhHl6R0@n+eUpPEDt^3KY|`0n^%zq{1#JKV(-V0p67a| z2cEv^p$kYcQ>|M++}SfPlyOv74?=k_-|3RL)TEKr=1hJ3N~1r0J;KA|fOL5xebe@z zy}gNvqPcuj(@I%+C3!Se#}<{MX#0ArPhIF))wpnxEPUYUW|=S8k#5w)pvuCTjUgS6 z?E|)3>D`v~H!L>R$TtTmM{ilz`z9>$DT$KA#i5xLQMrq4BorF(Ou1p2!fXQp{ zRWJbfJkHC@i``A|gcD%cwgViM@-w0-t`r)#6a-7^^&o7AO3MQ-IgVYcCN0(vzrLzv zNd7qaX@&)c#1s+fARatuiNXbQnRUel(veq=dL~Df$pmGsJAsN$zX3WRxU-NyL9>fs zo=7)IoOO1Tc1gV)rynsybA9syde!oPmTrkfFH+g+<#r^RwcuUTdJQM%KjTqm3f%G1 zkNn~%^}-IwKtas%7UxZ>$t_c(Pcu^v1TGAkKoixu^VI^FFHSnb*IIh=xnEsc-*jGl zx7+PVd8Olk!{}?RVmD}&Q8=rSKLdtU|J-`3n3aH>Cn+EFJ`_Z~wG|QL+7Au1(Io7Q zjEvHmCtxsHK0LZIIB^FudG{Edzc5r|K#l>!(2}$u5Db)%U`_Iji7ZtEGuoR#6ZBOn zK`)h;Gm3T`yOE4unq~6Gn=}8LYs;&eUSalQ+6J-Y31gAI5oUQz+bGJZde<(bVtFFV zF8&@x!j?5o+$o141LreSqA%JnGantm$*44Csxg+u2Lr`i+m01=jM%75tjQ=`vJjeWwM8CXiW+?N^1N!(HH)9C3xhsQq=Cf%0zqBc&1g#%T7UdoTmv%dH?x2`x# z-WD|7o{t^BIng@bmTO(?>+2WV`|+N2P{%%S$oSRL=j{+TyFYpPOU!8m0*Y74*AI~S z9}EW+$|fei@Mu~_!-SUU?7%bUteB{wTifZ`7Up>c+9vUZo-J-OrwR^6NSD%06PD|T zBQ4BS!U39zL-_1Anqs81IHf9Vpb`}=MPS>@eQKs#V9HMkGm52a)&3^uUtZ`Qf{{nx z>M-&Sk4@zuEdk(y`6?VcK=7Z1G=53d>92r$;osc0W5*9yz+WwV*|Kx}roWvg8-t)Q zw8n&U7A;z!N#f+?v2a%D&{MbK&v zH>D`*hpD*no6Y$+%)($beuA{I!8WwFD{cK|OKlouJmcop-DfJiYeZcj2enO;zr3Oc ze(UNa6C3*_py_zkBL-f1EGcC+pR+7|e{*Z=CPl+zxH4d`Imbidf8xY&dw%|<2yLKn zOM<%8tBwRR3Pc^)NC|(77C7P~@h;G=Z9^e*ED;@wt}JRYt9r`oR6eGQ1)08MU>_=R#4&3_D4~62 z5FWWkY<@%6xWC-1>Zu1*vD8Ds3<)5$Aw7Z1zidf2jeh^oI!HOoiZyf3{kiM;xX8{= zohUr@!{!%;zrcQm+}yQiMpr*4|J+mTUT|>b*GwyQF@5mqeuLjoF^Xf2kD9)! zZG1+Kd{`~Z;3yYg+}v78Q%ZNaJKBeIdk^nhmfBH0#IsNDv2X(j8JDK&akoyvun?kXRtaTEOYVy82hRdu_T~QuO*M%&Pra{niXXH4xgeq~(SJGuX8n1xF z^9EJJE|=^$aF$OE%NA>RM@?ntC)hGF=r50FC+krIi%UI>za5Uc;Ogp15_74s-9Lfl zS`bO%IYzRw&F&h-%>EYS`Z%6djhy4)Uza?CCAApGf;f-Q_o+BfECU5gV989zb@N2s zy&#Xu%GjI+Mhyds^ziVwyejt^K`r}7MFjyVP?uM*{atN?k7Af1X6|EJAgoS;uman6 zm(tZ3&Ht&7p8g``h0z1TRAXVtOK_UPS7lMIy`XQ`ytxmjao+DxQu0%|FXuVh-m`OX z0ql~fP5>MRuf7LfO@C#tplCG|7%Ak>xOS1NBK_ngP_+i%RjbHgx4?+=)}XYF*xiEW zB0BVKOw{T;jePAJPvntF%p$iIP_H#5S zzU8TvS{n^M-R;YY_~$uUqhQss-`-Uz?Cqo1=RTHpzlxz2^3~ojnA~*@lug#o)TZC@ z>29F9U*uHAfI9tElBKkVSx#Eo6MRPf2q0BED31V+Bq-v%aAA5tt>=%EIws6Ho}FK* zZ&m-VwUIIPEx~qNT`DwI=`nZDPRu3B!=_ zZt*4D<@+-xg~r!^Uf)6p*zxOK=C>-Yq!Gf)?A0JWmVYW$#y15F-i zIPh=dzy(MLK{b4H!py+|V&zAE2`-v$HM?=rndf#ZixwB!cpj&4#~T?PQ4(heRv&V# z5KYk&T&Yx=!$>Y2T$x6)m%Fm?-JPAM_bEiIA*FJsv-bK7{@b^24e=?IzxDR@iI&8= zdIa{PJw}H+p~=!EVhxHaPBZ;$&aJF04mrU;c=r0GW8iX%r)N*Kf11Mi&XJ_cbO?cY znrZ*Xj@N5UZ9^TW{7eP_g~4dcQPq!fE86Poc;@T<{rw5JMIyM5P`shDrl!Wz(~~1p zhGm&Red2kPr^Y$-DR@KV=1rT9#7C+46A#<5n7FuP8H9uI^_9197+!lNbMuD%LH%Bt z7+*^s_25B)AlEuSi!5zNxw^T@=f|5VNfO&^y1Vg^prhEf7Pg{~d0+V#b)5nTY;a#_ zdOFbS+_|~AIq)a<1_sUqW}>y=D~h`KLu_BF`3MV4_oMTdb9Ev6xtkm?`H9C zv&=W``F0W>N43!27mALk@bMJxP}CEN3DNv97K=6gX?$lBNl$lEvQo?)HWfv{raRml zFB;0%u9D#b#DUaQiKN*&I-Ywlr7huk?S0sst_O$1GmD5TE07 zFy(TB15FU<+@2En)G<%1a*K+JWJ1aC@UR`n-r8C?%#k;3Xm!rgt*xuG*thQm<69S` z>O;AOg+*9j-PU8rcJ5S}#0x@O0^2PttR;cAmP3bMO+9gs_?~O@N5#GXF)%drV&n0F ziPKJ4EV25?fdhUvtZtQzx74<@lsE>Bn?1dykVJS?P|y@LMmQm~IO_t1LQxbEVLE#{ zl;5&@zUty*NK$=66-wA9Z47QH3azWDDS!Svu>PQ|SF-2t@kHMg@yBeeBk5vseCq1E zE*J6*3=H-@OhOHVIz^GM07#|@jSC` zKJ6dFBe*Y5y1L$_>)~hX($dnrPM&m}jzuQ(CvO{~P;z2ZlY_08Ge1xz5*aH?cEZ`j zsT&brbXJ$)u0(`}h23A$WwQ+vP=z+_$3N#Vyl1iDa(EIxG^T+ z_iA4g$3x_3F&&u@z+?A!b#(<*aX)h@;I>@bQe5=q38Gfq+r0p=MqB+Kfm{9k{a#dQ zooMrk&x^COz6iJlG$Cq2kETL^Y0=rK!{u`Gk%NQDU}o6a#>HW>F+a9X_Qrj^8i|-Z u$pUirg?)c*vJ9Cs%G literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4b091658c9b94936d207e34c34ef237670c7c733 GIT binary patch literal 11392 zcmeHNX;@QN8otOVwg|!EsDP4o>`1jD3MvRBX;narfE}hrmJp~c3PMlV5n70RXT%as1d{0Kg&}0RG^yehv5}uKM&Q0I&g09Q*vQxRQBJ zVo&K>{0mvIwl;J3+Wosuy(nOq*}MtnDs3aOwlg@}a>a=;Ix0VmM#g`o-UV=KX535g(ukT;I|M(B*R@)EO99V7NGqX3g z+1~u1BsjrX^H8z3UjXXQ{GP43+9J|!U3b0f;u%jB2g(J!E z4`Vd|FuzL$su7WY3aJxclMUE;ZOF~%6Io+1=3h65>OuBN^IiS>o||i;hUM%P-OrEq zKzpW0vIj*_N*s~_1%MaK#?;ZX<=nvjE=PsX9qJyr z?@aY1t=r|k?mCio$wn;@m;*0d6gEcyKz%TgN6S=uo*#VFDt&~c&JBT-psxG?>BihTU(Z*Sz%!RGuZ^>+!m}=?mt-;z8}MD*6Ncf$`RXp3h$AiY#>?}vln;X<(ngO$ zD(|OGd^24};Eq#LT&P%Cl){=I`l-S?h%P87mbNIEJ~#H-Ig(SDqf&eyfu`xja0ybX zA2d_BaKDWo66d_N>=OS9w8S;$m2r86KH%_i|FCEAEtv?z8;t@(6Y#hiCSo~X!3?8k ztw>7Lvq712i5QX=`K(zoDpD+o*@%qU$)lZ}wB;eu7OP;%1D`yEUOj=NEV3{dZtd(Z z3^=~yk0dQkrJqIl7w)AgACgzbr{QuWNi*{>&pOLFos&8YCrA~;P_6naBsx5yD>qwxO2TktuuUh^q*xgXtAa#%51l`Lw&P~UzJA!!%}HPpW#{9=cot^43GF-q|2 zu74r-FsQDfj4~RI-!yfL4M9vUxYJ}mcIP`mFSc)VA`@Q)xN~Z~oXW8B?z3ml(&cBL zBCBXBnl=!zqCAnmb33m8b3aG?+v|T+S*5jw-9lvHUNO+J>$h+3>Y@r7`NIzDCMhY? z&rr>23nI_CnTNSm!4-k9*+=`p!JVP|KD=OmyTVi)g&K|OytEExb6Ue=|F+fsx*nhtgj1dc1ZnLgc4T^dVBhu0@@ zngSf$BZx8|1gV)nVC4r*>4|Kxa!}s1GpKSO2bR_+vV(J`FDxs!U`86FaL*@xu1Q*E zHR$KfrKDc9S~HD)&dbt@nX@~BearB=HwxKZ(9I2BfYCg0MU-uBt!Abtt#q)V`h{Gr z;R$q&^mf!B2lNz#{B{RD7_vK@a!K$}inX2N$$PE>&@Y1Ef;%LNq=~L+cY-g;@`6fT z7iSIl4A6=CY#Sy3W4BfqT-#u|KZd>nnpf`}RzKhAfbo{K+gkLIM{DBf!h=)85d?95 z5L}~t9mFFUuD4?P(vzr*KUI{4f&oiXYw2G4Z*8yUlU6$2SygBRUjEh`;(1PF8JJ)R<+D^IwW~Wdg&x_9lAySm3r5cH+)2R?;8#qJpGlKA0kKLn0{rGmD2rz%ste8tj0TzKsOBR7Hz zMbb&qQK^Evae6*GEu*yD?-nUp5`PXUYC=Lz{Ncnio|fNj@#2Pu@7K)&ME z)#(?vhu0*KFGBW^bk!ns#!NP9qy?{dicXz*l6yL+)H8Kqd=>DIy@P8I?1LWP4F7ku zM;(}&F!NFeqGvcFfK_m8oWJc0;X!nd` zE)cPu^2)HQC$O44XtTaN*Lo(zNNB6$`_IJa^qX$JV8nCqXA%ufq9N!8ru`Mu-jWdx zOjX_Qu^2KfoM|)ozt{*TgxAUeV8eFfxd70WOnd4k;n>Ip|IMEI0)2j*6U0e3>yjOP zZ%xH#mYdFffqMT=)286i`nfM^>`NhvU7i7N9H54M2j{LZDJ=h|$oh!d+dKCry0H8X z;U#8cUw#sktP9zEWGwN*w|yK@>Y_l4wQi7>5Y2$>^}n48F}3eb$C&29G!J0Jn&RUB z8y6zIm}CR{+LV*0rhK3fEOV$uF zw`kWkkA4_&SxKqE(3Wzbn+tE|*}*PD}J}U3DFEM^4O`d z!|%@Py-2HVsN+5T>vaHzK+x66)kXIzd+O_?pRNO?Lvp5slFrMlSl?e$QxhB<%+u-< z@*H8II4SkP_CkgrtRcy2!v=3$vOzX=w>LcvizRBkc&PAjT^Fwpxmz_Sa$v==kT=r8 z_eyE5u5$T3x8l5(CSaa%ZK8zqAX6hK9z*#_rzjVlWsT`lB#dNBr$;6+4}7 zwDuOetE4=`eD6?vYGP$*u;QbYdI|-9QN|x19~X8{?r3U;SZ^TeL2Vbhn1~QEgBqh8 zbZb@-DbmZcx#=02eh3afeMexSk|KBC?Z}0Mg@xTHr)V@^|B^r&o|)lrxil9Vc1|wv z_u;|ta?9@o^3b}mQ-*ux<>gw1ip^%b^A5YYDcC$+)B0C_dDgXcbg?>CFjQxI^yrQq21lGczALuZ+1X7MduZ>d$1j4?pu|ta+ulV+q?f&e1CmQ3#byXU zOHZd%d+*;LabSGVpp`0nl*$Y~3_Ejb;}6Z`qO!84WIowP;rx|93H8b#EVehP=!(SEH|F(Dvz(Lsd@VNacsS-_Kj-SpKz4$tfgNI(&5cf6}Zc*iFstP zy}kYJy95*p#j${JsVQ-NWw4Iu{T>IsbvMxZxeA0<)6+w3PESHNXQblslrv*>qMVP} zoXmyNfq}MM2x+D+CnpE#>kAjApoy}#-#K6~I!aTM=b~>_?8NwlgyORMPbw=D&z}zo4W08EN1wcvmj`w5j>wQ7NU8ou=#zUzC5@M29#w}s z!Vk7wTwYx^UuBl0JCfW*z9e-5&S2v=EOSyunqX)vroQGFPk4j z_ufh+wl0KZGzczUD3J%Z4sRj+=rZ$u*FD&2+d^l5>+Q$Q0-aw*`&L=7fh4=-BF=9}^TIyIwF zfoMstPVP5IypYuir)Kr3n?OYXU`6EVzIKwG4OkjaKK?X&i&4J61V>>o^zn_OoK8)Gh*QpQv+jB#Kpl>lIZ2>>ubq^Ugs z%YmsqFtrCpSortbgZGTX0PmPOaTC0NabSX%KQp|1zqv8#UtGYSavEI`rxw?Ze8)|f z)mK^UPK!K1AHgR>?DH$mJqiGTu2ENzM%cc`8QnN{jcYyPu=HHw<{O(%I6eFrdtf_s z@H80!@*Ca@QBmyxp!LU-EWBiYXLT9r$@Sd0G1Zt)L84uy#SfL;o*RJenbjaS5q%?q zc4p!^@m=Y`h$dD0IAOov-Sw-|4VFObhjbi&_~`XyoUN5}hnjJJD92s#HQyc_d&bCQ zY~N+nk#=S=Fe%OZy?&&GnZDmOO4+I^k0%=ybx3U601grgTCocvpbg6ZzO33ho#TEW zp#Dvub#!strvTvB`-Pn}td?JXOcmOA_Pq3_3pw|8T3?Wp{uPaa*zUG&lNU&gWDn2? zi@b#T?--y`Z&)|GmI~$=bTg~2frH%L01$KBXwTPu6sCm^zP8487I-$B6=Mq+XcJOXMTzOI#R(HouHxY>w zs+BlKvRB(AE}of0<9^tu&4N;b73J&Z8f;D8jJt@w57h z0$)uZ2H(?L>H)r(LYRD&M_Q`LoR+j0LgSd|g;$+6k+s@qN33+Wtb^>!^~+R}q$oTw zw0{1=xTe>GlRg(N(iBn&Q%XJtp?I=0S40OLBqJGCJ3{*5DmX2+59G>PpPYvnO@7(| zK@j@6ag@f>-6JeL2a_@Aq#fW3>$7wk2Mlq(!im^nCt6WIpq9fkm1eGCdcj4D7WqXt zSG(AkXL_=fG>Rnx+hHjZ)Fw@I+K?unA2ZB4UWrYJWqr6hD@F#5rcI zj60XfHFMR?iR^GT1>4?!(IPi*RoX05LZ#m7$?I{wB{hZ(W(@6=TgzfUG>srmW!rn$ zJEq9ntgUHTSryZz9=Ymt(B&Z^Awi23{`UAux%WJe?L^WBcnJ?iaL8V=dVZo^y-b%i z{@Sou!*+neaOck}e(SIzEk8iPaZY<&c*;H;fkiHm+Ud@D~)f&72M^?p2g)cXez5N0J6H%HWwJXuhMJ z_APNQS904DVrf%(D@&7#(#3JH*x8><;YufH|M%FxX^-C~Qe%b{R zsryfWG0}n{&Ruej(yy=)LRGQr$ByEcaOLPkyG1cV{pAm2PqZy8#;8oP4Gh;2^3t|1Z3AJt{@qwhJO9VYb<4=9?d^N zjUr0wMjUa1Bq%W!%mKHIfnOd}H_Zf1Af*m0e=`d<|R5SiBlUn#El8 zQI3vJQdrul<+%|~nNPA|lhx>>)E=y&Y#J8Vck@sV>W0(}l_>!~`rQpkqe;9#grwGa z7?~yZVB06pPZd)ewNy8#j3`^J>ac1ibY3BXfl?U~+gp+(R8NyMgA~o!^&lR)VJvI) z8|vYipL5JOtxc(O#@zI|e!ZtC68mIF?sp;<@qGVeCYUj|a~)wTcusiJQji&KbeI{ao@m}uyA8}BbQ<%@ zRL*}g;q@&DHS)QnH$dVV7Q%19IDxjbdcT1PjQ z6))?|Nm_Vh#!~$b#8?X}@Ye3XcQak_FUxOTDt_1!=k1h#ZM|bC&)v2W*ncXJhaLH4 zOc~L{X$RpPY%pM3>k_gwavO?H+m>Fs29=CA!9|Ju@+tC26xb6Ol`0uc?VgO9?t^3Z zUtMntV*a&I0ok$H_(4qz8~=$Z=pQLJO!HvVJQz&uKW4jZT1Nd35MKXJs*O*i0}=qX zeqh`eVB(8SVEw8ir%niLw1>$ZFC9#c~9z|;MuQ^pX2_zw=X`$x3_ZU z;FlPJw&TS;o5Ry#ZdFm-i~+x!jkU~^PTWbl*;)VFH`*5BLe0-L)V%GBqmB#}%LaV} ztYpPS^WQgvnB@AV7?U4NegMl@wkZz&PsTwsw4Y+&U!HJ2d>HB$#rQ2#CAD_GZC`K*YeuoSnIN z>PSF9KuE}7O-zo?|0*o=bPtrm3+DN(&w5+aY8&cA55B$vz!8X+6>LpOX;p81oow%x zn3xy}QA!8-rb_c?G#U-$*+i@QgaSu+Sh|e)i$ihGRCq(8<<_mRbgW@vqOcE_mXbnP zg^D60BD8D~2llrILvZ^L<0{spzV(ki{LkdO97Sv@k9Z2*lm5 zb~ZIbthN&LN(tX-8I2J42Q_|cr`@;~fzi;z%}v#)7EfQ_6E~*JR5Ij8g`K&O@bK`w zJ9M@B)T0E_$jr=`P{?v)rOYa(jvW=j@d}HdrW9dyykJA=ojZ3{7gc;d-%I4<;jzdU zX`9TS`WIN$*44S}+xL+3&M}ms>w$}lOTti{^^qexcN!ei74huYJ{K1cRjj8g*Za}b ztswM=68m+ejE36U*&&4_Qf!9!V;qiN19NweIw*KkqaTs)aB&lApQJ&#mOkb!sJhO7>t(Q z)O6TWDViIhE-yRi@9hj1(x)z=%s*-(9DNTll9W9t{27^Wcwk^4jw*RAF|GjgE~O-$o}lLs z4-X?*n!07nqpzhiGZB&DE^s_{0@7lL1XJPJGYg4CLPm{_62NTm@=QrdD@yykZ}LUT zn?~z_w412)&T8B5le0gaTtI+k7z}&oGgiQpEynr6CV=F^KpbPXmm5v|;%MM!)t^RR F_$O3@gJA#w literal 0 HcmV?d00001 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? From f0e3f1a319cad84be9ceaf9ff7acb23fbc416c6d Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 17 Feb 2026 14:27:36 +0100 Subject: [PATCH 04/12] :bug: Fix watch script in wasm --- render-wasm/watch | 2 ++ 1 file changed, 2 insertions(+) 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'"; From cd4b9ddd47942bd7779f3b5851dfc44eee24c09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Tue, 17 Feb 2026 14:32:03 +0100 Subject: [PATCH 05/12] :sparkles: Add regression test for bug 13415 --- .../data/workspace/get-file-13415.json | 135 ++++++++++++++++++ .../data/workspace/update-file-13415.json | 18 +++ .../playwright/ui/specs/workspace.spec.js | 22 +++ ...is-not-removed-when-deleting-a-board-1.png | Bin 0 -> 9528 bytes 4 files changed, 175 insertions(+) create mode 100644 frontend/playwright/data/workspace/get-file-13415.json create mode 100644 frontend/playwright/data/workspace/update-file-13415.json create mode 100644 frontend/playwright/ui/specs/workspace.spec.js-snapshots/BUG-13415---Grid-layout-overlay-is-not-removed-when-deleting-a-board-1.png diff --git a/frontend/playwright/data/workspace/get-file-13415.json b/frontend/playwright/data/workspace/get-file-13415.json new file mode 100644 index 0000000000..1ad5dcb9ec --- /dev/null +++ b/frontend/playwright/data/workspace/get-file-13415.json @@ -0,0 +1,135 @@ +{ + "~:features": { + "~#set": [ + "fdata/path-data", + "plugins/runtime", + "design-tokens/v1", + "variants/v1", + "layout/grid", + "styles/v2", + "fdata/objects-map", + "render-wasm/v1", + "components/v2", + "fdata/shape-data-type" + ] + }, + "~:team-id": "~u99e49e93-362f-80ef-8007-3450ea52c9a4", + "~:permissions": { + "~:type": "~:membership", + "~:is-owner": true, + "~:is-admin": true, + "~:can-edit": true, + "~:can-read": true, + "~:is-logged": true + }, + "~:has-media-trimmed": false, + "~:comment-thread-seqn": 0, + "~:name": "BUG 13415", + "~:revn": 14, + "~:modified-at": "~m1771334256704", + "~:vern": 0, + "~:id": "~u0472abff-2573-8186-8007-961793e53f45", + "~:is-shared": false, + "~:migrations": { + "~#ordered-set": [ + "legacy-2", + "legacy-3", + "legacy-5", + "legacy-6", + "legacy-7", + "legacy-8", + "legacy-9", + "legacy-10", + "legacy-11", + "legacy-12", + "legacy-13", + "legacy-14", + "legacy-16", + "legacy-17", + "legacy-18", + "legacy-19", + "legacy-25", + "legacy-26", + "legacy-27", + "legacy-28", + "legacy-29", + "legacy-31", + "legacy-32", + "legacy-33", + "legacy-34", + "legacy-36", + "legacy-37", + "legacy-38", + "legacy-39", + "legacy-40", + "legacy-41", + "legacy-42", + "legacy-43", + "legacy-44", + "legacy-45", + "legacy-46", + "legacy-47", + "legacy-48", + "legacy-49", + "legacy-50", + "legacy-51", + "legacy-52", + "legacy-53", + "legacy-54", + "legacy-55", + "legacy-56", + "legacy-57", + "legacy-59", + "legacy-62", + "legacy-65", + "legacy-66", + "legacy-67", + "0001-remove-tokens-from-groups", + "0002-normalize-bool-content-v2", + "0002-clean-shape-interactions", + "0003-fix-root-shape", + "0003-convert-path-content-v2", + "0005-deprecate-image-type", + "0006-fix-old-texts-fills", + "0008-fix-library-colors-v4", + "0009-clean-library-colors", + "0009-add-partial-text-touched-flags", + "0010-fix-swap-slots-pointing-non-existent-shapes", + "0011-fix-invalid-text-touched-flags", + "0012-fix-position-data", + "0013-fix-component-path", + "0013-clear-invalid-strokes-and-fills", + "0014-fix-tokens-lib-duplicate-ids", + "0014-clear-components-nil-objects", + "0015-fix-text-attrs-blank-strings", + "0015-clean-shadow-color", + "0016-copy-fills-from-position-data-to-text-node" + ] + }, + "~:version": 67, + "~:project-id": "~ucd8f7672-e5d1-810f-8007-87e124eda82a", + "~:created-at": "~m1771326794644", + "~:backend": "legacy-db", + "~:data": { + "~:pages": [ + "~u0472abff-2573-8186-8007-961793e53f46" + ], + "~:pages-index": { + "~u0472abff-2573-8186-8007-961793e53f46": { + "~:objects": { + "~#penpot/objects-map/v2": { + "~u00000000-0000-0000-0000-000000000000": "[\"~#shape\",[\"^ \",\"~:y\",0,\"~:hide-fill-on-export\",false,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:name\",\"Root Frame\",\"~:width\",0.01,\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",0.0,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.01]],[\"^:\",[\"^ \",\"~:x\",0.0,\"~:y\",0.01]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^3\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",0,\"~:proportion\",1.0,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",0,\"~:y\",0,\"^6\",0.01,\"~:height\",0.01,\"~:x1\",0,\"~:y1\",0,\"~:x2\",0.01,\"~:y2\",0.01]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^H\",0.01,\"~:flip-y\",null,\"~:shapes\",[\"~uaef184da-e9c1-80f8-8007-961cf253d534\"]]]", + "~uaef184da-e9c1-80f8-8007-961cf253d534": "[\"~#shape\",[\"^ \",\"~:y\",286,\"~:layout-grid-columns\",[[\"^ \",\"~:type\",\"~:flex\",\"~:value\",1],[\"^ \",\"^2\",\"^3\",\"^4\",1]],\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",0,\"~:p2\",0,\"~:p3\",0,\"~:p4\",0],\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:grow-type\",\"~:fixed\",\"~:layout\",\"~:grid\",\"~:hide-in-viewer\",false,\"~:name\",\"Board\",\"~:layout-align-items\",\"~:start\",\"~:width\",298,\"~:layout-grid-cells\",[\"^ \",\"~uaef184da-e9c1-80f8-8007-961cf50d67b4\",[\"^ \",\"~:justify-self\",\"~:auto\",\"~:column\",1,\"~:id\",\"~uaef184da-e9c1-80f8-8007-961cf50d67b4\",\"~:position\",\"^L\",\"~:column-span\",1,\"~:align-self\",\"^L\",\"~:row\",1,\"~:row-span\",1,\"~:shapes\",[]],\"~uaef184da-e9c1-80f8-8007-961cf50d67b5\",[\"^ \",\"^K\",\"^L\",\"^M\",2,\"^N\",\"~uaef184da-e9c1-80f8-8007-961cf50d67b5\",\"^O\",\"^L\",\"^P\",1,\"^Q\",\"^L\",\"^R\",1,\"^S\",1,\"^T\",[]],\"~uaef184da-e9c1-80f8-8007-961cf50d67b6\",[\"^ \",\"^K\",\"^L\",\"^M\",1,\"^N\",\"~uaef184da-e9c1-80f8-8007-961cf50d67b6\",\"^O\",\"^L\",\"^P\",1,\"^Q\",\"^L\",\"^R\",2,\"^S\",1,\"^T\",[]],\"~uaef184da-e9c1-80f8-8007-961cf50d67b7\",[\"^ \",\"^K\",\"^L\",\"^M\",2,\"^N\",\"~uaef184da-e9c1-80f8-8007-961cf50d67b7\",\"^O\",\"^L\",\"^P\",1,\"^Q\",\"^L\",\"^R\",2,\"^S\",1,\"^T\",[]]],\"~:layout-padding-type\",\"~:simple\",\"^2\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",322,\"~:y\",286]],[\"^10\",[\"^ \",\"~:x\",620,\"~:y\",286]],[\"^10\",[\"^ \",\"~:x\",620,\"~:y\",552]],[\"^10\",[\"^ \",\"~:x\",322,\"~:y\",552]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",0,\"~:column-gap\",0],\"~:transform-inverse\",[\"^>\",[\"^ \",\"~: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/specs/workspace.spec.js b/frontend/playwright/ui/specs/workspace.spec.js index 8c20a9efbe..2d9188d171 100644 --- a/frontend/playwright/ui/specs/workspace.spec.js +++ b/frontend/playwright/ui/specs/workspace.spec.js @@ -492,3 +492,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 0000000000000000000000000000000000000000..199d021532d30e10175858a4a3846ac600f18686 GIT binary patch literal 9528 zcmeHNSx{3~7``YXrBdx8aa0Jcqf#}AiV&0ltwPa;5{E6-7=mcUKp-ee2oPXu)w0Pj zEk+hel|l+y0#=q-2w38Rl%+~o!V)EHYLY8Lu0gUi7uzSF>hz_Z^Yov)%$#$+^Znny z%t_zt?`vzb(guPc+daFz10ZN|8U$IoSuZfZiKq_w0D_i5d%QmlN+?qGZLxqHmqC}X zDnZ~E2j60!T5*-9G5-cZ&FrXo>*)A{1v=PmeRTf$y#*^#oAynb6>1$n1fNkH04#tG zW*Pu50qOu$5x4;el4wu_$pOfj%rpSG;v443M^Gn%Y=D@cFaR+DVq&HN5R*3)lh^CB zU+R@TfA<2+$bu5~b%+2gz~BBge*bYgnK}Rq_N~lr|-8m3&O0Kb=B{Bazwo{KKz(l&zoq)K#n{Ak|$taRRjPBfCH*i z|6?A&V)8okB>@?FF8~eA|Mp({vfKEk#PON@S_HX56{!?Wrr-08xw((#^6q6$SY^n1 zjk>cE$pZmTBMwhC$ZH1b6qV)W+{eFRGB2|Avs$ci@=i@n&8_1E)&*_67$BGZ?8) zf)rEluP^qzro2dDIjQX}=A&>Jaeo1=tW1~zc@T+py4dOq`T51n7$(lDq@+Z^Mfy1k zp3u6>+1XjCR4NR^S8^OY_9wuNm+kp&W504>1VKC#Hk)))_Yn61xm==E!<+DUqk+vA z3Wbr8k;DjBYG(WaJlwR!O?UtF+XFcb&$HR*vWH9)vMY<1I$Yhz7r4zY>1e+WgGim% zqUQj4ihFu``t$qq^742B`HRUv0=76iy9Y`K!#8gwozUyjKf;SDD?_MM(N$7tXeb`R zs-J8K$@C+6x`r*t6>yDkaYp$rCtMiW)MOiLN)>UtJC^+=^sA*~~8cDU!vASs&R z#w08f?KRSoBR+`HziK##5#{bXVuo()E6=K}t?B6Oq);dX&*Z-D?x0QW9qr4-V&&dD zckjk>IGvbK636he<}zIDF*keTI5(QtSUdiJOeRmqP2+I50l28BNZ&3>4YnNnZhcZ= zVIjuO&NU*VRKzpn-M)R>e6B{L@#f7`ZA^o_n!f9haA@k-Mg)W!K_&Ry(abd-hC+?Gn8n)1+^uq`Ge3?y~I! zJWgZd2m}l{xKr=d8Xxb#jW|5oSA7VZpe~n4R-HP9oe~ooVi81LS7$sxr`y{bI)A1S zlM>JI`f}~z!DB6W-J)&ioXvO_B9W4nL#0xQuC90-PRp_!`@Hmc1$=_3WR7QJa21-I zp{8SpswxjSxDl&PB4kF&?8BR7xw*MQky@j{7idSN-p39<6=#)|mGPUN%i3*y9>+vQ zG3Yd0G^u`SPGP8(NF+_B+4JYms|hTYmzjICRdV?NIqAnpR`O*_bRAGqJK Date: Tue, 17 Feb 2026 15:08:30 +0100 Subject: [PATCH 06/12] :wrench: Run cargo clean on devenv start --- frontend/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index 052fb1c580..3c6ed1439c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -40,8 +40,9 @@ "watch:app:libs": "node ./scripts/build-libs.js --watch", "watch:app:main": "clojure -M:dev:shadow-cljs watch main worker storybook", "clear:shadow-cache": "rm -rf .shadow-cljs", + "clear:wasm": "cargo clean --manifest-path ../render-wasm/Cargo.toml", "watch": "exit 0", - "watch:app": "pnpm run clear:shadow-cache && pnpm run build:wasm && concurrently --kill-others-on-fail \"pnpm run watch:app:assets\" \"pnpm run watch:app:main\" \"pnpm run watch:app:libs\"", + "watch:app": "pnpm run clear:shadow-cache && pnpm run clear:wasm && pnpm run build:wasm && concurrently --kill-others-on-fail \"pnpm run watch:app:assets\" \"pnpm run watch:app:main\" \"pnpm run watch:app:libs\"", "watch:storybook": "pnpm run build:storybook:assets && concurrently --kill-others-on-fail \"storybook dev -p 6006 --no-open\" \"node ./scripts/watch-storybook.js\"" }, "devDependencies": { From f00b222262ddba48747d6416dd79393c8b0d84a0 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 17 Feb 2026 16:23:04 +0100 Subject: [PATCH 07/12] Revert ":recycle: Replace some components with DS ones" (#8384) * Revert ":recycle: Replace some components with DS ones" This reverts commit 6879f54e5da45b38173c3e2660d88b4ea6939bb0. * :paperclip: Restore missing styles * :paperclip: Fix tests --------- Co-authored-by: Luis de Dios --- frontend/playwright/ui/pages/WorkspacePage.js | 8 +- .../playwright/ui/specs/design-tab.spec.js | 4 +- .../playwright/ui/specs/tokens/crud.spec.js | 6 +- .../playwright/ui/specs/workspace.spec.js | 25 +- .../styles/common/refactor/design-tokens.scss | 14 + .../app/main/ui/components/file_uploader.cljs | 4 +- .../app/main/ui/components/radio_buttons.cljs | 107 ++++ .../app/main/ui/components/radio_buttons.scss | 79 +++ frontend/src/app/main/ui/dashboard/fonts.cljs | 12 +- .../src/app/main/ui/dashboard/import.cljs | 10 +- frontend/src/app/main/ui/dashboard/team.cljs | 10 +- frontend/src/app/main/ui/delete_shared.cljs | 27 +- frontend/src/app/main/ui/delete_shared.scss | 15 +- .../src/app/main/ui/ds/buttons/button.scss | 1 - frontend/src/app/main/ui/exports/assets.cljs | 2 +- frontend/src/app/main/ui/inspect/code.cljs | 44 +- frontend/src/app/main/ui/inspect/code.scss | 16 +- .../src/app/main/ui/settings/profile.cljs | 12 +- frontend/src/app/main/ui/viewer/comments.cljs | 5 +- frontend/src/app/main/ui/viewer/header.cljs | 159 ++--- frontend/src/app/main/ui/viewer/header.scss | 79 ++- .../src/app/main/ui/viewer/share_link.cljs | 54 +- .../src/app/main/ui/viewer/share_link.scss | 28 +- .../app/main/ui/workspace/colorpicker.cljs | 47 +- .../app/main/ui/workspace/colorpicker.scss | 46 ++ .../src/app/main/ui/workspace/libraries.cljs | 54 +- .../src/app/main/ui/workspace/libraries.scss | 100 ++- .../src/app/main/ui/workspace/main_menu.cljs | 3 +- .../src/app/main/ui/workspace/palette.cljs | 37 +- .../src/app/main/ui/workspace/palette.scss | 48 +- .../src/app/main/ui/workspace/presence.cljs | 2 +- .../app/main/ui/workspace/right_header.cljs | 87 +-- .../app/main/ui/workspace/right_header.scss | 140 +++- .../app/main/ui/workspace/sidebar/assets.cljs | 52 +- .../app/main/ui/workspace/sidebar/assets.scss | 91 ++- .../workspace/sidebar/assets/components.cljs | 34 +- .../sidebar/assets/typographies.cljs | 25 +- .../app/main/ui/workspace/sidebar/layers.cljs | 13 +- .../app/main/ui/workspace/sidebar/layers.scss | 36 +- .../sidebar/options/drawing/frame.cljs | 26 +- .../sidebar/options/menus/align.cljs | 108 ++-- .../sidebar/options/menus/align.scss | 26 + .../workspace/sidebar/options/menus/blur.cljs | 11 +- .../workspace/sidebar/options/menus/blur.scss | 14 + .../workspace/sidebar/options/menus/bool.cljs | 74 ++- .../workspace/sidebar/options/menus/bool.scss | 29 +- .../sidebar/options/menus/border_radius.cljs | 4 +- .../sidebar/options/menus/border_radius.scss | 6 + .../options/menus/color_selection.cljs | 19 +- .../options/menus/color_selection.scss | 4 +- .../sidebar/options/menus/component.cljs | 34 +- .../sidebar/options/menus/component.scss | 9 +- .../sidebar/options/menus/constraints.cljs | 21 +- .../sidebar/options/menus/constraints.scss | 32 + .../sidebar/options/menus/exports.cljs | 11 +- .../sidebar/options/menus/exports.scss | 8 +- .../workspace/sidebar/options/menus/fill.cljs | 21 +- .../workspace/sidebar/options/menus/fill.scss | 9 + .../sidebar/options/menus/frame_grid.cljs | 31 +- .../sidebar/options/menus/frame_grid.scss | 24 +- .../sidebar/options/menus/grid_cell.cljs | 109 ++-- .../sidebar/options/menus/grid_cell.scss | 15 +- .../sidebar/options/menus/interactions.cljs | 58 +- .../options/menus/layout_container.cljs | 600 +++++++++--------- .../options/menus/layout_container.scss | 105 ++- .../sidebar/options/menus/layout_item.cljs | 227 ++++--- .../sidebar/options/menus/layout_item.scss | 18 +- .../sidebar/options/menus/measures.cljs | 102 +-- .../sidebar/options/menus/measures.scss | 37 ++ .../workspace/sidebar/options/menus/text.cljs | 258 ++++---- .../sidebar/options/menus/typography.cljs | 46 +- .../sidebar/options/menus/typography.scss | 9 + .../sidebar/options/rows/shadow_row.cljs | 5 +- .../sidebar/options/rows/shadow_row.scss | 10 +- .../sidebar/options/shapes/group.cljs | 2 +- .../sidebar/options/shapes/multiple.cljs | 2 +- .../sidebar/options/shapes/text.cljs | 9 +- .../tokens/management/forms/shadow.cljs | 28 +- .../tokens/management/forms/typography.cljs | 29 +- .../workspace/tokens/themes/create_modal.cljs | 1 - .../app/main/ui/workspace/top_toolbar.cljs | 184 +++--- .../app/main/ui/workspace/top_toolbar.scss | 18 +- .../viewport/grid_layout_editor.cljs | 11 +- .../viewport/grid_layout_editor.scss | 14 +- .../ui/workspace/viewport/path_actions.cljs | 160 ++--- .../ui/workspace/viewport/path_actions.scss | 18 +- .../main/ui/workspace/viewport/top_bar.cljs | 6 +- .../main/ui/workspace/viewport/top_bar.scss | 5 +- frontend/translations/en.po | 66 +- frontend/translations/es.po | 75 +-- 90 files changed, 2638 insertions(+), 1646 deletions(-) create mode 100644 frontend/src/app/main/ui/components/radio_buttons.cljs create mode 100644 frontend/src/app/main/ui/components/radio_buttons.scss diff --git a/frontend/playwright/ui/pages/WorkspacePage.js b/frontend/playwright/ui/pages/WorkspacePage.js index e2e12ae2ad..0aab8bdd4d 100644 --- a/frontend/playwright/ui/pages/WorkspacePage.js +++ b/frontend/playwright/ui/pages/WorkspacePage.js @@ -198,10 +198,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", }); 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/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.spec.js b/frontend/playwright/ui/specs/workspace.spec.js index 8c20a9efbe..02cc3958f1 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(); }); 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 c1aa638671..f84d694893 100644 --- a/frontend/src/app/main/ui/dashboard/fonts.cljs +++ b/frontend/src/app/main/ui/dashboard/fonts.cljs @@ -17,7 +17,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]] @@ -184,11 +184,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/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 61a736188f..f4928f67f8 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5426,10 +5426,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." @@ -5720,10 +5716,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" @@ -5776,30 +5768,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" @@ -6400,30 +6368,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" @@ -6869,14 +6813,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" @@ -7715,7 +7651,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 daa6c2cdae..683f73d6c4 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -5407,10 +5407,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." @@ -5696,12 +5692,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 @@ -5752,30 +5744,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" @@ -6340,30 +6308,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" @@ -6809,14 +6753,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" @@ -7655,11 +7591,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" @@ -8216,7 +8148,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" From b8f3bee3aca2ae86eba0848279fe03c784fd4e41 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 16 Feb 2026 17:08:18 +0100 Subject: [PATCH 08/12] :bug: Fix problem with flex layout auto sizing --- .../workspace/get-file-13382-fragment.json | 22 +++ .../data/workspace/get-file-13382.json | 131 ++++++++++++++++++ .../ui/specs/workspace-modifers.spec.js | 33 ++++- render-wasm/src/shapes/modifiers.rs | 8 +- 4 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 frontend/playwright/data/workspace/get-file-13382-fragment.json create mode 100644 frontend/playwright/data/workspace/get-file-13382.json diff --git a/frontend/playwright/data/workspace/get-file-13382-fragment.json b/frontend/playwright/data/workspace/get-file-13382-fragment.json new file mode 100644 index 0000000000..9b63994447 --- /dev/null +++ b/frontend/playwright/data/workspace/get-file-13382-fragment.json @@ -0,0 +1,22 @@ +{ + "~:file-id": "~u52c4e771-3853-8190-8007-9506c70e8100", + "~:id": "~u4173a29d-4020-80b4-8007-96527ba9d8af", + "~:created-at": "~m1771342236330", + "~:modified-at": "~m1771342236330", + "~:type": "fragment", + "~:backend": "db", + "~:data": { + "~:id": "~uecb0cfd0-0f0b-81f7-8007-950628f9665b", + "~:name": "Page 1", + "~:objects": { + "~#penpot/objects-map/v2": { + "~ude9c6736-45ce-80a1-8007-950643da554d": "[\"~#shape\",[\"^ \",\"~:y\",383.99998939037323,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:grow-type\",\"~:fixed\",\"~:hide-in-viewer\",false,\"~:name\",\"R1\",\"~:width\",74,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",831.999992787838,\"~:y\",383.99998939037323]],[\"^<\",[\"^ \",\"~:x\",905.999992787838,\"~:y\",383.99998939037323]],[\"^<\",[\"^ \",\"~:x\",905.999992787838,\"~:y\",429.99998664855957]],[\"^<\",[\"^ \",\"~:x\",831.999992787838,\"~:y\",429.99998664855957]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^2\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-950643da554d\",\"~:parent-id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:frame-id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:strokes\",[],\"~:x\",831.999992787838,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",831.999992787838,\"~:y\",383.99998939037323,\"^8\",74,\"~:height\",45.99999725818634,\"~:x1\",831.999992787838,\"~:y1\",383.99998939037323,\"~:x2\",905.999992787838,\"~:y2\",429.99998664855957]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^K\",45.99999725818634,\"~:flip-y\",null]]", + "~ude9c6736-45ce-80a1-8007-95065b4599ea": "[\"~#shape\",[\"^ \",\"~:y\",439.999969256975,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:grow-type\",\"~:fixed\",\"~:hide-in-viewer\",false,\"~:name\",\"R2\",\"~:width\",300.00007388362076,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",832.0000015918991,\"~:y\",439.99996925697496]],[\"^<\",[\"^ \",\"~:x\",1132.00007547552,\"~:y\",439.99996925697496]],[\"^<\",[\"^ \",\"~:x\",1132.00007547552,\"~:y\",589.9999658711585]],[\"^<\",[\"^ \",\"~:x\",832.0000015918991,\"~:y\",589.9999658711585]]],\"~:r2\",0,\"~:layout-item-h-sizing\",\"~:fix\",\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^2\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:layout-item-v-sizing\",\"^?\",\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-95065b4599ea\",\"~:parent-id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:frame-id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:strokes\",[],\"~:x\",832.0000015918993,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",832.0000015918993,\"~:y\",439.999969256975,\"^8\",300.00007388362076,\"~:height\",149.9999966141835,\"~:x1\",832.0000015918993,\"~:y1\",439.999969256975,\"~:x2\",1132.0000754755201,\"~:y2\",589.9999658711586]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^N\",149.9999966141835,\"~:flip-y\",null]]", + "~u00000000-0000-0000-0000-000000000000": "[\"~#shape\",[\"^ \",\"~:y\",0,\"~:hide-fill-on-export\",false,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:name\",\"Root Frame\",\"~:width\",0.01,\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",0.0,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.01]],[\"^:\",[\"^ \",\"~:x\",0.0,\"~:y\",0.01]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^3\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",0,\"~:proportion\",1.0,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",0,\"~:y\",0,\"^6\",0.01,\"~:height\",0.01,\"~:x1\",0,\"~:y1\",0,\"~:x2\",0.01,\"~:y2\",0.01]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^I\",0.01,\"~:flip-y\",null,\"~:shapes\",[\"~ude9c6736-45ce-80a1-8007-95062aa41d6b\"]]]", + "~ude9c6736-45ce-80a1-8007-95062aa41d6b": "[\"~#shape\",[\"^ \",\"~:y\",342.0000208153068,\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",0,\"~:p2\",0,\"~:p3\",0,\"~:p4\",0],\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:layout-wrap-type\",\"~:nowrap\",\"~:grow-type\",\"~:fixed\",\"~:layout\",\"~:flex\",\"~:hide-in-viewer\",false,\"~:name\",\"A\",\"~:layout-align-items\",\"~:start\",\"~:width\",392.9999889135361,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",787.9999763965607,\"~:y\",342.0000208153068]],[\"^L\",[\"^ \",\"~:x\",1180.9999653100967,\"~:y\",342.0000208153068]],[\"^L\",[\"^ \",\"~:x\",1180.9999653100967,\"~:y\",704.000018450968]],[\"^L\",[\"^ \",\"~:x\",787.9999763965607,\"~:y\",704.000018450968]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",0,\"~:column-gap\",0],\"~:transform-inverse\",[\"^:\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:layout-item-v-sizing\",\"~:fix\",\"~:r3\",0,\"~:layout-justify-content\",\"^E\",\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-95062aa41d6b\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:layout-flex-dir\",\"~:column\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",787.9999763965607,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",787.9999763965607,\"~:y\",342.0000208153068,\"^F\",392.9999889135361,\"~:height\",361.9999976356612,\"~:x1\",787.9999763965607,\"~:y1\",342.0000208153068,\"~:x2\",1180.9999653100967,\"~:y2\",704.000018450968]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^19\",361.9999976356612,\"~:flip-y\",null,\"~:shapes\",[\"~ude9c6736-45ce-80a1-8007-95062fafbb88\"]]]", + "~ude9c6736-45ce-80a1-8007-95063a202e52": "[\"~#shape\",[\"^ \",\"~:y\",374.00001145409465,\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",10,\"~:p2\",10,\"~:p3\",10,\"~:p4\",10],\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:layout-wrap-type\",\"~:nowrap\",\"~:grow-type\",\"~:fixed\",\"~:layout\",\"~:flex\",\"~:hide-in-viewer\",true,\"~:name\",\"C\",\"~:layout-align-items\",\"~:start\",\"~:width\",320.00009969013945,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",821.9999915631233,\"~:y\",374.0000114540946]],[\"^L\",[\"^ \",\"~:x\",1142.0000912532628,\"~:y\",374.0000114540946]],[\"^L\",[\"^ \",\"~:x\",1142.0000912532628,\"~:y\",600.0000518384436]],[\"^L\",[\"^ \",\"~:x\",821.9999915631233,\"~:y\",600.0000518384436]]],\"~:r2\",0,\"~:layout-item-h-sizing\",\"~:auto\",\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",10,\"~:column-gap\",0],\"~:transform-inverse\",[\"^:\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:layout-item-v-sizing\",\"^O\",\"~:r3\",0,\"~:layout-justify-content\",\"^E\",\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:parent-id\",\"~ude9c6736-45ce-80a1-8007-95062fafbb88\",\"~:layout-flex-dir\",\"~:column\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~ude9c6736-45ce-80a1-8007-95062fafbb88\",\"~:strokes\",[[\"^ \",\"~:stroke-alignment\",\"~:inner\",\"~:stroke-style\",\"~:solid\",\"~:stroke-color\",\"#000000\",\"~:stroke-opacity\",1,\"~:stroke-width\",1]],\"~:x\",821.9999915631233,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",821.9999915631233,\"~:y\",374.00001145409465,\"^F\",320.00009969013945,\"~:height\",226.000040384349,\"~:x1\",821.9999915631233,\"~:y1\",374.00001145409465,\"~:x2\",1142.0000912532628,\"~:y2\",600.0000518384436]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^1A\",226.000040384349,\"~:flip-y\",null,\"~:shapes\",[\"~ude9c6736-45ce-80a1-8007-95065b4599ea\",\"~ude9c6736-45ce-80a1-8007-950643da554d\"]]]", + "~ude9c6736-45ce-80a1-8007-95062fafbb88": "[\"~#shape\",[\"^ \",\"~:y\",342.0000083402533,\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",31.999953508377075,\"~:p2\",34.000026052944804,\"~:p3\",31.999953508377075,\"~:p4\",34.000026052944804],\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:layout-wrap-type\",\"~:nowrap\",\"~:grow-type\",\"~:fixed\",\"~:layout\",\"~:flex\",\"~:hide-in-viewer\",true,\"~:name\",\"B\",\"~:layout-align-items\",\"~:start\",\"~:width\",392.9999979687366,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",788.0000295450811,\"~:y\",342.00000834025326]],[\"^L\",[\"^ \",\"~:x\",1181.0000275138177,\"~:y\",342.00000834025326]],[\"^L\",[\"^ \",\"~:x\",1181.0000275138177,\"~:y\",631.9999659712]],[\"^L\",[\"^ \",\"~:x\",788.0000295450811,\"~:y\",631.9999659712]]],\"~:r2\",0,\"~:layout-item-h-sizing\",\"~:fill\",\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",0,\"~:column-gap\",0],\"~:transform-inverse\",[\"^:\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:layout-item-v-sizing\",\"~:auto\",\"~:r3\",0,\"~:layout-justify-content\",\"^E\",\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-95062fafbb88\",\"~:parent-id\",\"~ude9c6736-45ce-80a1-8007-95062aa41d6b\",\"~:layout-flex-dir\",\"~:column\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~ude9c6736-45ce-80a1-8007-95062aa41d6b\",\"~:strokes\",[[\"^ \",\"~:stroke-alignment\",\"~:inner\",\"~:stroke-style\",\"~:solid\",\"~:stroke-color\",\"#000000\",\"~:stroke-opacity\",1,\"~:stroke-width\",1]],\"~:x\",788.0000295450811,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",788.0000295450811,\"~:y\",342.0000083402533,\"^F\",392.9999979687366,\"~:height\",289.99995763094677,\"~:x1\",788.0000295450811,\"~:y1\",342.0000083402533,\"~:x2\",1181.0000275138177,\"~:y2\",631.9999659712]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^1B\",289.99995763094677,\"~:flip-y\",null,\"~:shapes\",[\"~ude9c6736-45ce-80a1-8007-95063a202e52\"]]]" + } + } + } +} diff --git a/frontend/playwright/data/workspace/get-file-13382.json b/frontend/playwright/data/workspace/get-file-13382.json new file mode 100644 index 0000000000..a182ef53e0 --- /dev/null +++ b/frontend/playwright/data/workspace/get-file-13382.json @@ -0,0 +1,131 @@ +{ + "~:features": { + "~#set": [ + "fdata/path-data", + "design-tokens/v1", + "variants/v1", + "layout/grid", + "fdata/pointer-map", + "fdata/objects-map", + "components/v2", + "fdata/shape-data-type" + ] + }, + "~:team-id": "~ud715d0a5-a44e-8056-8005-a79999e18b64", + "~:permissions": { + "~:type": "~:membership", + "~:is-owner": true, + "~:is-admin": true, + "~:can-edit": true, + "~:can-read": true, + "~:is-logged": true + }, + "~:has-media-trimmed": false, + "~:comment-thread-seqn": 0, + "~:name": "bug flex", + "~:revn": 33, + "~:modified-at": "~m1771342236324", + "~:vern": 0, + "~:id": "~u52c4e771-3853-8190-8007-9506c70e8100", + "~:is-shared": false, + "~:migrations": { + "~#ordered-set": [ + "legacy-2", + "legacy-3", + "legacy-5", + "legacy-6", + "legacy-7", + "legacy-8", + "legacy-9", + "legacy-10", + "legacy-11", + "legacy-12", + "legacy-13", + "legacy-14", + "legacy-16", + "legacy-17", + "legacy-18", + "legacy-19", + "legacy-25", + "legacy-26", + "legacy-27", + "legacy-28", + "legacy-29", + "legacy-31", + "legacy-32", + "legacy-33", + "legacy-34", + "legacy-36", + "legacy-37", + "legacy-38", + "legacy-39", + "legacy-40", + "legacy-41", + "legacy-42", + "legacy-43", + "legacy-44", + "legacy-45", + "legacy-46", + "legacy-47", + "legacy-48", + "legacy-49", + "legacy-50", + "legacy-51", + "legacy-52", + "legacy-53", + "legacy-54", + "legacy-55", + "legacy-56", + "legacy-57", + "legacy-59", + "legacy-62", + "legacy-65", + "legacy-66", + "legacy-67", + "0001-remove-tokens-from-groups", + "0002-normalize-bool-content-v2", + "0002-clean-shape-interactions", + "0003-fix-root-shape", + "0003-convert-path-content-v2", + "0005-deprecate-image-type", + "0006-fix-old-texts-fills", + "0008-fix-library-colors-v4", + "0009-clean-library-colors", + "0009-add-partial-text-touched-flags", + "0010-fix-swap-slots-pointing-non-existent-shapes", + "0011-fix-invalid-text-touched-flags", + "0012-fix-position-data", + "0013-fix-component-path", + "0013-clear-invalid-strokes-and-fills", + "0014-fix-tokens-lib-duplicate-ids", + "0014-clear-components-nil-objects", + "0015-fix-text-attrs-blank-strings", + "0015-clean-shadow-color", + "0016-copy-fills-from-position-data-to-text-node" + ] + }, + "~:version": 67, + "~:project-id": "~u76eab896-accf-81a5-8007-2b264ebe7817", + "~:created-at": "~m1771255281717", + "~:backend": "legacy-db", + "~:data": { + "~:pages": [ + "~uecb0cfd0-0f0b-81f7-8007-950628f9665b" + ], + "~:pages-index": { + "~uecb0cfd0-0f0b-81f7-8007-950628f9665b": { + "~#penpot/pointer": [ + "~u4173a29d-4020-80b4-8007-96527ba9d8af", + { + "~:created-at": "~m1771342236327" + } + ] + } + }, + "~:id": "~u52c4e771-3853-8190-8007-9506c70e8100", + "~:options": { + "~:components-v2": true, + "~:base-font-size": "16px" + } + } +} 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/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)] From 5718698bff1d76492c4f1e23ba072d345ee30558 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 17 Feb 2026 17:04:58 +0100 Subject: [PATCH 09/12] :sparkles: Update mcp api_types.yml file with latest plugins doc updates --- mcp/packages/server/data/api_types.yml | 1086 +++++++++++++++++++++++- 1 file changed, 1049 insertions(+), 37 deletions(-) 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. From 8eb5bd3dd81a910612017b2f0396519c1e874cbb Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 17 Feb 2026 17:05:26 +0100 Subject: [PATCH 10/12] :wrench: Add minor adjustments to mcp build-types script --- mcp/scripts/build-types | 1 + 1 file changed, 1 insertion(+) 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 From 916107ce041b124eff4e1312fc2238b8bb0a8c07 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 17 Feb 2026 17:07:12 +0100 Subject: [PATCH 11/12] :paperclip: Update pnpm-lock.yaml file on plugins module --- plugins/pnpm-lock.yaml | 873 ----------------------------------------- 1 file changed, 873 deletions(-) diff --git a/plugins/pnpm-lock.yaml b/plugins/pnpm-lock.yaml index ee0b678928..31e97b6de6 100644 --- a/plugins/pnpm-lock.yaml +++ b/plugins/pnpm-lock.yaml @@ -243,69 +243,11 @@ importers: libs/plugins-styles: {} - libs/ui/dist: - dependencies: - react: - specifier: '>=19.2' - version: 19.2.4 - react-dom: - specifier: '>=19.2' - version: 19.2.4(react@19.2.4) - devDependencies: - '@babel/core': - specifier: ^7.14.5 - version: 7.29.0 - '@babel/preset-react': - specifier: ^7.14.5 - version: 7.28.5(@babel/core@7.29.0) - '@storybook/react': - specifier: 10.2.0 - version: 10.2.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) - '@storybook/react-vite': - specifier: 10.2.0 - version: 10.2.0(esbuild@0.27.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(esbuild@0.27.2)) - '@testing-library/dom': - specifier: 10.4.0 - version: 10.4.0 - '@testing-library/react': - specifier: 16.3.0 - version: 16.3.0(@testing-library/dom@10.4.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@types/react': - specifier: ^19.0.0 - version: 19.2.14 - '@types/react-dom': - specifier: ^19.0.0 - version: 19.2.3(@types/react@19.2.14) - '@vitejs/plugin-react': - specifier: ^4.2.0 - version: 4.7.0(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - eslint-plugin-import: - specifier: 2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-jsx-a11y: - specifier: 6.10.1 - version: 6.10.1(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-react: - specifier: 7.35.0 - version: 7.35.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-react-hooks: - specifier: 7.0.1 - version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) - react-compiler-runtime: - specifier: ^1.0.0 - version: 1.0.0(react@19.2.4) - storybook: - specifier: 10.2.0 - version: 10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - packages: '@acemir/cssom@0.9.31': resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} - '@adobe/css-tools@4.4.4': - resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@algolia/abtesting@1.12.2': resolution: {integrity: sha512-oWknd6wpfNrmRcH0vzed3UPX0i17o4kYLM5OMITyMVM2xLgaRbIafoxL0e8mcrNNb0iORCJA0evnNDKRYth5WQ==} engines: {node: '>= 14.0.0'} @@ -784,12 +726,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.28.6': - resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6': resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} @@ -1030,42 +966,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-display-name@7.28.0': - resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-development@7.27.1': - resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx@7.28.6': - resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-pure-annotations@7.27.1': - resolution: {integrity: sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.29.0': resolution: {integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==} engines: {node: '>=6.9.0'} @@ -1155,12 +1055,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/preset-react@7.28.5': - resolution: {integrity: sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} @@ -1607,10 +1501,6 @@ packages: resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} engines: {node: 20 || >=22} - '@isaacs/brace-expansion@5.0.1': - resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} - engines: {node: 20 || >=22} - '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -1619,15 +1509,6 @@ packages: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4': - resolution: {integrity: sha512-6PyZBYKnnVNqOSB0YFly+62R7dmov8segT27A+RVTBVd4iAE6kbW9QBJGlyR2yG4D4ohzhZSTIu7BK1UTtmFFA==} - peerDependencies: - typescript: '>= 4.3.x' - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - typescript: - optional: true - '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -2239,9 +2120,6 @@ packages: cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - '@rolldown/pluginutils@1.0.0-beta.58': resolution: {integrity: sha512-qWhDs6yFGR5xDfdrwiSa3CWGIHxD597uGE/A9xGqytBjANvh4rLCTTkq7szhMV4+Ygh+PMS90KVJ8xWG/TkX4w==} @@ -2539,97 +2417,9 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@storybook/builder-vite@10.2.0': - resolution: {integrity: sha512-S1+62ipGmQzGPZfcbgNqpbrCezsqkvbhj+MBbQ6VS46b2HcPjm4H8V6FzGly0Ja2pSgu8gT1BQ5N+3yOG8UNTw==} - peerDependencies: - storybook: ^10.2.0 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@storybook/csf-plugin@10.2.0': - resolution: {integrity: sha512-Cty+tZ0r1AZhwBBzqI4RyCpMVGt9wHGTtG4YCRUuNgVFO1MnjaFBHKRT+oT7md28+BWYjFz4Qtpge/fcWANJ0w==} - peerDependencies: - esbuild: '*' - rollup: '*' - storybook: ^10.2.0 - vite: '*' - webpack: '*' - peerDependenciesMeta: - esbuild: - optional: true - rollup: - optional: true - vite: - optional: true - webpack: - optional: true - - '@storybook/global@5.0.0': - resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} - - '@storybook/icons@2.0.1': - resolution: {integrity: sha512-/smVjw88yK3CKsiuR71vNgWQ9+NuY2L+e8X7IMrFjexjm6ZR8ULrV2DRkTA61aV6ryefslzHEGDInGpnNeIocg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - '@storybook/react-dom-shim@10.2.0': - resolution: {integrity: sha512-PEQofiruE6dBGzUQPXZZREbuh1t62uRBWoUPRFNAZi79zddlk7+b9qu08VV9cvf68mwOqqT1+VJ1P+3ClD2ZVw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.0 - - '@storybook/react-vite@10.2.0': - resolution: {integrity: sha512-tIXRfrA+wREFuA+bIJccMCV1YVFdACENcSnSlnB5Be3m8ynMHukOz6ObX9jI5WsWZnqrk0/eHyiYJyVhpY9rhQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.0 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@storybook/react@10.2.0': - resolution: {integrity: sha512-ciJlh1UGm0GBXQgqrYFeLmiix+KGFB3v37OnAYjGghPS9OP6S99XyshxY/6p0sMOYtS+eWS2gPsOKNXNnLDGYw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.0 - typescript: '>= 4.9.x' - peerDependenciesMeta: - typescript: - optional: true - '@swc/helpers@0.5.18': resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} - '@testing-library/dom@10.4.0': - resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} - engines: {node: '>=18'} - - '@testing-library/jest-dom@6.9.1': - resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} - engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - - '@testing-library/react@16.3.0': - resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==} - engines: {node: '>=18'} - peerDependencies: - '@testing-library/dom': ^10.0.0 - '@types/react': ^18.0.0 || ^19.0.0 - '@types/react-dom': ^18.0.0 || ^19.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@testing-library/user-event@14.6.1': - resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} - engines: {node: '>=12', npm: '>=6'} - peerDependencies: - '@testing-library/dom': '>=7.21.4' - '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} @@ -2647,21 +2437,6 @@ packages: '@types/argparse@1.0.38': resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - '@types/body-parser@1.19.6': resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} @@ -2680,9 +2455,6 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/doctrine@0.0.9': - resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} - '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -2734,17 +2506,6 @@ packages: '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.14': - resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - - '@types/resolve@1.20.6': - resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} - '@types/retry@0.12.2': resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} @@ -2932,12 +2693,6 @@ packages: peerDependencies: vite: ^6.0.0 || ^7.0.0 - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - '@vitest/coverage-v8@4.0.17': resolution: {integrity: sha512-/6zU2FLGg0jsd+ePZcwHRy3+WpNTBBhDY56P4JTRqUN/Dp6CvOEa9HrikcQ4KfV2b2kAHUFB4dl1SuocWXSFEw==} peerDependencies: @@ -2947,23 +2702,9 @@ packages: '@vitest/browser': optional: true - '@vitest/expect@3.2.4': - resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.0.17': resolution: {integrity: sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==} - '@vitest/mocker@3.2.4': - resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - '@vitest/mocker@4.0.17': resolution: {integrity: sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==} peerDependencies: @@ -2975,9 +2716,6 @@ packages: vite: optional: true - '@vitest/pretty-format@3.2.4': - resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.0.17': resolution: {integrity: sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==} @@ -2987,9 +2725,6 @@ packages: '@vitest/snapshot@4.0.17': resolution: {integrity: sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==} - '@vitest/spy@3.2.4': - resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/spy@4.0.17': resolution: {integrity: sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==} @@ -2998,9 +2733,6 @@ packages: peerDependencies: vitest: 4.0.17 - '@vitest/utils@3.2.4': - resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.0.17': resolution: {integrity: sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==} @@ -3196,10 +2928,6 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -3214,9 +2942,6 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} - aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -3271,10 +2996,6 @@ packages: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} - ast-types@0.16.1: - resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} - engines: {node: '>=4'} - ast-v8-to-istanbul@0.3.11: resolution: {integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==} @@ -3469,10 +3190,6 @@ packages: caniuse-lite@1.0.30001767: resolution: {integrity: sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==} - chai@5.3.3: - resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} - engines: {node: '>=18'} - chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -3488,10 +3205,6 @@ packages: chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} - check-error@2.1.3: - resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} - engines: {node: '>= 16'} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -3684,9 +3397,6 @@ packages: resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} engines: {node: '>= 6'} - css.escape@1.5.1: - resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} - cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -3696,9 +3406,6 @@ packages: resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==} engines: {node: '>=20'} - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -3753,10 +3460,6 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -3796,10 +3499,6 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -3830,16 +3529,6 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} - - dom-accessibility-api@0.6.3: - resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -3880,10 +3569,6 @@ packages: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} - empathic@2.0.0: - resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} - engines: {node: '>=14'} - encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -4378,10 +4063,6 @@ packages: resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} engines: {node: 20 || >=22} - glob@13.0.2: - resolution: {integrity: sha512-035InabNu/c1lW0tzPhAgapKctblppqsKKG9ZaNzbr+gXwWMjXoiyGSyB9sArzrjG7jY+zntRq5ZSUYemrnWVQ==} - engines: {node: 20 || >=22} - globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -4569,10 +4250,6 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -4994,9 +4671,6 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - loupe@3.2.1: - resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - lru-cache@11.2.5: resolution: {integrity: sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==} engines: {node: 20 || >=22} @@ -5015,10 +4689,6 @@ packages: lunr@2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} - lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -5111,10 +4781,6 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - mini-css-extract-plugin@2.9.4: resolution: {integrity: sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ==} engines: {node: '>= 12.13.0'} @@ -5132,10 +4798,6 @@ packages: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} - minimatch@10.1.2: - resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} - engines: {node: 20 || >=22} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -5475,10 +5137,6 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@2.0.1: - resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} - engines: {node: '>= 14.16'} - pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} @@ -5579,10 +5237,6 @@ packages: engines: {node: '>=14'} hasBin: true - pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - proc-log@6.1.0: resolution: {integrity: sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==} engines: {node: ^20.17.0 || >=22.9.0} @@ -5660,39 +5314,9 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} - react-compiler-runtime@1.0.0: - resolution: {integrity: sha512-rRfjYv66HlG8896yPUDONgKzG5BxZD1nV9U6rkm+7VCuvQc903C4MjcoZR4zPw53IKSOX9wMQVpA1IAbRtzQ7w==} - peerDependencies: - react: ^17.0.0 || ^18.0.0 || ^19.0.0 || ^0.0.0-experimental - - react-docgen-typescript@2.4.0: - resolution: {integrity: sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==} - peerDependencies: - typescript: '>= 4.3.x' - - react-docgen@8.0.2: - resolution: {integrity: sha512-+NRMYs2DyTP4/tqWz371Oo50JqmWltR1h2gcdgUMAWZJIAvrd0/SqlCfx7tpzpl/s36rzw6qH2MjoNrxtRNYhA==} - engines: {node: ^20.9.0 || >=22} - - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} - peerDependencies: - react: ^19.2.4 - react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} - engines: {node: '>=0.10.0'} - readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -5712,14 +5336,6 @@ packages: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} - recast@0.23.11: - resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} - engines: {node: '>= 4'} - - redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} - reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -6003,9 +5619,6 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} @@ -6215,15 +5828,6 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} - storybook@10.2.0: - resolution: {integrity: sha512-fIQnFtpksRRgHR1CO1onGX3djaog4qsW/c5U8arqYTkUEr2TaWpn05mIJDOBoPJFlOdqFrB4Ttv0PZJxV7avhw==} - hasBin: true - peerDependencies: - prettier: ^2 || ^3 - peerDependenciesMeta: - prettier: - optional: true - streamx@2.23.0: resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} @@ -6284,14 +5888,6 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - - strip-indent@4.1.1: - resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} - engines: {node: '>=12'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -6380,18 +5976,10 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} - tinyrainbow@3.0.3: resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} - tinyspy@4.0.4: - resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} - engines: {node: '>=14.0.0'} - tldts-core@7.0.21: resolution: {integrity: sha512-oVOMdHvgjqyzUZH1rOESgJP1uNe2bVrfK0jUHHmiM2rpEiRbf3j4BrsIc6JigJRbHGanQwuZv/R+LTcHsw+bLA==} @@ -6441,10 +6029,6 @@ packages: peerDependencies: typescript: '>=4.8.4' - ts-dedent@2.2.0: - resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} - engines: {node: '>=6.10'} - tsconfck@3.1.6: resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} engines: {node: ^18 || >=20} @@ -6458,10 +6042,6 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - tsconfig-paths@4.2.0: - resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} - engines: {node: '>=6'} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -6585,10 +6165,6 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - unplugin@2.3.11: - resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} - engines: {node: '>=18.12.0'} - update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -6598,11 +6174,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -6871,9 +6442,6 @@ packages: html-webpack-plugin: optional: true - webpack-virtual-modules@0.6.2: - resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack@5.104.1: resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} engines: {node: '>=10.13.0'} @@ -7065,8 +6633,6 @@ snapshots: '@acemir/cssom@0.9.31': {} - '@adobe/css-tools@4.4.4': {} - '@algolia/abtesting@1.12.2': dependencies: '@algolia/client-common': 5.46.2 @@ -7736,11 +7302,6 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 @@ -8013,45 +7574,6 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 @@ -8214,18 +7736,6 @@ snapshots: '@babel/types': 7.29.0 esutils: 2.0.3 - '@babel/preset-react@7.28.5(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - '@babel/runtime@7.28.4': {} '@babel/template@7.28.6': @@ -8582,24 +8092,12 @@ snapshots: dependencies: '@isaacs/balanced-match': 4.0.1 - '@isaacs/brace-expansion@5.0.1': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.2 '@istanbuljs/schema@0.1.3': {} - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - glob: 13.0.2 - react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - optionalDependencies: - typescript: 5.9.3 - '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -9173,8 +8671,6 @@ snapshots: '@rolldown/binding-win32-x64-msvc@1.0.0-beta.58': optional: true - '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rolldown/pluginutils@1.0.0-beta.58': {} '@rollup/pluginutils@5.3.0(rollup@4.57.1)': @@ -9421,117 +8917,11 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/builder-vite@10.2.0(esbuild@0.27.2)(rollup@4.57.1)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(esbuild@0.27.2))': - dependencies: - '@storybook/csf-plugin': 10.2.0(esbuild@0.27.2)(rollup@4.57.1)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(esbuild@0.27.2)) - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - storybook: 10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - ts-dedent: 2.2.0 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - esbuild - - msw - - rollup - - webpack - - '@storybook/csf-plugin@10.2.0(esbuild@0.27.2)(rollup@4.57.1)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(esbuild@0.27.2))': - dependencies: - storybook: 10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - unplugin: 2.3.11 - optionalDependencies: - esbuild: 0.27.2 - rollup: 4.57.1 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - webpack: 5.104.1(esbuild@0.27.2) - - '@storybook/global@5.0.0': {} - - '@storybook/icons@2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - - '@storybook/react-dom-shim@10.2.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': - dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - storybook: 10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - - '@storybook/react-vite@10.2.0(esbuild@0.27.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(esbuild@0.27.2))': - dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@rollup/pluginutils': 5.3.0(rollup@4.57.1) - '@storybook/builder-vite': 10.2.0(esbuild@0.27.2)(rollup@4.57.1)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(esbuild@0.27.2)) - '@storybook/react': 10.2.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) - empathic: 2.0.0 - magic-string: 0.30.21 - react: 19.2.4 - react-docgen: 8.0.2 - react-dom: 19.2.4(react@19.2.4) - resolve: 1.22.11 - storybook: 10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - tsconfig-paths: 4.2.0 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - esbuild - - msw - - rollup - - supports-color - - typescript - - webpack - - '@storybook/react@10.2.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': - dependencies: - '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.2.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - react: 19.2.4 - react-docgen: 8.0.2 - react-dom: 19.2.4(react@19.2.4) - storybook: 10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@swc/helpers@0.5.18': dependencies: tslib: 2.8.1 optional: true - '@testing-library/dom@10.4.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.28.4 - '@types/aria-query': 5.0.4 - aria-query: 5.3.0 - chalk: 4.1.2 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - pretty-format: 27.5.1 - - '@testing-library/jest-dom@6.9.1': - dependencies: - '@adobe/css-tools': 4.4.4 - aria-query: 5.3.2 - css.escape: 1.5.1 - dom-accessibility-api: 0.6.3 - picocolors: 1.1.1 - redent: 3.0.0 - - '@testing-library/react@16.3.0(@testing-library/dom@10.4.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@babel/runtime': 7.28.4 - '@testing-library/dom': 10.4.0 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0)': - dependencies: - '@testing-library/dom': 10.4.0 - '@tootallnate/quickjs-emscripten@0.23.0': {} '@tufjs/canonical-json@2.0.0': {} @@ -9548,29 +8938,6 @@ snapshots: '@types/argparse@1.0.38': {} - '@types/aria-query@5.0.4': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.29.0 - '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 @@ -9596,8 +8963,6 @@ snapshots: '@types/deep-eql@4.0.2': {} - '@types/doctrine@0.0.9': {} - '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 @@ -9656,16 +9021,6 @@ snapshots: '@types/range-parser@1.2.7': {} - '@types/react-dom@19.2.3(@types/react@19.2.14)': - dependencies: - '@types/react': 19.2.14 - - '@types/react@19.2.14': - dependencies: - csstype: 3.2.3 - - '@types/resolve@1.20.6': {} - '@types/retry@0.12.2': {} '@types/send@0.17.6': @@ -9934,18 +9289,6 @@ snapshots: dependencies: vite: 7.3.0(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitejs/plugin-react@4.7.0(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - supports-color - '@vitest/coverage-v8@4.0.17(vitest@4.0.17)': dependencies: '@bcoe/v8-coverage': 1.0.2 @@ -9960,14 +9303,6 @@ snapshots: tinyrainbow: 3.0.3 vitest: 4.0.17(@types/node@25.0.10)(@vitest/ui@4.0.17)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.4.0)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/expect@3.2.4': - dependencies: - '@types/chai': 5.2.3 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - tinyrainbow: 2.0.0 - '@vitest/expect@4.0.17': dependencies: '@standard-schema/spec': 1.1.0 @@ -9977,14 +9312,6 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.17 @@ -9993,10 +9320,6 @@ snapshots: optionalDependencies: vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/pretty-format@3.2.4': - dependencies: - tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.0.17': dependencies: tinyrainbow: 3.0.3 @@ -10012,10 +9335,6 @@ snapshots: magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@3.2.4': - dependencies: - tinyspy: 4.0.4 - '@vitest/spy@4.0.17': {} '@vitest/ui@4.0.17(vitest@4.0.17)': @@ -10029,12 +9348,6 @@ snapshots: tinyrainbow: 3.0.3 vitest: 4.0.17(@types/node@25.0.10)(@vitest/ui@4.0.17)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.4.0)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/utils@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.2.1 - tinyrainbow: 2.0.0 - '@vitest/utils@4.0.17': dependencies: '@vitest/pretty-format': 4.0.17 @@ -10280,8 +9593,6 @@ snapshots: dependencies: color-convert: 2.0.1 - ansi-styles@5.2.0: {} - ansi-styles@6.2.3: {} anymatch@3.1.3: @@ -10295,10 +9606,6 @@ snapshots: argparse@2.0.1: {} - aria-query@5.3.0: - dependencies: - dequal: 2.0.3 - aria-query@5.3.2: {} array-buffer-byte-length@1.0.2: @@ -10380,10 +9687,6 @@ snapshots: dependencies: tslib: 2.8.1 - ast-types@0.16.1: - dependencies: - tslib: 2.8.1 - ast-v8-to-istanbul@0.3.11: dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -10619,14 +9922,6 @@ snapshots: caniuse-lite@1.0.30001767: {} - chai@5.3.3: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.3 - deep-eql: 5.0.2 - loupe: 3.2.1 - pathval: 2.0.1 - chai@6.2.2: {} chalk@4.1.2: @@ -10638,8 +9933,6 @@ snapshots: chardet@2.1.1: {} - check-error@2.1.3: {} - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -10843,8 +10136,6 @@ snapshots: css-what@7.0.0: {} - css.escape@1.5.1: {} - cssesc@3.0.0: {} cssstyle@5.3.7: @@ -10854,8 +10145,6 @@ snapshots: css-tree: 3.1.0 lru-cache: 11.2.5 - csstype@3.2.3: {} - damerau-levenshtein@1.0.8: {} data-uri-to-buffer@6.0.2: {} @@ -10899,8 +10188,6 @@ snapshots: decimal.js@10.6.0: {} - deep-eql@5.0.2: {} - deep-is@0.1.4: {} default-browser-id@5.0.1: {} @@ -10936,8 +10223,6 @@ snapshots: depd@2.0.0: {} - dequal@2.0.3: {} - destroy@1.2.0: {} detect-libc@2.1.2: @@ -10961,14 +10246,6 @@ snapshots: dependencies: esutils: 2.0.3 - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - dom-accessibility-api@0.5.16: {} - - dom-accessibility-api@0.6.3: {} - dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -11007,8 +10284,6 @@ snapshots: emojis-list@3.0.0: {} - empathic@2.0.0: {} - encodeurl@2.0.0: {} encoding@0.1.13: @@ -11725,12 +11000,6 @@ snapshots: minipass: 7.1.2 path-scurry: 2.0.1 - glob@13.0.2: - dependencies: - minimatch: 10.1.2 - minipass: 7.1.2 - path-scurry: 2.0.1 - globals@14.0.0: {} globals@17.3.0: {} @@ -11934,8 +11203,6 @@ snapshots: imurmurhash@0.1.4: {} - indent-string@4.0.0: {} - inherits@2.0.4: {} ini@6.0.0: {} @@ -12370,8 +11637,6 @@ snapshots: dependencies: js-tokens: 4.0.0 - loupe@3.2.1: {} - lru-cache@11.2.5: {} lru-cache@5.1.1: @@ -12386,8 +11651,6 @@ snapshots: lunr@2.3.9: {} - lz-string@1.5.0: {} - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -12491,8 +11754,6 @@ snapshots: mimic-function@5.0.1: {} - min-indent@1.0.1: {} - mini-css-extract-plugin@2.9.4(webpack@5.104.1(esbuild@0.27.2)): dependencies: schema-utils: 4.3.3 @@ -12509,10 +11770,6 @@ snapshots: dependencies: '@isaacs/brace-expansion': 5.0.0 - minimatch@10.1.2: - dependencies: - '@isaacs/brace-expansion': 5.0.1 - minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -12919,8 +12176,6 @@ snapshots: pathe@2.0.3: {} - pathval@2.0.1: {} - pend@1.2.0: {} picocolors@1.1.1: {} @@ -13006,12 +12261,6 @@ snapshots: prettier@3.8.1: {} - pretty-format@27.5.1: - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - proc-log@6.1.0: {} process-nextick-args@2.0.1: {} @@ -13123,42 +12372,8 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 - react-compiler-runtime@1.0.0(react@19.2.4): - dependencies: - react: 19.2.4 - - react-docgen-typescript@2.4.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - react-docgen@8.0.2: - dependencies: - '@babel/core': 7.29.0 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.28.0 - '@types/doctrine': 0.0.9 - '@types/resolve': 1.20.6 - doctrine: 3.0.0 - resolve: 1.22.11 - strip-indent: 4.1.1 - transitivePeerDependencies: - - supports-color - - react-dom@19.2.4(react@19.2.4): - dependencies: - react: 19.2.4 - scheduler: 0.27.0 - react-is@16.13.1: {} - react-is@17.0.2: {} - - react-refresh@0.17.0: {} - - react@19.2.4: {} - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -13183,19 +12398,6 @@ snapshots: readdirp@5.0.0: {} - recast@0.23.11: - dependencies: - ast-types: 0.16.1 - esprima: 4.0.1 - source-map: 0.6.1 - tiny-invariant: 1.3.3 - tslib: 2.8.1 - - redent@3.0.0: - dependencies: - indent-string: 4.0.0 - strip-indent: 3.0.0 - reflect-metadata@0.2.2: {} reflect.getprototypeof@1.0.10: @@ -13500,8 +12702,6 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.27.0: {} - schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 @@ -13787,29 +12987,6 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 - storybook@10.2.0(@testing-library/dom@10.4.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): - dependencies: - '@storybook/global': 5.0.0 - '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@testing-library/jest-dom': 6.9.1 - '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) - '@vitest/expect': 3.2.4 - '@vitest/spy': 3.2.4 - esbuild: 0.27.2 - open: 10.2.0 - recast: 0.23.11 - semver: 7.7.3 - use-sync-external-store: 1.6.0(react@19.2.4) - ws: 8.19.0 - optionalDependencies: - prettier: 3.8.1 - transitivePeerDependencies: - - '@testing-library/dom' - - bufferutil - - react - - react-dom - - utf-8-validate - streamx@2.23.0: dependencies: events-universal: 1.0.1 @@ -13906,12 +13083,6 @@ snapshots: strip-bom@3.0.0: {} - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 - - strip-indent@4.1.1: {} - strip-json-comments@3.1.1: {} supports-color@7.2.0: @@ -14006,12 +13177,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - tinyrainbow@2.0.0: {} - tinyrainbow@3.0.3: {} - tinyspy@4.0.4: {} - tldts-core@7.0.21: {} tldts@7.0.21: @@ -14048,8 +13215,6 @@ snapshots: dependencies: typescript: 5.9.3 - ts-dedent@2.2.0: {} - tsconfck@3.1.6(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -14061,12 +13226,6 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tsconfig-paths@4.2.0: - dependencies: - json5: 2.2.3 - minimist: 1.2.8 - strip-bom: 3.0.0 - tslib@2.8.1: {} tsx@4.21.0: @@ -14200,13 +13359,6 @@ snapshots: unpipe@1.0.0: {} - unplugin@2.3.11: - dependencies: - '@jridgewell/remapping': 2.3.5 - acorn: 8.15.0 - picomatch: 4.0.3 - webpack-virtual-modules: 0.6.2 - update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 @@ -14217,10 +13369,6 @@ snapshots: dependencies: punycode: 2.3.1 - use-sync-external-store@1.6.0(react@19.2.4): - dependencies: - react: 19.2.4 - util-deprecate@1.0.2: {} utils-merge@1.0.1: {} @@ -14332,25 +13480,6 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.3)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - esbuild: 0.27.2 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 25.0.10 - fsevents: 2.3.3 - jiti: 2.6.1 - less: 4.4.2 - sass: 1.97.3 - sass-embedded: 1.97.3 - terser: 5.44.1 - tsx: 4.21.0 - yaml: 2.8.2 - vitest@4.0.17(@types/node@25.0.10)(@vitest/ui@4.0.17)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.4.0)(less@4.4.2)(sass-embedded@1.97.3)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.17 @@ -14483,8 +13612,6 @@ snapshots: typed-assert: 1.0.9 webpack: 5.104.1(esbuild@0.27.2) - webpack-virtual-modules@0.6.2: {} - webpack@5.104.1(esbuild@0.27.2): dependencies: '@types/eslint-scope': 3.7.7 From 70013fde7404197ed896d862fe1b38443562c21d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 17 Feb 2026 17:46:09 +0100 Subject: [PATCH 12/12] :bug: Fix exporter bundle deps issue with pnpm --- docker/images/Dockerfile.exporter | 3 ++- exporter/scripts/build | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) 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 <