mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
🐛 Resize fit-content flex boards while typing in v3 text editor (#12330)
* 🐛 Resize fit-content flex boards while typing in v3 text editor Typing in an auto-width text did not resize its fit-content layout parent until the editor closed. The v3 editor now previews the live text size in the layout on each keystroke, also when the text sits in a group. * 🐛 Preview text layout when typing with a pending caret style Both v3 editor commit paths share v3-update-editor-content. * 🐛 Skip the layout preview for absolute texts Absolute layout items do not affect their board. * ⚡ Preview text layout only when the text size changes Each preview propagates modifiers, so skip unchanged sizes. * 🐛 Leave interactive render mode when the v3 editor closes Finalize only ends it when it applies geometry.
This commit is contained in:
parent
4c655e6e9e
commit
c99980327f
727
frontend/playwright/data/text-editor/get-file-12325.json
Normal file
727
frontend/playwright/data/text-editor/get-file-12325.json
Normal file
@ -0,0 +1,727 @@
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"fdata/path-data",
|
||||
"plugins/runtime",
|
||||
"design-tokens/v1",
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/pointer-map",
|
||||
"fdata/objects-map",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type",
|
||||
"text-editor/v2"
|
||||
]
|
||||
},
|
||||
"~:team-id": "~u9e6e22b2-db76-81d6-8006-75d7cdbb8bad",
|
||||
"~: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 12325",
|
||||
"~:revn": 3,
|
||||
"~:modified-at": "~m1753957736516",
|
||||
"~:vern": 0,
|
||||
"~:id": "~u238a17e0-75ff-8075-8006-934586ea2230",
|
||||
"~: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",
|
||||
"0004-clean-shadow-color",
|
||||
"0005-deprecate-image-type",
|
||||
"0006-fix-old-texts-fills",
|
||||
"0007-clear-invalid-strokes-and-fills-v2",
|
||||
"0008-fix-library-colors-v4",
|
||||
"0009-clean-library-colors",
|
||||
"0009-add-partial-text-touched-flags"
|
||||
]
|
||||
},
|
||||
"~:version": 67,
|
||||
"~:project-id": "~u9e6e22b2-db76-81d6-8006-75d7cdc30669",
|
||||
"~:created-at": "~m1753957644225",
|
||||
"~:data": {
|
||||
"~:pages": ["~u238a17e0-75ff-8075-8006-934586ea2231"],
|
||||
"~:pages-index": {
|
||||
"~u238a17e0-75ff-8075-8006-934586ea2231": {
|
||||
"~:objects": {
|
||||
"~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
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0.01,
|
||||
"~:y": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0.01,
|
||||
"~:y": 0.01
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0.0,
|
||||
"~:y": 0.01
|
||||
}
|
||||
}
|
||||
],
|
||||
"~:r2": 0,
|
||||
"~:proportion-lock": false,
|
||||
"~:transform-inverse": {
|
||||
"~#matrix": {
|
||||
"~: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,
|
||||
"~:width": 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,
|
||||
"~:height": 0.01,
|
||||
"~:flip-y": null,
|
||||
"~:shapes": [
|
||||
"~uc0a701d6-7df9-80ac-8008-c9e6c5b7f7f4",
|
||||
"~uc0a701d6-7df9-80ac-8008-c9e6c8b2a9e2"
|
||||
]
|
||||
}
|
||||
},
|
||||
"~uc0a701d6-7df9-80ac-8008-c9e6c5b7f7f4": {
|
||||
"~#shape": {
|
||||
"~:id": "~uc0a701d6-7df9-80ac-8008-c9e6c5b7f7f4",
|
||||
"~:name": "Text board",
|
||||
"~:type": "~:frame",
|
||||
"~:parent-id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:frame-id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:shapes": ["~uc0a701d6-7df9-80ac-8008-c9e6c47fbce4"],
|
||||
"~:fills": [
|
||||
{
|
||||
"~:fill-color": "#B1B2B5",
|
||||
"~:fill-opacity": 1
|
||||
}
|
||||
],
|
||||
"~:strokes": [],
|
||||
"~:hide-fill-on-export": false,
|
||||
"~:show-content": true,
|
||||
"~:proportion-lock": false,
|
||||
"~:proportion": 1,
|
||||
"~:r1": 0,
|
||||
"~:r2": 0,
|
||||
"~:r3": 0,
|
||||
"~:r4": 0,
|
||||
"~:layout": "~:flex",
|
||||
"~:layout-flex-dir": "~:row",
|
||||
"~:layout-wrap-type": "~:nowrap",
|
||||
"~:layout-gap-type": "~:multiple",
|
||||
"~:layout-gap": {
|
||||
"~:row-gap": 0,
|
||||
"~:column-gap": 0
|
||||
},
|
||||
"~:layout-padding-type": "~:simple",
|
||||
"~:layout-padding": {
|
||||
"~:p1": 0,
|
||||
"~:p2": 0,
|
||||
"~:p3": 0,
|
||||
"~:p4": 0
|
||||
},
|
||||
"~:layout-align-items": "~:start",
|
||||
"~:layout-justify-content": "~:start",
|
||||
"~:layout-align-content": "~:stretch",
|
||||
"~:layout-item-h-sizing": "~:auto",
|
||||
"~:layout-item-v-sizing": "~:auto",
|
||||
"~:x": 0,
|
||||
"~:y": 0,
|
||||
"~:width": 99.99999904632568,
|
||||
"~:height": 17,
|
||||
"~:transform": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:transform-inverse": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:rotation": 0,
|
||||
"~:points": [
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 99.99999904632568,
|
||||
"~:y": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 99.99999904632568,
|
||||
"~:y": 17
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 17
|
||||
}
|
||||
}
|
||||
],
|
||||
"~:selrect": {
|
||||
"~#rect": {
|
||||
"~:x": 0,
|
||||
"~:y": 0,
|
||||
"~:width": 99.99999904632568,
|
||||
"~:height": 17,
|
||||
"~:x1": 0,
|
||||
"~:y1": 0,
|
||||
"~:x2": 99.99999904632568,
|
||||
"~:y2": 17
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"~uc0a701d6-7df9-80ac-8008-c9e6c47fbce4": {
|
||||
"~#shape": {
|
||||
"~:id": "~uc0a701d6-7df9-80ac-8008-c9e6c47fbce4",
|
||||
"~:name": "Hello wide world",
|
||||
"~:type": "~:text",
|
||||
"~:grow-type": "~:auto-width",
|
||||
"~:parent-id": "~uc0a701d6-7df9-80ac-8008-c9e6c5b7f7f4",
|
||||
"~:frame-id": "~uc0a701d6-7df9-80ac-8008-c9e6c5b7f7f4",
|
||||
"~:content": {
|
||||
"~:type": "root",
|
||||
"~:children": [
|
||||
{
|
||||
"~:type": "paragraph-set",
|
||||
"~:children": [
|
||||
{
|
||||
"~:type": "paragraph",
|
||||
"~:children": [
|
||||
{
|
||||
"~:line-height": "1.2",
|
||||
"~:font-style": "normal",
|
||||
"~:typography-ref-id": null,
|
||||
"~:text-transform": "none",
|
||||
"~:text-align": "left",
|
||||
"~:font-id": "sourcesanspro",
|
||||
"~:font-size": "14",
|
||||
"~:font-weight": "400",
|
||||
"~:typography-ref-file": null,
|
||||
"~:text-direction": "ltr",
|
||||
"~:font-variant-id": "regular",
|
||||
"~:text-decoration": "none",
|
||||
"~:letter-spacing": "0",
|
||||
"~:fills": [
|
||||
{
|
||||
"~:fill-color": "#000000",
|
||||
"~:fill-opacity": 1
|
||||
}
|
||||
],
|
||||
"~:font-family": "sourcesanspro",
|
||||
"~:text": "Hello wide world"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"~:x": 0,
|
||||
"~:y": 0,
|
||||
"~:width": 99.99999904632568,
|
||||
"~:height": 17,
|
||||
"~:transform": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:transform-inverse": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:rotation": 0,
|
||||
"~:points": [
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 99.99999904632568,
|
||||
"~:y": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 99.99999904632568,
|
||||
"~:y": 17
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 17
|
||||
}
|
||||
}
|
||||
],
|
||||
"~:selrect": {
|
||||
"~#rect": {
|
||||
"~:x": 0,
|
||||
"~:y": 0,
|
||||
"~:width": 99.99999904632568,
|
||||
"~:height": 17,
|
||||
"~:x1": 0,
|
||||
"~:y1": 0,
|
||||
"~:x2": 99.99999904632568,
|
||||
"~:y2": 17
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"~uc0a701d6-7df9-80ac-8008-c9e6c8b2a9e2": {
|
||||
"~#shape": {
|
||||
"~:id": "~uc0a701d6-7df9-80ac-8008-c9e6c8b2a9e2",
|
||||
"~:name": "Group board",
|
||||
"~:type": "~:frame",
|
||||
"~:parent-id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:frame-id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:shapes": ["~uc0a701d6-7df9-80ac-8008-c9e6ca7a304a"],
|
||||
"~:fills": [
|
||||
{
|
||||
"~:fill-color": "#B1B2B5",
|
||||
"~:fill-opacity": 1
|
||||
}
|
||||
],
|
||||
"~:strokes": [],
|
||||
"~:hide-fill-on-export": false,
|
||||
"~:show-content": true,
|
||||
"~:proportion-lock": false,
|
||||
"~:proportion": 1,
|
||||
"~:r1": 0,
|
||||
"~:r2": 0,
|
||||
"~:r3": 0,
|
||||
"~:r4": 0,
|
||||
"~:layout": "~:flex",
|
||||
"~:layout-flex-dir": "~:row",
|
||||
"~:layout-wrap-type": "~:nowrap",
|
||||
"~:layout-gap-type": "~:multiple",
|
||||
"~:layout-gap": {
|
||||
"~:row-gap": 0,
|
||||
"~:column-gap": 0
|
||||
},
|
||||
"~:layout-padding-type": "~:simple",
|
||||
"~:layout-padding": {
|
||||
"~:p1": 0,
|
||||
"~:p2": 0,
|
||||
"~:p3": 0,
|
||||
"~:p4": 0
|
||||
},
|
||||
"~:layout-align-items": "~:start",
|
||||
"~:layout-justify-content": "~:start",
|
||||
"~:layout-align-content": "~:stretch",
|
||||
"~:layout-item-h-sizing": "~:auto",
|
||||
"~:layout-item-v-sizing": "~:auto",
|
||||
"~:x": 0,
|
||||
"~:y": 100,
|
||||
"~:width": 120.99999821186066,
|
||||
"~:height": 17,
|
||||
"~:transform": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:transform-inverse": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:rotation": 0,
|
||||
"~:points": [
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 120.99999821186066,
|
||||
"~:y": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 120.99999821186066,
|
||||
"~:y": 117
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 117
|
||||
}
|
||||
}
|
||||
],
|
||||
"~:selrect": {
|
||||
"~#rect": {
|
||||
"~:x": 0,
|
||||
"~:y": 100,
|
||||
"~:width": 120.99999821186066,
|
||||
"~:height": 17,
|
||||
"~:x1": 0,
|
||||
"~:y1": 100,
|
||||
"~:x2": 120.99999821186066,
|
||||
"~:y2": 117
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"~uc0a701d6-7df9-80ac-8008-c9e6ca7a304a": {
|
||||
"~#shape": {
|
||||
"~:id": "~uc0a701d6-7df9-80ac-8008-c9e6ca7a304a",
|
||||
"~:name": "Group",
|
||||
"~:type": "~:group",
|
||||
"~:parent-id": "~uc0a701d6-7df9-80ac-8008-c9e6c8b2a9e2",
|
||||
"~:frame-id": "~uc0a701d6-7df9-80ac-8008-c9e6c8b2a9e2",
|
||||
"~:shapes": ["~uc0a701d6-7df9-80ac-8008-c9e6c781a50f"],
|
||||
"~:fills": [],
|
||||
"~:strokes": [],
|
||||
"~:proportion-lock": false,
|
||||
"~:proportion": 1,
|
||||
"~:x": 0,
|
||||
"~:y": 100,
|
||||
"~:width": 120.99999821186066,
|
||||
"~:height": 17,
|
||||
"~:transform": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:transform-inverse": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:rotation": 0,
|
||||
"~:points": [
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 120.99999821186066,
|
||||
"~:y": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 120.99999821186066,
|
||||
"~:y": 117
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 117
|
||||
}
|
||||
}
|
||||
],
|
||||
"~:selrect": {
|
||||
"~#rect": {
|
||||
"~:x": 0,
|
||||
"~:y": 100,
|
||||
"~:width": 120.99999821186066,
|
||||
"~:height": 17,
|
||||
"~:x1": 0,
|
||||
"~:y1": 100,
|
||||
"~:x2": 120.99999821186066,
|
||||
"~:y2": 117
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"~uc0a701d6-7df9-80ac-8008-c9e6c781a50f": {
|
||||
"~#shape": {
|
||||
"~:id": "~uc0a701d6-7df9-80ac-8008-c9e6c781a50f",
|
||||
"~:name": "Hello grouped world",
|
||||
"~:type": "~:text",
|
||||
"~:grow-type": "~:auto-width",
|
||||
"~:parent-id": "~uc0a701d6-7df9-80ac-8008-c9e6ca7a304a",
|
||||
"~:frame-id": "~uc0a701d6-7df9-80ac-8008-c9e6c8b2a9e2",
|
||||
"~:content": {
|
||||
"~:type": "root",
|
||||
"~:children": [
|
||||
{
|
||||
"~:type": "paragraph-set",
|
||||
"~:children": [
|
||||
{
|
||||
"~:type": "paragraph",
|
||||
"~:children": [
|
||||
{
|
||||
"~:line-height": "1.2",
|
||||
"~:font-style": "normal",
|
||||
"~:typography-ref-id": null,
|
||||
"~:text-transform": "none",
|
||||
"~:text-align": "left",
|
||||
"~:font-id": "sourcesanspro",
|
||||
"~:font-size": "14",
|
||||
"~:font-weight": "400",
|
||||
"~:typography-ref-file": null,
|
||||
"~:text-direction": "ltr",
|
||||
"~:font-variant-id": "regular",
|
||||
"~:text-decoration": "none",
|
||||
"~:letter-spacing": "0",
|
||||
"~:fills": [
|
||||
{
|
||||
"~:fill-color": "#000000",
|
||||
"~:fill-opacity": 1
|
||||
}
|
||||
],
|
||||
"~:font-family": "sourcesanspro",
|
||||
"~:text": "Hello grouped world"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"~:x": 0,
|
||||
"~:y": 100,
|
||||
"~:width": 120.99999821186066,
|
||||
"~:height": 17,
|
||||
"~:transform": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:transform-inverse": {
|
||||
"~#matrix": {
|
||||
"~:a": 1,
|
||||
"~:b": 0,
|
||||
"~:c": 0,
|
||||
"~:d": 1,
|
||||
"~:e": 0,
|
||||
"~:f": 0
|
||||
}
|
||||
},
|
||||
"~:rotation": 0,
|
||||
"~:points": [
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 120.99999821186066,
|
||||
"~:y": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 120.99999821186066,
|
||||
"~:y": 117
|
||||
}
|
||||
},
|
||||
{
|
||||
"~#point": {
|
||||
"~:x": 0,
|
||||
"~:y": 117
|
||||
}
|
||||
}
|
||||
],
|
||||
"~:selrect": {
|
||||
"~#rect": {
|
||||
"~:x": 0,
|
||||
"~:y": 100,
|
||||
"~:width": 120.99999821186066,
|
||||
"~:height": 17,
|
||||
"~:x1": 0,
|
||||
"~:y1": 100,
|
||||
"~:x2": 120.99999821186066,
|
||||
"~:y2": 117
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:id": "~u238a17e0-75ff-8075-8006-934586ea2231",
|
||||
"~:name": "Page 1"
|
||||
}
|
||||
},
|
||||
"~:id": "~u238a17e0-75ff-8075-8006-934586ea2230",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -23,7 +23,6 @@ async function openEditorAndSelectAll(workspace) {
|
||||
await workspace.page.keyboard.press("ControlOrMeta+a");
|
||||
}
|
||||
|
||||
|
||||
test("Typography at a collapsed caret only styles newly typed text", async ({
|
||||
page,
|
||||
}) => {
|
||||
@ -218,8 +217,6 @@ test.describe("BUG 11083 - Changing typography must not quit the editor", () =>
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
test("BUG 10467 - Auto-width text captures every typed character", async ({
|
||||
page,
|
||||
}) => {
|
||||
@ -681,3 +678,74 @@ test.describe("Text Editor context menu", () => {
|
||||
await expect(menuItem(page, "Select all")).not.toHaveAttribute("disabled");
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("BUG 12325 - Fit-content flex board follows an auto-width text while typing", () => {
|
||||
// Two grey fit-content flex boards, one per test. The content
|
||||
// (0, 0)-(121, 117) loads centred in the viewport at zoom 1.
|
||||
const CONTENT_CENTER = { x: 60.5, y: 58.5 };
|
||||
|
||||
// Screenshot of a small canvas patch centred on (x, y), in canvas
|
||||
// coordinates.
|
||||
async function patchAt(workspace, x, y) {
|
||||
const viewport = await workspace.viewport.boundingBox();
|
||||
const px = viewport.x + viewport.width / 2 + x - CONTENT_CENTER.x;
|
||||
const py = viewport.y + viewport.height / 2 + y - CONTENT_CENTER.y;
|
||||
return workspace.page.screenshot({
|
||||
clip: { x: px - 2, y: py - 2, width: 4, height: 4 },
|
||||
});
|
||||
}
|
||||
|
||||
async function openFile(page) {
|
||||
const workspace = new WasmWorkspacePage(page, { textEditor: true });
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockGetFile("text-editor/get-file-12325.json");
|
||||
await workspace.goToWorkspace();
|
||||
await workspace.waitForFirstRender();
|
||||
return workspace;
|
||||
}
|
||||
|
||||
// Shrinks `text` to its first character while editing and checks that a spot
|
||||
// in the right part of its board, at `boardY`, shows the empty canvas.
|
||||
async function expectBoardShrinksWhileTyping(workspace, text, boardY) {
|
||||
const x = 80;
|
||||
const inside = boardY + 8;
|
||||
const outside = boardY + 50;
|
||||
expect(await patchAt(workspace, x, inside)).not.toEqual(
|
||||
await patchAt(workspace, x, outside),
|
||||
);
|
||||
|
||||
await workspace.textEditor.startEditing();
|
||||
await workspace.page.keyboard.press("End");
|
||||
for (let i = 0; i < text.length - 1; i++) {
|
||||
await workspace.page.keyboard.press("Backspace");
|
||||
}
|
||||
|
||||
// Without leaving the editor, the board already shrank around the text, so
|
||||
// the spot shows the empty canvas.
|
||||
await expect
|
||||
.poll(async () =>
|
||||
(await patchAt(workspace, x, inside)).equals(
|
||||
await patchAt(workspace, x, outside),
|
||||
),
|
||||
)
|
||||
.toBe(true);
|
||||
}
|
||||
|
||||
test("The board shrinks with the text", async ({ page }) => {
|
||||
const workspace = await openFile(page);
|
||||
await workspace.clickToggableLayer("Text board");
|
||||
await workspace.clickLeafLayer("Hello wide world");
|
||||
|
||||
await expectBoardShrinksWhileTyping(workspace, "Hello wide world", 0);
|
||||
});
|
||||
|
||||
test("The board shrinks with a text inside a group", async ({ page }) => {
|
||||
const workspace = await openFile(page);
|
||||
await workspace.clickToggableLayer("Group board");
|
||||
// The first "Group" match is the board row.
|
||||
await workspace.clickToggableLayer("Group", {}, 1);
|
||||
await workspace.clickLeafLayer("Hello grouped world");
|
||||
|
||||
await expectBoardShrinksWhileTyping(workspace, "Hello grouped world", 100);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1453,18 +1453,77 @@
|
||||
(gsh/transform-shape (ctm/change-size shape width height))))))
|
||||
{:undo-group (when new-shape? id)}))))))))
|
||||
|
||||
(defn- layout-item
|
||||
"The ancestor of `shape` (or `shape` itself) that is a direct child of its board."
|
||||
[objects shape]
|
||||
(loop [item shape]
|
||||
(let [parent-id (:parent-id item)]
|
||||
(if (or (= parent-id (:frame-id shape))
|
||||
(nil? (get objects parent-id)))
|
||||
item
|
||||
(recur (get objects parent-id))))))
|
||||
|
||||
(defn- v3-sync-text-layout
|
||||
"Previews an auto-grow text's live size in its layout, so a fit-content parent
|
||||
follows it while typing. Geometry is committed on finalize."
|
||||
[id]
|
||||
(ptk/reify ::v3-sync-text-layout
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
preview? (and (cfh/text-shape? shape)
|
||||
(not= :fixed (:grow-type shape))
|
||||
(ctl/any-layout-descent? objects shape)
|
||||
(not (ctl/position-absolute? (layout-item objects shape))))
|
||||
size (when preview?
|
||||
(dwwt/get-wasm-text-new-size shape))
|
||||
previous (or (get-in state [::layout-preview id])
|
||||
(select-keys (:selrect shape) [:width :height]))]
|
||||
;; Modifiers are costly, so skip keystrokes that keep the size.
|
||||
(if (and (some? size)
|
||||
(not (and (mth/close? (:width size) (:width previous))
|
||||
(mth/close? (:height size) (:height previous)))))
|
||||
(rx/of #(assoc-in % [::layout-preview id] size)
|
||||
(dwm/set-wasm-modifiers (dwwt/resize-wasm-text-modifiers shape)))
|
||||
(rx/empty))))))
|
||||
|
||||
(defn v3-stop-text-layout-preview
|
||||
"Drops the layout preview of the text `id` and leaves interactive render mode."
|
||||
[id]
|
||||
(ptk/reify ::v3-stop-text-layout-preview
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(if (contains? (get state ::layout-preview) id)
|
||||
(rx/of #(update % ::layout-preview dissoc id)
|
||||
(dwm/clear-local-transform))
|
||||
(rx/empty)))))
|
||||
|
||||
(defn v3-update-editor-content
|
||||
"Commits `content` from the WASM editor to the text `shape-id` and, while
|
||||
editing, previews its new size in the layout."
|
||||
[shape-id content & {:keys [finalize?]}]
|
||||
(let [text (txt/content->text content)
|
||||
name (when (not= text "")
|
||||
(txt/generate-shape-name text))
|
||||
update-event (v2-update-text-shape-content shape-id content
|
||||
:update-name? true
|
||||
:name name
|
||||
:finalize? finalize?)]
|
||||
(if finalize?
|
||||
update-event
|
||||
(ptk/reify ::v3-update-editor-content
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of update-event
|
||||
(v3-sync-text-layout shape-id)))))))
|
||||
|
||||
(defn v3-sync-editor-content
|
||||
"Event pushing the WASM editor content back into the shape, or nil when there is
|
||||
nothing to sync. Every text edit commits through it, menu or keystroke alike."
|
||||
[& {:keys [finalize?]}]
|
||||
(when-let [{:keys [shape-id content]} (wasm.text-editor/text-editor-sync-content)]
|
||||
(let [text (txt/content->text content)
|
||||
name (when (not= text "")
|
||||
(txt/generate-shape-name text))]
|
||||
(v2-update-text-shape-content shape-id content
|
||||
:update-name? true
|
||||
:name name
|
||||
:finalize? finalize?))))
|
||||
(v3-update-editor-content shape-id content :finalize? finalize?)))
|
||||
|
||||
(defn- sync-editor-content-stream
|
||||
"Stream of the sync event for `reason`, after asking WASM to repaint."
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.text :as txt]
|
||||
[app.config :as cf]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace :as dw]
|
||||
@ -87,12 +86,7 @@
|
||||
;; Sync first so the cached content stays index-aligned with WASM.
|
||||
(text-editor/text-editor-sync-content)
|
||||
(if-let [{:keys [content]} (wasm.api/apply-pending-caret-styles! shape-id range)]
|
||||
(let [text (txt/content->text content)
|
||||
name (when (not= text "") (txt/generate-shape-name text))]
|
||||
(st/emit! (dwt/v2-update-text-shape-content
|
||||
shape-id content
|
||||
:update-name? true
|
||||
:name name)))
|
||||
(st/emit! (dwt/v3-update-editor-content shape-id content))
|
||||
(sync-wasm-text-editor-content!))))
|
||||
|
||||
(defn- collapse-input-caret
|
||||
@ -663,6 +657,7 @@
|
||||
(fn []
|
||||
(on-blur)
|
||||
(st/emit! dw/hide-context-menu
|
||||
(dwt/v3-stop-text-layout-preview shape-id)
|
||||
(dwu/commit-undo-transaction shape-id))
|
||||
(text-editor/text-editor-dispose)
|
||||
(wasm.api/request-render-preserving-target "text-editor-dispose"))))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user