lucid-extension-sdk 0.0.9 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/interop.d.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  declare namespace lucid {
3
3
  export function executeCommand(name: string, params: any): any;
4
4
  export function listen(msg: any): void;
5
+ export function getPackageId(): string;
6
+ export function getVersion(): string;
5
7
  }
6
8
 
7
9
  /** @ignore */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lucid-extension-sdk",
3
- "version": "0.0.9",
3
+ "version": "0.0.13",
4
4
  "description": "Utility classes for writing Lucid Software editor extensions",
5
5
  "main": "sdk/index.js",
6
6
  "types": "sdk/index.d.ts",
@@ -5,6 +5,7 @@ import { JsonObject, JsonSerializable } from './core/jsonserializable';
5
5
  import { LinearOffsetType } from './core/offsettype';
6
6
  import { SerializedDataError } from './core/serializeddataerror';
7
7
  import { ShapeDataInheritance } from './core/shapedatainheritance';
8
+ import { SerializedLineTextAreaPositioning } from './document/linetextareapositioning';
8
9
  import { Box, Point } from './math';
9
10
  import { MenuLocation, MenuType } from './ui/menu';
10
11
  import { PanelLocation } from './ui/panel';
@@ -16,6 +17,7 @@ import { PanelLocation } from './ui/panel';
16
17
  * To use these directly, use [EditorClient.sendCommand](#classes_editorclient-EditorClient_sendcommand).
17
18
  */
18
19
  export declare const enum CommandName {
20
+ AddLineTextArea = "alta",
19
21
  AddMenuItem = "ami",
20
22
  AddShapeData = "asd",
21
23
  AnimateViewport = "av",
@@ -44,6 +46,9 @@ export declare const enum CommandName {
44
46
  GetShapeData = "gsd",
45
47
  HideModal = "hm",
46
48
  HidePanel = "hp",
49
+ HookCreateItems = "hci",
50
+ HookSelection = "hs",
51
+ HookTextEdit = "hte",
47
52
  KillExtension = "k",
48
53
  ListBlocks = "lb",
49
54
  ListCollectionFields = "lcf",
@@ -72,7 +77,10 @@ export declare const enum CommandName {
72
77
  SetShapeData = "ssd",
73
78
  ShowModal = "sm",
74
79
  ShowPanel = "spn",
75
- SleepForTestCase = "sleep"
80
+ SleepForTestCase = "sleep",
81
+ UnhookCreateItems = "uci",
82
+ UnhookSelection = "us",
83
+ UnhookTextEdit = "ute"
76
84
  }
77
85
  /**
78
86
  * This is a type declaration whose purpose is to allow TypeScript to enforce the correct parameter and
@@ -80,9 +88,9 @@ export declare const enum CommandName {
80
88
  * which command name you pass in as the first parameter.
81
89
  */
82
90
  export declare type CommandArgs = {
83
- [CommandName.AnimateViewport]: {
84
- query: AnimateViewportQuery;
85
- result: AnimateViewportResult;
91
+ [CommandName.AddLineTextArea]: {
92
+ query: AddLineTextAreaQuery;
93
+ result: AddLineTextAreaResult;
86
94
  };
87
95
  [CommandName.AddMenuItem]: {
88
96
  query: AddMenuItemQuery;
@@ -92,6 +100,10 @@ export declare type CommandArgs = {
92
100
  query: AddShapeDataQuery;
93
101
  result: AddShapeDataResult;
94
102
  };
103
+ [CommandName.AnimateViewport]: {
104
+ query: AnimateViewportQuery;
105
+ result: AnimateViewportResult;
106
+ };
95
107
  [CommandName.Bootstrap]: {
96
108
  query: BootstrapQuery;
97
109
  result: BootstrapResult;
@@ -192,6 +204,18 @@ export declare type CommandArgs = {
192
204
  query: HidePanelQuery;
193
205
  result: HidePanelResult;
194
206
  };
207
+ [CommandName.HookCreateItems]: {
208
+ query: HookCreateItemsQuery;
209
+ result: HookCreateItemsResult;
210
+ };
211
+ [CommandName.HookSelection]: {
212
+ query: HookSelectionQuery;
213
+ result: HookSelectionResult;
214
+ };
215
+ [CommandName.HookTextEdit]: {
216
+ query: HookTextEditQuery;
217
+ result: HookTextEditResult;
218
+ };
195
219
  [CommandName.KillExtension]: {
196
220
  query: KillExtensionQuery;
197
221
  result: KillExtensionResult;
@@ -308,7 +332,29 @@ export declare type CommandArgs = {
308
332
  query: SleepForTestCaseQuery;
309
333
  result: SleepForTestCaseResult;
310
334
  };
335
+ [CommandName.UnhookCreateItems]: {
336
+ query: UnhookCreateItemsQuery;
337
+ result: UnhookCreateItemsResult;
338
+ };
339
+ [CommandName.UnhookSelection]: {
340
+ query: UnhookSelectionQuery;
341
+ result: UnhookSelectionResult;
342
+ };
343
+ [CommandName.UnhookTextEdit]: {
344
+ query: UnhookTextEditQuery;
345
+ result: UnhookTextEditResult;
346
+ };
347
+ };
348
+ export declare type AddLineTextAreaQuery = {
349
+ /** Which line */
350
+ 'id': string;
351
+ /** Where to place the text along the line */
352
+ 'p': SerializedLineTextAreaPositioning;
353
+ /** Plain text to put at this location (will be styled with document theme) */
354
+ 't': string;
311
355
  };
356
+ /** The name of the created text area */
357
+ export declare type AddLineTextAreaResult = string;
312
358
  /** @ignore */
313
359
  export declare type UnionToIntersection<T> = (T extends any ? (x: T) => unknown : never) extends (x: infer R) => unknown ? R : never;
314
360
  export declare type AddMenuItemQuery = {
@@ -509,6 +555,21 @@ export declare type HidePanelQuery = {
509
555
  'n': string;
510
556
  };
511
557
  export declare type HidePanelResult = undefined;
558
+ export declare type HookCreateItemsQuery = {
559
+ /** Name of the action for receiving events. Will be called with an array of strings of all recently created item IDs. */
560
+ 'n': string;
561
+ };
562
+ export declare type HookCreateItemsResult = undefined;
563
+ export declare type HookSelectionQuery = {
564
+ /** Name of the action for receiving events. Will be called with an array of strings of all selected item IDs. */
565
+ 'n': string;
566
+ };
567
+ export declare type HookSelectionResult = undefined;
568
+ export declare type HookTextEditQuery = {
569
+ /** Name of the action for receiving these events */
570
+ 'n': string;
571
+ };
572
+ export declare type HookTextEditResult = undefined;
512
573
  export declare type KillExtensionQuery = void;
513
574
  export declare type KillExtensionResult = undefined;
514
575
  export declare type ListChildrenQuery = {
@@ -641,6 +702,7 @@ export declare type RawSendXHRResponse = {
641
702
  'to'?: boolean;
642
703
  };
643
704
  export declare type SendXHRResponse = Promise<RawSendXHRResponse>;
705
+ export declare function isRawSendXHRResponse(val: any): val is RawSendXHRResponse;
644
706
  export declare type SetCurrentPageQuery = string;
645
707
  export declare type SetCurrentPageResult = Promise<void>;
646
708
  export declare type SetPropertyQuery = {
@@ -690,3 +752,18 @@ export declare type ShowPanelQuery = {
690
752
  export declare type ShowPanelResult = undefined;
691
753
  export declare type SleepForTestCaseQuery = number;
692
754
  export declare type SleepForTestCaseResult = Promise<void>;
755
+ export declare type UnhookCreateItemsQuery = {
756
+ /** Name of the action passed to HookCreateItems */
757
+ 'n': string;
758
+ };
759
+ export declare type UnhookCreateItemsResult = undefined;
760
+ export declare type UnhookSelectionQuery = {
761
+ /** Name of the action for receiving these events */
762
+ 'n': string;
763
+ };
764
+ export declare type UnhookSelectionResult = undefined;
765
+ export declare type UnhookTextEditQuery = {
766
+ /** Name of the action for receiving these events */
767
+ 'n': string;
768
+ };
769
+ export declare type UnhookTextEditResult = undefined;
@@ -1,2 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRawSendXHRResponse = void 0;
4
+ const checks_1 = require("./core/checks");
5
+ function isRawSendXHRResponse(val) {
6
+ return (0, checks_1.isString)(val['url']) && (0, checks_1.isString)(val['t']) && (0, checks_1.isNumber)(val['s']) && (0, checks_1.isObject)(val['h']);
7
+ }
8
+ exports.isRawSendXHRResponse = isRawSendXHRResponse;
@@ -22,3 +22,9 @@ export declare type UnTypedSerializedFlattenedReference = {
22
22
  };
23
23
  export declare type SerializedFlattenedReference = TypedSerializedFlattenedReference | UnTypedSerializedFlattenedReference;
24
24
  export declare type SerializedReferenceKeyType = SerializedReferenceKey | SerializedFlattenedReference;
25
+ /** @ignore */
26
+ export declare function isTypedSerializedFlattenedReference(data: unknown): data is TypedSerializedFlattenedReference;
27
+ /** @ignore */
28
+ export declare function isUnTypedSerializedFlattenedReference(data: unknown): data is UnTypedSerializedFlattenedReference;
29
+ /** @ignore */
30
+ export declare function isSerializedFlattenedReference(data: unknown): data is SerializedFlattenedReference;
@@ -1,5 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FlattenedReferenceKeyName = exports.FlattenedReferenceKeyId = void 0;
3
+ exports.isSerializedFlattenedReference = exports.isUnTypedSerializedFlattenedReference = exports.isTypedSerializedFlattenedReference = exports.FlattenedReferenceKeyName = exports.FlattenedReferenceKeyId = void 0;
4
+ const checks_1 = require("../../checks");
4
5
  exports.FlattenedReferenceKeyId = '192d0e9f-2f5a-4032-9f03-59bbf1ea5891';
5
6
  exports.FlattenedReferenceKeyName = '192d0e9f-2f5a-4032-9f03-59bbf1ea5891_n';
7
+ /** @ignore */
8
+ function isTypedSerializedFlattenedReference(data) {
9
+ return (0, checks_1.isObject)(data) && (0, checks_1.isObject)(data['sc']) && (0, checks_1.isObject)(data['d']);
10
+ }
11
+ exports.isTypedSerializedFlattenedReference = isTypedSerializedFlattenedReference;
12
+ /** @ignore */
13
+ function isUnTypedSerializedFlattenedReference(data) {
14
+ return (0, checks_1.isObject)(data) && data[exports.FlattenedReferenceKeyId] === true;
15
+ }
16
+ exports.isUnTypedSerializedFlattenedReference = isUnTypedSerializedFlattenedReference;
17
+ /** @ignore */
18
+ function isSerializedFlattenedReference(data) {
19
+ return isUnTypedSerializedFlattenedReference(data) || isTypedSerializedFlattenedReference(data);
20
+ }
21
+ exports.isSerializedFlattenedReference = isSerializedFlattenedReference;
@@ -30,7 +30,7 @@ export interface CollectionReferenceKeyDefinition {
30
30
  */
31
31
  export interface FlattenedReferenceDefinition {
32
32
  /** Name to display to the user for the reference key (what would normally be the collection name) */
33
- name: string;
33
+ name?: string;
34
34
  /** Schema of the data stored at this key */
35
35
  schema: SchemaDefinition;
36
36
  /** Field values available at this reference key */
@@ -41,3 +41,5 @@ export declare type ReferenceKeyDefinition = CollectionReferenceKeyDefinition |
41
41
  export declare function isCollectionReferenceKeyDefinition(def: ReferenceKeyDefinition): def is CollectionReferenceKeyDefinition;
42
42
  /** @ignore */
43
43
  export declare function serializeReferenceKeyDefinition(def: ReferenceKeyDefinition): SerializedReferenceKeyType;
44
+ /** @ignore */
45
+ export declare function parseReferenceKeyDefinition(def: SerializedReferenceKeyType): ReferenceKeyDefinition;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.serializeReferenceKeyDefinition = exports.isCollectionReferenceKeyDefinition = void 0;
3
+ exports.parseReferenceKeyDefinition = exports.serializeReferenceKeyDefinition = exports.isCollectionReferenceKeyDefinition = void 0;
4
4
  const checks_1 = require("../core/checks");
5
+ const serializedreferencekey_1 = require("../core/data/referencekeys/serializedreferencekey");
5
6
  const schemadefinition_1 = require("./schemadefinition");
6
7
  /** @ignore */
7
8
  function isCollectionReferenceKeyDefinition(def) {
@@ -27,3 +28,25 @@ function serializeReferenceKeyDefinition(def) {
27
28
  }
28
29
  }
29
30
  exports.serializeReferenceKeyDefinition = serializeReferenceKeyDefinition;
31
+ /** @ignore */
32
+ function parseReferenceKeyDefinition(def) {
33
+ if ((0, serializedreferencekey_1.isTypedSerializedFlattenedReference)(def)) {
34
+ return {
35
+ schema: (0, schemadefinition_1.parseSchemaDefinition)(def['sc']),
36
+ name: def['n'],
37
+ data: def['d'],
38
+ };
39
+ }
40
+ else if ((0, serializedreferencekey_1.isUnTypedSerializedFlattenedReference)(def)) {
41
+ throw new Error('Untyped serialized flattened references not implemented');
42
+ }
43
+ else {
44
+ return {
45
+ collectionId: def['cid'],
46
+ primaryKey: def['pk'],
47
+ fieldWhitelist: def['wl'],
48
+ readonly: def['ro'],
49
+ };
50
+ }
51
+ }
52
+ exports.parseReferenceKeyDefinition = parseReferenceKeyDefinition;
@@ -6,4 +6,8 @@ export declare class ReferenceKeyProxy {
6
6
  private readonly client;
7
7
  private readonly settings;
8
8
  constructor(elementId: string | undefined, key: string | number, client: EditorClient, settings: SerializedReferenceKeyType);
9
+ get collectionId(): string | undefined;
10
+ get primaryKey(): string | undefined;
11
+ get definition(): import("./referencekeydefinition").ReferenceKeyDefinition;
12
+ getItem(): import("./dataitemproxy").DataItemProxy;
9
13
  }
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ReferenceKeyProxy = void 0;
4
+ const serializedreferencekey_1 = require("../core/data/referencekeys/serializedreferencekey");
5
+ const collectionproxy_1 = require("./collectionproxy");
6
+ const referencekeydefinition_1 = require("./referencekeydefinition");
4
7
  class ReferenceKeyProxy {
5
8
  constructor(elementId, key, client, settings) {
6
9
  this.elementId = elementId;
@@ -8,5 +11,27 @@ class ReferenceKeyProxy {
8
11
  this.client = client;
9
12
  this.settings = settings;
10
13
  }
14
+ get collectionId() {
15
+ if ((0, serializedreferencekey_1.isSerializedFlattenedReference)(this.settings)) {
16
+ return undefined;
17
+ }
18
+ return this.settings['cid'];
19
+ }
20
+ get primaryKey() {
21
+ if ((0, serializedreferencekey_1.isSerializedFlattenedReference)(this.settings)) {
22
+ return undefined;
23
+ }
24
+ return this.settings['pk'];
25
+ }
26
+ get definition() {
27
+ return (0, referencekeydefinition_1.parseReferenceKeyDefinition)(this.settings);
28
+ }
29
+ getItem() {
30
+ const collectionId = this.collectionId;
31
+ if ((0, serializedreferencekey_1.isSerializedFlattenedReference)(this.settings) || !collectionId) {
32
+ throw new Error('Not implemented for flattened references');
33
+ }
34
+ return new collectionproxy_1.CollectionProxy(collectionId, this.client).items.get(this.settings['pk']);
35
+ }
11
36
  }
12
37
  exports.ReferenceKeyProxy = ReferenceKeyProxy;
@@ -20,3 +20,5 @@ export interface SchemaDefinition {
20
20
  }
21
21
  /** @ignore */
22
22
  export declare function serializeSchemaDefinition(def: SchemaDefinition): SerializedSchema;
23
+ /** @ignore */
24
+ export declare function parseSchemaDefinition(def: SerializedSchema): SchemaDefinition;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.serializeSchemaDefinition = void 0;
3
+ exports.parseSchemaDefinition = exports.serializeSchemaDefinition = void 0;
4
4
  const fieldtypedefinition_1 = require("../core/data/fieldtypedefinition/fieldtypedefinition");
5
5
  /** @ignore */
6
6
  function serializeSchemaDefinition(def) {
@@ -13,3 +13,14 @@ function serializeSchemaDefinition(def) {
13
13
  };
14
14
  }
15
15
  exports.serializeSchemaDefinition = serializeSchemaDefinition;
16
+ /** @ignore */
17
+ function parseSchemaDefinition(def) {
18
+ return {
19
+ fields: def['Fields'].map((field) => ({
20
+ name: field['Name'],
21
+ type: (0, fieldtypedefinition_1.deserializeFieldTypeDefinition)(field['Type']),
22
+ })),
23
+ primaryKey: def['PrimaryKey'],
24
+ };
25
+ }
26
+ exports.parseSchemaDefinition = parseSchemaDefinition;
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.findProxyClass = void 0;
4
+ const customblockproxy_1 = require("./customblockproxy");
4
5
  const erdblockproxy_1 = require("./erdblockproxy");
5
- const allProxyClasses = [erdblockproxy_1.ERDBlockProxy];
6
+ const allProxyClasses = [erdblockproxy_1.ERDBlockProxy, customblockproxy_1.CustomBlockProxy];
6
7
  function findProxyClass(className) {
7
8
  return allProxyClasses.find((proxy) => proxy.classNameRegex.test(className));
8
9
  }
@@ -0,0 +1,6 @@
1
+ import { BlockProxy } from '../blockproxy';
2
+ export declare class CustomBlockProxy extends BlockProxy {
3
+ static classNameRegex: RegExp;
4
+ isFromStencil(library: string, shape: string): boolean;
5
+ getStencilTextAreaName(stencilTextAreaName: string): string | undefined;
6
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CustomBlockProxy = void 0;
4
+ const checks_1 = require("../../core/checks");
5
+ const blockproxy_1 = require("../blockproxy");
6
+ class CustomBlockProxy extends blockproxy_1.BlockProxy {
7
+ isFromStencil(library, shape) {
8
+ const stencil = this.properties.get('Stencil');
9
+ if ((0, checks_1.isObject)(stencil)) {
10
+ const sourceStencil = this.client.sendCommand("gp" /* GetProperty */, { 'p': 'Stencil-' + stencil['id'] });
11
+ if ((0, checks_1.isObject)(sourceStencil) && (0, checks_1.isObject)(sourceStencil['sourcePackage'])) {
12
+ return (sourceStencil['sourcePackage']['packageId'] === lucid.getPackageId() &&
13
+ sourceStencil['sourcePackage']['library'] === library &&
14
+ sourceStencil['sourcePackage']['shape'] === shape);
15
+ }
16
+ }
17
+ return false;
18
+ }
19
+ getStencilTextAreaName(stencilTextAreaName) {
20
+ return this.textAreas.keys().find((name) => name.endsWith('_' + stencilTextAreaName));
21
+ }
22
+ }
23
+ exports.CustomBlockProxy = CustomBlockProxy;
24
+ CustomBlockProxy.classNameRegex = /^CustomBlock$/;
@@ -19,4 +19,16 @@ export declare class BlockProxy extends ItemProxy {
19
19
  * @returns An array of lines that have one or both endpoints connected to this block.
20
20
  */
21
21
  getConnectedLines(): import("./lineproxy").LineProxy[];
22
+ /**
23
+ * Link a text area to a data field, so that editing the text area will also update the
24
+ * associated data, and vice versa.
25
+ *
26
+ * To use this, first establish a reference key on this block with
27
+ * [setReferenceKey](/extension-sdk/#classes_document_blockproxy-BlockProxy_setreferencekey).
28
+ *
29
+ * @param textAreaKey
30
+ * @param referenceKey
31
+ * @param field
32
+ */
33
+ linkText(textAreaKey: string, referenceKey: string | number, field: string): void;
22
34
  }
@@ -29,5 +29,28 @@ class BlockProxy extends itemproxy_1.ItemProxy {
29
29
  const ids = this.client.sendCommand("gcl" /* GetConnectedLines */, this.id);
30
30
  return ids.map((id) => this.client.getLineProxy(id));
31
31
  }
32
+ /**
33
+ * Link a text area to a data field, so that editing the text area will also update the
34
+ * associated data, and vice versa.
35
+ *
36
+ * To use this, first establish a reference key on this block with
37
+ * [setReferenceKey](/extension-sdk/#classes_document_blockproxy-BlockProxy_setreferencekey).
38
+ *
39
+ * @param textAreaKey
40
+ * @param referenceKey
41
+ * @param field
42
+ */
43
+ linkText(textAreaKey, referenceKey, field) {
44
+ if (!this.textAreas.keys().includes(textAreaKey)) {
45
+ throw new Error('Invalid text area key');
46
+ }
47
+ if (!this.referenceKeys.keys().includes(referenceKey)) {
48
+ throw new Error('Invalid reference key');
49
+ }
50
+ this.properties.set(textAreaKey + '_Link', {
51
+ 'ref': referenceKey,
52
+ 'f': field,
53
+ });
54
+ }
32
55
  }
33
56
  exports.BlockProxy = BlockProxy;
@@ -1,5 +1,6 @@
1
1
  import { EditorClient } from '../editorclient';
2
2
  import { ElementProxy } from './elementproxy';
3
+ import { ItemProxy } from './itemproxy';
3
4
  import { MapProxy } from './mapproxy';
4
5
  import { PageDefinition } from './pagedefinition';
5
6
  import { PageProxy } from './pageproxy';
@@ -7,6 +8,8 @@ import { PageProxy } from './pageproxy';
7
8
  * The currently-open Lucid document
8
9
  */
9
10
  export declare class DocumentProxy extends ElementProxy {
11
+ private static nextHookId;
12
+ private static getNextHookName;
10
13
  /**
11
14
  * The set of pages on this document, organized by ID
12
15
  */
@@ -27,4 +30,21 @@ export declare class DocumentProxy extends ElementProxy {
27
30
  * @returns The title of this document
28
31
  */
29
32
  getTitle(): string;
33
+ /**
34
+ * Watch for new blocks, lines, or groups added to this document. The callback will
35
+ * be called with new items created by the current user, but will not be called with items
36
+ * created
37
+ *
38
+ * - As part of a generated diagram, e.g. org chart
39
+ * - As a result of undo or redo
40
+ * - By another user on the same document
41
+ *
42
+ * @param callback
43
+ * @returns A handle that can be passed to `unhookCreateItems`
44
+ */
45
+ hookCreateItems(callback: (items: ItemProxy[]) => void): string;
46
+ /**
47
+ * @param handle Return value from `hookCreateItems`
48
+ */
49
+ unhookCreateItems(handle: string): void;
30
50
  }
@@ -15,6 +15,9 @@ class DocumentProxy extends elementproxy_1.ElementProxy {
15
15
  */
16
16
  this.pages = new mapproxy_1.MapProxy(() => this.client.sendCommand("lp" /* ListPages */, undefined), (pageId) => new pageproxy_1.PageProxy(pageId, this.client));
17
17
  }
18
+ static getNextHookName() {
19
+ return '__documentproxy__hook' + DocumentProxy.nextHookId++;
20
+ }
18
21
  /**
19
22
  * Add a new page to the current document
20
23
  * @param def Definition of the page to add
@@ -39,5 +42,33 @@ class DocumentProxy extends elementproxy_1.ElementProxy {
39
42
  getTitle() {
40
43
  return this.properties.get('Title');
41
44
  }
45
+ /**
46
+ * Watch for new blocks, lines, or groups added to this document. The callback will
47
+ * be called with new items created by the current user, but will not be called with items
48
+ * created
49
+ *
50
+ * - As part of a generated diagram, e.g. org chart
51
+ * - As a result of undo or redo
52
+ * - By another user on the same document
53
+ *
54
+ * @param callback
55
+ * @returns A handle that can be passed to `unhookCreateItems`
56
+ */
57
+ hookCreateItems(callback) {
58
+ const actionName = DocumentProxy.getNextHookName();
59
+ this.client.registerAction(actionName, (msg) => {
60
+ callback(msg['ids'].map((id) => this.client.getItemProxy(id)));
61
+ });
62
+ this.client.sendCommand("hci" /* HookCreateItems */, { 'n': actionName });
63
+ return actionName;
64
+ }
65
+ /**
66
+ * @param handle Return value from `hookCreateItems`
67
+ */
68
+ unhookCreateItems(handle) {
69
+ this.client.deleteAction(handle);
70
+ this.client.sendCommand("uci" /* UnhookCreateItems */, { 'n': handle });
71
+ }
42
72
  }
43
73
  exports.DocumentProxy = DocumentProxy;
74
+ DocumentProxy.nextHookId = 0;
@@ -2,6 +2,7 @@ import { Point } from '../math';
2
2
  import { BlockProxy } from './blockproxy';
3
3
  import { ItemProxy } from './itemproxy';
4
4
  import { EndpointDefinition } from './linedefinition';
5
+ import { LineTextAreaPositioning } from './linetextareapositioning';
5
6
  /**
6
7
  * A line on the current Lucid document
7
8
  */
@@ -52,4 +53,29 @@ export declare class LineProxy extends ItemProxy {
52
53
  * @returns The coordinate of that relative position, relative to the containing page
53
54
  */
54
55
  getRelativePosition(relative: number): Point;
56
+ /**
57
+ *
58
+ * @param name
59
+ * @returns The position of the given text area on this line, if it exists, or undefined if it does not exist.
60
+ */
61
+ getTextAreaPosition(name: string): LineTextAreaPositioning | undefined;
62
+ /**
63
+ * Updates the position of the given text area, if it exists. If not, an error is thrown.
64
+ * @param name
65
+ * @param position
66
+ */
67
+ setTextAreaPosition(name: string, position: LineTextAreaPositioning): void;
68
+ /**
69
+ * Adds a new text area to this line at the given location with the given initial plain text.
70
+ * The text will be styled with the document theme, if any.
71
+ * @param text
72
+ * @param position
73
+ * @returns The name of the text area added
74
+ */
75
+ addTextArea(text: string, position: LineTextAreaPositioning): string;
76
+ /**
77
+ * Deletes the given text area from the line, if it exists.
78
+ * @param name
79
+ */
80
+ deleteTextArea(name: string): void;
55
81
  }
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LineProxy = void 0;
4
+ const checks_1 = require("../core/checks");
4
5
  const blockproxy_1 = require("./blockproxy");
5
6
  const itemproxy_1 = require("./itemproxy");
7
+ const linetextareapositioning_1 = require("./linetextareapositioning");
6
8
  /**
7
9
  * A line on the current Lucid document
8
10
  */
@@ -136,5 +138,49 @@ class LineProxy extends itemproxy_1.ItemProxy {
136
138
  getRelativePosition(relative) {
137
139
  return this.client.sendCommand("grlp" /* GetRelativeLinePosition */, { 'id': this.id, 'p': relative });
138
140
  }
141
+ /**
142
+ *
143
+ * @param name
144
+ * @returns The position of the given text area on this line, if it exists, or undefined if it does not exist.
145
+ */
146
+ getTextAreaPosition(name) {
147
+ const serializedTextAreas = this.properties.get('TextAreas');
148
+ if ((0, checks_1.isObject)(serializedTextAreas)) {
149
+ const rawEntry = serializedTextAreas[name];
150
+ if ((0, linetextareapositioning_1.isSerializedLineTextAreaPositioning)(rawEntry)) {
151
+ return (0, linetextareapositioning_1.deserializeLineTextAreaPositioning)(rawEntry);
152
+ }
153
+ }
154
+ return undefined;
155
+ }
156
+ /**
157
+ * Updates the position of the given text area, if it exists. If not, an error is thrown.
158
+ * @param name
159
+ * @param position
160
+ */
161
+ setTextAreaPosition(name, position) {
162
+ this.properties.set('TextAreas', { [name]: (0, linetextareapositioning_1.serializeLineTextAreaPositioning)(position) });
163
+ }
164
+ /**
165
+ * Adds a new text area to this line at the given location with the given initial plain text.
166
+ * The text will be styled with the document theme, if any.
167
+ * @param text
168
+ * @param position
169
+ * @returns The name of the text area added
170
+ */
171
+ addTextArea(text, position) {
172
+ return this.client.sendCommand("alta" /* AddLineTextArea */, {
173
+ 'id': this.id,
174
+ 'p': (0, linetextareapositioning_1.serializeLineTextAreaPositioning)(position),
175
+ 't': text,
176
+ });
177
+ }
178
+ /**
179
+ * Deletes the given text area from the line, if it exists.
180
+ * @param name
181
+ */
182
+ deleteTextArea(name) {
183
+ this.properties.set('TextAreas', { [name]: null });
184
+ }
139
185
  }
140
186
  exports.LineProxy = LineProxy;
@@ -0,0 +1,31 @@
1
+ export interface LineTextAreaPositioning {
2
+ /**
3
+ * A number between 0 and 1 representing how far this text lies along the line, where 0 puts the text
4
+ * at the same location as the first endpoint, and 1 puts the text at the same location as the second
5
+ * endpoint.
6
+ */
7
+ location: number;
8
+ /**
9
+ * Which side of the line the text is displayed on. If zero, the text is on top of the line. If -1,
10
+ * the text is to the left of the line as you travel from the first to second endpoints. If 1, the
11
+ * text is to the right of the line as you travel from the first to second endpoints.
12
+ */
13
+ side: -1 | 0 | 1;
14
+ /**
15
+ * Normally text on a line is not allowed to overlap a block that is connected to either end of the
16
+ * line. If `allowOverBlock` is true, then the text is allowed to overlap an attached block.
17
+ */
18
+ allowOverBlock?: boolean;
19
+ }
20
+ /** @ignore */
21
+ export declare type SerializedLineTextAreaPositioning = {
22
+ 'Location': number;
23
+ 'Side': -1 | 0 | 1;
24
+ 'AllowOverBlock'?: boolean;
25
+ };
26
+ /** @ignore */
27
+ export declare function isSerializedLineTextAreaPositioning(raw: unknown): raw is SerializedLineTextAreaPositioning;
28
+ /** @ignore */
29
+ export declare function deserializeLineTextAreaPositioning(raw: SerializedLineTextAreaPositioning): LineTextAreaPositioning;
30
+ /** @ignore */
31
+ export declare function serializeLineTextAreaPositioning(data: LineTextAreaPositioning): SerializedLineTextAreaPositioning;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serializeLineTextAreaPositioning = exports.deserializeLineTextAreaPositioning = exports.isSerializedLineTextAreaPositioning = void 0;
4
+ const checks_1 = require("../core/checks");
5
+ /** @ignore */
6
+ function isSerializedLineTextAreaPositioning(raw) {
7
+ return ((0, checks_1.isObject)(raw) &&
8
+ (0, checks_1.isNumber)(raw['Location']) &&
9
+ (0, checks_1.isNumber)(raw['Side']) &&
10
+ ((0, checks_1.isBoolean)(raw['AllowOverBlock']) || (0, checks_1.isUndefined)(raw['AllowOverBlock'])));
11
+ }
12
+ exports.isSerializedLineTextAreaPositioning = isSerializedLineTextAreaPositioning;
13
+ /** @ignore */
14
+ function deserializeLineTextAreaPositioning(raw) {
15
+ return {
16
+ location: raw['Location'],
17
+ side: raw['Side'],
18
+ allowOverBlock: raw['AllowOverBlock'],
19
+ };
20
+ }
21
+ exports.deserializeLineTextAreaPositioning = deserializeLineTextAreaPositioning;
22
+ /** @ignore */
23
+ function serializeLineTextAreaPositioning(data) {
24
+ return {
25
+ 'Location': data.location,
26
+ 'Side': data.side,
27
+ 'AllowOverBlock': data.allowOverBlock,
28
+ };
29
+ }
30
+ exports.serializeLineTextAreaPositioning = serializeLineTextAreaPositioning;
@@ -8,8 +8,9 @@ export declare class MapProxy<KEY, VALUE> {
8
8
  constructor(getKeys: () => KEY[], getItem: (key: KEY) => VALUE);
9
9
  /** @ignore */
10
10
  [Symbol.iterator](): Iterator<[KEY, VALUE]>;
11
- values(): Iterator<VALUE>;
11
+ values(): Generator<VALUE, void, unknown>;
12
12
  keys(): KEY[];
13
+ get size(): number;
13
14
  get(key: KEY): VALUE;
14
15
  first(): VALUE | undefined;
15
16
  }
@@ -30,6 +30,9 @@ class MapProxy {
30
30
  keys() {
31
31
  return this.getKeys();
32
32
  }
33
+ get size() {
34
+ return this.keys().length;
35
+ }
33
36
  get(key) {
34
37
  return this.getItem(key);
35
38
  }
@@ -3,6 +3,7 @@ import { JsonSerializable } from './core/jsonserializable';
3
3
  import { BlockDefinition } from './document/blockdefinition';
4
4
  import { BlockProxy } from './document/blockproxy';
5
5
  import { ElementProxy } from './document/elementproxy';
6
+ import { GroupProxy } from './document/groupproxy';
6
7
  import { LineProxy } from './document/lineproxy';
7
8
  import { PageProxy } from './document/pageproxy';
8
9
  export interface XHRRequest {
@@ -164,6 +165,11 @@ export declare class EditorClient {
164
165
  * @returns the given page
165
166
  */
166
167
  getPageProxy(id: string): PageProxy;
168
+ /**
169
+ * @param id ID of the item to create a proxy for
170
+ * @returns the given item
171
+ */
172
+ getItemProxy(id: string): BlockProxy | LineProxy | GroupProxy;
167
173
  /**
168
174
  * @param id ID of the element to create a proxy for
169
175
  * @returns the given element
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EditorClient = void 0;
4
- const checks_1 = require("./core/checks");
4
+ const commandtypes_1 = require("./commandtypes");
5
5
  const blockproxyregistry_1 = require("./document/blockclasses/blockproxyregistry");
6
6
  const blockproxy_1 = require("./document/blockproxy");
7
7
  const documentproxy_1 = require("./document/documentproxy");
@@ -71,13 +71,14 @@ class EditorClient {
71
71
  timeout: raw['to'],
72
72
  };
73
73
  })
74
- .catch((raw) => {
74
+ .catch((error) => {
75
+ const raw = (0, commandtypes_1.isRawSendXHRResponse)(error) ? error : undefined;
75
76
  throw {
76
- url: raw['url'],
77
- responseText: raw['t'],
78
- status: raw['s'],
79
- headers: raw['h'],
80
- timeout: raw['to'],
77
+ url: raw ? raw['url'] : '',
78
+ responseText: raw ? raw['t'] : 'An unknown error occurred',
79
+ status: raw ? raw['s'] : 0,
80
+ headers: raw ? raw['h'] : {},
81
+ timeout: raw ? raw['to'] : undefined,
81
82
  };
82
83
  });
83
84
  }
@@ -99,7 +100,8 @@ class EditorClient {
99
100
  timeout: raw['to'],
100
101
  };
101
102
  })
102
- .catch((raw) => {
103
+ .catch((error) => {
104
+ const raw = (0, commandtypes_1.isRawSendXHRResponse)(error) ? error : error;
103
105
  throw {
104
106
  url: raw['url'],
105
107
  responseText: raw['t'],
@@ -261,6 +263,23 @@ class EditorClient {
261
263
  getPageProxy(id) {
262
264
  return new pageproxy_1.PageProxy(id, this);
263
265
  }
266
+ /**
267
+ * @param id ID of the item to create a proxy for
268
+ * @returns the given item
269
+ */
270
+ getItemProxy(id) {
271
+ const type = this.sendCommand("get" /* GetElementType */, { 'id': id });
272
+ switch (type) {
273
+ case 'block':
274
+ return this.getBlockProxy(id);
275
+ case 'line':
276
+ return this.getLineProxy(id);
277
+ case 'group':
278
+ return new groupproxy_1.GroupProxy(id, this);
279
+ default:
280
+ throw new Error('Element ' + id + ' is not an Item; type found is ' + type);
281
+ }
282
+ }
264
283
  /**
265
284
  * @param id ID of the element to create a proxy for
266
285
  * @returns the given element
@@ -288,11 +307,7 @@ class EditorClient {
288
307
  listenToEditor() {
289
308
  lucid.listen((msg) => {
290
309
  var _a;
291
- const value = (_a = this.callbacks.get(msg['id'])) === null || _a === void 0 ? void 0 : _a(msg);
292
- if ((0, checks_1.isPromise)(value)) {
293
- return undefined;
294
- }
295
- return value;
310
+ return (_a = this.callbacks.get(msg['id'])) === null || _a === void 0 ? void 0 : _a(msg);
296
311
  });
297
312
  }
298
313
  }
@@ -1,9 +1,20 @@
1
1
  import { ItemProxy } from '../document/itemproxy';
2
2
  import { PageProxy } from '../document/pageproxy';
3
3
  import { EditorClient } from '../editorclient';
4
+ /**
5
+ * A text editing hook provided to [Viewport.hookTextEdit](/extension-sdk/#classes_ui_viewport-Viewport_hooktextedit)
6
+ * may return a TextEditCompletionCallback to specify what behavior should happen when the user finishes editing text.
7
+ *
8
+ * If this callback returns false, the edit is reverted.
9
+ *
10
+ * If this callback returns a string, the typed value is replaced with that string.
11
+ */
12
+ export declare type TextEditCompletionCallback = (newValue: string) => boolean | string | Promise<boolean | string>;
4
13
  export declare class Viewport {
5
14
  private readonly client;
15
+ private static nextHookId;
6
16
  constructor(client: EditorClient);
17
+ private static nextHookName;
7
18
  /**
8
19
  * @param deep If true, and groups are selected, include the contents of those groups in the array
9
20
  * @returns An array of currently-selected items on the currently-visible page
@@ -24,4 +35,38 @@ export declare class Viewport {
24
35
  * @param items The items the camera should zoom to
25
36
  */
26
37
  focusCameraOnItems(items: ItemProxy[]): void;
38
+ /**
39
+ * If `callback` returns false, text editing is prevented.
40
+ * If `callback` returns true, text editing continues as normal.
41
+ *
42
+ * If `callback` returns a [TextEditCompletionCallback](/extension-sdk/#modules_ui_viewport_texteditcompletioncallback), then text editing
43
+ * is allowed, but that completion callback is called
44
+ * when the user finishes editing that text. That completion callback may return true or false to allow or deny the edit, or
45
+ * also may return a replacement string to use instead of the text the user actually typed. If replacement text is provided,
46
+ * it will be styled as close to the original as possible, but styles that apply to only parts of the original text will be
47
+ * discarded.
48
+ *
49
+ * @param callback Called just before the user starts editing text.
50
+ *
51
+ * @returns A handle representing this hook, which can be passed to unhookTextEdit to remove this hook.
52
+ */
53
+ hookTextEdit(callback: (item: ItemProxy, textAreaKey: string) => boolean | TextEditCompletionCallback | Promise<boolean | TextEditCompletionCallback>): string;
54
+ /**
55
+ * Remove a hook set by hookTextEdit.
56
+ *
57
+ * @param handle The return value of hookTextEdit.
58
+ */
59
+ unhookTextEdit(handle: string): void;
60
+ /**
61
+ * @param callback Called when the user changes their selection of items
62
+ *
63
+ * @returns A handle representing this hook, which can be passed to unhookSelection to remove this hook.
64
+ */
65
+ hookSelection(callback: (items: ItemProxy[]) => void): string;
66
+ /**
67
+ * Remove a hook set by hookSelection.
68
+ *
69
+ * @param handle The return value of hookSelection.
70
+ */
71
+ unhookSelection(handle: string): void;
27
72
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Viewport = void 0;
4
+ const checks_1 = require("../core/checks");
4
5
  const itemproxy_1 = require("../document/itemproxy");
5
6
  const pageproxy_1 = require("../document/pageproxy");
6
7
  const math_1 = require("../math");
@@ -8,6 +9,9 @@ class Viewport {
8
9
  constructor(client) {
9
10
  this.client = client;
10
11
  }
12
+ static nextHookName() {
13
+ return '__viewport__hook' + Viewport.nextHookId++;
14
+ }
11
15
  /**
12
16
  * @param deep If true, and groups are selected, include the contents of those groups in the array
13
17
  * @returns An array of currently-selected items on the currently-visible page
@@ -47,5 +51,81 @@ class Viewport {
47
51
  });
48
52
  }
49
53
  }
54
+ /**
55
+ * If `callback` returns false, text editing is prevented.
56
+ * If `callback` returns true, text editing continues as normal.
57
+ *
58
+ * If `callback` returns a [TextEditCompletionCallback](/extension-sdk/#modules_ui_viewport_texteditcompletioncallback), then text editing
59
+ * is allowed, but that completion callback is called
60
+ * when the user finishes editing that text. That completion callback may return true or false to allow or deny the edit, or
61
+ * also may return a replacement string to use instead of the text the user actually typed. If replacement text is provided,
62
+ * it will be styled as close to the original as possible, but styles that apply to only parts of the original text will be
63
+ * discarded.
64
+ *
65
+ * @param callback Called just before the user starts editing text.
66
+ *
67
+ * @returns A handle representing this hook, which can be passed to unhookTextEdit to remove this hook.
68
+ */
69
+ hookTextEdit(callback) {
70
+ const actionName = Viewport.nextHookName();
71
+ this.client.registerAction(actionName, async (textHookParam) => {
72
+ const element = this.client.getElementProxy(textHookParam['i']);
73
+ if (element instanceof itemproxy_1.ItemProxy) {
74
+ const result = await callback(element, textHookParam['t']);
75
+ if ((0, checks_1.isBoolean)(result)) {
76
+ return result;
77
+ }
78
+ else {
79
+ const completeName = Viewport.nextHookName();
80
+ this.client.registerAction(completeName, (textCompleteParam) => {
81
+ this.client.deleteAction(completeName);
82
+ return result(textCompleteParam['v']);
83
+ });
84
+ return completeName;
85
+ }
86
+ }
87
+ else {
88
+ //Shouldn't be possible, but just in case allow text editing as normal
89
+ return true;
90
+ }
91
+ });
92
+ this.client.sendCommand("hte" /* HookTextEdit */, { 'n': actionName });
93
+ return actionName;
94
+ }
95
+ /**
96
+ * Remove a hook set by hookTextEdit.
97
+ *
98
+ * @param handle The return value of hookTextEdit.
99
+ */
100
+ unhookTextEdit(handle) {
101
+ this.client.deleteAction(handle);
102
+ this.client.sendCommand("ute" /* UnhookTextEdit */, { 'n': handle });
103
+ }
104
+ /**
105
+ * @param callback Called when the user changes their selection of items
106
+ *
107
+ * @returns A handle representing this hook, which can be passed to unhookSelection to remove this hook.
108
+ */
109
+ hookSelection(callback) {
110
+ const actionName = Viewport.nextHookName();
111
+ this.client.registerAction(actionName, async (param) => {
112
+ const elements = param['ids']
113
+ .map((id) => this.client.getElementProxy(id))
114
+ .filter((element) => element instanceof itemproxy_1.ItemProxy);
115
+ callback(elements);
116
+ });
117
+ this.client.sendCommand("hs" /* HookSelection */, { 'n': actionName });
118
+ return actionName;
119
+ }
120
+ /**
121
+ * Remove a hook set by hookSelection.
122
+ *
123
+ * @param handle The return value of hookSelection.
124
+ */
125
+ unhookSelection(handle) {
126
+ this.client.deleteAction(handle);
127
+ this.client.sendCommand("us" /* UnhookSelection */, { 'n': handle });
128
+ }
50
129
  }
51
130
  exports.Viewport = Viewport;
131
+ Viewport.nextHookId = 0;