@ankhorage/zora 20.1.5 → 20.2.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.
Files changed (74) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphNodeOverlay.d.ts +13 -0
  4. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphNodeOverlay.d.ts.map +1 -0
  5. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphNodeOverlay.js +71 -0
  6. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphNodeOverlay.js.map +1 -0
  7. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.d.ts +87 -0
  8. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.d.ts.map +1 -0
  9. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.js +132 -0
  10. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.js.map +1 -0
  11. package/dist/features/graph-view/adapters/inbound/web-artifact/bindGraphEvents.d.ts +7 -0
  12. package/dist/features/graph-view/adapters/inbound/web-artifact/bindGraphEvents.d.ts.map +1 -0
  13. package/dist/features/graph-view/adapters/inbound/web-artifact/bindGraphEvents.js +59 -0
  14. package/dist/features/graph-view/adapters/inbound/web-artifact/bindGraphEvents.js.map +1 -0
  15. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.d.ts +7 -0
  16. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.d.ts.map +1 -0
  17. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js +32 -0
  18. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js.map +1 -0
  19. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphResizeObserver.d.ts +22 -0
  20. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphResizeObserver.d.ts.map +1 -0
  21. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphResizeObserver.js +41 -0
  22. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphResizeObserver.js.map +1 -0
  23. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.d.ts +30 -0
  24. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.d.ts.map +1 -0
  25. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js +222 -0
  26. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js.map +1 -0
  27. package/dist/features/graph-view/adapters/inbound/web-artifact/createRenderableGraphElements.d.ts +5 -0
  28. package/dist/features/graph-view/adapters/inbound/web-artifact/createRenderableGraphElements.d.ts.map +1 -0
  29. package/dist/features/graph-view/adapters/inbound/web-artifact/createRenderableGraphElements.js +51 -0
  30. package/dist/features/graph-view/adapters/inbound/web-artifact/createRenderableGraphElements.js.map +1 -0
  31. package/dist/features/graph-view/adapters/inbound/web-artifact/fitGraphViewport.d.ts +5 -0
  32. package/dist/features/graph-view/adapters/inbound/web-artifact/fitGraphViewport.d.ts.map +1 -0
  33. package/dist/features/graph-view/adapters/inbound/web-artifact/fitGraphViewport.js +18 -0
  34. package/dist/features/graph-view/adapters/inbound/web-artifact/fitGraphViewport.js.map +1 -0
  35. package/dist/features/graph-view/adapters/inbound/web-artifact/readGraphRenderedNodes.d.ts +5 -0
  36. package/dist/features/graph-view/adapters/inbound/web-artifact/readGraphRenderedNodes.d.ts.map +1 -0
  37. package/dist/features/graph-view/adapters/inbound/web-artifact/readGraphRenderedNodes.js +14 -0
  38. package/dist/features/graph-view/adapters/inbound/web-artifact/readGraphRenderedNodes.js.map +1 -0
  39. package/dist/features/graph-view/adapters/inbound/web-artifact/runGraphLayout.d.ts +14 -0
  40. package/dist/features/graph-view/adapters/inbound/web-artifact/runGraphLayout.d.ts.map +1 -0
  41. package/dist/features/graph-view/adapters/inbound/web-artifact/runGraphLayout.js +34 -0
  42. package/dist/features/graph-view/adapters/inbound/web-artifact/runGraphLayout.js.map +1 -0
  43. package/dist/features/graph-view/adapters/inbound/web-artifact/scheduleGraphFrame.d.ts +3 -0
  44. package/dist/features/graph-view/adapters/inbound/web-artifact/scheduleGraphFrame.d.ts.map +1 -0
  45. package/dist/features/graph-view/adapters/inbound/web-artifact/scheduleGraphFrame.js +10 -0
  46. package/dist/features/graph-view/adapters/inbound/web-artifact/scheduleGraphFrame.js.map +1 -0
  47. package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.d.ts +5 -0
  48. package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.d.ts.map +1 -0
  49. package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.js +12 -0
  50. package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.js.map +1 -0
  51. package/dist/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.d.ts.map +1 -1
  52. package/dist/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.js +25 -10
  53. package/dist/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.js.map +1 -1
  54. package/package.json +5 -3
  55. package/src/features/graph-view/adapters/inbound/web-artifact/GraphNodeOverlay.tsx +142 -0
  56. package/src/features/graph-view/adapters/inbound/web-artifact/GraphView.tsx +293 -0
  57. package/src/features/graph-view/adapters/inbound/web-artifact/bindGraphEvents.ts +102 -0
  58. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts +38 -0
  59. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphResizeObserver.ts +80 -0
  60. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.ts +301 -0
  61. package/src/features/graph-view/adapters/inbound/web-artifact/createRenderableGraphElements.test.ts +49 -0
  62. package/src/features/graph-view/adapters/inbound/web-artifact/createRenderableGraphElements.ts +72 -0
  63. package/src/features/graph-view/adapters/inbound/web-artifact/fitGraphViewport.ts +20 -0
  64. package/src/features/graph-view/adapters/inbound/web-artifact/readGraphRenderedNodes.ts +20 -0
  65. package/src/features/graph-view/adapters/inbound/web-artifact/runGraphLayout.ts +53 -0
  66. package/src/features/graph-view/adapters/inbound/web-artifact/scheduleGraphFrame.ts +13 -0
  67. package/src/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.ts +19 -0
  68. package/src/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.test.ts +47 -31
  69. package/src/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.ts +47 -11
  70. package/src/types/cytoscape-elk.d.ts +4 -0
  71. package/web-dist/graph-view/GraphView.d.ts +87 -0
  72. package/web-dist/graph-view/GraphView.js +123308 -0
  73. package/web-dist/graph-view/artifact.json +7 -0
  74. package/web-dist/tree-view/artifact.json +7 -0
