Skip to content

Commit

Permalink
XD 17 documentation changes:
Browse files Browse the repository at this point in the history
- Selections spanning multiple groups and the resultant changes to
  edit-context rules
- Update notifications
  • Loading branch information
peterflynn committed Mar 12, 2019
1 parent 66d9ce4 commit 8ac0d85
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 36 deletions.
34 changes: 33 additions & 1 deletion changes.md
Original file line number Original file line Diff line number Diff line change
@@ -1,11 +1,43 @@
# Change Log # Change Log


## XD Release 17.0.12 (March 2019)

### New API Features

* **[Select & edit across groups](./reference/core/edit-context.md):** Users can now select multiple items that are in different containers at the same time. This has several effects on plugins:
* _Do not assume all selected items have the same parent node._ Previously, this was already true in certain special cases -- for example, users could select items that are the immediate
children of several different artboards. Now, it can happen in far more cases, so plugins must take extra care to avoid any assumptions about node parents.
* _Wider "edit scope" surrounding the selection._ Previously, plugins could edit the selected nodes and all their siblings (with a slightly broader scope as a special case in the "root edit
context"). Now, plugins can edit any nodes in the subtree of the common ancestor of all the selected nodes, _if_ those nodes are connected to the common ancestor through a parent chain
consisting entirely of plain Groups (or Artboards). See the [edit context documentation](./reference/core/edit-context.md) for details and examples.
* _Plugins still cannot edit globally across the entire document at once, even though in very simple testing it may _appear_ that this works. Non-Group containers act as blockades that
the edit scope cannot cross - if the selection is outside such a container, you cannot edit inside it; and if the selection is inside such a container, you cannot edit outside it.

### Breaking Changes

No breaking changes.

### Fixes and improvements

No other API changes.

### User-facing plugin features

* **Plugin update notifications:** Users see an in-app notification when any installed plugins have a newer version available in the plugins listing.

### Known Issues

No new known issues. See the [Known Issues page](./known-issues.md) for a comprehensive list of existing known issues.


----

## XD Release 16.0.12 (February 2019) ## XD Release 16.0.12 (February 2019)


### New API Features ### New API Features


* **setTimeout() & friends:** `setTimeout()`, `setInterval()`, `setImmediate()`, and the corresponding `clear*()` methods are now available as global APIs. These APIs _do not_ allow plugins to * **setTimeout() & friends:** `setTimeout()`, `setInterval()`, `setImmediate()`, and the corresponding `clear*()` methods are now available as global APIs. These APIs _do not_ allow plugins to
control animations in the XD document - plugins can still only modify the document as part of an atomic operation while the UI is blocked. But timeout APIs _do_ allow for simple animations in control animations in the XD document -- plugins can still only modify the document as part of an atomic operation while the UI is blocked. But timeout APIs _do_ allow for simple animations in
your plugin's dialog UI (e.g. a progress indicator), "debouncing" user input, etc. – and they help support web frameworks like React with fewer polyfills needed. your plugin's dialog UI (e.g. a progress indicator), "debouncing" user input, etc. – and they help support web frameworks like React with fewer polyfills needed.


### Breaking Changes ### Breaking Changes
Expand Down
Binary file added images/edit-context-example1-simple.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/edit-context-example1-special.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/edit-context-example2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/edit-context-example3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/edit-context-outline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed images/editContexts.png
Binary file not shown.
69 changes: 62 additions & 7 deletions reference/core/edit-context.md
Original file line number Original file line Diff line number Diff line change
@@ -1,14 +1,60 @@
# Edit context rules # Edit context rules


The **edit context** is the scope in which selection and edit operations must occur: The **edit context** is the scope within which your plugin is allowed to make edits or set the selection. It is a "neighborhood"
- If the user has drilled down into a container node, that container is the current edit context and only its immediate children of scenegraph nodes around the user's current selection. To access the contents of many container nodes such as RepeatGrids or
are in scope for selection/editing. SymbolInstances, the user must first drill down into the container by double clicking or Cmd-clicking it (Ctrl-clicking on Windows).
- If the user hasn't drilled into any container nodes, then XD is in the _root edit context_, and its scope includes all immediate
children of the pasteboard (including Artboards), *and* all immediate children of all those Artboards.


Like nearly all edit operations in XD, your plugin is limited to making changes inside the scope of the current edit context. Like nearly all commands in XD, your plugin is limited to making changes only within the scope of the current edit context.


![diagram of Edit Contexts](../../images/editContexts.png) _Note: these rules have changed in **XD 17**. If you intend to support XD 16 or earlier, follow the more restrictive edit context rules
described in [the previous version of these docs](https://github.com/AdobeXD/plugin-docs/blob/XD16/reference/core/edit-context.md)._

The current edit context's scope is derived from the current selection:

* The **"edit context root"** is the node which is the closest common ancestor of all the selected nodes. It's typically indicated
by a soft blue outline in the UI:
<img src="../../images/edit-context-outline.png" alt="screenshot of soft blue outline" />
As a special case, if the edit context root would be an Artboard, it is moved up to the root of the entire scenegraph instead.

* Nodes within this subtree are "in scope" for editing (or selection) _if_ they are connected to the edit context root by a parent
chain consisting entirely of plain Groups or Artboards. (A "plain Group" is a Group node with no [mask](../scenegraph.md#Group-mask)).

* You can always safely assume that all selected nodes are in scope for editing.


### Examples

_**Scenario 1:**_ The user has selected two items inside a Group.

<img src="../../images/edit-context-example1-simple.png" alt="edit context with items in Group selected" />

The Group is the edit context root, and all its children are within scope for editing. In addition, if any of those children are nested
Groups, their children are also in scope for editing (recursively, if any of those are Groups too).

If any of the children are a different container type, however, the edit scope does not include that node's children:

<img src="../../images/edit-context-example1-special.png" alt="edit context containing special container types" />

_**Scenario 2:**_ The user has selected two items, each inside different Groups.

<img src="../../images/edit-context-example2.png" alt="edit context with items in different Groups selected" />

The edit context root is Group 1, the closest common ancestor of the selected items. In this case, all nodes in the subtree of Group 1 are
in scope for editing, but if this subtree contained any non-Group containers, their children would be off limits (as in the second example
in Scenario 1).

_**Scenario 3:**_ The user has selected one item that is an immediate child of an Artboard.

<img src="../../images/edit-context-example3.png" alt="edit context with item on Artboard selected" />

Per the special case noted above, the edit context root is the root of the entire document (the scenegraph's RootNode). This is true
any time the user hasn't drilled into a particular container. The editable scope encompasses -- at _minumum_ -- all Artboards, all
other immediate children of the root node (aka the pasteboard), and all immediate children of _all_ artboards (not just the one
containing the selection). If any of those nodes is a plain Group, its children are also in scope for editing (recursively, if any
of those are Groups too).


### What changes are allowed within the edit context?


**Simple changes** can be made directly to the scenegraph nodes that are in scope: **Simple changes** can be made directly to the scenegraph nodes that are in scope:
- Change a property - Change a property
Expand All @@ -22,3 +68,12 @@ structural changes by scripting XD commands:
- Rearrange Z order - use commands such as [`bringToFront()`](../commands.md#module_commands-bringToFront) - Rearrange Z order - use commands such as [`bringToFront()`](../commands.md#module_commands-bringToFront)


If a plugin breaks any of these rules, its entire edit operation will be reverted to protect the user's document from corruption. If a plugin breaks any of these rules, its entire edit operation will be reverted to protect the user's document from corruption.


### Exceptions to these rules

* You can set [`pluginData`](../scenegraph.md#SceneNode-pluginData) on the root node of the scenegraph regardless of the current edit
context, making it useful for storing plugin settings that are document-specific.
* The RepeatGrid APIs [`attachTextDataSeries()`](../scenegraph.md#RepeatGrid-attachTextDataSeries) and [`attachImageDataSeries()`](
../scenegraph.md#RepeatGrid-attachImageDataSeries) can be called when _either_ the RepeatGrid node _or_ the target node being
attached to is in the current edit context.
16 changes: 10 additions & 6 deletions reference/scenegraph.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1654,14 +1654,16 @@ repeated as necessary to cover all the grid cells. This is a persistent data bin
to increase the number of grid cells, items from this sequence will be used to fill the text values of the new cells. to increase the number of grid cells, items from this sequence will be used to fill the text values of the new cells.


You can call this API from either of _two different edit contexts_: You can call this API from either of _two different edit contexts_:
- Edit context is the parent node of this RepeatGrid (i.e. a context where the RepeatGrid could be selected) - Edit context where the RepeatGrid node is in scope (where properties of the RepeatGrid node itself could be edited) - e.g.
- Edit context is the RepeatGrid cell which is the parent of textNode (i.e. a context where textNode could be selected) when the RepeatGrid is selected
- Edit context where textNode is in scope (where properties of the textNode could be edited) - e.g. when textNode is selected
or when the user has otherwise drilled down into the grid cell containing it.


**Kind**: instance method of [<code>RepeatGrid</code>](#RepeatGrid) **Kind**: instance method of [<code>RepeatGrid</code>](#RepeatGrid)


| Param | Type | Description | | Param | Type | Description |
| --- | --- | --- | | --- | --- | --- |
| textNode | <code>!Text</code> | A Text node exemplar that is an immediate child of one of this RepeatGrid's cells. The data series will be bound to this text node and all corresponding copies of it in the other grid cells. | | textNode | <code>!Text</code> | A Text node exemplar that would be in scope for editing if the current edit context was one of this RepeatGrid's cells. The data series will be bound to this text node and all corresponding copies of it in the other grid cells. |
| textValues | <code>!Array&lt;string&gt;</code> | Array of one or more strings. Empty strings are ignored. | | textValues | <code>!Array&lt;string&gt;</code> | Array of one or more strings. Empty strings are ignored. |


* * * * * *
Expand All @@ -1674,14 +1676,16 @@ repeated as necessary to cover all the grid cells. This is a persistent data bin
to increase the number of grid cells, items from this sequence will be used to set the image fill in the new cells. to increase the number of grid cells, items from this sequence will be used to set the image fill in the new cells.


You can call this API from either of _two different edit contexts_: You can call this API from either of _two different edit contexts_:
- Edit context is the parent node of this RepeatGrid (i.e. a context where the RepeatGrid could be selected) - Edit context where the RepeatGrid node is in scope (where properties of the RepeatGrid node itself could be edited) - e.g.
- Edit context is the RepeatGrid cell which is the parent of shapeNode (i.e. a context where shapeNode could be selected) when the RepeatGrid is selected
- Edit context where shapeNode is in scope (where properties of the shapeNode could be edited) - e.g. when shapeNode is selected
or when the user has otherwise drilled down into the grid cell containing it.


**Kind**: instance method of [<code>RepeatGrid</code>](#RepeatGrid) **Kind**: instance method of [<code>RepeatGrid</code>](#RepeatGrid)


| Param | Type | Description | | Param | Type | Description |
| --- | --- | --- | | --- | --- | --- |
| shapeNode | <code>!GraphicNode</code> | A shape node exemplar that is an immediate child of one of this RepeatGrid's cells. The image series will be bound to this node and all corresponding copies of it in the other grid cells. Must be a node type that supports image fills (e.g. Rectangle, but not Text or Line). | | shapeNode | <code>!GraphicNode</code> | A shape node exemplar that would be in scope for editing if the current edit context was one of this RepeatGrid's cells. The image series will be bound to this node and all corresponding copies of it in the other grid cells. Must be a node type that supports image fills (e.g. Rectangle, but not Text or Line). |
| images | <code>!Array&lt;string&gt;</code> | Array of one or more ImageFills. | | images | <code>!Array&lt;string&gt;</code> | Array of one or more ImageFills. |


* * * * * *
Expand Down
64 changes: 42 additions & 22 deletions reference/selection.md
Original file line number Original file line Diff line number Diff line change
@@ -1,8 +1,28 @@
<a name="selection"></a> <a name="selection"></a>


## selection ## selection
The `selection` object represents the currently selected set of nodes in the UI. You can set the selection to use it as input The `selection` object represents the currently selected set of nodes in the UI. You can change the selection to use it as input
for [commands](commands.md), or to determine what is left selected for the user when your plugin's edit operation completes. for [commands](commands.md), or to control what is left selected for the user when your plugin's edit operation completes.

**Selected items might not all have the same parent node.** For example, the selection could be split between two sibling
Group nodes, or half the selection could be inside a Group and half inside its parent. Or the selection could be split between
multiple different artboards along with items on the pasteboard (immediate children of the root node).

Your plugin can only modify nodes in the "neighborhood" of the user's selection, a subset of the scenegraph tree called the
**_[edit context](/reference/core/edit-context.md)_**. You can only set the selection to other nodes within the edit context.
The edit context does not update to reflect any changes to the selection until after a plugin operation completes.

**Other restrictions on selection**

* The selection cannot contain both artboards and non-artboards at the same time.

* The selection cannot contain both a node and one of its ancestors at the same time.

* Items that are _locked_ cannot be in the selection. If the user or your plugin attempts to select any locked items, they are
automatically filtered into a separate list ([itemsIncludingLocked](#selection-itemsIncludingLocked)) which is generally only used by the Unlock
command.

**Accessing the selection**


The current selection state is passed to your _command handler function_ as an argument: The current selection state is passed to your _command handler function_ as an argument:
```js ```js
Expand All @@ -14,20 +34,6 @@ module.exports.commands = { myCommandId: myCommand };


You can also access this object from the [`scenegraph.selection`](./scenegraph.md#module_scenegraph-selection) property. You can also access this object from the [`scenegraph.selection`](./scenegraph.md#module_scenegraph-selection) property.


The selection can only contain items within the current [_edit context_](/reference/core/edit-context.md):
- If the user has drilled down into a container node, the container is the current edit context and only its immediate children
can be selected.
- If the user hasn't drilled into any container, the root of the document is the edit context, and the selection may contain any
artboard _or_ any combination of the pasteboard's immediate children and one or more artboards' immediate children. The selection
cannot contain both artboards and non-artboards at the same time, however.

**Don't assume that all selected items have the same parent node:** in the root edit context, the selection can contain items with
differing parents (multiple different artboards, as well as the root node).

Items that are _locked_ cannot be in the selection. If the user or your plugin attempts to select any locked items, they are
automatically filtered into a separate list ([itemsIncludingLocked](#selection-itemsIncludingLocked)) which is generally only used by the Unlock
command.

**Kind**: object **Kind**: object


* [selection](#selection) * [selection](#selection)
Expand All @@ -45,17 +51,19 @@ command.
<a name="selection-items"></a> <a name="selection-items"></a>


### selection.items : <code>!Array&lt;\![SceneNode](scenegraph.md#SceneNode)&gt;</code> ### selection.items : <code>!Array&lt;\![SceneNode](scenegraph.md#SceneNode)&gt;</code>
Array representing the current selection. Empty array if nothing is selected (never null). Never includes locked nodes. Array representing the current selection. Empty array if nothing is selected (never null). _Items might not all have the same
May include items with different parents (for example, an item in an artboard plus an item on the pasteboard can be selected parent node._ Never includes locked nodes. Never mixes artboards with other nodes: a selection is either all artboards or all
at the same time). Never mixes artboards with other nodes: a selection is either all artboards or all non-artboards. non-artboards. Never includes any ancestors of any other item in the selection.


As a convenience, the setter also accepts a single node or null as valid input. However, the getter always returns an array. As a convenience, the setter also accepts a single node or null as valid input. However, the getter always returns an array.


If the user selects nodes one-by-one, by Shift-clicking, this array lists the nodes in the order they were added to the selection. If the user selects nodes one-by-one, by Shift-clicking, this array lists the nodes in the order they were added to the selection.
If the user selected by other means, e.g. dragging a marquee, the order has no meaning. If the user selected by other means, e.g. dragging a marquee, the order has no meaning.


Returns a fresh array each time, so this can be mutated by the caller without interfering with anything. Mutating the array Returns a fresh array each time, so modifying the array returned by the getter does not change the selection -- only invoking
does not change the selection - only invoking the 'items' setter changes selection. the 'items' setter changes selection.

The selection can only contain items which are in the current _[edit context](/reference/core/edit-context.md)._


**Kind**: instance property of [<code>selection</code>](#selection) **Kind**: instance property of [<code>selection</code>](#selection)
**Example** **Example**
Expand Down Expand Up @@ -107,7 +115,18 @@ True if the selection isn’t empty and consists of one or more Artboards. Never
<a name="selection-editContext"></a> <a name="selection-editContext"></a>


### selection.editContext : <code>\![SceneNode](scenegraph.md#SceneNode)</code> ### selection.editContext : <code>\![SceneNode](scenegraph.md#SceneNode)</code>
The context in which selection and edit operations must occur. If the user hasn't drilled into any container node, this value is the document root, and its scope includes all immediate children of the pasteboard (including Artboards), *and* all immediate children of all those Artboards. The common ancestor node of all selected items - also the root node of the subtree containing the "[edit context](/reference/core/edit-context.md),"
which is the scope in which selection and edit operations must occur for the current plugin command. The scope does not
necessarily cover the entire subtree rooted at the editContext root node -- it may only cover a subset of this tree. See
edit context documentation page for more details.

If the user hasn't drilled into any container node, this value is the document root.

The value of `editContext` does not change while your plugin is running. However, the `editContext` may change after your plugin
operation ends:
- If your plugin changes the value of `selection.items` to include fewer nodes, the edit context may be narrowed.
- If your plugin has deleted nodes such that the current container is now empty, the edit context will pop up a level and the now-empty
container is automatically cleaned up.


**Kind**: instance property of [<code>selection</code>](#selection) **Kind**: instance property of [<code>selection</code>](#selection)
**Read only**: true **Read only**: true
Expand All @@ -118,6 +137,7 @@ The context in which selection and edit operations must occur. If the user hasn'


### selection.insertionParent : <code>\![SceneNode](scenegraph.md#SceneNode)</code> ### selection.insertionParent : <code>\![SceneNode](scenegraph.md#SceneNode)</code>
The preferred parent to insert newly added content into. Takes into account the current edit context as well as the "focused artboard" if in the root context. The preferred parent to insert newly added content into. Takes into account the current edit context as well as the "focused artboard" if in the root context.
Typically this is the same parent where, for example, XD's shape drawing tools would add items.


**Kind**: instance property of [<code>selection</code>](#selection) **Kind**: instance property of [<code>selection</code>](#selection)
**Read only**: true **Read only**: true
Expand Down

0 comments on commit 8ac0d85

Please sign in to comment.