mirror of
https://github.com/penpot/penpot.git
synced 2026-01-22 05:10:21 -05:00
Compare commits
6 Commits
niwinz-dev
...
eva-replac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
372a47ec9a | ||
|
|
6e6a0d48c0 | ||
|
|
fd91fc6d9c | ||
|
|
4af0ad17fd | ||
|
|
49eef0771b | ||
|
|
875155e032 |
@@ -474,8 +474,8 @@
|
||||
:height #{:sizing :dimensions}
|
||||
:max-width #{:sizing :dimensions}
|
||||
:max-height #{:sizing :dimensions}
|
||||
:x #{:spacing :dimensions}
|
||||
:y #{:spacing :dimensions}
|
||||
:x #{:dimensions}
|
||||
:y #{:dimensions}
|
||||
:rotation #{:number :rotation}
|
||||
:border-radius #{:border-radius :dimensions}
|
||||
:row-gap #{:spacing :dimensions}
|
||||
@@ -488,6 +488,7 @@
|
||||
:sided-margins #{:spacing :dimensions}
|
||||
:line-height #{:line-height :number}
|
||||
:opacity #{:opacity}
|
||||
:stroke-width #{:stroke-width}
|
||||
:font-size #{:font-size}
|
||||
:letter-spacing #{:letter-spacing}
|
||||
:fill #{:color}
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"fdata/path-data",
|
||||
"plugins/runtime",
|
||||
"design-tokens/v1",
|
||||
"variants/v1",
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/objects-map",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:team-id": "~u55ffbd0f-2d3f-8023-8007-6b89af7ca1aa",
|
||||
"~: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": "Nuevo Archivo 2",
|
||||
"~:revn": 18,
|
||||
"~:modified-at": "~m1768994999265",
|
||||
"~:vern": 0,
|
||||
"~:id": "~u8bb92298-e24e-805c-8007-6ce64314bfe8",
|
||||
"~: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": "~u55ffbd0f-2d3f-8023-8007-6b89af7cd5eb",
|
||||
"~:created-at": "~m1768562403410",
|
||||
"~:backend": "legacy-db",
|
||||
"~:data": {
|
||||
"~:pages": [
|
||||
"~u8bb92298-e24e-805c-8007-6ce64314cfc5"
|
||||
],
|
||||
"~:pages-index": {
|
||||
"~u8bb92298-e24e-805c-8007-6ce64314cfc5": {
|
||||
"~: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\",[\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~u8506e3f3-e05b-807c-8007-6ceac380abc1\"]]]",
|
||||
"~u6c65a5dc-fb40-8072-8007-6ce644905054": "[\"~#shape\",[\"^ \",\"~:y\",159,\"~: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\",\"Board\",\"~:layout-align-items\",\"~:start\",\"~:width\",389,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",303,\"~:y\",159]],[\"^L\",[\"^ \",\"~:x\",692,\"~:y\",159]],[\"^L\",[\"^ \",\"~:x\",692,\"~:y\",599]],[\"^L\",[\"^ \",\"~:x\",303,\"~:y\",599]]],\"~: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\",\"^E\",\"~:r1\",0,\"~:id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:layout-flex-dir\",\"~:row\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",303,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",303,\"~:y\",159,\"^F\",389,\"~:height\",440,\"~:x1\",303,\"~:y1\",159,\"~:x2\",692,\"~:y2\",599]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^16\",440,\"~:flip-y\",null,\"~:shapes\",[\"~u6c65a5dc-fb40-8072-8007-6ce655b5dbe9\",\"~u6c65a5dc-fb40-8072-8007-6ce65472f217\",\"~u6c65a5dc-fb40-8072-8007-6ce6535e8d62\"]]]",
|
||||
"~u6c65a5dc-fb40-8072-8007-6ce6535e8d62": "[\"~#shape\",[\"^ \",\"~:y\",159,\"~: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\",\"Rectangle\",\"~:width\",95,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",303,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",398,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",398,\"~:y\",259]],[\"^<\",[\"^ \",\"~:x\",303,\"~:y\",259]]],\"~: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]],\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~u6c65a5dc-fb40-8072-8007-6ce6535e8d62\",\"~:parent-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:frame-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:strokes\",[],\"~:x\",303,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",303,\"~:y\",159,\"^8\",95,\"~:height\",100,\"~:x1\",303,\"~:y1\",159,\"~:x2\",398,\"~:y2\",259]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",100,\"~:flip-y\",null]]",
|
||||
"~u6c65a5dc-fb40-8072-8007-6ce65472f217": "[\"~#shape\",[\"^ \",\"~:y\",159,\"~: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\",\"Rectangle\",\"~:width\",140.99999999999994,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",398,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",539,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",539,\"~:y\",296]],[\"^<\",[\"^ \",\"~:x\",398,\"~:y\",296]]],\"~: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]],\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~u6c65a5dc-fb40-8072-8007-6ce65472f217\",\"~:parent-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:frame-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:strokes\",[],\"~:x\",398.00000000000006,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",398.00000000000006,\"~:y\",159,\"^8\",140.99999999999994,\"~:height\",137,\"~:x1\",398.00000000000006,\"~:y1\",159,\"~:x2\",539,\"~:y2\",296]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",137,\"~:flip-y\",null]]",
|
||||
"~u6c65a5dc-fb40-8072-8007-6ce655b5dbe9": "[\"~#shape\",[\"^ \",\"~:y\",159,\"~: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\",\"Rectangle\",\"~:width\",82,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",539,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",621,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",621,\"~:y\",259]],[\"^<\",[\"^ \",\"~:x\",539,\"~:y\",259]]],\"~: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]],\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~u6c65a5dc-fb40-8072-8007-6ce655b5dbe9\",\"~:parent-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:frame-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:strokes\",[],\"~:x\",539,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",539,\"~:y\",159,\"^8\",82,\"~:height\",100,\"~:x1\",539,\"~:y1\",159,\"~:x2\",621,\"~:y2\",259]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",100,\"~:flip-y\",null]]",
|
||||
"~u8506e3f3-e05b-807c-8007-6ceac380abc1": "[\"~#shape\",[\"^ \",\"~:y\",405,\"~: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\",\"Rectangle\",\"~:width\",59,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",817,\"~:y\",405]],[\"^<\",[\"^ \",\"~:x\",876,\"~:y\",405]],[\"^<\",[\"^ \",\"~:x\",876,\"~:y\",472]],[\"^<\",[\"^ \",\"~:x\",817,\"~:y\",472]]],\"~: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]],\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~u8506e3f3-e05b-807c-8007-6ceac380abc1\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",817,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",817,\"~:y\",405,\"^8\",59,\"~:height\",67,\"~:x1\",817,\"~:y1\",405,\"~:x2\",876,\"~:y2\",472]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",67,\"~:flip-y\",null]]"
|
||||
}
|
||||
},
|
||||
"~:id": "~u8bb92298-e24e-805c-8007-6ce64314cfc5",
|
||||
"~:name": "Page 1"
|
||||
}
|
||||
},
|
||||
"~:id": "~u8bb92298-e24e-805c-8007-6ce64314bfe8",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
},
|
||||
"~:tokens-lib": {
|
||||
"~#penpot/tokens-lib": {
|
||||
"~:sets": {
|
||||
"~#ordered-map": [
|
||||
[
|
||||
"S-Global",
|
||||
{
|
||||
"~#penpot/token-set": {
|
||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce67f8f2592",
|
||||
"~:name": "Global",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768994999268",
|
||||
"~:tokens": {
|
||||
"~#ordered-map": [
|
||||
[
|
||||
"dim.xs",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce67f8f2591",
|
||||
"~:name": "dim.xs",
|
||||
"~:type": "~:dimensions",
|
||||
"~:value": "20",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768562465340"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"dim.md",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce68a2f3c3f",
|
||||
"~:name": "dim.md",
|
||||
"~:type": "~:dimensions",
|
||||
"~:value": "50",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768562476220"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"dim.xl",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce694f47726",
|
||||
"~:name": "dim.xl",
|
||||
"~:type": "~:dimensions",
|
||||
"~:value": "100",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768562487249"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"sz.sm",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce6d6e519b1",
|
||||
"~:name": "sz.sm",
|
||||
"~:type": "~:sizing",
|
||||
"~:value": "200",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768562554772"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"sz.xl",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce6e4165307",
|
||||
"~:name": "sz.xl",
|
||||
"~:type": "~:sizing",
|
||||
"~:value": "500",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768562568281"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"sp.mid",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce6f5fb2867",
|
||||
"~:name": "sp.mid",
|
||||
"~:type": "~:spacing",
|
||||
"~:value": "50",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768562586604"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"sp.l",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce71009cd91",
|
||||
"~:name": "sp.l",
|
||||
"~:type": "~:spacing",
|
||||
"~:value": "{dim.xl}",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768562613287"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"test",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~uc49f25e6-1298-8004-8007-709f660875be",
|
||||
"~:name": "test",
|
||||
"~:type": "~:dimensions",
|
||||
"~:value": "20",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768812262433"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"width-big",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u3b3e4320-53fb-8096-8007-73585edb4dd6",
|
||||
"~:name": "width-big",
|
||||
"~:type": "~:stroke-width",
|
||||
"~:value": "20",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768994969453"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"width-small",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u3b3e4320-53fb-8096-8007-73586a5ec516",
|
||||
"~:name": "width-small",
|
||||
"~:type": "~:stroke-width",
|
||||
"~:value": "5",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768994981243"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"red",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u3b3e4320-53fb-8096-8007-735871dccede",
|
||||
"~:name": "red",
|
||||
"~:type": "~:color",
|
||||
"~:value": "red",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768994988915"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"green",
|
||||
{
|
||||
"~#penpot/token": {
|
||||
"~:id": "~u3b3e4320-53fb-8096-8007-735879045aa2",
|
||||
"~:name": "green",
|
||||
"~:type": "~:color",
|
||||
"~:value": "green",
|
||||
"~:description": "",
|
||||
"~:modified-at": "~m1768994996241"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"~:themes": {
|
||||
"~#ordered-map": [
|
||||
[
|
||||
"",
|
||||
{
|
||||
"~#ordered-map": [
|
||||
[
|
||||
"__PENPOT__HIDDEN__TOKEN__THEME__",
|
||||
{
|
||||
"~#penpot/token-theme": {
|
||||
"~:id": "~u00000000-0000-0000-0000-000000000000",
|
||||
"~:name": "__PENPOT__HIDDEN__TOKEN__THEME__",
|
||||
"~:group": "",
|
||||
"~:description": "",
|
||||
"~:is-source": false,
|
||||
"~:external-id": "",
|
||||
"~:modified-at": "~m1768562468391",
|
||||
"~:sets": {
|
||||
"~#set": [
|
||||
"Global"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"~:active-themes": {
|
||||
"~#set": [
|
||||
"/__PENPOT__HIDDEN__TOKEN__THEME__"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,12 +149,14 @@ test.describe("Tokens: Apply token", () => {
|
||||
await detachButton.click();
|
||||
|
||||
// Open dropdown from input
|
||||
const dropdownBtn = layerMenuSection.getByLabel('Open token list');
|
||||
const dropdownBtn = layerMenuSection.getByLabel("Open token list");
|
||||
await expect(dropdownBtn).toBeVisible();
|
||||
await dropdownBtn.click();
|
||||
|
||||
// Change token from dropdown
|
||||
const opacityLowOption = layerMenuSection.getByRole('option', { name: 'opacity.low' });
|
||||
const opacityLowOption = layerMenuSection.getByRole("option", {
|
||||
name: "opacity.low",
|
||||
});
|
||||
await expect(opacityLowOption).toBeVisible();
|
||||
await opacityLowOption.click();
|
||||
|
||||
@@ -482,4 +484,279 @@ test.describe("Tokens: Apply token", () => {
|
||||
await expect(shadowSection).toHaveCount(2);
|
||||
});
|
||||
});
|
||||
|
||||
test("User applies dimension token to a shape on width and height", async ({
|
||||
page,
|
||||
}) => {
|
||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
||||
await setupTokensFile(page);
|
||||
|
||||
// Unfolds dimensions on token panel
|
||||
await page.getByRole("tab", { name: "Layers" }).click();
|
||||
|
||||
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
||||
|
||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
||||
await tokensTabButton.click();
|
||||
|
||||
unfoldTokenTree(tokensSidebar, "dimensions", "dimension.dimension.sm");
|
||||
|
||||
// Apply token to width and height token from token panel
|
||||
await tokensSidebar.getByRole("button", { name: "dimension.sm" }).click();
|
||||
|
||||
// Check if measures sections is visible on right sidebar
|
||||
const measuresSection = page.getByRole("region", {
|
||||
name: "shape-measures-section",
|
||||
});
|
||||
await expect(measuresSection).toBeVisible();
|
||||
|
||||
// Check if token pill is visible on design tab on right sidebar
|
||||
const dimensionSMTokenPill = measuresSection.getByRole("button", {
|
||||
name: "dimension.sm",
|
||||
});
|
||||
await expect(dimensionSMTokenPill).toHaveCount(2);
|
||||
await dimensionSMTokenPill.nth(1).click();
|
||||
|
||||
// Change token from dropdown
|
||||
const dimensionTokenOptionXl = measuresSection.getByLabel("dimension.xl");
|
||||
await expect(dimensionTokenOptionXl).toBeVisible();
|
||||
await dimensionTokenOptionXl.click();
|
||||
|
||||
await expect(dimensionSMTokenPill).toHaveCount(1);
|
||||
const dimensionXLTokenPill = measuresSection.getByRole("button", {
|
||||
name: "dimension.xl",
|
||||
});
|
||||
await expect(dimensionXLTokenPill).toBeVisible();
|
||||
|
||||
// Detach token from design tab on right sidebar
|
||||
const detachButton = measuresSection.getByRole("button", {
|
||||
name: "Detach token",
|
||||
});
|
||||
await detachButton.nth(1).click();
|
||||
await expect(dimensionXLTokenPill).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("User applies dimension token to a shape on x position", async ({
|
||||
page,
|
||||
}) => {
|
||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
||||
await setupTokensFile(page);
|
||||
|
||||
// Unfolds dimensions on token panel
|
||||
await page.getByRole("tab", { name: "Layers" }).click();
|
||||
|
||||
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
||||
|
||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
||||
await tokensTabButton.click();
|
||||
|
||||
unfoldTokenTree(tokensSidebar, "dimensions", "dimension.dimension.sm");
|
||||
|
||||
// Apply token to width and height token from token panel
|
||||
await tokensSidebar
|
||||
.getByRole("button", { name: "dimension.sm" })
|
||||
.click({ button: "right" });
|
||||
await tokenContextMenuForToken.getByText("AxisX").click();
|
||||
|
||||
// Check if measures sections is visible on right sidebar
|
||||
const measuresSection = page.getByRole("region", {
|
||||
name: "shape-measures-section",
|
||||
});
|
||||
await expect(measuresSection).toBeVisible();
|
||||
|
||||
// Check if token pill is visible on design tab on right sidebar
|
||||
const dimensionSMTokenPill = measuresSection.getByRole("button", {
|
||||
name: "dimension.sm",
|
||||
});
|
||||
await expect(dimensionSMTokenPill).toBeVisible();
|
||||
await dimensionSMTokenPill.click();
|
||||
|
||||
// Change token from dropdown
|
||||
const dimensionTokenOptionXl = measuresSection.getByLabel("dimension.xl");
|
||||
await expect(dimensionTokenOptionXl).toBeVisible();
|
||||
await dimensionTokenOptionXl.click();
|
||||
|
||||
await expect(dimensionSMTokenPill).not.toBeVisible();
|
||||
const dimensionXLTokenPill = measuresSection.getByRole("button", {
|
||||
name: "dimension.xl",
|
||||
});
|
||||
await expect(dimensionXLTokenPill).toBeVisible();
|
||||
|
||||
// Detach token from design tab on right sidebar
|
||||
const detachButton = measuresSection.getByRole("button", {
|
||||
name: "Detach token",
|
||||
});
|
||||
await detachButton.nth(0).click();
|
||||
await expect(dimensionXLTokenPill).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("User applies dimension token to a shape on y position", async ({
|
||||
page,
|
||||
}) => {
|
||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
||||
await setupTokensFile(page);
|
||||
|
||||
// Unfolds dimensions on token panel
|
||||
await page.getByRole("tab", { name: "Layers" }).click();
|
||||
|
||||
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
||||
|
||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
||||
await tokensTabButton.click();
|
||||
|
||||
unfoldTokenTree(tokensSidebar, "dimensions", "dimension.dimension.sm");
|
||||
|
||||
// Apply token to width and height token from token panel
|
||||
await tokensSidebar
|
||||
.getByRole("button", { name: "dimension.sm" })
|
||||
.click({ button: "right" });
|
||||
await tokenContextMenuForToken.getByText("Y").click();
|
||||
|
||||
// Check if measures sections is visible on right sidebar
|
||||
const measuresSection = page.getByRole("region", {
|
||||
name: "shape-measures-section",
|
||||
});
|
||||
await expect(measuresSection).toBeVisible();
|
||||
|
||||
// Check if token pill is visible on design tab on right sidebar
|
||||
const dimensionSMTokenPill = measuresSection.getByRole("button", {
|
||||
name: "dimension.sm",
|
||||
});
|
||||
await expect(dimensionSMTokenPill).toBeVisible();
|
||||
await dimensionSMTokenPill.click();
|
||||
|
||||
// Change token from dropdown
|
||||
const dimensionTokenOptionXl = measuresSection.getByLabel("dimension.xl");
|
||||
await expect(dimensionTokenOptionXl).toBeVisible();
|
||||
await dimensionTokenOptionXl.click();
|
||||
|
||||
await expect(dimensionSMTokenPill).not.toBeVisible();
|
||||
const dimensionXLTokenPill = measuresSection.getByRole("button", {
|
||||
name: "dimension.xl",
|
||||
});
|
||||
await expect(dimensionXLTokenPill).toBeVisible();
|
||||
|
||||
// Detach token from design tab on right sidebar
|
||||
const detachButton = measuresSection.getByRole("button", {
|
||||
name: "Detach token",
|
||||
});
|
||||
await detachButton.nth(0).click();
|
||||
await expect(dimensionXLTokenPill).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("User applies dimension token to a shape border-radius", async ({
|
||||
page,
|
||||
}) => {
|
||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
||||
await setupTokensFile(page);
|
||||
|
||||
// Unfolds dimensions on token panel
|
||||
await page.getByRole("tab", { name: "Layers" }).click();
|
||||
|
||||
await workspacePage.layers.getByTestId("layer-row").nth(2).click();
|
||||
|
||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
||||
await tokensTabButton.click();
|
||||
|
||||
unfoldTokenTree(tokensSidebar, "dimensions", "dimension.dimension.xs");
|
||||
|
||||
// Apply token to width and height token from token panel
|
||||
await tokensSidebar
|
||||
.getByRole("button", { name: "dimension.xs" })
|
||||
.click({ button: "right" });
|
||||
await tokenContextMenuForToken.getByText("Border radius").hover();
|
||||
await tokenContextMenuForToken.getByText("RadiusAll").click();
|
||||
|
||||
// Check if border radius sections is visible on right sidebar
|
||||
const borderRadiusSection = page.getByRole("region", {
|
||||
name: "border-radius-section",
|
||||
});
|
||||
await expect(borderRadiusSection).toBeVisible();
|
||||
|
||||
// Check if token pill is visible on design tab on right sidebar
|
||||
const dimensionXSTokenPill = borderRadiusSection.getByRole("button", {
|
||||
name: "dimension.xs",
|
||||
});
|
||||
await expect(dimensionXSTokenPill).toBeVisible();
|
||||
await dimensionXSTokenPill.click();
|
||||
|
||||
// Change token from dropdown
|
||||
const dimensionTokenOptionXl =
|
||||
borderRadiusSection.getByLabel("dimension.xl");
|
||||
await expect(dimensionTokenOptionXl).toBeVisible();
|
||||
await dimensionTokenOptionXl.click();
|
||||
|
||||
await expect(dimensionXSTokenPill).not.toBeVisible();
|
||||
const dimensionXLTokenPill = borderRadiusSection.getByRole("button", {
|
||||
name: "dimension.xl",
|
||||
});
|
||||
await expect(dimensionXLTokenPill).toBeVisible();
|
||||
|
||||
// Detach token from design tab on right sidebar
|
||||
const detachButton = borderRadiusSection.getByRole("button", {
|
||||
name: "Detach token",
|
||||
});
|
||||
await detachButton.nth(0).click();
|
||||
await expect(dimensionXLTokenPill).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("User applies stroke width token to a shape", async ({ page }) => {
|
||||
const workspace = new WorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
// Set up
|
||||
await workspace.mockConfigFlags(["enable-feature-token-input"]);
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockGetFile("workspace/get-file-layout-stroke-token-json");
|
||||
await workspace.goToWorkspace();
|
||||
|
||||
// Select shape apply stroke
|
||||
await workspace.layers.getByTestId("layer-row").nth(0).click();
|
||||
const rightSidebar = page.getByTestId("right-sidebar");
|
||||
await expect(rightSidebar).toBeVisible();
|
||||
await rightSidebar.getByTestId("add-stroke").click();
|
||||
|
||||
// Apply stroke width token from token panel
|
||||
const tokensTab = page.getByRole("tab", { name: "Tokens" });
|
||||
await expect(tokensTab).toBeVisible();
|
||||
await tokensTab.click();
|
||||
await page.getByRole("button", { name: "Stroke Width 2" }).click();
|
||||
const tokensSidebar = workspace.tokensSidebar;
|
||||
await expect(
|
||||
tokensSidebar.getByRole("button", { name: "width-big" }),
|
||||
).toBeVisible();
|
||||
await tokensSidebar.getByRole("button", { name: "width-big" }).click();
|
||||
|
||||
// Check if token pill is visible on right sidebar
|
||||
const strokeSectionSidebar = rightSidebar.getByRole("region", {
|
||||
name: "stroke-section",
|
||||
});
|
||||
await expect(strokeSectionSidebar).toBeVisible();
|
||||
const firstStrokeRow = strokeSectionSidebar.getByLabel("stroke-row-0");
|
||||
await expect(firstStrokeRow).toBeVisible();
|
||||
const StrokeWidthPill = firstStrokeRow.getByRole("button", {
|
||||
name: "width-big",
|
||||
});
|
||||
await expect(StrokeWidthPill).toBeVisible();
|
||||
|
||||
// Detach token from right sidebar and apply another from dropdown
|
||||
const detachButton = firstStrokeRow.getByRole("button", {
|
||||
name: "Detach token",
|
||||
});
|
||||
await detachButton.click();
|
||||
await expect(StrokeWidthPill).not.toBeVisible();
|
||||
|
||||
const tokenDropdown = firstStrokeRow.getByRole("button", {
|
||||
name: "Open token list",
|
||||
});
|
||||
await tokenDropdown.click();
|
||||
|
||||
const widthOptionSmall = firstStrokeRow.getByLabel("width-small");
|
||||
await expect(widthOptionSmall).toBeVisible();
|
||||
await widthOptionSmall.click();
|
||||
const StrokeWidthPillSmall = firstStrokeRow.getByRole("button", {
|
||||
name: "width-small",
|
||||
});
|
||||
await expect(StrokeWidthPillSmall).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -191,16 +191,6 @@
|
||||
(when (:fill attributes) (update-fill value shape-ids attributes page-id))
|
||||
(when (:stroke-color attributes) (update-stroke-color value shape-ids attributes page-id)))))))
|
||||
|
||||
(defn update-shape-dimensions
|
||||
([value shape-ids attributes] (update-shape-dimensions value shape-ids attributes nil))
|
||||
([value shape-ids attributes page-id]
|
||||
(ptk/reify ::update-shape-dimensions
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(when (number? value)
|
||||
(rx/of
|
||||
(when (:width attributes) (dwtr/update-dimensions shape-ids :width value {:ignore-touched true :page-id page-id}))
|
||||
(when (:height attributes) (dwtr/update-dimensions shape-ids :height value {:ignore-touched true :page-id page-id}))))))))
|
||||
|
||||
(defn- attributes->layout-gap [attributes value]
|
||||
(let [layout-gap (-> (set/intersection attributes #{:column-gap :row-gap})
|
||||
@@ -248,21 +238,6 @@
|
||||
{:ignore-touched true
|
||||
:page-id page-id}))))))))
|
||||
|
||||
(defn update-layout-spacing
|
||||
([value shape-ids attributes] (update-layout-spacing value shape-ids attributes nil))
|
||||
([value shape-ids attributes page-id]
|
||||
(ptk/reify ::update-layout-spacing
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when (number? value)
|
||||
(let [ids-with-layout (shape-ids-with-layout state (or page-id (:current-page-id state)) shape-ids)
|
||||
layout-attributes (attributes->layout-gap attributes value)]
|
||||
(rx/of
|
||||
(dwsl/update-layout ids-with-layout
|
||||
layout-attributes
|
||||
{:ignore-touched true
|
||||
:page-id page-id}))))))))
|
||||
|
||||
(defn update-shape-position
|
||||
([value shape-ids attributes] (update-shape-position value shape-ids attributes nil))
|
||||
([value shape-ids attributes page-id]
|
||||
@@ -276,6 +251,20 @@
|
||||
{:ignore-touched true
|
||||
:page-id page-id})))))))))
|
||||
|
||||
(defn update-layout-gap
|
||||
[value shape-ids attributes page-id]
|
||||
(ptk/reify ::update-layout-gao
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when (number? value)
|
||||
(let [ids-with-layout (shape-ids-with-layout state (or page-id (:current-page-id state)) shape-ids)
|
||||
layout-attributes (attributes->layout-gap attributes value)]
|
||||
(rx/of
|
||||
(dwsl/update-layout ids-with-layout
|
||||
layout-attributes
|
||||
{:ignore-touched true
|
||||
:page-id page-id})))))))
|
||||
|
||||
(defn update-layout-sizing-limits
|
||||
([value shape-ids attributes] (update-layout-sizing-limits value shape-ids attributes nil))
|
||||
([value shape-ids attributes page-id]
|
||||
@@ -470,20 +459,126 @@
|
||||
value
|
||||
[shape-ids attributes page-id])))))
|
||||
|
||||
(defn update-typography-interactive
|
||||
([value shape-ids attributes] (update-typography value shape-ids attributes nil))
|
||||
(defn update-shape-dimensions
|
||||
([value shape-ids attributes] (update-shape-dimensions value shape-ids attributes nil))
|
||||
([value shape-ids attributes page-id]
|
||||
(when (map? value)
|
||||
(rx/merge
|
||||
(apply-functions-map
|
||||
{:font-size update-font-size
|
||||
:font-family update-font-family-interactive
|
||||
:font-weight update-font-weight-interactive
|
||||
:letter-spacing update-letter-spacing
|
||||
:text-case update-text-case
|
||||
:text-decoration update-text-decoration-interactive}
|
||||
value
|
||||
[shape-ids attributes page-id])))))
|
||||
(ptk/reify ::update-shape-dimensions
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(when (number? value)
|
||||
(rx/of
|
||||
(when (:width attributes) (dwtr/update-dimensions shape-ids :width value {:ignore-touched true :page-id page-id}))
|
||||
(when (:height attributes) (dwtr/update-dimensions shape-ids :height value {:ignore-touched true :page-id page-id}))))))))
|
||||
|
||||
(defn- attributes->actions
|
||||
[{:keys [value shape-ids attributes page-id]}]
|
||||
(cond-> []
|
||||
(some attributes #{:width :height})
|
||||
(conj #(update-shape-dimensions
|
||||
value shape-ids
|
||||
(set (filter attributes #{:width :height}))
|
||||
page-id))
|
||||
|
||||
(some attributes #{:x :y})
|
||||
(conj #(update-shape-position
|
||||
value shape-ids
|
||||
(set (filter attributes #{:x :y}))
|
||||
page-id))
|
||||
|
||||
(some attributes #{:p1 :p2 :p3 :p4})
|
||||
(conj #(update-layout-padding
|
||||
value shape-ids
|
||||
(set (filter attributes #{:p1 :p2 :p3 :p4}))
|
||||
page-id))
|
||||
|
||||
(some attributes #{:m1 :m2 :m3 :m4})
|
||||
(conj #(update-layout-item-margin
|
||||
value shape-ids
|
||||
(set (filter attributes #{:m1 :m2 :m3 :m4}))
|
||||
page-id))
|
||||
|
||||
(some attributes #{:row-gap :column-gap})
|
||||
(conj #(update-layout-gap
|
||||
value shape-ids
|
||||
(set (filter attributes #{:row-gap :column-gap}))
|
||||
page-id))
|
||||
|
||||
(some attributes #{:r1 :r2 :r3 :r4})
|
||||
(conj #(if (= attributes #{:r1 :r2 :r3 :r4})
|
||||
(update-shape-radius-all value shape-ids attributes page-id)
|
||||
(update-shape-radius-for-corners
|
||||
value shape-ids
|
||||
(set (filter attributes #{:r1 :r2 :r3 :r4}))
|
||||
page-id)))
|
||||
|
||||
(some attributes #{:strole-width})
|
||||
(conj #(update-stroke-width
|
||||
value shape-ids
|
||||
#{:strole-width}
|
||||
page-id))
|
||||
(some attributes #{:max-width :max-height})
|
||||
(conj #(update-layout-sizing-limits
|
||||
value shape-ids
|
||||
(set (filter attributes #{:max-width :max-height}))
|
||||
page-id))))
|
||||
|
||||
(defn use-dimensions-token
|
||||
([value shape-ids attributes] (use-dimensions-token value shape-ids attributes nil))
|
||||
([value shape-ids attributes page-id]
|
||||
(ptk/reify ::use-dimensions-token
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when (number? value)
|
||||
(let [actions (attributes->actions
|
||||
{:value value
|
||||
:shape-ids shape-ids
|
||||
:attributes attributes
|
||||
:page-id page-id
|
||||
:state state})]
|
||||
(apply rx/of (map #(%) actions))))))))
|
||||
|
||||
(defn use-spacing-token
|
||||
([value shape-ids attributes] (use-spacing-token value shape-ids attributes nil))
|
||||
([value shape-ids attributes page-id]
|
||||
(ptk/reify ::use-spacing-token
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [spacing-attrs
|
||||
#{:row-gap :column-gap
|
||||
:m1 :m2 :m3 :m4
|
||||
:p1 :p2 :p3 :p4}]
|
||||
(when (and (number? value)
|
||||
(set? attributes)
|
||||
(set/subset? attributes spacing-attrs))
|
||||
|
||||
(let [actions (attributes->actions
|
||||
{:value value
|
||||
:shape-ids shape-ids
|
||||
:attributes attributes
|
||||
:page-id page-id
|
||||
:state state})]
|
||||
(apply rx/of (map #(%) actions)))))))))
|
||||
|
||||
(defn use-sizing-token
|
||||
([value shape-ids attributes] (use-sizing-token value shape-ids attributes nil))
|
||||
([value shape-ids attributes page-id]
|
||||
(ptk/reify ::use-sizing-token
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [sizing-attrs
|
||||
#{:width :height
|
||||
:max-width :max-height}]
|
||||
(when (and (number? value)
|
||||
(set? attributes)
|
||||
(set/subset? attributes sizing-attrs))
|
||||
|
||||
(let [actions (attributes->actions
|
||||
{:value value
|
||||
:shape-ids shape-ids
|
||||
:attributes attributes
|
||||
:page-id page-id
|
||||
:state state})]
|
||||
(apply rx/of (map #(%) actions)))))))))
|
||||
|
||||
;; Events to apply / unapply tokens to shapes ------------------------------------------------------------
|
||||
|
||||
@@ -623,54 +718,19 @@
|
||||
:token token
|
||||
:shape-ids shape-ids}))
|
||||
(rx/of
|
||||
(case (:type token)
|
||||
:spacing
|
||||
(cond
|
||||
(and (= (:type token) :spacing)
|
||||
(nil? attrs))
|
||||
(apply-spacing-token {:token token
|
||||
:attr attrs
|
||||
:shapes shapes})
|
||||
|
||||
:else
|
||||
(apply-token {:attributes (if (empty? attrs) attributes attrs)
|
||||
:token token
|
||||
:shape-ids shape-ids
|
||||
:on-update-shape on-update-shape}))))))))
|
||||
|
||||
(defn toggle-border-radius-token
|
||||
[{:keys [token attrs shape-ids expand-with-children]}]
|
||||
(ptk/reify ::on-toggle-border-radius-token
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
shapes (into [] (keep (d/getf objects)) shape-ids)
|
||||
|
||||
shapes
|
||||
(if expand-with-children
|
||||
(into []
|
||||
(mapcat (fn [shape]
|
||||
(if (= (:type shape) :group)
|
||||
(keep objects (:shapes shape))
|
||||
[shape])))
|
||||
shapes)
|
||||
shapes)
|
||||
|
||||
{:keys [attributes all-attributes]}
|
||||
(get token-properties (:type token))
|
||||
|
||||
unapply-tokens?
|
||||
(cft/shapes-token-applied? token shapes (or attrs all-attributes attributes))
|
||||
|
||||
shape-ids (map :id shapes)]
|
||||
|
||||
(if unapply-tokens?
|
||||
(rx/of
|
||||
(unapply-token {:attributes (or attrs all-attributes attributes)
|
||||
:token token
|
||||
:shape-ids shape-ids}))
|
||||
(rx/of
|
||||
(apply-token {:attributes attrs
|
||||
:token token
|
||||
:shape-ids shape-ids
|
||||
:on-update-shape update-shape-radius-for-corners})))))))
|
||||
|
||||
|
||||
(defn apply-token-on-selected
|
||||
[color-operations token]
|
||||
(ptk/reify ::apply-token-on-selected
|
||||
@@ -800,7 +860,7 @@
|
||||
{:title "Sizing"
|
||||
:attributes #{:width :height}
|
||||
:all-attributes ctt/sizing-keys
|
||||
:on-update-shape update-shape-dimensions
|
||||
:on-update-shape use-sizing-token
|
||||
:modal {:key :tokens/sizing
|
||||
:fields [{:label "Sizing"
|
||||
:key :sizing}]}}
|
||||
@@ -813,7 +873,7 @@
|
||||
ctt/border-radius-keys
|
||||
ctt/axis-keys
|
||||
ctt/stroke-width-keys)
|
||||
:on-update-shape update-shape-dimensions
|
||||
:on-update-shape use-dimensions-token
|
||||
:modal {:key :tokens/dimensions
|
||||
:fields [{:label "Dimensions"
|
||||
:key :dimensions}]}}
|
||||
@@ -846,7 +906,7 @@
|
||||
{:title "Spacing"
|
||||
:attributes #{:column-gap :row-gap}
|
||||
:all-attributes ctt/spacing-keys
|
||||
:on-update-shape update-layout-spacing
|
||||
:on-update-shape use-spacing-token
|
||||
:modal {:key :tokens/spacing
|
||||
:fields [{:label "Spacing"
|
||||
:key :spacing}]}}))
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
{ctt/border-radius-keys dwta/update-shape-radius-for-corners
|
||||
ctt/color-keys dwta/update-fill-stroke
|
||||
ctt/stroke-width-keys dwta/update-stroke-width
|
||||
ctt/sizing-keys dwta/update-shape-dimensions
|
||||
ctt/sizing-keys dwta/use-dimensions-token
|
||||
ctt/opacity-keys dwta/update-opacity
|
||||
ctt/rotation-keys dwta/update-rotation
|
||||
|
||||
@@ -73,8 +73,8 @@
|
||||
#{:x :y} dwta/update-shape-position
|
||||
#{:p1 :p2 :p3 :p4} dwta/update-layout-padding
|
||||
#{:m1 :m2 :m3 :m4} dwta/update-layout-item-margin
|
||||
#{:column-gap :row-gap} dwta/update-layout-spacing
|
||||
#{:width :height} dwta/update-shape-dimensions
|
||||
#{:column-gap :row-gap} dwta/update-layout-gap
|
||||
#{:width :height} dwta/use-dimensions-token
|
||||
#{:layout-item-min-w :layout-item-min-h :layout-item-max-w :layout-item-max-h} dwta/update-layout-sizing-limits})
|
||||
|
||||
(def ^:private attribute-actions-map
|
||||
|
||||
@@ -192,11 +192,10 @@
|
||||
(st/emit!
|
||||
(change-radius (fn [shape]
|
||||
(ctsr/set-radius-to-all-corners shape value))))
|
||||
(doseq [attr [:r1 :r2 :r3 :r4]]
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids}))))))
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{:r1 :r2 :r3 :r4}
|
||||
:shape-ids ids})))))
|
||||
|
||||
|
||||
on-single-radius-change
|
||||
@@ -205,9 +204,10 @@
|
||||
(fn [value attr]
|
||||
(if (or (string? value) (number? value))
|
||||
(st/emit! (change-one-radius #(ctsr/set-radius-to-single-corner % attr value) attr))
|
||||
(st/emit! (dwta/toggle-border-radius-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids})))))
|
||||
(st/emit! (st/emit!
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids}))))))
|
||||
|
||||
on-radius-r1-change #(on-single-radius-change % :r1)
|
||||
on-radius-r2-change #(on-single-radius-change % :r2)
|
||||
|
||||
@@ -369,12 +369,12 @@
|
||||
(if (or (string? value) (int? value))
|
||||
(on-change :simple attr value event)
|
||||
(do
|
||||
(let [resolved-value (:resolved-value (first value))
|
||||
updated-attr (if (= :p1 attr) #{:p1 :p3} #{:p2 :p4})]
|
||||
(st/emit! (dwta/toggle-token {:token (first value)
|
||||
:attrs updated-attr
|
||||
:shape-ids ids}))
|
||||
(on-change :simple attr resolved-value event))))))
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs (if (= :p1 attr)
|
||||
#{:p1 :p3}
|
||||
#{:p2 :p4})
|
||||
:shape-ids ids}))))))
|
||||
|
||||
on-detach-token
|
||||
(mf/use-fn
|
||||
@@ -483,11 +483,9 @@
|
||||
(if (or (string? value) (int? value))
|
||||
(on-change :multiple attr value event)
|
||||
(do
|
||||
(let [resolved-value (:resolved-value (first value))]
|
||||
(st/emit! (dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids}))
|
||||
(on-change :multiple attr resolved-value event))))))
|
||||
(st/emit! (dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids}))))))
|
||||
|
||||
on-focus
|
||||
(mf/use-fn
|
||||
@@ -716,11 +714,12 @@
|
||||
(if (or (string? value) (int? value))
|
||||
(on-change (= "nowrap" wrap-type) attr value event)
|
||||
(do
|
||||
(let [resolved-value (:resolved-value (first value))]
|
||||
(st/emit! (dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids}))
|
||||
(on-change (= "nowrap" wrap-type) attr resolved-value event))))))
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs (if (= "nowrap" wrap-type)
|
||||
#{:row-gap :colum-gap}
|
||||
#{attr})
|
||||
:shape-ids ids}))))))
|
||||
|
||||
on-detach-token
|
||||
(mf/use-fn
|
||||
|
||||
@@ -9,13 +9,17 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.types.token :as tk]
|
||||
[app.main.data.workspace :as udw]
|
||||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.features :as features]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.numeric-input :as deprecated-input]
|
||||
[app.main.ui.components.title-bar :refer [title-bar*]]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
|
||||
[app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
@@ -24,6 +28,43 @@
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc numeric-input-wrapper*
|
||||
{::mf/private true}
|
||||
[{:keys [values name applied-tokens align on-detach] :rest props}]
|
||||
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
|
||||
input-type (cond
|
||||
(some #{:p2 :p4} [name])
|
||||
:horizontal-padding
|
||||
|
||||
(some #{:p1 :p3} [name])
|
||||
:vertical-padding
|
||||
:else
|
||||
name)
|
||||
|
||||
tokens (mf/with-memo [tokens input-type]
|
||||
(delay
|
||||
(-> (deref tokens)
|
||||
(select-keys (get tk/tokens-by-input input-type))
|
||||
(not-empty))))
|
||||
on-detach-attr
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach name)
|
||||
#(on-detach % name))
|
||||
|
||||
props (mf/spread-props props
|
||||
{:placeholder (if (or (= :multiple (:applied-tokens values))
|
||||
(= :multiple (get values name))
|
||||
(nil? (get values name)))
|
||||
(tr "settings.multiple")
|
||||
"--")
|
||||
:class (stl/css :numeric-input-layout)
|
||||
:applied-token (get applied-tokens name)
|
||||
:tokens tokens
|
||||
:align align
|
||||
:on-detach on-detach-attr
|
||||
:value (get values name)})]
|
||||
[:> numeric-input* props]))
|
||||
|
||||
(def layout-item-attrs
|
||||
[:layout-item-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0}
|
||||
:layout-item-margin-type ;; :simple :multiple
|
||||
@@ -46,8 +87,12 @@
|
||||
(select-margins (= prop :m1) (= prop :m2) (= prop :m3) (= prop :m4)))
|
||||
|
||||
(mf/defc margin-simple*
|
||||
[{:keys [value on-change on-blur]}]
|
||||
(let [m1 (:m1 value)
|
||||
[{:keys [value on-change on-blur applied-tokens ids]}]
|
||||
(let [token-numeric-inputs
|
||||
(features/use-feature "tokens/numeric-input")
|
||||
_ (prn "applied-tokens" applied-tokens)
|
||||
|
||||
m1 (:m1 value)
|
||||
m2 (:m2 value)
|
||||
m3 (:m3 value)
|
||||
m4 (:m4 value)
|
||||
@@ -70,6 +115,28 @@
|
||||
|
||||
(dom/select-target event))))
|
||||
|
||||
on-detach-token
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [token attr]
|
||||
(st/emit! (dwta/unapply-token {:token (first token)
|
||||
:attributes #{attr}
|
||||
:shape-ids ids}))))
|
||||
|
||||
on-change'
|
||||
(mf/use-fn
|
||||
(mf/deps on-change ids)
|
||||
(fn [value attr event]
|
||||
(if (or (string? value) (int? value))
|
||||
(on-change :simple attr value)
|
||||
(do
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs (if (= :p1 attr)
|
||||
#{:p1 :p3}
|
||||
#{:p2 :p4})
|
||||
:shape-ids ids}))))))
|
||||
|
||||
on-change'
|
||||
(mf/use-fn
|
||||
(mf/deps on-change)
|
||||
@@ -77,21 +144,39 @@
|
||||
(let [attr (-> (dom/get-current-target event)
|
||||
(dom/get-data "name")
|
||||
(keyword))]
|
||||
(on-change :simple attr value))))]
|
||||
(on-change :simple attr value))))
|
||||
|
||||
on-change-m1 ()
|
||||
on-change-m2]
|
||||
|
||||
[:div {:class (stl/css :margin-simple)}
|
||||
[:div {:class (stl/css :vertical-margin)
|
||||
:title "Vertical margin"}
|
||||
[:span {:class (stl/css :icon)}
|
||||
deprecated-icon/margin-top-bottom]
|
||||
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
|
||||
:placeholder m1-placeholder
|
||||
:data-name "m1"
|
||||
:on-focus on-focus
|
||||
:on-change on-change'
|
||||
:on-blur on-blur
|
||||
:nillable true
|
||||
:value m1}]]
|
||||
(if token-numeric-inputs
|
||||
|
||||
[:> numeric-input-wrapper*
|
||||
{:on-change on-change'
|
||||
:on-detach on-detach-token
|
||||
:on-blur on-blur
|
||||
:on-focus on-focus
|
||||
:icon i/padding-top-bottom
|
||||
:min 0
|
||||
:name :m1
|
||||
:property "Vertical margin "
|
||||
:nillable true
|
||||
:applied-tokens {:m1 applied-to-p1}
|
||||
:values {:m1 p1}}]
|
||||
|
||||
[:div {:class (stl/css :vertical-margin)
|
||||
:title "Vertical margin"}
|
||||
[:span {:class (stl/css :icon)}
|
||||
deprecated-icon/margin-top-bottom]
|
||||
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
|
||||
:placeholder m1-placeholder
|
||||
:data-name "m1"
|
||||
:on-focus on-focus
|
||||
:on-change on-change'
|
||||
:on-blur on-blur
|
||||
:nillable true
|
||||
:value m1}]])
|
||||
|
||||
[:div {:class (stl/css :horizontal-margin)
|
||||
:title "Horizontal margin"}
|
||||
@@ -107,8 +192,11 @@
|
||||
:value m2}]]]))
|
||||
|
||||
(mf/defc margin-multiple*
|
||||
[{:keys [value on-change on-blur]}]
|
||||
(let [m1 (:m1 value)
|
||||
[{:keys [value on-change on-blur applied-tokens]}]
|
||||
(let [token-numeric-inputs
|
||||
(features/use-feature "tokens/numeric-input")
|
||||
_ (prn "applied-tokens" applied-tokens)
|
||||
m1 (:m1 value)
|
||||
m2 (:m2 value)
|
||||
m3 (:m3 value)
|
||||
m4 (:m4 value)
|
||||
@@ -183,10 +271,9 @@
|
||||
:nillable true
|
||||
:value m4}]]]))
|
||||
|
||||
|
||||
(mf/defc margin-section*
|
||||
{::mf/private true
|
||||
::mf/expect-props #{:value :type :on-type-change :on-change}}
|
||||
::mf/expect-props #{:value :type :on-type-change :on-change :applied-tokens :ids}}
|
||||
[{:keys [type on-type-change] :as props}]
|
||||
(let [type (d/nilv type :simple)
|
||||
on-blur (mf/use-fn #(select-margins false false false false))
|
||||
@@ -293,7 +380,7 @@
|
||||
:value "end"}]}])
|
||||
|
||||
(mf/defc layout-item-menu
|
||||
{::mf/memo #{:ids :values :type :is-layout-child? :is-grid-parent :is-flex-parent? :is-grid-layout? :is-flex-layout?}
|
||||
{::mf/memo #{:ids :values :type :is-layout-child? :is-grid-parent :is-flex-parent? :is-grid-layout? :is-flex-layout? :applied-tokens}
|
||||
::mf/props :obj}
|
||||
[{:keys [ids values
|
||||
^boolean is-layout-child?
|
||||
@@ -301,7 +388,8 @@
|
||||
^boolean is-grid-parent?
|
||||
^boolean is-flex-parent?
|
||||
^boolean is-flex-layout?
|
||||
^boolean is-grid-layout?]}]
|
||||
^boolean is-grid-layout?
|
||||
applied-tokens]}]
|
||||
|
||||
(let [selection-parents* (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
|
||||
selection-parents (mf/deref selection-parents*)
|
||||
@@ -483,6 +571,8 @@
|
||||
[:> margin-section* {:value (:layout-item-margin values)
|
||||
:type (:layout-item-margin-type values)
|
||||
:on-type-change on-margin-type-change
|
||||
:applied-tokens applied-tokens
|
||||
:ids ids
|
||||
:on-change on-margin-change}])
|
||||
|
||||
(when (or (= h-sizing :fill)
|
||||
|
||||
@@ -284,28 +284,17 @@
|
||||
(st/emit! (udw/change-orientation ids (keyword orientation)))))
|
||||
|
||||
;; SIZE AND PROPORTION LOCK
|
||||
do-size-change
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [value attr]
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||
(udw/update-dimensions ids attr value))))
|
||||
|
||||
on-size-change
|
||||
(mf/use-fn
|
||||
(mf/deps ids shapes)
|
||||
(fn [value attr]
|
||||
(if (or (string? value) (number? value))
|
||||
(do
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
||||
(run! #(do-size-change value attr) shapes))
|
||||
(do
|
||||
(let [resolved-value (:resolved-value (first value))]
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids}))
|
||||
(run! #(do-size-change resolved-value attr) shapes))))))
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||
(udw/update-dimensions ids attr value))
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids})))))
|
||||
|
||||
on-proportion-lock-change
|
||||
(mf/use-fn
|
||||
@@ -315,11 +304,6 @@
|
||||
(run! #(st/emit! (udw/set-shape-proportion-lock % new-lock)) ids))))
|
||||
|
||||
;; POSITION
|
||||
do-position-change
|
||||
(mf/use-fn
|
||||
(fn [shape' value attr]
|
||||
(st/emit! (udw/update-position (:id shape') {attr value}))))
|
||||
|
||||
on-position-change
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
@@ -327,21 +311,11 @@
|
||||
(if (or (string? value) (number? value))
|
||||
(do
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
||||
(run! #(do-position-change %1 value attr) shapes))
|
||||
(do
|
||||
(let [resolved-value (:resolved-value (first value))]
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids}))
|
||||
(run! #(do-position-change %1 resolved-value attr) shapes))))))
|
||||
|
||||
;; ROTATION
|
||||
do-rotation-change
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [value]
|
||||
(st/emit! (udw/increase-rotation ids value))))
|
||||
(st/emit! (udw/update-position ids {attr value})))
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{attr}
|
||||
:shape-ids ids})))))
|
||||
|
||||
on-rotation-change
|
||||
(mf/use-fn
|
||||
@@ -350,14 +324,11 @@
|
||||
(if (or (string? value) (number? value))
|
||||
(do
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
||||
(run! #(do-rotation-change value) shapes))
|
||||
(do
|
||||
(let [resolved-value (:resolved-value (first value))]
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{:rotation}
|
||||
:shape-ids ids}))
|
||||
(run! #(do-rotation-change resolved-value) shapes))))))
|
||||
(st/emit! (udw/increase-rotation ids value)))
|
||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||
(dwta/toggle-token {:token (first value)
|
||||
:attrs #{:rotation}
|
||||
:shape-ids ids})))))
|
||||
|
||||
on-width-change
|
||||
(mf/use-fn (mf/deps on-size-change) #(on-size-change % :width))
|
||||
@@ -410,7 +381,8 @@
|
||||
(fn []
|
||||
(st/emit! (dwt/selected-fit-content))))]
|
||||
|
||||
[:div {:class (stl/css :element-set)}
|
||||
[:section {:class (stl/css :element-set)
|
||||
:aria-label "shape-measures-section"}
|
||||
(when (and (options :presets)
|
||||
(or (nil? all-types) (= (count all-types) 1)))
|
||||
[:div {:class (stl/css :presets)}
|
||||
|
||||
@@ -176,7 +176,8 @@
|
||||
:token token
|
||||
:shape-ids ids}))))]
|
||||
|
||||
[:div {:class (stl/css :stroke-section)}
|
||||
[:section {:class (stl/css :stroke-section)
|
||||
:aria-label "stroke-section"}
|
||||
[:div {:class (stl/css :stroke-title)}
|
||||
[:> title-bar* {:collapsable has-strokes?
|
||||
:collapsed (not open?)
|
||||
|
||||
@@ -9,18 +9,50 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.token :as tk]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
[app.main.features :as features]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
||||
[app.main.ui.components.numeric-input :as deprecated-input]
|
||||
[app.main.ui.components.reorder-handler :refer [reorder-handler*]]
|
||||
[app.main.ui.components.select :refer [select]]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||
[app.main.ui.hooks :as h]
|
||||
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc numeric-input-wrapper*
|
||||
{::mf/private true}
|
||||
[{:keys [values name applied-tokens align on-detach] :rest props}]
|
||||
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
|
||||
tokens (mf/with-memo [tokens name]
|
||||
(delay
|
||||
(-> (deref tokens)
|
||||
(select-keys (get tk/tokens-by-input name))
|
||||
(not-empty))))
|
||||
|
||||
on-detach-attr (mf/use-fn
|
||||
(mf/deps on-detach name)
|
||||
#(on-detach % name))
|
||||
|
||||
applied-token (get applied-tokens name)
|
||||
|
||||
props (mf/spread-props props
|
||||
{:placeholder (if (= :multiple values)
|
||||
(tr "settings.multiple")
|
||||
"--")
|
||||
:applied-token applied-token
|
||||
:tokens (if (delay? tokens) @tokens tokens)
|
||||
:align align
|
||||
:on-detach on-detach-attr
|
||||
:name name
|
||||
:value values})]
|
||||
[:> numeric-input* props]))
|
||||
|
||||
(mf/defc stroke-row*
|
||||
[{:keys [index
|
||||
stroke
|
||||
@@ -45,7 +77,10 @@
|
||||
select-on-focus
|
||||
ids]}]
|
||||
|
||||
(let [on-drop
|
||||
(let [token-numeric-inputs
|
||||
(features/use-feature "tokens/numeric-input")
|
||||
|
||||
on-drop
|
||||
(mf/use-fn
|
||||
(mf/deps on-reorder index)
|
||||
(fn [relative-pos data]
|
||||
@@ -88,7 +123,13 @@
|
||||
on-width-change
|
||||
(mf/use-fn
|
||||
(mf/deps index on-stroke-width-change)
|
||||
#(on-stroke-width-change index %))
|
||||
(fn [value]
|
||||
(if (or (string? value) (int? value))
|
||||
(on-stroke-width-change index value)
|
||||
(do
|
||||
(st/emit! (dwta/toggle-token {:token (first value)
|
||||
:attrs #{:stroke-width}
|
||||
:shape-ids ids}))))))
|
||||
|
||||
stroke-alignment (or (:stroke-alignment stroke) :center)
|
||||
|
||||
@@ -149,6 +190,12 @@
|
||||
(fn [token]
|
||||
(on-detach-token token #{:stroke-color})))
|
||||
|
||||
on-detach-token-width
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach-token)
|
||||
(fn [token]
|
||||
(on-detach-token (first token) #{:stroke-width})))
|
||||
|
||||
stroke-caps-options
|
||||
[{:value nil :label (tr "workspace.options.stroke-cap.none")}
|
||||
:separator
|
||||
@@ -169,7 +216,8 @@
|
||||
[:div {:class (stl/css-case
|
||||
:stroke-data true
|
||||
:dnd-over-top (= (:over dprops) :top)
|
||||
:dnd-over-bot (= (:over dprops) :bot))}
|
||||
:dnd-over-bot (= (:over dprops) :bot))
|
||||
:aria-label (str "stroke-row-" index)}
|
||||
|
||||
(when (some? on-reorder)
|
||||
[:> reorder-handler* {:ref dref}])
|
||||
@@ -195,17 +243,30 @@
|
||||
|
||||
;; Stroke Width, Alignment & Style
|
||||
[:div {:class (stl/css :stroke-options)}
|
||||
[:div {:class (stl/css :stroke-width-input)
|
||||
:title (tr "workspace.options.stroke-width")}
|
||||
[:> icon* {:icon-id i/stroke-size
|
||||
:size "s"}]
|
||||
[:> numeric-input* {:value stroke-width
|
||||
:min 0
|
||||
:placeholder (tr "settings.multiple")
|
||||
:on-change on-width-change
|
||||
:on-focus on-focus
|
||||
:select-on-focus select-on-focus
|
||||
:on-blur on-blur}]]
|
||||
(if token-numeric-inputs
|
||||
[:> numeric-input-wrapper* {:on-change on-width-change
|
||||
:on-detach on-detach-token-width
|
||||
:icon i/stroke-size
|
||||
:min 0
|
||||
:on-focus on-focus
|
||||
:on-blur on-blur
|
||||
:name :stroke-width
|
||||
:class (stl/css :numeric-input-wrapper)
|
||||
:property (tr "workspace.options.stroke-width")
|
||||
:applied-tokens applied-tokens
|
||||
:values stroke-width}]
|
||||
|
||||
[:div {:class (stl/css :stroke-width-input)
|
||||
:title (tr "workspace.options.stroke-width")}
|
||||
[:> icon* {:icon-id i/stroke-size
|
||||
:size "s"}]
|
||||
[:> deprecated-input/numeric-input* {:value stroke-width
|
||||
:min 0
|
||||
:placeholder (tr "settings.multiple")
|
||||
:on-change on-width-change
|
||||
:on-focus on-focus
|
||||
:select-on-focus select-on-focus
|
||||
:on-blur on-blur}]])
|
||||
|
||||
[:div {:class (stl/css :stroke-alignment-select)
|
||||
:data-testid "stroke.alignment"}
|
||||
|
||||
@@ -45,6 +45,11 @@
|
||||
padding-inline-start: var(--sp-xs);
|
||||
}
|
||||
|
||||
.numeric-input-wrapper {
|
||||
grid-column: span 2;
|
||||
--dropdown-width: var(--7-columns-dropdown-width);
|
||||
}
|
||||
|
||||
.stroke-alignment-select {
|
||||
grid-column: span 3;
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
:is-layout-child? true
|
||||
:is-flex-parent? is-flex-parent?
|
||||
:is-grid-parent? is-grid-parent?
|
||||
:applied-tokens applied-tokens
|
||||
:shape shape}])
|
||||
|
||||
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
:is-layout-container? false
|
||||
:is-flex-parent? is-flex-parent?
|
||||
:is-grid-parent? is-grid-parent?
|
||||
:applied-tokens applied-tokens
|
||||
:shape shape}])
|
||||
|
||||
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
|
||||
|
||||
@@ -135,6 +135,7 @@
|
||||
:is-flex-layout? is-flex-layout?
|
||||
:is-grid-layout? is-grid-layout?
|
||||
:is-layout-child? is-layout-child?
|
||||
:applied-tokens applied-tokens
|
||||
:is-layout-container? is-layout-container?
|
||||
:shape shape}])
|
||||
|
||||
|
||||
@@ -139,6 +139,7 @@
|
||||
:is-layout-container? false
|
||||
:is-flex-parent? is-flex-parent?
|
||||
:is-grid-parent? is-grid-parent?
|
||||
:applied-tokens applied-tokens
|
||||
:values layout-item-values}])
|
||||
|
||||
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
|
||||
|
||||
@@ -409,7 +409,7 @@
|
||||
[layout-container-ids layout-container-values layout-container-tokens]
|
||||
(get-attrs shapes objects :layout-container)
|
||||
|
||||
[layout-item-ids layout-item-values {}]
|
||||
[layout-item-ids layout-item-values layout-item-tokens]
|
||||
(get-attrs shapes objects :layout-item)
|
||||
|
||||
components
|
||||
@@ -471,6 +471,7 @@
|
||||
:is-layout-container? all-flex-layout-container?
|
||||
:is-flex-parent? is-flex-parent?
|
||||
:is-grid-parent? is-grid-parent?
|
||||
:applied-tokens layout-item-tokens
|
||||
:values layout-item-values}])
|
||||
|
||||
(when-not (or (empty? constraint-ids) ^boolean is-layout-child?)
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
:is-layout-container? false
|
||||
:is-flex-parent? is-flex-parent?
|
||||
:is-grid-parent? is-grid-parent?
|
||||
:applied-tokens applied-tokens
|
||||
:shape shape}])
|
||||
|
||||
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
|
||||
|
||||
@@ -112,6 +112,7 @@
|
||||
:values layout-item-values
|
||||
:is-layout-child? true
|
||||
:is-flex-parent? is-flex-parent?
|
||||
:applied-tokens applied-tokens
|
||||
:is-grid-parent? is-grid-parent?
|
||||
:shape shape}])
|
||||
|
||||
|
||||
@@ -180,6 +180,7 @@
|
||||
:is-layout-child? true
|
||||
:is-flex-parent? is-flex-parent?
|
||||
:is-grid-parent? is-grid-parent?
|
||||
:applied-tokens applied-tokens
|
||||
:shape shape}])
|
||||
|
||||
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
|
||||
|
||||
@@ -154,6 +154,7 @@
|
||||
:is-layout-child? true
|
||||
:is-flex-parent? is-flex-parent?
|
||||
:is-grid-parent? is-grid-parent?
|
||||
:applied-tokens applied-tokens
|
||||
:shape shape}])
|
||||
|
||||
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
|
||||
|
||||
@@ -223,7 +223,7 @@
|
||||
gap-items (all-or-separate-actions {:attribute-labels {:column-gap "Column Gap"
|
||||
:row-gap "Row Gap"}
|
||||
:hint (tr "workspace.tokens.gaps")
|
||||
:on-update-shape dwta/update-layout-spacing}
|
||||
:on-update-shape dwta/update-layout-gap}
|
||||
context-data)]
|
||||
(->> (concat
|
||||
gap-items
|
||||
@@ -239,7 +239,7 @@
|
||||
(all-or-separate-actions {:attribute-labels {:width "Width"
|
||||
:height "Height"}
|
||||
:hint (tr "workspace.tokens.size")
|
||||
:on-update-shape dwta/update-shape-dimensions}
|
||||
:on-update-shape dwta/use-dimensions-token}
|
||||
context-data)
|
||||
[:separator]
|
||||
(all-or-separate-actions {:attribute-labels {:layout-item-min-w "Min Width"
|
||||
|
||||
@@ -260,7 +260,7 @@
|
||||
events [(dwta/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:width :height}
|
||||
:token (toht/get-token file "dimensions.sm")
|
||||
:on-update-shape dwta/update-shape-dimensions})]]
|
||||
:on-update-shape dwta/use-dimensions-token})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
@@ -333,7 +333,7 @@
|
||||
events [(dwta/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:width :height}
|
||||
:token (toht/get-token file "sizing.sm")
|
||||
:on-update-shape dwta/update-shape-dimensions})]]
|
||||
:on-update-shape dwta/use-dimensions-token})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
|
||||
Reference in New Issue
Block a user