@@ -3,39 +3,55 @@ import { expect, test } from 'bun:test';
3
3
  import type { WebComponentArtifactFileSystemPort } from '../ports/outbound/WebComponentArtifactFileSystemPort';
4
4
  import { materializeWebComponentArtifactAsync } from './materializeWebComponentArtifactAsync';
5
5
 
6
- test('materializes the packaged tree-view web artifact without source ownership transfer', async () => {
7
- const packageRoot = '/package';
8
- const outputDirectory = '/consumer/src/generated/zora/tree-view';
9
- const writes = new Map<string, string>();
10
- const sources = new Map<string, string>([
11
- ['/package/web-dist/tree-view/TreeView.js', 'export const TreeView = 1;\n'],
12
- ['/package/web-dist/tree-view/TreeView.d.ts', 'export declare const TreeView: unknown;\n'],
13
- ]);
14
- const fileSystem = createFakeFileSystem(sources, writes);
6
+ for (const artifact of [
7
+ { component: 'tree-view', outputName: 'TreeView' },
8
+ { component: 'graph-view', outputName: 'GraphView' },
9
+ ] as const) {
10
+ test(`materializes packaged ${artifact.component} without source ownership transfer`, async () => {
11
+ const packageRoot = '/package';
12
+ const outputDirectory = `/consumer/src/generated/zora/${artifact.component}`;
13
+ const writes = new Map<string, string>();
14
+ const sourceDirectory = `${packageRoot}/web-dist/${artifact.component}`;
15
+ const sources = new Map<string, string>([
16
+ [
17
+ `${sourceDirectory}/artifact.json`,
18
+ JSON.stringify({
19
+ component: artifact.component,
20
+ files: [`${artifact.outputName}.js`, `${artifact.outputName}.d.ts`],
21
+ }),
22
+ ],
23
+ [`${sourceDirectory}/${artifact.outputName}.js`, 'export const component = 1;\n'],
24
+ [
25
+ `${sourceDirectory}/${artifact.outputName}.d.ts`,
26
+ 'export declare const component: unknown;\n',
27
+ ],
28
+ ]);
29
+ const fileSystem = createFakeFileSystem(sources, writes);
15
30
 
16
- const result = await materializeWebComponentArtifactAsync(
17
- {
18
- component: 'tree-view',
19
- outputDirectory,
20
- packageRoot,
21
- packageVersion: '1.2.3',
22
- },
23
- fileSystem,
24
- );
31
+ const result = await materializeWebComponentArtifactAsync(
32
+ {
33
+ component: artifact.component,
34
+ outputDirectory,
35
+ packageRoot,
36
+ packageVersion: '1.2.3',
37
+ },
38
+ fileSystem,
39
+ );
25
40
 
26
- expect(result.platform).toBe('web');
27
- expect(result.createdFiles).toEqual([
28
- `${outputDirectory}/TreeView.js`,
29
- `${outputDirectory}/TreeView.d.ts`,
30
- `${outputDirectory}/zora-artifact.json`,
31
- ]);
32
- expect(writes.get(`${outputDirectory}/TreeView.js`)).toStartWith(
33
- '// Generated by @ankhorage/zora v1.2.3. Do not edit manually.',
34
- );
35
- expect(writes.get(`${outputDirectory}/zora-artifact.json`)).toContain(
36
- '"owner": "@ankhorage/zora"',
37
- );
38
- });
41
+ expect(result.platform).toBe('web');
42
+ expect(result.createdFiles).toEqual([
43
+ `${outputDirectory}/${artifact.outputName}.js`,
44
+ `${outputDirectory}/${artifact.outputName}.d.ts`,
45
+ `${outputDirectory}/zora-artifact.json`,
46
+ ]);
47
+ expect(writes.get(`${outputDirectory}/${artifact.outputName}.js`)).toStartWith(
48
+ '// Generated by @ankhorage/zora v1.2.3. Do not edit manually.',
49
+ );
50
+ expect(writes.get(`${outputDirectory}/zora-artifact.json`)).toContain(
51
+ '"owner": "@ankhorage/zora"',
52
+ );
53
+ });
54
+ }
39
55
 
