@d3-polytree/editor 0.2.0 → 0.3.0
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/README.md +36 -0
- package/dist/editor.umd.js +6 -6
- package/dist/editor.umd.js.map +1 -1
- package/dist/index.cjs +89 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -5
- package/dist/index.d.ts +31 -5
- package/dist/index.js +89 -10
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -310,7 +310,7 @@ function fromHtml(html) {
|
|
|
310
310
|
}
|
|
311
311
|
var FORM_CONTROLS = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA", "SELECT"]);
|
|
312
312
|
var _PropertiesPanel = class _PropertiesPanel {
|
|
313
|
-
constructor(sideTabsProvider, eventBus, propertiesProvider, diagramSettings) {
|
|
313
|
+
constructor(sideTabsProvider, eventBus, propertiesProvider, diagramSettings, commandStack) {
|
|
314
314
|
this._entries = {};
|
|
315
315
|
this._container = null;
|
|
316
316
|
this._tabsEl = null;
|
|
@@ -318,9 +318,27 @@ var _PropertiesPanel = class _PropertiesPanel {
|
|
|
318
318
|
this._eventBus = eventBus;
|
|
319
319
|
this._propertiesProvider = propertiesProvider;
|
|
320
320
|
this._diagramSettings = diagramSettings;
|
|
321
|
+
this._commandStack = commandStack;
|
|
322
|
+
this._registerUpdatePropertiesCommand();
|
|
321
323
|
this._registerSideTab(sideTabsProvider);
|
|
322
324
|
this._registerSelectionListener();
|
|
323
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* Register the `element.updateProperties` command. Its apply logic is
|
|
328
|
+
* editor-specific (a property `scope` plus the provider's drawing update), so
|
|
329
|
+
* the panel — which owns both — registers it on the shared stack rather than
|
|
330
|
+
* the core modelling orchestrator.
|
|
331
|
+
*/
|
|
332
|
+
_registerUpdatePropertiesCommand() {
|
|
333
|
+
const apply = (ctx, props) => {
|
|
334
|
+
ctx.scope.set(ctx.definition, props);
|
|
335
|
+
this._propertiesProvider.updateDrawing(ctx.definition);
|
|
336
|
+
};
|
|
337
|
+
this._commandStack.registerHandler("element.updateProperties", {
|
|
338
|
+
execute: (ctx) => apply(ctx, ctx.after),
|
|
339
|
+
revert: (ctx) => apply(ctx, ctx.before)
|
|
340
|
+
});
|
|
341
|
+
}
|
|
324
342
|
_registerSideTab(provider) {
|
|
325
343
|
provider.registerSideTab(
|
|
326
344
|
{
|
|
@@ -402,10 +420,16 @@ var _PropertiesPanel = class _PropertiesPanel {
|
|
|
402
420
|
if (!entry) {
|
|
403
421
|
return;
|
|
404
422
|
}
|
|
405
|
-
const
|
|
406
|
-
deepSet(
|
|
407
|
-
|
|
408
|
-
|
|
423
|
+
const after = {};
|
|
424
|
+
deepSet(after, entryId, newValue);
|
|
425
|
+
const before = {};
|
|
426
|
+
deepSet(before, entryId, deepGet(entry.definition, entryId));
|
|
427
|
+
this._commandStack.execute("element.updateProperties", {
|
|
428
|
+
scope: entry.scope,
|
|
429
|
+
definition: entry.definition,
|
|
430
|
+
before,
|
|
431
|
+
after
|
|
432
|
+
});
|
|
409
433
|
}
|
|
410
434
|
_selectTab(tabId) {
|
|
411
435
|
this._tabsEl?.querySelectorAll(".tab-sheet").forEach((tab) => {
|
|
@@ -471,7 +495,8 @@ _PropertiesPanel.$inject = [
|
|
|
471
495
|
"sideTabsProvider",
|
|
472
496
|
"eventBus",
|
|
473
497
|
"propertiesProvider",
|
|
474
|
-
"d3polytree.definitions.settings"
|
|
498
|
+
"d3polytree.definitions.settings",
|
|
499
|
+
"commandStack"
|
|
475
500
|
];
|
|
476
501
|
_PropertiesPanel.HTML_MARKUP = '<div id="pfdjs-pp-container"><div class="pfdjs-pp-tabs"><ul class="tab-sheets"></ul></div><div class="pfdjs-pp-contents"></div></div>';
|
|
477
502
|
var PropertiesPanel = _PropertiesPanel;
|
|
@@ -485,10 +510,41 @@ var propertiesPanelModule = {
|
|
|
485
510
|
// src/index.ts
|
|
486
511
|
var INITIAL_DIAGRAM = '<?xml version="1.0" encoding="UTF-8"?><pfdn:diagram xmlns:pfdn="http://pfdn" xmlns="http://pfdn"><settings author="No Author" name="No Name Diagram" status="1"><zoom><offset x="0" y="0" /><scale>1</scale></zoom><grid /></settings><node id="node_1" label="label_1" status="1"><position x="20" y="100" /></node><label id="label_1" fontSize="12" isReadOnly="true" status="1"><position x="33" y="140" /><text>Node 1</text></label></pfdn:diagram>';
|
|
487
512
|
var _Editor = class _Editor extends import_interactive_viewer.InteractiveViewer {
|
|
488
|
-
constructor() {
|
|
489
|
-
super(
|
|
513
|
+
constructor(options = {}) {
|
|
514
|
+
super(options);
|
|
490
515
|
/** The document a fresh editor opens with (used by {@link createDiagram}). */
|
|
491
516
|
this.initialDiagram = INITIAL_DIAGRAM;
|
|
517
|
+
this._onKeydown = (event) => this._handleKeydown(event);
|
|
518
|
+
options.container?.addEventListener("keydown", this._onKeydown);
|
|
519
|
+
}
|
|
520
|
+
_handleKeydown(event) {
|
|
521
|
+
const target = event.target;
|
|
522
|
+
if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA")) {
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
if (!this.getHost()) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const mod = event.ctrlKey || event.metaKey;
|
|
529
|
+
if (!mod) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
const key = event.key.toLowerCase();
|
|
533
|
+
if (key === "z" && event.shiftKey) {
|
|
534
|
+
event.preventDefault();
|
|
535
|
+
this.redo();
|
|
536
|
+
} else if (key === "z") {
|
|
537
|
+
event.preventDefault();
|
|
538
|
+
this.undo();
|
|
539
|
+
} else if (key === "y") {
|
|
540
|
+
event.preventDefault();
|
|
541
|
+
this.redo();
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
/** Tear down the editor, removing the keyboard binding. */
|
|
545
|
+
destroy() {
|
|
546
|
+
this.options.container?.removeEventListener("keydown", this._onKeydown);
|
|
547
|
+
super.destroy();
|
|
492
548
|
}
|
|
493
549
|
/** (Re)open the initial diagram. */
|
|
494
550
|
createDiagram() {
|
|
@@ -501,9 +557,16 @@ var _Editor = class _Editor extends import_interactive_viewer.InteractiveViewer
|
|
|
501
557
|
...import_viewer.Viewer.modules
|
|
502
558
|
];
|
|
503
559
|
}
|
|
504
|
-
/**
|
|
560
|
+
/**
|
|
561
|
+
* Create a node (and its associated label) at an optional position.
|
|
562
|
+
*
|
|
563
|
+
* Routed through the command stack so it persists and is undoable (since B10
|
|
564
|
+
* the draw-layer `.created` event no longer persists on its own).
|
|
565
|
+
*/
|
|
505
566
|
createNode(parameters = {}) {
|
|
506
|
-
|
|
567
|
+
const ctx = { className: "node", parameters: [parameters] };
|
|
568
|
+
this.get("commandStack").execute("element.create", ctx);
|
|
569
|
+
return ctx.created;
|
|
507
570
|
}
|
|
508
571
|
/** Select an element by definition (e.g. to prepare a delete). */
|
|
509
572
|
select(definition) {
|
|
@@ -516,6 +579,22 @@ var _Editor = class _Editor extends import_interactive_viewer.InteractiveViewer
|
|
|
516
579
|
deleteSelected() {
|
|
517
580
|
this.get("selection").deleteSelected();
|
|
518
581
|
}
|
|
582
|
+
/** Undo the last edit (a whole gesture is one step). No-op if nothing to undo. */
|
|
583
|
+
undo() {
|
|
584
|
+
this.get("commandStack").undo();
|
|
585
|
+
}
|
|
586
|
+
/** Redo the last undone edit. No-op if nothing to redo. */
|
|
587
|
+
redo() {
|
|
588
|
+
this.get("commandStack").redo();
|
|
589
|
+
}
|
|
590
|
+
/** Whether there is an edit to undo. */
|
|
591
|
+
canUndo() {
|
|
592
|
+
return this.get("commandStack").canUndo();
|
|
593
|
+
}
|
|
594
|
+
/** Whether there is an undone edit to redo. */
|
|
595
|
+
canRedo() {
|
|
596
|
+
return this.get("commandStack").canRedo();
|
|
597
|
+
}
|
|
519
598
|
};
|
|
520
599
|
/** Editing modules on top of the interaction layer. */
|
|
521
600
|
_Editor.editionModules = [
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/properties-panel/utils.ts","../src/properties-panel/EntryFactory.ts","../src/properties-panel/PfdnPropertiesProvider.ts","../src/properties-panel/PropertiesPanel.ts","../src/properties-panel/index.ts"],"sourcesContent":["/**\n * @d3-polytree/editor — create and modify polytree diagrams.\n *\n * Extends the {@link InteractiveViewer} with the editing layer: element\n * dragging plus the modelling create/save/delete flows. Element creation is\n * exposed programmatically here; the palette toolbar UI is layered on next.\n */\nimport { InteractiveViewer, type InteractiveViewerOptions } from '@d3-polytree/interactive-viewer';\nimport { Viewer } from '@d3-polytree/viewer';\nimport {\n dragModule,\n modellingModule,\n exportingModule,\n localStorageModule,\n uploadModule,\n paletteModule,\n resizeElementModule,\n type DiagramModule,\n type DrawingRegistry,\n type ModellingNodes,\n type ModellingModelElement,\n type CreateParameters,\n type Selection\n} from '@d3-polytree/core';\n// The properties panel used to be its own package; it is now folded in here\n// (the editor was its only consumer) and re-exported below.\nimport {\n entryFactoryModule,\n pfdnPropertiesProviderModule,\n propertiesPanelModule\n} from './properties-panel';\n\nexport * from './properties-panel';\n\n/** The document a fresh editor opens with. */\nconst INITIAL_DIAGRAM =\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' +\n '<pfdn:diagram xmlns:pfdn=\"http://pfdn\" xmlns=\"http://pfdn\">' +\n '<settings author=\"No Author\" name=\"No Name Diagram\" status=\"1\">' +\n '<zoom><offset x=\"0\" y=\"0\" /><scale>1</scale></zoom><grid />' +\n '</settings>' +\n '<node id=\"node_1\" label=\"label_1\" status=\"1\"><position x=\"20\" y=\"100\" /></node>' +\n '<label id=\"label_1\" fontSize=\"12\" isReadOnly=\"true\" status=\"1\">' +\n '<position x=\"33\" y=\"140\" /><text>Node 1</text></label>' +\n '</pfdn:diagram>';\n\nexport type EditorOptions = InteractiveViewerOptions;\n\nexport class Editor extends InteractiveViewer {\n /** Editing modules on top of the interaction layer. */\n static readonly editionModules: readonly DiagramModule[] = [\n dragModule as DiagramModule,\n modellingModule as DiagramModule,\n exportingModule as DiagramModule,\n localStorageModule as DiagramModule,\n uploadModule as DiagramModule,\n paletteModule as DiagramModule,\n resizeElementModule as DiagramModule,\n // the properties panel (registers a side tab; side-tabs + search-panel are\n // inherited from InteractiveViewer)\n entryFactoryModule as DiagramModule,\n pfdnPropertiesProviderModule as DiagramModule,\n propertiesPanelModule as DiagramModule\n ];\n\n /** The document a fresh editor opens with (used by {@link createDiagram}). */\n initialDiagram = INITIAL_DIAGRAM;\n\n /** (Re)open the initial diagram. */\n createDiagram(): Promise<void> {\n return this.importDiagram(this.initialDiagram);\n }\n\n getModules(): readonly DiagramModule[] {\n // interaction + editing features first (they subscribe / swap the layer),\n // then the drawers\n return [\n ...InteractiveViewer.interactionModules,\n ...Editor.editionModules,\n ...Viewer.modules\n ];\n }\n\n /** Create a node (and its associated label) at an optional position. */\n createNode(parameters: CreateParameters = {}): ModellingModelElement {\n return this.get<ModellingNodes>('modellingNodes').create(parameters);\n }\n\n /** Select an element by definition (e.g. to prepare a delete). */\n select(definition: ModellingModelElement): void {\n const element = this.get<DrawingRegistry>('drawingRegistry').get(definition.id as string);\n if (element) {\n this.get<Selection>('selection').select(element, definition);\n }\n }\n\n /** Delete the current selection (cascading to associated labels). */\n deleteSelected(): void {\n this.get<Selection>('selection').deleteSelected();\n }\n}\n\nexport default Editor;\n","/** A moddle model element as read/written by the properties panel. */\nexport interface Definition {\n id?: string;\n label?: Definition;\n $instanceOf(type: string): boolean;\n get(property: string): unknown;\n [key: string]: unknown;\n}\n\n/** `definition.$instanceOf(elementType)` — ported from `utils/modelUtils`. */\nexport function is(definition: Definition, elementType: string): boolean {\n return definition.$instanceOf(elementType);\n}\n\n/** Read a dotted property path (`label.text`) by plain property access. */\nexport function deepGet(obj: unknown, path: string): unknown {\n return path\n .split('.')\n .reduce<unknown>(\n (o, k) => (o == null ? undefined : (o as Record<string, unknown>)[k]),\n obj\n );\n}\n\n/** Write a dotted property path, creating intermediate objects as needed. */\nexport function deepSet(obj: Record<string, unknown>, path: string, value: unknown): void {\n const keys = path.split('.');\n let cursor = obj;\n for (let i = 0; i < keys.length - 1; i += 1) {\n const key = keys[i];\n if (cursor[key] == null || typeof cursor[key] !== 'object') {\n cursor[key] = {};\n }\n cursor = cursor[key] as Record<string, unknown>;\n }\n cursor[keys[keys.length - 1]] = value;\n}\n\n/** Trailing-nothing leading-edge? No — trailing debounce, like lodash's default. */\nexport function debounce<A extends unknown[]>(\n fn: (...args: A) => void,\n wait: number\n): (...args: A) => void {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: A) => {\n if (timer) {\n clearTimeout(timer);\n }\n timer = setTimeout(() => fn(...args), wait);\n };\n}\n\n/** Title-case a token (`lineColor` → `Line Color`, `aws-ec2` → `Aws Ec 2`). */\nexport function startCase(input: string): string {\n return input\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/([a-zA-Z])([0-9])/g, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\n/** Whether a string is a `#rrggbb` colour (accepted by `<input type=color>`). */\nexport function isHexColor(value: unknown): value is string {\n return typeof value === 'string' && /^#[0-9a-fA-F]{6}$/.test(value);\n}\n","import type EventEmitter from 'eventemitter3';\nimport { deepGet, deepSet, isHexColor, type Definition } from './utils';\n\n/** A `{name,value}` option for a select entry. */\nexport interface SelectOption {\n name: string;\n value: string;\n}\n\n/** Options accepted when building an entry. */\nexport interface EntryOptions {\n id: string;\n modelProperty: string;\n label?: string;\n description?: string;\n type?: string;\n allowEmpty?: boolean;\n selectOptions?: SelectOption[];\n}\n\n/** A rendered property entry: its markup plus get/set behaviour. */\nexport interface EntryResource extends EntryOptions {\n html: string;\n get: (element: Definition, formNode: HTMLElement) => void;\n set: (element: Definition, values: Record<string, unknown>) => boolean;\n validate: () => Record<string, unknown>;\n triggerUpdate: (propertyId: string, element: Definition) => void;\n}\n\nfunction ensureNotNull(prop: string | undefined): string {\n if (!prop) {\n throw new Error(`${prop} must be set.`);\n }\n return prop;\n}\n\n/**\n * Builds property-panel entries (text / select / colour / spreadsheet). Ported\n * from `@d3-polytree/properties-panel`'s `entryFactory/*`, de-jQuery-ed onto\n * native DOM; the colour entry uses a native `<input type=\"color\">` in place of\n * spectrum-colorpicker.\n */\nexport class EntryFactory {\n static readonly $inject = ['eventBus'];\n\n private readonly _eventBus: EventEmitter;\n\n constructor(eventBus: EventEmitter) {\n this._eventBus = eventBus;\n }\n\n setDefaultParameters(options: EntryOptions): EntryResource {\n const eventBus = this._eventBus;\n\n const defaultGet = (element: Definition, formNode: HTMLElement): void => {\n const prop = ensureNotNull(options.modelProperty);\n const value = deepGet(element, prop);\n const input = formNode.querySelector('input');\n if (input) {\n (input as HTMLInputElement).value = value == null ? '' : String(value);\n }\n };\n\n const defaultSet = (element: Definition, values: Record<string, unknown>): boolean => {\n const prop = ensureNotNull(options.modelProperty);\n deepSet(element as unknown as Record<string, unknown>, prop, deepGet(values, prop));\n return true;\n };\n\n const triggerUpdate = (propertyId: string, element: Definition): void => {\n eventBus.emit('PropertiesPanel.propertyChanged', propertyId, element);\n };\n\n return {\n html: '',\n description: '',\n get: defaultGet,\n set: defaultSet,\n validate: () => ({}),\n ...options,\n triggerUpdate\n };\n }\n\n textField(options: EntryOptions): EntryResource {\n return textInputField(this.setDefaultParameters(options));\n }\n\n selectBox(options: EntryOptions): EntryResource {\n return selectBoxField(this.setDefaultParameters(options));\n }\n\n colorPicker(options: EntryOptions): EntryResource {\n return colorPickerField(this.setDefaultParameters(options));\n }\n\n spreadsheet(options: EntryOptions): EntryResource {\n // Placeholder in the source engine; kept as an API-compatible no-op.\n return this.setDefaultParameters(options);\n }\n}\n\nfunction fieldWrapper(resource: EntryResource, inner: string): string {\n const label = resource.label ?? resource.id;\n return (\n `<div class=\"pfdjs-pp-field-wrapper\">` +\n `<label for=\"pfdjs-${resource.id}\">${label}</label>${inner}</div>`\n );\n}\n\nfunction textInputField(resource: EntryResource): EntryResource {\n const type = resource.type ?? 'text';\n resource.html = fieldWrapper(\n resource,\n `<input id=\"pfdjs-${resource.id}\" type=\"${type}\" name=\"${resource.modelProperty}\" />`\n );\n return resource;\n}\n\nfunction selectBoxField(resource: EntryResource): EntryResource {\n const allowEmpty = resource.allowEmpty ?? true;\n const options = Array.isArray(resource.selectOptions)\n ? resource.selectOptions.concat(allowEmpty ? [{ name: '', value: '' }] : [])\n : [{ name: '', value: '' }];\n\n const optionsHtml = options\n .map((o) => `<option value=\"${o.value}\">${o.name}</option>`)\n .join('');\n resource.html = fieldWrapper(\n resource,\n `<select id=\"pfdjs-${resource.id}\" name=\"${resource.modelProperty}\">${optionsHtml}</select>`\n );\n\n resource.get = (element, formNode) => {\n const value = element.get(resource.modelProperty) ?? 'default';\n formNode\n .querySelectorAll<HTMLOptionElement>(`select#pfdjs-${resource.id} > option`)\n .forEach((option) => {\n option.selected = option.value === value;\n });\n };\n\n return resource;\n}\n\nfunction colorPickerField(resource: EntryResource): EntryResource {\n resource.html = fieldWrapper(\n resource,\n `<input id=\"pfdjs-${resource.id}\" type=\"color\" name=\"${resource.modelProperty}\" />`\n );\n resource.get = (element, formNode) => {\n const input = formNode.querySelector<HTMLInputElement>('input[type=color]');\n const value = deepGet(element, resource.modelProperty);\n if (input && isHexColor(value)) {\n input.value = value;\n }\n };\n return resource;\n}\n\n/** didi module contributing the entry factory. */\nexport const entryFactoryModule = {\n __init__: ['entryFactory'],\n entryFactory: ['type', EntryFactory]\n};\n","import type EventEmitter from 'eventemitter3';\nimport type { EntryFactory, EntryResource } from './EntryFactory';\nimport { is, startCase, type Definition } from './utils';\n\n/** A group of entries within a tab. */\nexport interface PropertiesGroup {\n id: string;\n label: string;\n entries: EntryResource[];\n}\n\n/** A properties-panel tab. */\nexport interface PropertiesTab {\n id: string;\n label: string;\n groups: PropertiesGroup[];\n}\n\n/** Icon registry token: icon type → SVG source. */\nexport type IconMap = Record<string, string>;\n\n/** A properties provider: supplies the tabs for a selected element. */\nexport interface PropertiesProvider {\n getTabs(element: Definition): PropertiesTab[];\n updateDrawing(definition: Definition): void;\n}\n\n// --- pfdn property parts (ported from provider/pfdn/tabs/parts/*) ------------\n\nfunction nameProps(group: PropertiesGroup, element: Definition, factory: EntryFactory): void {\n if (is(element, 'pfdn:Node')) {\n group.entries.push(factory.textField({ id: 'name', label: 'Name', modelProperty: 'name' }));\n group.entries.push(factory.textField({ id: 'tag', label: 'Tag', modelProperty: 'tag' }));\n group.entries.push(\n factory.textField({ id: 'label.text', label: 'Diagram label', modelProperty: 'label.text' })\n );\n } else if (is(element, 'pfdn:Settings')) {\n group.entries.push(factory.textField({ id: 'name', label: 'Diagram name', modelProperty: 'name' }));\n group.entries.push(factory.textField({ id: 'author', label: \"Author's name\", modelProperty: 'author' }));\n } else if (is(element, 'pfdn:Link')) {\n group.entries.push(\n factory.textField({ id: 'label.text', label: 'Diagram label', modelProperty: 'label.text' })\n );\n } else if (is(element, 'pfdn:Label')) {\n group.entries.push(factory.textField({ id: 'text', label: 'Label', modelProperty: 'text' }));\n }\n}\n\nfunction nodeFormatProps(\n group: PropertiesGroup,\n element: Definition,\n factory: EntryFactory,\n icons: IconMap\n): void {\n if (!is(element, 'pfdn:Node')) {\n return;\n }\n const selectOptions = Object.keys(icons).map((key) => ({ value: key, name: startCase(key) }));\n group.entries.push(\n factory.selectBox({\n id: 'type',\n label: 'Icon',\n modelProperty: 'type',\n allowEmpty: false,\n selectOptions\n })\n );\n group.entries.push(\n factory.textField({ id: 'size', label: 'Size', modelProperty: 'size', type: 'number' })\n );\n}\n\nfunction linkFormatProps(group: PropertiesGroup, element: Definition, factory: EntryFactory): void {\n if (!is(element, 'pfdn:Link')) {\n return;\n }\n group.entries.push(\n factory.textField({ id: 'lineWidth', label: 'Line width', modelProperty: 'lineWidth', type: 'number' })\n );\n group.entries.push(\n factory.colorPicker({ id: 'lineColor', label: 'Line color', modelProperty: 'lineColor' })\n );\n}\n\nfunction labelFormatProps(group: PropertiesGroup, element: Definition, factory: EntryFactory): void {\n if (is(element, 'pfdn:Node') || is(element, 'pfdn:Link')) {\n group.entries.push(\n factory.textField({\n id: 'label.fontSize',\n label: 'Font size',\n modelProperty: 'label.fontSize',\n type: 'number'\n })\n );\n group.entries.push(\n factory.colorPicker({ id: 'label.color', label: 'Color', modelProperty: 'label.color' })\n );\n } else if (is(element, 'pfdn:Label')) {\n group.entries.push(\n factory.textField({ id: 'fontSize', label: 'Font size', modelProperty: 'fontSize', type: 'number' })\n );\n group.entries.push(factory.colorPicker({ id: 'color', label: 'Color', modelProperty: 'color' }));\n }\n}\n\nfunction gridFormatProps(group: PropertiesGroup, element: Definition, factory: EntryFactory): void {\n if (!is(element, 'pfdn:Settings')) {\n return;\n }\n group.entries.push(\n factory.colorPicker({ id: 'backgroundColor', label: 'Background color', modelProperty: 'backgroundColor' })\n );\n group.entries.push(\n factory.colorPicker({ id: 'grid.lineColor', label: 'Line color', modelProperty: 'grid.lineColor' })\n );\n group.entries.push(\n factory.textField({ id: 'grid.size', label: 'Square size', modelProperty: 'grid.size', type: 'number' })\n );\n group.entries.push(\n factory.textField({ id: 'grid.lineWidth', label: 'Line width', modelProperty: 'grid.lineWidth', type: 'number' })\n );\n}\n\n/**\n * The PFDN properties provider: builds the Properties + Format tabs for the\n * selected element, and applies edits back to the drawing. Ported from\n * `provider/pfdn/*`.\n */\nexport class PfdnPropertiesProvider implements PropertiesProvider {\n static readonly $inject = ['icons', 'entryFactory', 'eventBus'];\n\n private readonly _icons: IconMap;\n private readonly _entryFactory: EntryFactory;\n private readonly _eventBus: EventEmitter;\n\n constructor(icons: IconMap, entryFactory: EntryFactory, eventBus: EventEmitter) {\n this._icons = icons;\n this._entryFactory = entryFactory;\n this._eventBus = eventBus;\n }\n\n updateDrawing(definition: Definition): void {\n if (is(definition, 'pfdn:Settings')) {\n this._eventBus.emit('canvas.resized');\n return;\n }\n this._eventBus.emit('element.updated', definition.id, definition);\n if (is(definition, 'pfdn:Link') || is(definition, 'pfdn:Node')) {\n const label = definition.label;\n if (label) {\n this._eventBus.emit('element.updated', label.id, label);\n }\n }\n }\n\n getTabs(element: Definition): PropertiesTab[] {\n const factory = this._entryFactory;\n return [this._propertiesTab(element, factory), this._formatTab(element, factory)];\n }\n\n private _propertiesTab(element: Definition, factory: EntryFactory): PropertiesTab {\n const general: PropertiesGroup = { id: 'general', label: 'General', entries: [] };\n nameProps(general, element, factory);\n return { id: 'properties', label: 'Properties', groups: [general] };\n }\n\n private _formatTab(element: Definition, factory: EntryFactory): PropertiesTab {\n const elementFormat: PropertiesGroup = { id: 'elementFormat', label: 'Element format', entries: [] };\n const labelFormat: PropertiesGroup = { id: 'labelFormat', label: 'Label format', entries: [] };\n const gridFormat: PropertiesGroup = { id: 'gridFormat', label: 'Grid format', entries: [] };\n\n nodeFormatProps(elementFormat, element, factory, this._icons);\n linkFormatProps(elementFormat, element, factory);\n labelFormatProps(labelFormat, element, factory);\n gridFormatProps(gridFormat, element, factory);\n\n return { id: 'format', label: 'Format', groups: [elementFormat, labelFormat, gridFormat] };\n }\n}\n\n/** didi module contributing the PFDN properties provider. */\nexport const pfdnPropertiesProviderModule = {\n __init__: ['propertiesProvider'],\n propertiesProvider: ['type', PfdnPropertiesProvider]\n};\n","import type EventEmitter from 'eventemitter3';\nimport type { EntryResource } from './EntryFactory';\nimport type { PropertiesProvider } from './PfdnPropertiesProvider';\nimport { debounce, deepGet, deepSet, type Definition } from './utils';\n\n/** The side-tab registration surface the panel needs (structural). */\nexport interface SideTabRegistration {\n title?: string;\n iconClassName?: string;\n action: {\n created?: (content: HTMLElement | null) => void;\n [gesture: string]: ((content: HTMLElement | null) => void) | undefined;\n };\n}\nexport interface SideTabsRegistrar {\n registerSideTab(tab: SideTabRegistration, index?: number): void;\n}\n\n/** A selection entry as delivered by the core `selection.changed` event. */\ninterface SelectionEntry {\n definition: Definition;\n}\n\ninterface TrackedEntry {\n scope: EntryResource;\n definition: Definition;\n formNode: HTMLElement;\n}\n\n/** Parse an HTML fragment into its first element. */\nfunction fromHtml(html: string): HTMLElement {\n const template = document.createElement('template');\n template.innerHTML = html.trim();\n return template.content.firstElementChild as HTMLElement;\n}\n\nconst FORM_CONTROLS = new Set(['INPUT', 'TEXTAREA', 'SELECT']);\n\n/**\n * The editor properties panel: a tabbed editor for the selected element's\n * model properties. Ported from `@d3-polytree/properties-panel`'s\n * `PropertiesPanel.js`, de-jQuery-ed onto native DOM; the `scroll-tabs` widget\n * is replaced by native click-to-select tabs.\n */\nexport class PropertiesPanel {\n static readonly $inject = [\n 'sideTabsProvider',\n 'eventBus',\n 'propertiesProvider',\n 'd3polytree.definitions.settings'\n ];\n\n private readonly _eventBus: EventEmitter;\n private readonly _propertiesProvider: PropertiesProvider;\n private readonly _diagramSettings: Definition;\n private _entries: Record<string, TrackedEntry> = {};\n\n private _container: HTMLElement | null = null;\n private _tabsEl: HTMLElement | null = null;\n private _contentsEl: HTMLElement | null = null;\n\n constructor(\n sideTabsProvider: SideTabsRegistrar,\n eventBus: EventEmitter,\n propertiesProvider: PropertiesProvider,\n diagramSettings: Definition\n ) {\n this._eventBus = eventBus;\n this._propertiesProvider = propertiesProvider;\n this._diagramSettings = diagramSettings;\n this._registerSideTab(sideTabsProvider);\n this._registerSelectionListener();\n }\n\n private _registerSideTab(provider: SideTabsRegistrar): void {\n provider.registerSideTab(\n {\n title: 'Properties',\n iconClassName: 'icon-sliders',\n action: { created: (content) => this._drawPanel(content) }\n },\n 1\n );\n }\n\n private _registerSelectionListener(): void {\n this._eventBus.on(\n 'selection.changed',\n (oldSelection: SelectionEntry[], newSelection: SelectionEntry[]) => {\n let selected: Definition = this._diagramSettings;\n if (\n newSelection.length === 1 &&\n (oldSelection.length !== 1 ||\n oldSelection[0].definition.id !== newSelection[0].definition.id)\n ) {\n selected = newSelection[0].definition;\n }\n this._update(selected);\n }\n );\n }\n\n private _drawPanel(content: HTMLElement | null): void {\n if (!content) {\n return;\n }\n this._drawContainer(content);\n this._update(this._diagramSettings);\n }\n\n private _drawContainer(content: HTMLElement): void {\n this._container = fromHtml(PropertiesPanel.HTML_MARKUP);\n content.insertBefore(this._container, content.firstChild);\n this._tabsEl = this._container.querySelector('.tab-sheets');\n this._contentsEl = this._container.querySelector('.pfdjs-pp-contents');\n\n this._container.addEventListener('click', (event) => {\n const tab = (event.target as Element).closest<HTMLElement>('.tab-sheet');\n if (tab) {\n this._selectTab(tab.getAttribute('data-tab-target'));\n event.stopImmediatePropagation();\n }\n });\n this._registerInputChangeHandlers();\n }\n\n private _registerInputChangeHandlers(): void {\n const container = this._container;\n if (!container) {\n return;\n }\n // debounce keystroke updates on text inputs/areas; selects fire on change.\n const debouncedApply = debounce((target: HTMLElement) => this._applyChange(target), 300);\n container.addEventListener('input', (event) => {\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n debouncedApply(target);\n }\n });\n container.addEventListener('change', (event) => {\n const target = event.target as HTMLElement;\n if (FORM_CONTROLS.has(target.tagName)) {\n this._applyChange(target);\n }\n });\n this._eventBus.on(\n 'PropertiesPanel.propertyChanged',\n (propertyId: string, definition: Definition) => this._applyChangeByProperty(propertyId, definition)\n );\n }\n\n private _applyChange(target: HTMLElement): void {\n const entryId = target.getAttribute('name');\n if (!entryId) {\n return;\n }\n this._commit(entryId, (target as HTMLInputElement).value);\n }\n\n private _applyChangeByProperty(propertyId: string, definition: Definition): void {\n this._commit(propertyId, deepGet(definition, propertyId));\n }\n\n private _commit(entryId: string, newValue: unknown): void {\n const entry = this._entries[entryId];\n if (!entry) {\n return;\n }\n const props: Record<string, unknown> = {};\n deepSet(props, entryId, newValue);\n entry.scope.set(entry.definition, props);\n this._propertiesProvider.updateDrawing(entry.definition);\n }\n\n private _selectTab(tabId: string | null): void {\n this._tabsEl?.querySelectorAll<HTMLElement>('.tab-sheet').forEach((tab) => {\n tab.classList.toggle('tab-sheet-active', tab.getAttribute('data-tab-target') === tabId);\n });\n this._contentsEl?.querySelectorAll<HTMLElement>('.pfdjs-pp-content').forEach((content) => {\n content.classList.toggle('open', content.getAttribute('data-tab-target') === tabId);\n });\n }\n\n private _update(definition: Definition | undefined): void {\n if (this._tabsEl && this._contentsEl) {\n this._tabsEl.replaceChildren();\n this._contentsEl.replaceChildren();\n }\n if (definition) {\n this._drawEntries(definition);\n }\n }\n\n private _drawEntries(definition: Definition): void {\n if (!this._tabsEl || !this._contentsEl) {\n return;\n }\n const tabs = this._propertiesProvider.getTabs(definition);\n const renderedTabs: { id: string; label: string }[] = [];\n this._entries = {};\n\n for (const tab of tabs) {\n const content = fromHtml(`<div class=\"pfdjs-pp-content\" data-tab-target=\"${tab.id}\"></div>`);\n let tabHasContent = false;\n\n for (const group of tab.groups) {\n if (group.entries.length === 0) {\n continue;\n }\n const groupContent = fromHtml(\n `<div class=\"pfdjs-pp-content-group\" data-group-target=\"${group.id}\">` +\n `<div class=\"tab-content-group-title\">${group.label}</div></div>`\n );\n for (const entry of group.entries) {\n const entryNode = fromHtml(`<div>${entry.html}</div>`);\n groupContent.appendChild(entryNode);\n this._entries[entry.id] = { scope: entry, definition, formNode: entryNode };\n }\n content.appendChild(groupContent);\n tabHasContent = true;\n }\n\n if (tabHasContent) {\n this._contentsEl.appendChild(content);\n renderedTabs.push({ id: tab.id, label: tab.label });\n }\n }\n\n // populate each entry from the model\n Object.values(this._entries).forEach((entry) => entry.scope.get(entry.definition, entry.formNode));\n\n // draw the tab strip\n let firstTab: string | null = null;\n for (const tab of renderedTabs) {\n firstTab ??= tab.id;\n this._tabsEl.appendChild(\n fromHtml(\n `<li class=\"tab-sheet\" data-tab-target=\"${tab.id}\"><a href=\"#\">${tab.label}</a></li>`\n )\n );\n }\n this._selectTab(firstTab);\n }\n\n static readonly HTML_MARKUP =\n '<div id=\"pfdjs-pp-container\">' +\n '<div class=\"pfdjs-pp-tabs\"><ul class=\"tab-sheets\"></ul></div>' +\n '<div class=\"pfdjs-pp-contents\"></div>' +\n '</div>';\n}\n","/**\n * @d3-polytree/properties-panel — the editor's element-properties panel.\n *\n * Modernised (B6) from the 2017 jQuery/spectrum/scroll-tabs source to TypeScript\n * + ESM with native DOM: jQuery is gone, the colour entry uses a native\n * `<input type=\"color\">`, and the `scroll-tabs` widget is replaced by native\n * click-to-select tabs. Ships three didi modules (entry factory, PFDN provider,\n * panel) for the editor to compose.\n */\nexport { EntryFactory, entryFactoryModule } from './EntryFactory';\nexport type { EntryOptions, EntryResource, SelectOption } from './EntryFactory';\nexport {\n PfdnPropertiesProvider,\n pfdnPropertiesProviderModule\n} from './PfdnPropertiesProvider';\nexport type {\n IconMap,\n PropertiesGroup,\n PropertiesProvider,\n PropertiesTab\n} from './PfdnPropertiesProvider';\nexport { PropertiesPanel } from './PropertiesPanel';\nexport type { SideTabRegistration, SideTabsRegistrar } from './PropertiesPanel';\nexport type { Definition } from './utils';\n\nimport { PropertiesPanel } from './PropertiesPanel';\n\n/** didi module contributing the properties panel (composes with the provider). */\nexport const propertiesPanelModule = {\n __init__: ['propertiesPanel'],\n propertiesPanel: ['type', PropertiesPanel]\n};\n\nexport default propertiesPanelModule;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/properties-panel/utils.ts","../src/properties-panel/EntryFactory.ts","../src/properties-panel/PfdnPropertiesProvider.ts","../src/properties-panel/PropertiesPanel.ts","../src/properties-panel/index.ts"],"sourcesContent":["/**\n * @d3-polytree/editor — create and modify polytree diagrams.\n *\n * Extends the {@link InteractiveViewer} with the editing layer: element\n * dragging plus the modelling create/save/delete flows. Element creation is\n * exposed programmatically here; the palette toolbar UI is layered on next.\n */\nimport { InteractiveViewer, type InteractiveViewerOptions } from '@d3-polytree/interactive-viewer';\nimport { Viewer } from '@d3-polytree/viewer';\nimport {\n dragModule,\n modellingModule,\n exportingModule,\n localStorageModule,\n uploadModule,\n paletteModule,\n resizeElementModule,\n type DiagramModule,\n type DrawingRegistry,\n type ModellingModelElement,\n type CreateParameters,\n type CommandStack,\n type CreateContext,\n type Selection\n} from '@d3-polytree/core';\n// The properties panel used to be its own package; it is now folded in here\n// (the editor was its only consumer) and re-exported below.\nimport {\n entryFactoryModule,\n pfdnPropertiesProviderModule,\n propertiesPanelModule\n} from './properties-panel';\n\nexport * from './properties-panel';\n\n/** The document a fresh editor opens with. */\nconst INITIAL_DIAGRAM =\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' +\n '<pfdn:diagram xmlns:pfdn=\"http://pfdn\" xmlns=\"http://pfdn\">' +\n '<settings author=\"No Author\" name=\"No Name Diagram\" status=\"1\">' +\n '<zoom><offset x=\"0\" y=\"0\" /><scale>1</scale></zoom><grid />' +\n '</settings>' +\n '<node id=\"node_1\" label=\"label_1\" status=\"1\"><position x=\"20\" y=\"100\" /></node>' +\n '<label id=\"label_1\" fontSize=\"12\" isReadOnly=\"true\" status=\"1\">' +\n '<position x=\"33\" y=\"140\" /><text>Node 1</text></label>' +\n '</pfdn:diagram>';\n\nexport type EditorOptions = InteractiveViewerOptions;\n\nexport class Editor extends InteractiveViewer {\n /** Editing modules on top of the interaction layer. */\n static readonly editionModules: readonly DiagramModule[] = [\n dragModule as DiagramModule,\n modellingModule as DiagramModule,\n exportingModule as DiagramModule,\n localStorageModule as DiagramModule,\n uploadModule as DiagramModule,\n paletteModule as DiagramModule,\n resizeElementModule as DiagramModule,\n // the properties panel (registers a side tab; side-tabs + search-panel are\n // inherited from InteractiveViewer)\n entryFactoryModule as DiagramModule,\n pfdnPropertiesProviderModule as DiagramModule,\n propertiesPanelModule as DiagramModule\n ];\n\n /** The document a fresh editor opens with (used by {@link createDiagram}). */\n initialDiagram = INITIAL_DIAGRAM;\n\n private readonly _onKeydown = (event: KeyboardEvent): void => this._handleKeydown(event);\n\n constructor(options: EditorOptions = {}) {\n super(options);\n // Keyboard undo/redo. Scoped to the editor container (greenfield — the\n // components had no keyboard handling); removed in destroy().\n options.container?.addEventListener('keydown', this._onKeydown);\n }\n\n private _handleKeydown(event: KeyboardEvent): void {\n // Never steal typing from a panel field.\n const target = event.target as HTMLElement | null;\n if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')) {\n return;\n }\n // Undo/redo only make sense once a document is open.\n if (!this.getHost()) {\n return;\n }\n const mod = event.ctrlKey || event.metaKey;\n if (!mod) {\n return;\n }\n const key = event.key.toLowerCase();\n if (key === 'z' && event.shiftKey) {\n event.preventDefault();\n this.redo();\n } else if (key === 'z') {\n event.preventDefault();\n this.undo();\n } else if (key === 'y') {\n event.preventDefault();\n this.redo();\n }\n }\n\n /** Tear down the editor, removing the keyboard binding. */\n destroy(): void {\n this.options.container?.removeEventListener('keydown', this._onKeydown);\n super.destroy();\n }\n\n /** (Re)open the initial diagram. */\n createDiagram(): Promise<void> {\n return this.importDiagram(this.initialDiagram);\n }\n\n getModules(): readonly DiagramModule[] {\n // interaction + editing features first (they subscribe / swap the layer),\n // then the drawers\n return [\n ...InteractiveViewer.interactionModules,\n ...Editor.editionModules,\n ...Viewer.modules\n ];\n }\n\n /**\n * Create a node (and its associated label) at an optional position.\n *\n * Routed through the command stack so it persists and is undoable (since B10\n * the draw-layer `.created` event no longer persists on its own).\n */\n createNode(parameters: CreateParameters = {}): ModellingModelElement {\n const ctx: CreateContext = { className: 'node', parameters: [parameters] };\n this.get<CommandStack>('commandStack').execute('element.create', ctx);\n return ctx.created as ModellingModelElement;\n }\n\n /** Select an element by definition (e.g. to prepare a delete). */\n select(definition: ModellingModelElement): void {\n const element = this.get<DrawingRegistry>('drawingRegistry').get(definition.id as string);\n if (element) {\n this.get<Selection>('selection').select(element, definition);\n }\n }\n\n /** Delete the current selection (cascading to associated labels). */\n deleteSelected(): void {\n this.get<Selection>('selection').deleteSelected();\n }\n\n /** Undo the last edit (a whole gesture is one step). No-op if nothing to undo. */\n undo(): void {\n this.get<CommandStack>('commandStack').undo();\n }\n\n /** Redo the last undone edit. No-op if nothing to redo. */\n redo(): void {\n this.get<CommandStack>('commandStack').redo();\n }\n\n /** Whether there is an edit to undo. */\n canUndo(): boolean {\n return this.get<CommandStack>('commandStack').canUndo();\n }\n\n /** Whether there is an undone edit to redo. */\n canRedo(): boolean {\n return this.get<CommandStack>('commandStack').canRedo();\n }\n}\n\nexport default Editor;\n","/** A moddle model element as read/written by the properties panel. */\nexport interface Definition {\n id?: string;\n label?: Definition;\n $instanceOf(type: string): boolean;\n get(property: string): unknown;\n [key: string]: unknown;\n}\n\n/** `definition.$instanceOf(elementType)` — ported from `utils/modelUtils`. */\nexport function is(definition: Definition, elementType: string): boolean {\n return definition.$instanceOf(elementType);\n}\n\n/** Read a dotted property path (`label.text`) by plain property access. */\nexport function deepGet(obj: unknown, path: string): unknown {\n return path\n .split('.')\n .reduce<unknown>(\n (o, k) => (o == null ? undefined : (o as Record<string, unknown>)[k]),\n obj\n );\n}\n\n/** Write a dotted property path, creating intermediate objects as needed. */\nexport function deepSet(obj: Record<string, unknown>, path: string, value: unknown): void {\n const keys = path.split('.');\n let cursor = obj;\n for (let i = 0; i < keys.length - 1; i += 1) {\n const key = keys[i];\n if (cursor[key] == null || typeof cursor[key] !== 'object') {\n cursor[key] = {};\n }\n cursor = cursor[key] as Record<string, unknown>;\n }\n cursor[keys[keys.length - 1]] = value;\n}\n\n/** Trailing-nothing leading-edge? No — trailing debounce, like lodash's default. */\nexport function debounce<A extends unknown[]>(\n fn: (...args: A) => void,\n wait: number\n): (...args: A) => void {\n let timer: ReturnType<typeof setTimeout> | undefined;\n return (...args: A) => {\n if (timer) {\n clearTimeout(timer);\n }\n timer = setTimeout(() => fn(...args), wait);\n };\n}\n\n/** Title-case a token (`lineColor` → `Line Color`, `aws-ec2` → `Aws Ec 2`). */\nexport function startCase(input: string): string {\n return input\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/([a-zA-Z])([0-9])/g, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\n/** Whether a string is a `#rrggbb` colour (accepted by `<input type=color>`). */\nexport function isHexColor(value: unknown): value is string {\n return typeof value === 'string' && /^#[0-9a-fA-F]{6}$/.test(value);\n}\n","import type EventEmitter from 'eventemitter3';\nimport type { DiagramEventMap } from '@d3-polytree/core';\nimport { deepGet, deepSet, isHexColor, type Definition } from './utils';\n\n/** A `{name,value}` option for a select entry. */\nexport interface SelectOption {\n name: string;\n value: string;\n}\n\n/** Options accepted when building an entry. */\nexport interface EntryOptions {\n id: string;\n modelProperty: string;\n label?: string;\n description?: string;\n type?: string;\n allowEmpty?: boolean;\n selectOptions?: SelectOption[];\n}\n\n/** A rendered property entry: its markup plus get/set behaviour. */\nexport interface EntryResource extends EntryOptions {\n html: string;\n get: (element: Definition, formNode: HTMLElement) => void;\n set: (element: Definition, values: Record<string, unknown>) => boolean;\n validate: () => Record<string, unknown>;\n triggerUpdate: (propertyId: string, element: Definition) => void;\n}\n\nfunction ensureNotNull(prop: string | undefined): string {\n if (!prop) {\n throw new Error(`${prop} must be set.`);\n }\n return prop;\n}\n\n/**\n * Builds property-panel entries (text / select / colour / spreadsheet). Ported\n * from `@d3-polytree/properties-panel`'s `entryFactory/*`, de-jQuery-ed onto\n * native DOM; the colour entry uses a native `<input type=\"color\">` in place of\n * spectrum-colorpicker.\n */\nexport class EntryFactory {\n static readonly $inject = ['eventBus'];\n\n private readonly _eventBus: EventEmitter<DiagramEventMap>;\n\n constructor(eventBus: EventEmitter<DiagramEventMap>) {\n this._eventBus = eventBus;\n }\n\n setDefaultParameters(options: EntryOptions): EntryResource {\n const eventBus = this._eventBus;\n\n const defaultGet = (element: Definition, formNode: HTMLElement): void => {\n const prop = ensureNotNull(options.modelProperty);\n const value = deepGet(element, prop);\n const input = formNode.querySelector('input');\n if (input) {\n (input as HTMLInputElement).value = value == null ? '' : String(value);\n }\n };\n\n const defaultSet = (element: Definition, values: Record<string, unknown>): boolean => {\n const prop = ensureNotNull(options.modelProperty);\n deepSet(element as unknown as Record<string, unknown>, prop, deepGet(values, prop));\n return true;\n };\n\n const triggerUpdate = (propertyId: string, element: Definition): void => {\n eventBus.emit('PropertiesPanel.propertyChanged', propertyId, element);\n };\n\n return {\n html: '',\n description: '',\n get: defaultGet,\n set: defaultSet,\n validate: () => ({}),\n ...options,\n triggerUpdate\n };\n }\n\n textField(options: EntryOptions): EntryResource {\n return textInputField(this.setDefaultParameters(options));\n }\n\n selectBox(options: EntryOptions): EntryResource {\n return selectBoxField(this.setDefaultParameters(options));\n }\n\n colorPicker(options: EntryOptions): EntryResource {\n return colorPickerField(this.setDefaultParameters(options));\n }\n\n spreadsheet(options: EntryOptions): EntryResource {\n // Placeholder in the source engine; kept as an API-compatible no-op.\n return this.setDefaultParameters(options);\n }\n}\n\nfunction fieldWrapper(resource: EntryResource, inner: string): string {\n const label = resource.label ?? resource.id;\n return (\n `<div class=\"pfdjs-pp-field-wrapper\">` +\n `<label for=\"pfdjs-${resource.id}\">${label}</label>${inner}</div>`\n );\n}\n\nfunction textInputField(resource: EntryResource): EntryResource {\n const type = resource.type ?? 'text';\n resource.html = fieldWrapper(\n resource,\n `<input id=\"pfdjs-${resource.id}\" type=\"${type}\" name=\"${resource.modelProperty}\" />`\n );\n return resource;\n}\n\nfunction selectBoxField(resource: EntryResource): EntryResource {\n const allowEmpty = resource.allowEmpty ?? true;\n const options = Array.isArray(resource.selectOptions)\n ? resource.selectOptions.concat(allowEmpty ? [{ name: '', value: '' }] : [])\n : [{ name: '', value: '' }];\n\n const optionsHtml = options\n .map((o) => `<option value=\"${o.value}\">${o.name}</option>`)\n .join('');\n resource.html = fieldWrapper(\n resource,\n `<select id=\"pfdjs-${resource.id}\" name=\"${resource.modelProperty}\">${optionsHtml}</select>`\n );\n\n resource.get = (element, formNode) => {\n const value = element.get(resource.modelProperty) ?? 'default';\n formNode\n .querySelectorAll<HTMLOptionElement>(`select#pfdjs-${resource.id} > option`)\n .forEach((option) => {\n option.selected = option.value === value;\n });\n };\n\n return resource;\n}\n\nfunction colorPickerField(resource: EntryResource): EntryResource {\n resource.html = fieldWrapper(\n resource,\n `<input id=\"pfdjs-${resource.id}\" type=\"color\" name=\"${resource.modelProperty}\" />`\n );\n resource.get = (element, formNode) => {\n const input = formNode.querySelector<HTMLInputElement>('input[type=color]');\n const value = deepGet(element, resource.modelProperty);\n if (input && isHexColor(value)) {\n input.value = value;\n }\n };\n return resource;\n}\n\n/** didi module contributing the entry factory. */\nexport const entryFactoryModule = {\n __init__: ['entryFactory'],\n entryFactory: ['type', EntryFactory]\n};\n","import type EventEmitter from 'eventemitter3';\nimport type { DiagramEventMap } from '@d3-polytree/core';\nimport type { EntryFactory, EntryResource } from './EntryFactory';\nimport { is, startCase, type Definition } from './utils';\n\n/** A group of entries within a tab. */\nexport interface PropertiesGroup {\n id: string;\n label: string;\n entries: EntryResource[];\n}\n\n/** A properties-panel tab. */\nexport interface PropertiesTab {\n id: string;\n label: string;\n groups: PropertiesGroup[];\n}\n\n/** Icon registry token: icon type → SVG source. */\nexport type IconMap = Record<string, string>;\n\n/** A properties provider: supplies the tabs for a selected element. */\nexport interface PropertiesProvider {\n getTabs(element: Definition): PropertiesTab[];\n updateDrawing(definition: Definition): void;\n}\n\n// --- pfdn property parts (ported from provider/pfdn/tabs/parts/*) ------------\n\nfunction nameProps(group: PropertiesGroup, element: Definition, factory: EntryFactory): void {\n if (is(element, 'pfdn:Node')) {\n group.entries.push(factory.textField({ id: 'name', label: 'Name', modelProperty: 'name' }));\n group.entries.push(factory.textField({ id: 'tag', label: 'Tag', modelProperty: 'tag' }));\n group.entries.push(\n factory.textField({ id: 'label.text', label: 'Diagram label', modelProperty: 'label.text' })\n );\n } else if (is(element, 'pfdn:Settings')) {\n group.entries.push(factory.textField({ id: 'name', label: 'Diagram name', modelProperty: 'name' }));\n group.entries.push(factory.textField({ id: 'author', label: \"Author's name\", modelProperty: 'author' }));\n } else if (is(element, 'pfdn:Link')) {\n group.entries.push(\n factory.textField({ id: 'label.text', label: 'Diagram label', modelProperty: 'label.text' })\n );\n } else if (is(element, 'pfdn:Label')) {\n group.entries.push(factory.textField({ id: 'text', label: 'Label', modelProperty: 'text' }));\n }\n}\n\nfunction nodeFormatProps(\n group: PropertiesGroup,\n element: Definition,\n factory: EntryFactory,\n icons: IconMap\n): void {\n if (!is(element, 'pfdn:Node')) {\n return;\n }\n const selectOptions = Object.keys(icons).map((key) => ({ value: key, name: startCase(key) }));\n group.entries.push(\n factory.selectBox({\n id: 'type',\n label: 'Icon',\n modelProperty: 'type',\n allowEmpty: false,\n selectOptions\n })\n );\n group.entries.push(\n factory.textField({ id: 'size', label: 'Size', modelProperty: 'size', type: 'number' })\n );\n}\n\nfunction linkFormatProps(group: PropertiesGroup, element: Definition, factory: EntryFactory): void {\n if (!is(element, 'pfdn:Link')) {\n return;\n }\n group.entries.push(\n factory.textField({ id: 'lineWidth', label: 'Line width', modelProperty: 'lineWidth', type: 'number' })\n );\n group.entries.push(\n factory.colorPicker({ id: 'lineColor', label: 'Line color', modelProperty: 'lineColor' })\n );\n}\n\nfunction labelFormatProps(group: PropertiesGroup, element: Definition, factory: EntryFactory): void {\n if (is(element, 'pfdn:Node') || is(element, 'pfdn:Link')) {\n group.entries.push(\n factory.textField({\n id: 'label.fontSize',\n label: 'Font size',\n modelProperty: 'label.fontSize',\n type: 'number'\n })\n );\n group.entries.push(\n factory.colorPicker({ id: 'label.color', label: 'Color', modelProperty: 'label.color' })\n );\n } else if (is(element, 'pfdn:Label')) {\n group.entries.push(\n factory.textField({ id: 'fontSize', label: 'Font size', modelProperty: 'fontSize', type: 'number' })\n );\n group.entries.push(factory.colorPicker({ id: 'color', label: 'Color', modelProperty: 'color' }));\n }\n}\n\nfunction gridFormatProps(group: PropertiesGroup, element: Definition, factory: EntryFactory): void {\n if (!is(element, 'pfdn:Settings')) {\n return;\n }\n group.entries.push(\n factory.colorPicker({ id: 'backgroundColor', label: 'Background color', modelProperty: 'backgroundColor' })\n );\n group.entries.push(\n factory.colorPicker({ id: 'grid.lineColor', label: 'Line color', modelProperty: 'grid.lineColor' })\n );\n group.entries.push(\n factory.textField({ id: 'grid.size', label: 'Square size', modelProperty: 'grid.size', type: 'number' })\n );\n group.entries.push(\n factory.textField({ id: 'grid.lineWidth', label: 'Line width', modelProperty: 'grid.lineWidth', type: 'number' })\n );\n}\n\n/**\n * The PFDN properties provider: builds the Properties + Format tabs for the\n * selected element, and applies edits back to the drawing. Ported from\n * `provider/pfdn/*`.\n */\nexport class PfdnPropertiesProvider implements PropertiesProvider {\n static readonly $inject = ['icons', 'entryFactory', 'eventBus'];\n\n private readonly _icons: IconMap;\n private readonly _entryFactory: EntryFactory;\n private readonly _eventBus: EventEmitter<DiagramEventMap>;\n\n constructor(icons: IconMap, entryFactory: EntryFactory, eventBus: EventEmitter<DiagramEventMap>) {\n this._icons = icons;\n this._entryFactory = entryFactory;\n this._eventBus = eventBus;\n }\n\n updateDrawing(definition: Definition): void {\n if (is(definition, 'pfdn:Settings')) {\n this._eventBus.emit('canvas.resized');\n return;\n }\n this._eventBus.emit('element.updated', definition.id!, definition);\n if (is(definition, 'pfdn:Link') || is(definition, 'pfdn:Node')) {\n const label = definition.label;\n if (label) {\n this._eventBus.emit('element.updated', label.id!, label);\n }\n }\n }\n\n getTabs(element: Definition): PropertiesTab[] {\n const factory = this._entryFactory;\n return [this._propertiesTab(element, factory), this._formatTab(element, factory)];\n }\n\n private _propertiesTab(element: Definition, factory: EntryFactory): PropertiesTab {\n const general: PropertiesGroup = { id: 'general', label: 'General', entries: [] };\n nameProps(general, element, factory);\n return { id: 'properties', label: 'Properties', groups: [general] };\n }\n\n private _formatTab(element: Definition, factory: EntryFactory): PropertiesTab {\n const elementFormat: PropertiesGroup = { id: 'elementFormat', label: 'Element format', entries: [] };\n const labelFormat: PropertiesGroup = { id: 'labelFormat', label: 'Label format', entries: [] };\n const gridFormat: PropertiesGroup = { id: 'gridFormat', label: 'Grid format', entries: [] };\n\n nodeFormatProps(elementFormat, element, factory, this._icons);\n linkFormatProps(elementFormat, element, factory);\n labelFormatProps(labelFormat, element, factory);\n gridFormatProps(gridFormat, element, factory);\n\n return { id: 'format', label: 'Format', groups: [elementFormat, labelFormat, gridFormat] };\n }\n}\n\n/** didi module contributing the PFDN properties provider. */\nexport const pfdnPropertiesProviderModule = {\n __init__: ['propertiesProvider'],\n propertiesProvider: ['type', PfdnPropertiesProvider]\n};\n","import type EventEmitter from 'eventemitter3';\nimport type { DiagramEventMap } from '@d3-polytree/core';\nimport type { CommandStack, CommandContext } from '@d3-polytree/core';\nimport type { EntryResource } from './EntryFactory';\nimport type { PropertiesProvider } from './PfdnPropertiesProvider';\nimport { debounce, deepGet, deepSet, type Definition } from './utils';\n\n/** The memento for an `element.updateProperties` command. */\ninterface UpdatePropsContext extends CommandContext {\n scope: EntryResource;\n definition: Definition;\n before: Record<string, unknown>;\n after: Record<string, unknown>;\n}\n\n/** The side-tab registration surface the panel needs (structural). */\nexport interface SideTabRegistration {\n title?: string;\n iconClassName?: string;\n action: {\n created?: (content: HTMLElement | null) => void;\n [gesture: string]: ((content: HTMLElement | null) => void) | undefined;\n };\n}\nexport interface SideTabsRegistrar {\n registerSideTab(tab: SideTabRegistration, index?: number): void;\n}\n\n/** A selection entry as delivered by the core `selection.changed` event. */\ninterface SelectionEntry {\n definition: Definition;\n}\n\ninterface TrackedEntry {\n scope: EntryResource;\n definition: Definition;\n formNode: HTMLElement;\n}\n\n/** Parse an HTML fragment into its first element. */\nfunction fromHtml(html: string): HTMLElement {\n const template = document.createElement('template');\n template.innerHTML = html.trim();\n return template.content.firstElementChild as HTMLElement;\n}\n\nconst FORM_CONTROLS = new Set(['INPUT', 'TEXTAREA', 'SELECT']);\n\n/**\n * The editor properties panel: a tabbed editor for the selected element's\n * model properties. Ported from `@d3-polytree/properties-panel`'s\n * `PropertiesPanel.js`, de-jQuery-ed onto native DOM; the `scroll-tabs` widget\n * is replaced by native click-to-select tabs.\n */\nexport class PropertiesPanel {\n static readonly $inject = [\n 'sideTabsProvider',\n 'eventBus',\n 'propertiesProvider',\n 'd3polytree.definitions.settings',\n 'commandStack'\n ];\n\n private readonly _eventBus: EventEmitter<DiagramEventMap>;\n private readonly _propertiesProvider: PropertiesProvider;\n private readonly _diagramSettings: Definition;\n private readonly _commandStack: CommandStack;\n private _entries: Record<string, TrackedEntry> = {};\n\n private _container: HTMLElement | null = null;\n private _tabsEl: HTMLElement | null = null;\n private _contentsEl: HTMLElement | null = null;\n\n constructor(\n sideTabsProvider: SideTabsRegistrar,\n eventBus: EventEmitter<DiagramEventMap>,\n propertiesProvider: PropertiesProvider,\n diagramSettings: Definition,\n commandStack: CommandStack\n ) {\n this._eventBus = eventBus;\n this._propertiesProvider = propertiesProvider;\n this._diagramSettings = diagramSettings;\n this._commandStack = commandStack;\n this._registerUpdatePropertiesCommand();\n this._registerSideTab(sideTabsProvider);\n this._registerSelectionListener();\n }\n\n /**\n * Register the `element.updateProperties` command. Its apply logic is\n * editor-specific (a property `scope` plus the provider's drawing update), so\n * the panel — which owns both — registers it on the shared stack rather than\n * the core modelling orchestrator.\n */\n private _registerUpdatePropertiesCommand(): void {\n const apply = (ctx: UpdatePropsContext, props: Record<string, unknown>): void => {\n ctx.scope.set(ctx.definition, props);\n this._propertiesProvider.updateDrawing(ctx.definition);\n };\n this._commandStack.registerHandler('element.updateProperties', {\n execute: (ctx) => apply(ctx as UpdatePropsContext, (ctx as UpdatePropsContext).after),\n revert: (ctx) => apply(ctx as UpdatePropsContext, (ctx as UpdatePropsContext).before)\n });\n }\n\n private _registerSideTab(provider: SideTabsRegistrar): void {\n provider.registerSideTab(\n {\n title: 'Properties',\n iconClassName: 'icon-sliders',\n action: { created: (content) => this._drawPanel(content) }\n },\n 1\n );\n }\n\n private _registerSelectionListener(): void {\n this._eventBus.on(\n 'selection.changed',\n (oldSelection: SelectionEntry[], newSelection: SelectionEntry[]) => {\n let selected: Definition = this._diagramSettings;\n if (\n newSelection.length === 1 &&\n (oldSelection.length !== 1 ||\n oldSelection[0].definition.id !== newSelection[0].definition.id)\n ) {\n selected = newSelection[0].definition;\n }\n this._update(selected);\n }\n );\n }\n\n private _drawPanel(content: HTMLElement | null): void {\n if (!content) {\n return;\n }\n this._drawContainer(content);\n this._update(this._diagramSettings);\n }\n\n private _drawContainer(content: HTMLElement): void {\n this._container = fromHtml(PropertiesPanel.HTML_MARKUP);\n content.insertBefore(this._container, content.firstChild);\n this._tabsEl = this._container.querySelector('.tab-sheets');\n this._contentsEl = this._container.querySelector('.pfdjs-pp-contents');\n\n this._container.addEventListener('click', (event) => {\n const tab = (event.target as Element).closest<HTMLElement>('.tab-sheet');\n if (tab) {\n this._selectTab(tab.getAttribute('data-tab-target'));\n event.stopImmediatePropagation();\n }\n });\n this._registerInputChangeHandlers();\n }\n\n private _registerInputChangeHandlers(): void {\n const container = this._container;\n if (!container) {\n return;\n }\n // debounce keystroke updates on text inputs/areas; selects fire on change.\n const debouncedApply = debounce((target: HTMLElement) => this._applyChange(target), 300);\n container.addEventListener('input', (event) => {\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {\n debouncedApply(target);\n }\n });\n container.addEventListener('change', (event) => {\n const target = event.target as HTMLElement;\n if (FORM_CONTROLS.has(target.tagName)) {\n this._applyChange(target);\n }\n });\n this._eventBus.on(\n 'PropertiesPanel.propertyChanged',\n (propertyId: string, definition: Definition) => this._applyChangeByProperty(propertyId, definition)\n );\n }\n\n private _applyChange(target: HTMLElement): void {\n const entryId = target.getAttribute('name');\n if (!entryId) {\n return;\n }\n this._commit(entryId, (target as HTMLInputElement).value);\n }\n\n private _applyChangeByProperty(propertyId: string, definition: Definition): void {\n this._commit(propertyId, deepGet(definition, propertyId));\n }\n\n private _commit(entryId: string, newValue: unknown): void {\n const entry = this._entries[entryId];\n if (!entry) {\n return;\n }\n const after: Record<string, unknown> = {};\n deepSet(after, entryId, newValue);\n // Capture the prior value of the same path so the edit is undoable.\n const before: Record<string, unknown> = {};\n deepSet(before, entryId, deepGet(entry.definition, entryId));\n this._commandStack.execute('element.updateProperties', {\n scope: entry.scope,\n definition: entry.definition,\n before,\n after\n } satisfies UpdatePropsContext);\n }\n\n private _selectTab(tabId: string | null): void {\n this._tabsEl?.querySelectorAll<HTMLElement>('.tab-sheet').forEach((tab) => {\n tab.classList.toggle('tab-sheet-active', tab.getAttribute('data-tab-target') === tabId);\n });\n this._contentsEl?.querySelectorAll<HTMLElement>('.pfdjs-pp-content').forEach((content) => {\n content.classList.toggle('open', content.getAttribute('data-tab-target') === tabId);\n });\n }\n\n private _update(definition: Definition | undefined): void {\n if (this._tabsEl && this._contentsEl) {\n this._tabsEl.replaceChildren();\n this._contentsEl.replaceChildren();\n }\n if (definition) {\n this._drawEntries(definition);\n }\n }\n\n private _drawEntries(definition: Definition): void {\n if (!this._tabsEl || !this._contentsEl) {\n return;\n }\n const tabs = this._propertiesProvider.getTabs(definition);\n const renderedTabs: { id: string; label: string }[] = [];\n this._entries = {};\n\n for (const tab of tabs) {\n const content = fromHtml(`<div class=\"pfdjs-pp-content\" data-tab-target=\"${tab.id}\"></div>`);\n let tabHasContent = false;\n\n for (const group of tab.groups) {\n if (group.entries.length === 0) {\n continue;\n }\n const groupContent = fromHtml(\n `<div class=\"pfdjs-pp-content-group\" data-group-target=\"${group.id}\">` +\n `<div class=\"tab-content-group-title\">${group.label}</div></div>`\n );\n for (const entry of group.entries) {\n const entryNode = fromHtml(`<div>${entry.html}</div>`);\n groupContent.appendChild(entryNode);\n this._entries[entry.id] = { scope: entry, definition, formNode: entryNode };\n }\n content.appendChild(groupContent);\n tabHasContent = true;\n }\n\n if (tabHasContent) {\n this._contentsEl.appendChild(content);\n renderedTabs.push({ id: tab.id, label: tab.label });\n }\n }\n\n // populate each entry from the model\n Object.values(this._entries).forEach((entry) => entry.scope.get(entry.definition, entry.formNode));\n\n // draw the tab strip\n let firstTab: string | null = null;\n for (const tab of renderedTabs) {\n firstTab ??= tab.id;\n this._tabsEl.appendChild(\n fromHtml(\n `<li class=\"tab-sheet\" data-tab-target=\"${tab.id}\"><a href=\"#\">${tab.label}</a></li>`\n )\n );\n }\n this._selectTab(firstTab);\n }\n\n static readonly HTML_MARKUP =\n '<div id=\"pfdjs-pp-container\">' +\n '<div class=\"pfdjs-pp-tabs\"><ul class=\"tab-sheets\"></ul></div>' +\n '<div class=\"pfdjs-pp-contents\"></div>' +\n '</div>';\n}\n","/**\n * @d3-polytree/properties-panel — the editor's element-properties panel.\n *\n * Modernised (B6) from the 2017 jQuery/spectrum/scroll-tabs source to TypeScript\n * + ESM with native DOM: jQuery is gone, the colour entry uses a native\n * `<input type=\"color\">`, and the `scroll-tabs` widget is replaced by native\n * click-to-select tabs. Ships three didi modules (entry factory, PFDN provider,\n * panel) for the editor to compose.\n */\nexport { EntryFactory, entryFactoryModule } from './EntryFactory';\nexport type { EntryOptions, EntryResource, SelectOption } from './EntryFactory';\nexport {\n PfdnPropertiesProvider,\n pfdnPropertiesProviderModule\n} from './PfdnPropertiesProvider';\nexport type {\n IconMap,\n PropertiesGroup,\n PropertiesProvider,\n PropertiesTab\n} from './PfdnPropertiesProvider';\nexport { PropertiesPanel } from './PropertiesPanel';\nexport type { SideTabRegistration, SideTabsRegistrar } from './PropertiesPanel';\nexport type { Definition } from './utils';\n\nimport { PropertiesPanel } from './PropertiesPanel';\n\n/** didi module contributing the properties panel (composes with the provider). */\nexport const propertiesPanelModule = {\n __init__: ['propertiesPanel'],\n propertiesPanel: ['type', PropertiesPanel]\n};\n\nexport default propertiesPanelModule;\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { InteractiveViewer, InteractiveViewerOptions } from '@d3-polytree/interactive-viewer';
|
|
2
|
-
import { DiagramModule, CreateParameters, ModellingModelElement } from '@d3-polytree/core';
|
|
2
|
+
import { DiagramEventMap, CommandStack, DiagramModule, CreateParameters, ModellingModelElement } from '@d3-polytree/core';
|
|
3
3
|
import EventEmitter from 'eventemitter3';
|
|
4
4
|
|
|
5
5
|
/** A moddle model element as read/written by the properties panel. */
|
|
@@ -43,7 +43,7 @@ interface EntryResource extends EntryOptions {
|
|
|
43
43
|
declare class EntryFactory {
|
|
44
44
|
static readonly $inject: string[];
|
|
45
45
|
private readonly _eventBus;
|
|
46
|
-
constructor(eventBus: EventEmitter);
|
|
46
|
+
constructor(eventBus: EventEmitter<DiagramEventMap>);
|
|
47
47
|
setDefaultParameters(options: EntryOptions): EntryResource;
|
|
48
48
|
textField(options: EntryOptions): EntryResource;
|
|
49
49
|
selectBox(options: EntryOptions): EntryResource;
|
|
@@ -85,7 +85,7 @@ declare class PfdnPropertiesProvider implements PropertiesProvider {
|
|
|
85
85
|
private readonly _icons;
|
|
86
86
|
private readonly _entryFactory;
|
|
87
87
|
private readonly _eventBus;
|
|
88
|
-
constructor(icons: IconMap, entryFactory: EntryFactory, eventBus: EventEmitter);
|
|
88
|
+
constructor(icons: IconMap, entryFactory: EntryFactory, eventBus: EventEmitter<DiagramEventMap>);
|
|
89
89
|
updateDrawing(definition: Definition): void;
|
|
90
90
|
getTabs(element: Definition): PropertiesTab[];
|
|
91
91
|
private _propertiesTab;
|
|
@@ -120,11 +120,19 @@ declare class PropertiesPanel {
|
|
|
120
120
|
private readonly _eventBus;
|
|
121
121
|
private readonly _propertiesProvider;
|
|
122
122
|
private readonly _diagramSettings;
|
|
123
|
+
private readonly _commandStack;
|
|
123
124
|
private _entries;
|
|
124
125
|
private _container;
|
|
125
126
|
private _tabsEl;
|
|
126
127
|
private _contentsEl;
|
|
127
|
-
constructor(sideTabsProvider: SideTabsRegistrar, eventBus: EventEmitter
|
|
128
|
+
constructor(sideTabsProvider: SideTabsRegistrar, eventBus: EventEmitter<DiagramEventMap>, propertiesProvider: PropertiesProvider, diagramSettings: Definition, commandStack: CommandStack);
|
|
129
|
+
/**
|
|
130
|
+
* Register the `element.updateProperties` command. Its apply logic is
|
|
131
|
+
* editor-specific (a property `scope` plus the provider's drawing update), so
|
|
132
|
+
* the panel — which owns both — registers it on the shared stack rather than
|
|
133
|
+
* the core modelling orchestrator.
|
|
134
|
+
*/
|
|
135
|
+
private _registerUpdatePropertiesCommand;
|
|
128
136
|
private _registerSideTab;
|
|
129
137
|
private _registerSelectionListener;
|
|
130
138
|
private _drawPanel;
|
|
@@ -169,15 +177,33 @@ declare class Editor extends InteractiveViewer {
|
|
|
169
177
|
static readonly editionModules: readonly DiagramModule[];
|
|
170
178
|
/** The document a fresh editor opens with (used by {@link createDiagram}). */
|
|
171
179
|
initialDiagram: string;
|
|
180
|
+
private readonly _onKeydown;
|
|
181
|
+
constructor(options?: EditorOptions);
|
|
182
|
+
private _handleKeydown;
|
|
183
|
+
/** Tear down the editor, removing the keyboard binding. */
|
|
184
|
+
destroy(): void;
|
|
172
185
|
/** (Re)open the initial diagram. */
|
|
173
186
|
createDiagram(): Promise<void>;
|
|
174
187
|
getModules(): readonly DiagramModule[];
|
|
175
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* Create a node (and its associated label) at an optional position.
|
|
190
|
+
*
|
|
191
|
+
* Routed through the command stack so it persists and is undoable (since B10
|
|
192
|
+
* the draw-layer `.created` event no longer persists on its own).
|
|
193
|
+
*/
|
|
176
194
|
createNode(parameters?: CreateParameters): ModellingModelElement;
|
|
177
195
|
/** Select an element by definition (e.g. to prepare a delete). */
|
|
178
196
|
select(definition: ModellingModelElement): void;
|
|
179
197
|
/** Delete the current selection (cascading to associated labels). */
|
|
180
198
|
deleteSelected(): void;
|
|
199
|
+
/** Undo the last edit (a whole gesture is one step). No-op if nothing to undo. */
|
|
200
|
+
undo(): void;
|
|
201
|
+
/** Redo the last undone edit. No-op if nothing to redo. */
|
|
202
|
+
redo(): void;
|
|
203
|
+
/** Whether there is an edit to undo. */
|
|
204
|
+
canUndo(): boolean;
|
|
205
|
+
/** Whether there is an undone edit to redo. */
|
|
206
|
+
canRedo(): boolean;
|
|
181
207
|
}
|
|
182
208
|
|
|
183
209
|
export { type Definition, Editor, type EditorOptions, EntryFactory, type EntryOptions, type EntryResource, type IconMap, PfdnPropertiesProvider, type PropertiesGroup, PropertiesPanel, type PropertiesProvider, type PropertiesTab, type SelectOption, type SideTabRegistration, type SideTabsRegistrar, Editor as default, entryFactoryModule, pfdnPropertiesProviderModule, propertiesPanelModule };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { InteractiveViewer, InteractiveViewerOptions } from '@d3-polytree/interactive-viewer';
|
|
2
|
-
import { DiagramModule, CreateParameters, ModellingModelElement } from '@d3-polytree/core';
|
|
2
|
+
import { DiagramEventMap, CommandStack, DiagramModule, CreateParameters, ModellingModelElement } from '@d3-polytree/core';
|
|
3
3
|
import EventEmitter from 'eventemitter3';
|
|
4
4
|
|
|
5
5
|
/** A moddle model element as read/written by the properties panel. */
|
|
@@ -43,7 +43,7 @@ interface EntryResource extends EntryOptions {
|
|
|
43
43
|
declare class EntryFactory {
|
|
44
44
|
static readonly $inject: string[];
|
|
45
45
|
private readonly _eventBus;
|
|
46
|
-
constructor(eventBus: EventEmitter);
|
|
46
|
+
constructor(eventBus: EventEmitter<DiagramEventMap>);
|
|
47
47
|
setDefaultParameters(options: EntryOptions): EntryResource;
|
|
48
48
|
textField(options: EntryOptions): EntryResource;
|
|
49
49
|
selectBox(options: EntryOptions): EntryResource;
|
|
@@ -85,7 +85,7 @@ declare class PfdnPropertiesProvider implements PropertiesProvider {
|
|
|
85
85
|
private readonly _icons;
|
|
86
86
|
private readonly _entryFactory;
|
|
87
87
|
private readonly _eventBus;
|
|
88
|
-
constructor(icons: IconMap, entryFactory: EntryFactory, eventBus: EventEmitter);
|
|
88
|
+
constructor(icons: IconMap, entryFactory: EntryFactory, eventBus: EventEmitter<DiagramEventMap>);
|
|
89
89
|
updateDrawing(definition: Definition): void;
|
|
90
90
|
getTabs(element: Definition): PropertiesTab[];
|
|
91
91
|
private _propertiesTab;
|
|
@@ -120,11 +120,19 @@ declare class PropertiesPanel {
|
|
|
120
120
|
private readonly _eventBus;
|
|
121
121
|
private readonly _propertiesProvider;
|
|
122
122
|
private readonly _diagramSettings;
|
|
123
|
+
private readonly _commandStack;
|
|
123
124
|
private _entries;
|
|
124
125
|
private _container;
|
|
125
126
|
private _tabsEl;
|
|
126
127
|
private _contentsEl;
|
|
127
|
-
constructor(sideTabsProvider: SideTabsRegistrar, eventBus: EventEmitter
|
|
128
|
+
constructor(sideTabsProvider: SideTabsRegistrar, eventBus: EventEmitter<DiagramEventMap>, propertiesProvider: PropertiesProvider, diagramSettings: Definition, commandStack: CommandStack);
|
|
129
|
+
/**
|
|
130
|
+
* Register the `element.updateProperties` command. Its apply logic is
|
|
131
|
+
* editor-specific (a property `scope` plus the provider's drawing update), so
|
|
132
|
+
* the panel — which owns both — registers it on the shared stack rather than
|
|
133
|
+
* the core modelling orchestrator.
|
|
134
|
+
*/
|
|
135
|
+
private _registerUpdatePropertiesCommand;
|
|
128
136
|
private _registerSideTab;
|
|
129
137
|
private _registerSelectionListener;
|
|
130
138
|
private _drawPanel;
|
|
@@ -169,15 +177,33 @@ declare class Editor extends InteractiveViewer {
|
|
|
169
177
|
static readonly editionModules: readonly DiagramModule[];
|
|
170
178
|
/** The document a fresh editor opens with (used by {@link createDiagram}). */
|
|
171
179
|
initialDiagram: string;
|
|
180
|
+
private readonly _onKeydown;
|
|
181
|
+
constructor(options?: EditorOptions);
|
|
182
|
+
private _handleKeydown;
|
|
183
|
+
/** Tear down the editor, removing the keyboard binding. */
|
|
184
|
+
destroy(): void;
|
|
172
185
|
/** (Re)open the initial diagram. */
|
|
173
186
|
createDiagram(): Promise<void>;
|
|
174
187
|
getModules(): readonly DiagramModule[];
|
|
175
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* Create a node (and its associated label) at an optional position.
|
|
190
|
+
*
|
|
191
|
+
* Routed through the command stack so it persists and is undoable (since B10
|
|
192
|
+
* the draw-layer `.created` event no longer persists on its own).
|
|
193
|
+
*/
|
|
176
194
|
createNode(parameters?: CreateParameters): ModellingModelElement;
|
|
177
195
|
/** Select an element by definition (e.g. to prepare a delete). */
|
|
178
196
|
select(definition: ModellingModelElement): void;
|
|
179
197
|
/** Delete the current selection (cascading to associated labels). */
|
|
180
198
|
deleteSelected(): void;
|
|
199
|
+
/** Undo the last edit (a whole gesture is one step). No-op if nothing to undo. */
|
|
200
|
+
undo(): void;
|
|
201
|
+
/** Redo the last undone edit. No-op if nothing to redo. */
|
|
202
|
+
redo(): void;
|
|
203
|
+
/** Whether there is an edit to undo. */
|
|
204
|
+
canUndo(): boolean;
|
|
205
|
+
/** Whether there is an undone edit to redo. */
|
|
206
|
+
canRedo(): boolean;
|
|
181
207
|
}
|
|
182
208
|
|
|
183
209
|
export { type Definition, Editor, type EditorOptions, EntryFactory, type EntryOptions, type EntryResource, type IconMap, PfdnPropertiesProvider, type PropertiesGroup, PropertiesPanel, type PropertiesProvider, type PropertiesTab, type SelectOption, type SideTabRegistration, type SideTabsRegistrar, Editor as default, entryFactoryModule, pfdnPropertiesProviderModule, propertiesPanelModule };
|