mirror of
https://github.com/penpot/penpot-mcp.git
synced 2026-04-25 11:18:37 +00:00
PenpotUtils.shapeStructure: Add essential information on layouts #26
This commit is contained in:
parent
4353f67322
commit
3c1bd875d8
@ -32,12 +32,12 @@ initial_instructions: |
|
|||||||
A `Group` is a more low-level grouping element used to organize low-level shapes into a logical unit.
|
A `Group` is a more low-level grouping element used to organize low-level shapes into a logical unit.
|
||||||
Actual low-level shape types are `Rectangle`, `Path`, `Text`, `Ellipse`, `Image`, `Boolean`, and `SvgRaw`.
|
Actual low-level shape types are `Rectangle`, `Path`, `Text`, `Ellipse`, `Image`, `Boolean`, and `SvgRaw`.
|
||||||
`ShapeBase` is a base type most shapes build upon.
|
`ShapeBase` is a base type most shapes build upon.
|
||||||
|
|
||||||
## Core Shape Properties
|
## Core Shape Properties
|
||||||
|
|
||||||
**Type**:
|
**Type**:
|
||||||
Any given shape contains information on the concrete type via its `type` field.
|
Any given shape contains information on the concrete type via its `type` field.
|
||||||
|
|
||||||
**Position and Dimensions**:
|
**Position and Dimensions**:
|
||||||
* The location properties `x` and `y` refer to the top left corner of a shape's bounding box in the absolute (Page) coordinate system.
|
* The location properties `x` and `y` refer to the top left corner of a shape's bounding box in the absolute (Page) coordinate system.
|
||||||
These are writable - set them directly to position shapes.
|
These are writable - set them directly to position shapes.
|
||||||
@ -45,24 +45,24 @@ initial_instructions: |
|
|||||||
To position a shape within its parent, set the absolute `x` and `y` properties accordingly.
|
To position a shape within its parent, set the absolute `x` and `y` properties accordingly.
|
||||||
* `width` and `height` are READ-ONLY. Use `resize(width, height)` method to change dimensions.
|
* `width` and `height` are READ-ONLY. Use `resize(width, height)` method to change dimensions.
|
||||||
* `bounds` is a READ-ONLY property. Use `x`, `y` with `resize()` to modify shape bounds.
|
* `bounds` is a READ-ONLY property. Use `x`, `y` with `resize()` to modify shape bounds.
|
||||||
|
|
||||||
**Other Writable Properties**:
|
**Other Writable Properties**:
|
||||||
* `name` - Shape name
|
* `name` - Shape name
|
||||||
* `fills`, `strokes` - Styling properties
|
* `fills`, `strokes` - Styling properties
|
||||||
* `rotation`, `opacity`, `blocked`, `hidden`, `visible`
|
* `rotation`, `opacity`, `blocked`, `hidden`, `visible`
|
||||||
|
|
||||||
**Z-Order**:
|
**Z-Order**:
|
||||||
* The z-order of shapes is determined by the order in the `children` array of the parent shape.
|
* The z-order of shapes is determined by the order in the `children` array of the parent shape.
|
||||||
Therefore, when creating shapes that should be on top of each other, add them to the parent in the correct order
|
Therefore, when creating shapes that should be on top of each other, add them to the parent in the correct order
|
||||||
(i.e. add background shapes first, then foreground shapes later).
|
(i.e. add background shapes first, then foreground shapes later).
|
||||||
* To modify z-order after creation, use these methods: `bringToFront()`, `sendToBack()`, `bringForward()`, `sendBackward()`,
|
* To modify z-order after creation, use these methods: `bringToFront()`, `sendToBack()`, `bringForward()`, `sendBackward()`,
|
||||||
and, for precise control, `setParentIndex(index)` (0-based).
|
and, for precise control, `setParentIndex(index)` (0-based).
|
||||||
|
|
||||||
**Modification Methods**:
|
**Modification Methods**:
|
||||||
* `resize(width, height)` - Change dimensions (required for width/height since they're read-only)
|
* `resize(width, height)` - Change dimensions (required for width/height since they're read-only)
|
||||||
* `rotate(angle, center?)` - Rotate shape
|
* `rotate(angle, center?)` - Rotate shape
|
||||||
* `remove()` - Permanently destroy the shape (use only for deletion, NOT for reparenting)
|
* `remove()` - Permanently destroy the shape (use only for deletion, NOT for reparenting)
|
||||||
|
|
||||||
**Reparenting (Moving Shapes Between Parents)**:
|
**Reparenting (Moving Shapes Between Parents)**:
|
||||||
* `newParent.appendChild(shape)` or `newParent.insertChild(index, shape)` - Move shape to new parent
|
* `newParent.appendChild(shape)` or `newParent.insertChild(index, shape)` - Move shape to new parent
|
||||||
- Automatically removes the shape from its old parent
|
- Automatically removes the shape from its old parent
|
||||||
@ -70,18 +70,18 @@ initial_instructions: |
|
|||||||
- You may need to adjust absolute x/y after reparenting to achieve desired visual layout
|
- You may need to adjust absolute x/y after reparenting to achieve desired visual layout
|
||||||
|
|
||||||
# Images
|
# Images
|
||||||
|
|
||||||
The `Image` type is a legacy type. Images are now typically mostly embedded in a `Fill` with `fillImage` set to an
|
The `Image` type is a legacy type. Images are now typically mostly embedded in a `Fill` with `fillImage` set to an
|
||||||
`ImageData` object, i.e. the `fills` property of of a shape (e.g. a `Rectangle`) will contain a fill where `fillImage` is set.
|
`ImageData` object, i.e. the `fills` property of of a shape (e.g. a `Rectangle`) will contain a fill where `fillImage` is set.
|
||||||
|
|
||||||
# Visual Inspection of Designs
|
# Visual Inspection of Designs
|
||||||
|
|
||||||
For many tasks, it can be critical to visually inspect the design. Remember to use the `export_shape` tool for this purpose!
|
For many tasks, it can be critical to visually inspect the design. Remember to use the `export_shape` tool for this purpose!
|
||||||
|
|
||||||
# Layout Systems
|
# Layout Systems
|
||||||
|
|
||||||
Boards can have layout systems that automatically control the positioning and spacing of their children:
|
Boards can have layout systems that automatically control the positioning and spacing of their children:
|
||||||
|
|
||||||
* **Flex Layout**: `board.flex` - A flexbox-style layout system
|
* **Flex Layout**: `board.flex` - A flexbox-style layout system
|
||||||
- Properties: `dir` (direction), `rowGap`, `columnGap`, `alignItems`, `justifyContent`
|
- Properties: `dir` (direction), `rowGap`, `columnGap`, `alignItems`, `justifyContent`
|
||||||
- Padding: `topPadding`, `rightPadding`, `bottomPadding`, `leftPadding`, or combined `verticalPadding`, `horizontalPadding`
|
- Padding: `topPadding`, `rightPadding`, `bottomPadding`, `leftPadding`, or combined `verticalPadding`, `horizontalPadding`
|
||||||
@ -102,7 +102,7 @@ initial_instructions: |
|
|||||||
# Semantic Containment vs Hierarchical Nesting
|
# Semantic Containment vs Hierarchical Nesting
|
||||||
|
|
||||||
Understanding the difference between hierarchical structure and visual containment is critical:
|
Understanding the difference between hierarchical structure and visual containment is critical:
|
||||||
|
|
||||||
* **Hierarchical nesting** (parent/child in the shape tree) does NOT always equal **visual containment**
|
* **Hierarchical nesting** (parent/child in the shape tree) does NOT always equal **visual containment**
|
||||||
* Visual containment means a child shape is fully within the visual bounds of its parent
|
* Visual containment means a child shape is fully within the visual bounds of its parent
|
||||||
* Common design patterns require semantic containment:
|
* Common design patterns require semantic containment:
|
||||||
@ -147,9 +147,10 @@ initial_instructions: |
|
|||||||
* getPages(): { id: string; name: string }[]
|
* getPages(): { id: string; name: string }[]
|
||||||
* getPageById(id: string): Page | null
|
* getPageById(id: string): Page | null
|
||||||
* getPageByName(name: string): Page | null
|
* getPageByName(name: string): Page | null
|
||||||
* shapeStructure(shape: Shape, maxDepth: number | undefined = undefined): object
|
* shapeStructure(shape: Shape, maxDepth: number | undefined = undefined): { id, name, type, children?, layout? }
|
||||||
Generates an overview structure of the given shape,
|
Generates an overview structure of the given shape.
|
||||||
providing the shape's id, name and type, and recursively the children's structure.
|
- children: recursive, limited by maxDepth
|
||||||
|
- layout: present if shape has flex/grid layout, contains { type: "flex" | "grid", ... }
|
||||||
* findShapeById(id: string): Shape | null
|
* findShapeById(id: string): Shape | null
|
||||||
* findShape(predicate: (shape: Shape) => boolean, root: Shape | null = null): Shape | null
|
* findShape(predicate: (shape: Shape) => boolean, root: Shape | null = null): Shape | null
|
||||||
If no root is provided, search globally (in all pages).
|
If no root is provided, search globally (in all pages).
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { Fill, Page, Rectangle, Shape } from "@penpot/plugin-types";
|
import { Fill, FlexLayout, GridLayout, Page, Rectangle, Shape } from "@penpot/plugin-types";
|
||||||
|
|
||||||
export class PenpotUtils {
|
export class PenpotUtils {
|
||||||
/**
|
/**
|
||||||
* Generates an overview structure of the given shape,
|
* Generates an overview structure of the given shape,
|
||||||
* providing its id, name and type, and recursively its children's attributes.
|
* providing its id, name and type, and recursively its children's attributes.
|
||||||
* The `type` field indicates the type in the Penpot API.
|
* The `type` field indicates the type in the Penpot API.
|
||||||
|
* If the shape has a layout system (flex or grid), includes layout information.
|
||||||
*
|
*
|
||||||
* @param shape - The root shape to generate the structure from
|
* @param shape - The root shape to generate the structure from
|
||||||
* @param maxDepth - Optional maximum depth to traverse (leave undefined for unlimited)
|
* @param maxDepth - Optional maximum depth to traverse (leave undefined for unlimited)
|
||||||
@ -19,12 +20,35 @@ export class PenpotUtils {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
|
const result: any = {
|
||||||
id: shape.id,
|
id: shape.id,
|
||||||
name: shape.name,
|
name: shape.name,
|
||||||
type: shape.type,
|
type: shape.type,
|
||||||
children: children,
|
children: children,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// add layout information if present
|
||||||
|
if ("flex" in shape && shape.flex) {
|
||||||
|
const flex: FlexLayout = shape.flex;
|
||||||
|
result.layout = {
|
||||||
|
type: "flex",
|
||||||
|
dir: flex.dir,
|
||||||
|
rowGap: flex.rowGap,
|
||||||
|
columnGap: flex.columnGap,
|
||||||
|
};
|
||||||
|
} else if ("grid" in shape && shape.grid) {
|
||||||
|
const grid: GridLayout = shape.grid;
|
||||||
|
result.layout = {
|
||||||
|
type: "grid",
|
||||||
|
rows: grid.rows,
|
||||||
|
columns: grid.columns,
|
||||||
|
rowGap: grid.rowGap,
|
||||||
|
columnGap: grid.columnGap,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user