40
56
  test('rejects unsupported web components explicitly', async () => {
41
57
  const fileSystem = createFakeFileSystem(new Map(), new Map());
@@ -19,8 +19,12 @@ export async function materializeWebComponentArtifactAsync(
19
19
  input: MaterializeWebComponentArtifactInput,
20
20
  fileSystem: WebComponentArtifactFileSystemPort,
21
21
  ): Promise<MaterializeWebComponentArtifactResult> {
22
- const artifact = resolveWebArtifact(input.component);
23
- const sourceDirectory = fileSystem.joinPath(input.packageRoot, 'web-dist', artifact.directory);
22
+ const sourceDirectory = fileSystem.joinPath(input.packageRoot, 'web-dist', input.component);
23
+ const artifact = await readWebArtifactDefinitionAsync(
24
+ sourceDirectory,
25
+ input.component,
26
+ fileSystem,
27
+ );
24
28
  await fileSystem.ensureDirectoryAsync(input.outputDirectory);
25
29
 
26
30
  const createdFiles = await Promise.all(
@@ -61,20 +65,52 @@ export async function materializeWebComponentArtifactAsync(
61
65
  }
62
66
 
63
67
  interface WebArtifactDefinition {
64
- readonly directory: string;
68
+ readonly component: string;
65
69
  readonly files: readonly string[];
66
70
  }
67
71
 
68
- /*** Resolve the canonical packaged web artifact for a requested component. */
69
- function resolveWebArtifact(component: string): WebArtifactDefinition {
70
- if (component === 'tree-view') {
71
- return {
72
- directory: 'tree-view',
73
- files: ['TreeView.js', 'TreeView.d.ts'],
74
- };
72
+ /*** Read one packaged artifact manifest so new web components require no CLI branching. */
73
+ async function readWebArtifactDefinitionAsync(
74
+ sourceDirectory: string,
75
+ component: string,
76
+ fileSystem: WebComponentArtifactFileSystemPort,
77
+ ): Promise<WebArtifactDefinition> {
78
+ const manifestPath = fileSystem.joinPath(sourceDirectory, 'artifact.json');
79
+ const manifestSource = await readWebArtifactManifestSourceAsync(
80
+ manifestPath,
81
+ component,
82
+ fileSystem,
83
+ );
84
+ const parsed = JSON.parse(manifestSource) as {
85
+ readonly component?: unknown;
86
+ readonly files?: unknown;
87
+ };
88
+ if (
89
+ parsed.component !== component ||
90
+ !Array.isArray(parsed.files) ||
91
+ parsed.files.length === 0 ||
92
+ !parsed.files.every((fileName) => typeof fileName === 'string' && fileName.length > 0)
93
+ ) {
94
+ throw new Error(`Invalid ZORA web artifact manifest: ${component}`);
75
95
  }
76
96
 
77
- throw new Error(`Unsupported ZORA web component: ${component}`);
97
+ return {
98
+ component,
99
+ files: parsed.files,
100
+ };
101
+ }
102
+
103
+ /*** Read an artifact manifest and translate missing packages into the CLI-facing error. */
104
+ async function readWebArtifactManifestSourceAsync(
105
+ manifestPath: string,
106
+ component: string,
107
+ fileSystem: WebComponentArtifactFileSystemPort,
108
+ ): Promise<string> {
109
+ try {
110
+ return await fileSystem.readTextFileAsync(manifestPath);
111
+ } catch {
112
+ throw new Error(`Unsupported ZORA web component: ${component}`);
113
+ }
78
114
  }
79
115
 
80
116
  /*** Add a generated-file marker without changing the compiled artifact semantics. */
@@ -0,0 +1,4 @@
1
+ declare module 'cytoscape-elk' {
2
+ const extension: unknown;
3
+ export default extension;
4
+ }
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ export type GraphViewLayoutName = 'breadthfirst' | 'circle' | 'concentric' | 'elk' | 'grid';
3
+ export type GraphViewElementEventType = 'press' | 'double-press' | 'select' | 'unselect' | 'pointer-enter' | 'pointer-leave';
4
+ export interface GraphViewNode {
5
+ readonly id: string;
6
+ readonly label?: string;
7
+ readonly parentId?: string;
8
+ readonly classes?: string;
9
+ readonly data?: Readonly<Record<string, unknown>>;
10
+ }
11
+ export interface GraphViewEdge {
12
+ readonly id?: string;
13
+ readonly source: string;
14
+ readonly target: string;
15
+ readonly classes?: string;
16
+ readonly data?: Readonly<Record<string, unknown>>;
17
+ }
18
+ export interface GraphViewStyleRule {
19
+ readonly selector: string;
20
+ readonly style: Readonly<Record<string, unknown>>;
21
+ }
22
+ export interface GraphViewPoint {
23
+ readonly x: number;
24
+ readonly y: number;
25
+ }
26
+ export interface GraphViewSize {
27
+ readonly width: number;
28
+ readonly height: number;
29
+ }
30
+ export interface GraphViewNodeRenderContext {
31
+ readonly hovered: boolean;
32
+ readonly node: GraphViewNode;
33
+ readonly selected: boolean;
34
+ readonly zoom: number;
35
+ }
36
+ export interface GraphViewRenderedNode {
37
+ readonly hovered: boolean;
38
+ readonly id: string;
39
+ readonly position: GraphViewPoint;
40
+ readonly selected: boolean;
41
+ readonly zoom: number;
42
+ }
43
+ export interface GraphViewViewport {
44
+ readonly zoom: number;
45
+ readonly pan: GraphViewPoint;
46
+ }
47
+ export interface GraphViewFitOptions {
48
+ readonly nodeIds?: readonly string[];
49
+ readonly padding?: number;
50
+ }
51
+ export interface GraphViewElementEvent {
52
+ readonly id: string;
53
+ readonly type: GraphViewElementEventType;
54
+ }
55
+ export interface GraphViewController {
56
+ fit(options?: GraphViewFitOptions): void;
57
+ getViewport(): GraphViewViewport;
58
+ setPan(pan: GraphViewPoint): void;
59
+ setZoom(zoom: number): void;
60
+ zoomBy(factor: number): void;
61
+ }
62
+ export interface GraphViewProps {
63
+ readonly nodes: readonly GraphViewNode[];
64
+ readonly edges: readonly GraphViewEdge[];
65
+ readonly layout?: GraphViewLayoutName;
66
+ readonly layoutOptions?: Readonly<Record<string, unknown>>;
67
+ readonly spacingFactor?: number;
68
+ readonly styleRules?: readonly GraphViewStyleRule[];
69
+ readonly selectedNodeIds?: readonly string[];
70
+ readonly renderNode?: (context: GraphViewNodeRenderContext) => React.ReactNode;
71
+ readonly getNodeSize?: (node: GraphViewNode) => GraphViewSize | undefined;
72
+ readonly fitPadding?: number;
73
+ readonly minZoom?: number;
74
+ readonly maxZoom?: number;
75
+ readonly className?: string;
76
+ readonly style?: React.CSSProperties;
77
+ readonly ariaLabel?: string;
78
+ readonly onReady?: (controller: GraphViewController) => void;
79
+ readonly onLayoutComplete?: (controller: GraphViewController) => void;
80
+ readonly onNodeEvent?: (event: GraphViewElementEvent) => void;
81
+ readonly onEdgeEvent?: (event: GraphViewElementEvent) => void;
82
+ readonly onViewportChange?: (viewport: GraphViewViewport) => void;
83
+ }
84
+ export type GraphViewCallbacks = Pick<GraphViewProps, 'onEdgeEvent' | 'onLayoutComplete' | 'onNodeEvent' | 'onReady' | 'onViewportChange'>;
85
+ /*** Render a browser graph while one runtime owns Cytoscape layout, viewport, and disposal. */
86
+ export declare function GraphView(props: GraphViewProps): React.JSX.Element;
87
+ //# sourceMappingURL=GraphView.d.ts.map