Skip to content

Commit 7f63665

Browse files
committed
Merge branch 'master' of github.com:AdobeXD/plugin-docs
2 parents 14d07f5 + 231c64c commit 7f63665

File tree

7 files changed

+475
-3
lines changed

7 files changed

+475
-3
lines changed

SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
* [Shadow](./reference/Shadow.md)
120120
* [Blur](./reference/Blur.md)
121121
* [selection](./reference/selection.md)
122+
* [PerPluginStorage](./reference/PerPluginStorage.md)
122123
* [application](./reference/application.md)
123124
* [assets](./reference/assets.md)
124125
* [clipboard](./reference/clipboard.md)

changes.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,60 @@
11
# Change Log
22

3+
XD Release 30.0.12 (June 2020)
4+
-------------------------------------
5+
6+
### New features
7+
* **Scrollable Groups** -- Plugins will see a new [ScrollableGroup](./reference/scenegraph.md#ScrollableGroup) node type and can read the scroll direction(s) and viewport size. Plugins cannot yet create a ScrollableGroup or modify its viewport, however.
8+
9+
### Known Issues
10+
* **Content Aware Stacks** -- Some plugin actions, such as changing a node's position or its Responsive Resize constraints, may be ignored or behave unexpectedly when the node's parent is a Group with Stack layout enabled. Plugins cannot yet create, read, or modify Stack layout settings on a Group.
11+
12+
* MouseEvent `clientX`/`clientY` and `offsetX`/`offsetY` values are incorrect (and always have been) -- these values will probably change in the _next_ XD release, so do not rely on them.
13+
14+
15+
XD Release 29.0.32 (May 2020)
16+
-------------------------------------
17+
18+
### New API features
19+
* **[Read & modify Responsive Resize constraints](./reference/scenegraph.md#SceneNode-horizontalConstraints)**
20+
* **[Set metadata readable by other plugins](./reference/scenegraph.md#SceneNode-sharedPluginData)**
21+
* [Check if two nodes share the same raster image asset](./reference/ImageFill.md#ImageFill-assetId)
22+
23+
### UXP upgrade
24+
The common plugin runtime has been upgraded to UXP 3.4.4, bringing a range of new features and bug fixes:
25+
26+
New features:
27+
* **`HTMLElement.innerText` property**
28+
* Custom text field styling using `appearance: none`
29+
* `HTMLElement.scrollTo()` method
30+
* SVG `<polygon>` and `<polyline>`
31+
* Get version of the UXP runtime & version of your own plugin via `require("uxp").versions.uxp` / `.versions.plugin`
32+
* Limited support for CustomElementRegistry (using `is` but not using custom HTML tags; Web Components APIs such as `attachShadow()` remain unsupported)
33+
* `HTMLImageElement.complete` flag
34+
35+
Bug fixes:
36+
* Fixed a crash when drag operations started
37+
* The data transfer is initiated properly at the start of the `dragend` event
38+
* Fixed the resolution of image URLs to plugin:, plugin-data, plugin-temp for UWP
39+
* Fixed a bug where context menus didn’t stay open
40+
* Fixed improper word breaking in certain edge cases
41+
* Improved stack trace length limitations
42+
43+
### Breaking API changes
44+
45+
* `ImageFill.toString()` has changed: it no longer includes the full path of the originally imported file, and adds image dimensions to aid in debugging console logs.
46+
47+
### Known Issues
48+
49+
* MouseEvent `clientX`/`clientY` and `offsetX`/`offsetY` values are incorrect (and always have been) -- these values will change in a near-future XD release, so do not rely on them.
50+
51+
### Plugin submission process
52+
53+
* The "Adobe I/O Console" has been renamed "Adobe Developer Console," with a new link: https://console.adobe.io/projects
54+
* Preview how your listing will look in XD before submitting it for review.
55+
* Publish updates at a specific time of your choosing by opting out of instant publishing when your plugin submission is approved.
56+
57+
358
XD Release 28.0.12 (March 2020)
459
-------------------------------------
560
XD 28 is a minor update for plugin developers:

known-issues.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888

8989
- Interactive elements do not support `Pointer%` events
9090
- `keypress` and `keyup` are not currently supported on macOS.
91+
- Mouse event `clientX`/`Y` & `offsetX`/`Y` properties have incorrect values. They will change in the near future -- do not rely on these properties right now.
9192

9293
### Drag & Drop
9394

reference/ImageFill.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ selection.items[0].fill = fill;
2424
* [ImageFill](#ImageFill)
2525
* [new ImageFill(fileOrDataURI)](#new_ImageFill_new)
2626
* [.clone()](#ImageFill-clone) ⇒ <code>!ImageFill</code>
27+
* [.assetId](#ImageFill-assetId) : <code>string</code>
2728
* [.scaleBehavior](#ImageFill-scaleBehavior) : <code>string</code>
2829
* [.naturalWidth](#ImageFill-naturalWidth) : <code>number</code>
2930
* [.naturalHeight](#ImageFill-naturalHeight) : <code>number</code>
@@ -50,6 +51,19 @@ Returns a new copy of this ImageFill.
5051
**Returns**: <code>!ImageFill</code>
5152

5253

54+
* * *
55+
56+
<a name="ImageFill-assetId"></a>
57+
58+
### *imageFill.assetId : <code>string</code>*
59+
**Since**: XD 29
60+
61+
A unique identifier for the image asset used by this ImageFill. May be shared by other ImageFills, including those with different cropping, size,
62+
rotation, or mirroring. If identical images are imported into XD from separate sources, they may have different `assetId`s however.
63+
64+
**Kind**: instance property of [<code>ImageFill</code>](#ImageFill)
65+
66+
5367
* * *
5468

5569
<a name="ImageFill-scaleBehavior"></a>

reference/PerPluginStorage.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
<a name="PerPluginStorage"></a>
2+
3+
## PerPluginStorage
4+
**Kind**: interface
5+
6+
**Since**: XD 29
7+
8+
Stores metadata accessible to multiple plugins, separated into silos by plugin ID. Your plugin can read & write the storage for its own plugin ID, but storage for other plugin IDs is *read-only*.
9+
10+
Each per-plugin storage silo is a collection of key-value pairs. Keys and values must both be strings.
11+
12+
*Each* scenenode has its own metadata storage, accessed via [`SceneNode.sharedPluginData`](scenegraph.md#SceneNode-sharedPluginData). To store general metadata that is not specific to one scenenode, use `sharedPluginData` on the [document's scenegraph root](scenegraph.md#module_scenegraph-root).
13+
14+
**Example**
15+
```js
16+
// This example shows how to save & retrieve rich JSON data in shared metadata storage.
17+
// See below for simpler examples of using individual APIs.
18+
const PLUGIN_ID = "<your manifest's plugin ID here>";
19+
20+
let richObject = {
21+
list: [2, 4, 6],
22+
name: "Hello world"
23+
};
24+
node.sharedPluginData.setItem(PLUGIN_ID, "richData", JSON.stringify(richObject));
25+
26+
// Later on...
27+
// (This could be in a different plugin, if it passes the original plugin's ID here)
28+
let jsonString = node.sharedPluginData.getItem(PLUGIN_ID, "richData");
29+
if (jsonString) { // may be undefined
30+
let richObjectCopy = JSON.parse(jsonString);
31+
console.log(richObjectCopy.list.length); // 3
32+
}
33+
```
34+
35+
* [PerPluginStorage](#PerPluginStorage)
36+
* [.getAll()](#getAll) ⇒ <code>!Object&lt; string, !Object&lt;string, string&gt; &gt;</code>
37+
* [.getForPluginId(pluginId)](#getForPluginId) ⇒ <code>!Object&lt;string, string&gt;</code>
38+
* [.keys(pluginId)](#keys) ⇒ <code>!Array&lt;string&gt;</code>
39+
* [.getItem(pluginId, key)](#getItem) ⇒ <code>?string</code>
40+
* [.setItem(pluginId, key, value)](#setItem)
41+
* [.removeItem(pluginId, key)](#removeItem)
42+
* [.toString()](#toString) ⇒ <code>string</code>
43+
* [.toJSON()](#toJSON) ⇒ <code>!Object</code>
44+
45+
46+
<a name="getAll"></a>
47+
## perPluginStorage.getAll() ⇒ <code>!Object&lt; string, !Object&lt;string, string&gt; &gt;</code>
48+
49+
Returns a map where key is plugin ID and value is a nested map containing all the shared metadata for that plugin ID (i.e. the result of calling `getForPluginId()` with that ID).
50+
51+
This map is a clone of the stored metadata, so modifying it has no effect.
52+
53+
**Example**
54+
```js
55+
let allSharedMetadata = node.sharedPluginData.getAll();
56+
console.log("Plugin A's 'foo' value:",
57+
allSharedMetadata["A"] && allSharedMetadata["A"].foo);
58+
console.log("All of plugin B's shared metadata on this node:",
59+
allSharedMetadata["B"]);
60+
console.log("List of plugins storing shared metadata on this node:",
61+
Object.keys(allSharedMetadata));
62+
```
63+
64+
65+
* * *
66+
67+
<a name="getForPluginId"></a>
68+
## perPluginStorage.getForPluginId(pluginId) ⇒ <code>!Object&lt;string, string&gt;</code>
69+
70+
Returns a map of key-value string pairs containing all shared metadata stored on this node by the given plugin. May be an empty object (zero keys), but is never null.
71+
72+
This map is a clone of the stored metadata, so modifying it has no effect.
73+
74+
| Param | Type |
75+
| ----- | ---- |
76+
| pluginId | `string` |
77+
78+
**Example**
79+
```js
80+
const MY_PLUGIN_ID = "<your manifest's plugin ID here>";
81+
let mySharedMetadata = node.sharedPluginData.getForPluginId(MY_PLUGIN_ID);
82+
console.log("My shared 'foo' & 'bar' values:",
83+
mySharedMetadata.foo, mySharedMetadata.bar);
84+
85+
console.log("Plugin B's shared 'foo' value:",
86+
node.sharedPluginData.getForPluginId("B").foo);
87+
```
88+
89+
90+
* * *
91+
92+
<a name="keys"></a>
93+
## perPluginStorage.keys(pluginId) ⇒ <code>!Array&lt;string&gt;</code>
94+
95+
Returns a list of all keys stored on this node by the given plugin. May be empty (length zero), but is never null.
96+
97+
| Param | Type |
98+
| ----- | ---- |
99+
| pluginId | `string` |
100+
101+
102+
**Example**
103+
```js
104+
console.log("All properties stored by plugin A on this node:",
105+
node.sharedPluginData.keys("A"));
106+
```
107+
108+
109+
* * *
110+
111+
<a name="getItem"></a>
112+
## perPluginStorage.getItem(pluginId, key) ⇒ <code>?string</code>
113+
114+
Returns the value stored under the given key on this node by the given plugin, or undefined if the plugin hasn't stored anything under the given key.
115+
116+
Because metadata is stored separately per plugin, two plugins can store two different values under the same key.
117+
118+
| Param | Type |
119+
| ----- | ---- |
120+
| pluginId | `string` |
121+
| key | `string` |
122+
123+
124+
**Example**
125+
```js
126+
// These are two different values, stored independently per plugin
127+
console.log("Plugin A's 'foo' value:", node.sharedPluginData.getItem("A", "foo"));
128+
console.log("Plugin B's 'foo' value:", node.sharedPluginData.getItem("B", "foo"));
129+
```
130+
131+
132+
* * *
133+
134+
<a name="setItem"></a>
135+
## perPluginStorage.setItem(pluginId, key, value)
136+
137+
Set a metadata key which can be read by any other plugin.
138+
139+
| Param | Type | Description |
140+
| ----- | ---- | ----------- |
141+
| pluginId | `string` | *Must* be equal to your plugin's ID. |
142+
| key | `string` | |
143+
| value | `string` or `undefined` | If undefined, behaves as if you'd called `removeItem()` instead. |
144+
145+
146+
**Example**
147+
```js
148+
const MY_PLUGIN_ID = "<your manifest's plugin ID here>";
149+
node.sharedPluginData.setItem(MY_PLUGIN_ID, "foo", "42");
150+
151+
node.sharedPluginData.setItem("other_plugin_id", "foo", "42");
152+
// ^ ERROR: other plugin's metadata is read-only
153+
154+
console.log(node.sharedPluginData.getItem(MY_PLUGIN_ID, "foo")); // "42"
155+
```
156+
157+
158+
* * *
159+
160+
<a name="removeItem"></a>
161+
## perPluginStorage.removeItem(pluginId, key)
162+
163+
Clears a shared metadata key stored by your plugin.
164+
165+
| Param | Type | Description |
166+
| ----- | ---- | ----------- |
167+
| pluginId | `string` | *Must* be equal to your plugin's ID. |
168+
| key | `string` | &nbsp; |
169+
170+
171+
**Example**
172+
```js
173+
const MY_PLUGIN_ID = "<your manifest's plugin ID here>";
174+
node.sharedPluginData.setItem(MY_PLUGIN_ID, "foo", "42");
175+
console.log(node.sharedPluginData.getItem(MY_PLUGIN_ID, "foo")); // "42"
176+
177+
node.sharedPluginData.removeItem(MY_PLUGIN_ID, "foo");
178+
console.log(node.sharedPluginData.getItem(MY_PLUGIN_ID, "foo")); // undefined
179+
```
180+
181+
182+
* * *
183+
184+
<a name="toString"></a>
185+
## perPluginStorage.toString() ⇒ <code>string</code>
186+
187+
Provided for convenience: you can `console.log(node.sharedPluginData)` to see the value of `getAll()`.
188+
189+
190+
* * *
191+
192+
<a name="toJSON"></a>
193+
## perPluginStorage.toJSON() ⇒ <code>!Object</code>
194+
195+
Provided for convenience: you can include a PerPluginStorage object inside data you are going to convert to JSON, even though it is not a plain JavaScript object. Returns the same value as `getAll()`.
196+
197+
**Example**
198+
```js
199+
let myData = {
200+
foo: 42,
201+
bar: "Some other data",
202+
metadata: node.sharedPluginData
203+
};
204+
let jsonString = JSON.stringify(myData);
205+
```

reference/core/automatic-cleanups.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,7 @@ To make writing your plugin simpler, XD performs a number of automated cleanups
1414

1515
* **Repeat Grid cell syncing** - Most changes you make inside a Repeat Grid cell are automatically mirrored to all its other cells, except for certain properties
1616
such as text and images which XD permits to vary between grid cells.
17+
18+
* **Content-Aware Group & Stack layout updates** -- The background layer (if any) of a Content-Aware Group will update automatically after a plugin changes the
19+
size or position of its contents. Similarly, changing a node inside a Group with Stack layout will automatically slide its adjacent siblings to preserve a
20+
constant margin around the node. These changes do not occur until after the plugin command finishes.

0 commit comments

Comments
 (0)