sfn-diagram-react 0.7.0 → 1.0.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 +45 -29
- package/dist/index.d.ts +10 -7
- package/dist/index.js +37 -6
- package/package.json +6 -13
- package/dist/index.cjs +0 -198
- package/dist/index.d.cts +0 -121
package/README.md
CHANGED
|
@@ -15,14 +15,15 @@ npm install sfn-diagram-react sfn-diagram
|
|
|
15
15
|
pnpm add sfn-diagram-react sfn-diagram
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
`react` and `sfn-diagram` are peer dependencies. `sfn-diagram
|
|
18
|
+
`react` and `sfn-diagram` are peer dependencies. `sfn-diagram-react` 1.x needs `sfn-diagram` 2, because `format="html"` renders through the `sfn-diagram/html` subpath that 2.0 introduced. Like core, it ships ES modules only and needs Node >= 22.12, where `require()` still loads it. Upgrading from 1.x? See [Migrating to 2.0](https://sfn.yusufaf.dev/upgrading-to-v2/), which also covers Jest's `transformIgnorePatterns`.
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
21
21
|
|
|
22
22
|
```tsx
|
|
23
|
+
import type { AslDefinition } from 'sfn-diagram'
|
|
23
24
|
import { SfnDiagram } from 'sfn-diagram-react'
|
|
24
25
|
|
|
25
|
-
const definition = {
|
|
26
|
+
const definition: AslDefinition = {
|
|
26
27
|
StartAt: 'Hello',
|
|
27
28
|
States: {
|
|
28
29
|
Hello: { Type: 'Pass', Next: 'World' },
|
|
@@ -42,13 +43,21 @@ export function Diagram() {
|
|
|
42
43
|
}
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
`definition` accepts
|
|
46
|
+
`definition` accepts an `AslDefinition` object or a JSON string. An unannotated object
|
|
47
|
+
in a variable widens `Type` to `string`, so annotate it
|
|
48
|
+
(`const definition: AslDefinition = {...}`). A definition imported from a `.json` file
|
|
49
|
+
is widened the same way: pass it as a string (`JSON.stringify(json)` or the raw file
|
|
50
|
+
text), or cast it with `as unknown as AslDefinition`. A direct `as AslDefinition` fails
|
|
51
|
+
for a Parallel whose branches name different states.
|
|
46
52
|
|
|
47
53
|
### Execution overlay
|
|
48
54
|
|
|
49
55
|
Pass an execution's `history` to overlay a real run onto the diagram: states are
|
|
50
|
-
coloured by outcome (succeeded / failed / caught / not-reached), the taken
|
|
51
|
-
emphasized, and per-state duration and retry counts are annotated.
|
|
56
|
+
coloured by outcome (succeeded / failed / caught / aborted / not-reached), the taken
|
|
57
|
+
path is emphasized, and per-state duration and retry counts are annotated. An aborted
|
|
58
|
+
state was entered but abandoned before it finished: another branch's or iteration's
|
|
59
|
+
failure stopped it, AWS aborted its container, or it was still open when the execution
|
|
60
|
+
was stopped.
|
|
52
61
|
|
|
53
62
|
```tsx
|
|
54
63
|
// historyJson: output of `aws stepfunctions get-execution-history`, as a JSON string
|
|
@@ -58,16 +67,14 @@ emphasized, and per-state duration and retry counts are annotated.
|
|
|
58
67
|
`history` accepts a `GetExecutionHistory` events array, the raw command output, or a
|
|
59
68
|
JSON string of either. In the browser, pass the JSON string.
|
|
60
69
|
|
|
61
|
-
`history` and `before` (diff mode, below) cannot be combined — core
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
`history` and `before` (diff mode, below) cannot be combined — core's SVG and Mermaid
|
|
71
|
+
functions can't overlay an execution onto a diff. Its interactive viewer can
|
|
72
|
+
(`generateHtml` takes both), but this package doesn't wire that up yet. Combining them
|
|
73
|
+
calls `onError` and renders `null`, the same way any other invalid input is handled.
|
|
64
74
|
|
|
65
75
|
**`format="mermaid"` combined with `history` honours the same options as plain
|
|
66
76
|
`format="mermaid"`** — `catchHandling`, `collapse`, `showVariables`, `layout` and
|
|
67
|
-
`theme
|
|
68
|
-
execution-overlay function (`generateMermaidExecution`) accept only the ASL definition,
|
|
69
|
-
`history`, `layout`, and `theme`, and ignore the rest. The SVG execution overlay
|
|
70
|
-
honours every option.
|
|
77
|
+
`theme`. The SVG execution overlay honours every option.
|
|
71
78
|
|
|
72
79
|
### Interactive viewer (`format="html"`)
|
|
73
80
|
|
|
@@ -84,8 +91,8 @@ Consequences worth knowing:
|
|
|
84
91
|
- `onStateClick` does not fire from inside it — clicks inside a sandboxed iframe never
|
|
85
92
|
reach the parent document's event handlers.
|
|
86
93
|
- `history` cannot be combined with `format="html"` yet — core's `generateHtml` accepts
|
|
87
|
-
`history` and `diff` overlays
|
|
88
|
-
|
|
94
|
+
`history` and `diff` overlays, but this package does not wire them up yet. Combining
|
|
95
|
+
them calls `onError` and renders `null`.
|
|
89
96
|
|
|
90
97
|
```tsx
|
|
91
98
|
<SfnDiagram definition={definition} format="html" style={{ height: 600, width: '100%' }} />
|
|
@@ -105,13 +112,15 @@ coloured (green / yellow / red) instead of the machine's normal styling.
|
|
|
105
112
|
```
|
|
106
113
|
|
|
107
114
|
- `before` accepts an ASL object or a JSON string, same as `definition`.
|
|
108
|
-
- `before` cannot be combined with `history`
|
|
109
|
-
|
|
115
|
+
- `before` cannot be combined with `history` (see
|
|
116
|
+
[Execution overlay](#execution-overlay)) or with `format="html"`. Core's
|
|
117
|
+
`generateHtml` takes a diff, but this package doesn't pass one to it yet. Combining
|
|
118
|
+
them calls `onError` and renders `null`.
|
|
110
119
|
- The **SVG diff** (`generateDiff`) honours every diagram option this package forwards
|
|
111
120
|
(`collapse`, `catchHandling`, `showIcons`, and the rest).
|
|
112
|
-
- The **Mermaid diff** ignores every prop
|
|
113
|
-
|
|
114
|
-
|
|
121
|
+
- The **Mermaid diff** ignores every diagram prop (`layout`, `theme`, `collapse`, …):
|
|
122
|
+
core's `generateMermaidDiff` accepts them, but this package doesn't forward them yet
|
|
123
|
+
(#393).
|
|
115
124
|
|
|
116
125
|
### `onStateClick`
|
|
117
126
|
|
|
@@ -148,15 +157,24 @@ There is no programmatic zoom/pan control — core doesn't expose the interactiv
|
|
|
148
157
|
viewer's controller from a public subpath yet, so a meaningful pan/zoom handle needs a
|
|
149
158
|
core change first.
|
|
150
159
|
|
|
160
|
+
### Several diagrams on one page
|
|
161
|
+
|
|
162
|
+
Each `<SfnDiagram>` (and each `useSfnDiagram` call) prefixes its SVG marker ids with a
|
|
163
|
+
value from React's `useId()`. Within one React root, two diagrams, even of the same
|
|
164
|
+
definition, never pick up each other's arrowheads, and server-rendered markup keeps the
|
|
165
|
+
same ids after hydration. When a page hydrates several roots, give each root its own
|
|
166
|
+
`identifierPrefix`, as React requires for `useId`.
|
|
167
|
+
|
|
151
168
|
### `useSfnDiagram`
|
|
152
169
|
|
|
153
170
|
For the raw output — the SVG/HTML string, Mermaid code, dimensions, and metadata —
|
|
154
171
|
without mounting anything, use the hook `<SfnDiagram>` is built on:
|
|
155
172
|
|
|
156
173
|
```tsx
|
|
174
|
+
import type { AslDefinition } from 'sfn-diagram'
|
|
157
175
|
import { useSfnDiagram } from 'sfn-diagram-react'
|
|
158
176
|
|
|
159
|
-
function DownloadSvgButton({ definition }: { definition:
|
|
177
|
+
function DownloadSvgButton({ definition }: { definition: AslDefinition }) {
|
|
160
178
|
const result = useSfnDiagram({ definition })
|
|
161
179
|
if (result.type !== 'svg') return null
|
|
162
180
|
|
|
@@ -178,31 +196,29 @@ ones (`className`, `onError`, `onStateClick`, `style`, `title`). Errors are retu
|
|
|
178
196
|
|
|
179
197
|
| Prop | Type | Default | Applies to | Description |
|
|
180
198
|
| --- | --- | --- | --- | --- |
|
|
181
|
-
| `before` | `
|
|
199
|
+
| `before` | `AslDefinition \| string` | — | svg, mermaid | The *original* side of a diff; `definition` becomes the *after* side. See [Diff mode](#diff-mode). |
|
|
182
200
|
| `catchHandling` | `'hide' \| 'show'` | `'show'` | svg, mermaid¹ | `'hide'` drops Catch error edges and handler-only nodes. |
|
|
183
201
|
| `className` | `string` | — | all | Applied to the wrapper element (`div`, `pre`, or `iframe`). |
|
|
184
202
|
| `collapse` | `string[] \| boolean` | — | svg, mermaid¹ | Collapse Parallel/Map containers into a placeholder node. `true` collapses every container; an array collapses only the named ones. |
|
|
185
|
-
| `definition` | `
|
|
203
|
+
| `definition` | `AslDefinition \| string` | — (required) | all | ASL definition as an object or JSON string. |
|
|
186
204
|
| `edgeOverrides` | `Record<string, EdgeStyleOverride>` | — | svg only | Per-edge style overrides keyed by `GraphEdge.id` (preferred, e.g. `Route->Work#choice#1`) or the legacy bare `${from}->${to}` (broad-matches every edge between that pair). |
|
|
187
|
-
| `edgeStyle` | `'straight' \| 'curved' \| 'orthogonal'` | `'curved'` | svg
|
|
205
|
+
| `edgeStyle` | `'straight' \| 'curved' \| 'orthogonal'` | `'curved'` | svg only | Edge path rendering style. |
|
|
188
206
|
| `format` | `'svg' \| 'mermaid' \| 'html'` | `'svg'` | — | Output format. See [Interactive viewer](#interactive-viewer-formathtml) for `'html'`. |
|
|
189
207
|
| `history` | `HistoryEvent[] \| GetExecutionHistoryCommandOutput \| string` | — | svg, mermaid | Execution history; when set, renders an execution overlay. See [Execution overlay](#execution-overlay). |
|
|
190
208
|
| `iconPosition` | `'left' \| 'top' \| 'right'` | `'left'` | svg only | Position of AWS service icons relative to the node label. |
|
|
191
209
|
| `iconSize` | `number` | `24` | svg only | Size of AWS service icons in pixels. |
|
|
192
|
-
| `layout` | `'TB' \| 'LR' \| 'RL' \| 'BT'` | `'TB'` | svg, mermaid | Graph layout direction. |
|
|
210
|
+
| `layout` | `'TB' \| 'LR' \| 'RL' \| 'BT'` | `'TB'` | svg, mermaid¹ | Graph layout direction. |
|
|
193
211
|
| `nodeOverrides` | `Record<string, Partial<NodeStyle>>` | — | svg only | Per-node style overrides keyed by graph node id. |
|
|
194
212
|
| `onError` | `(error: Error) => void` | — | all | Called when the definition fails to parse/render. |
|
|
195
213
|
| `onStateClick` | `(params: { event, stateId }) => void` | — | svg only | See [`onStateClick`](#onstateclick). |
|
|
196
214
|
| `showIcons` | `boolean` | `false` | svg only | Whether to display AWS service icons on Task state nodes. |
|
|
197
215
|
| `showVariables` | `boolean` | `true` | svg, mermaid¹ | Whether to annotate nodes with the variables they assign via ASL `Assign`. |
|
|
198
216
|
| `style` | `React.CSSProperties` | — | all | Applied to the wrapper element. |
|
|
199
|
-
| `theme` | `'light' \| 'dark' \| CustomTheme` | `'light'` | svg, mermaid | Diagram theme. |
|
|
217
|
+
| `theme` | `'light' \| 'dark' \| CustomTheme` | `'light'` | svg, mermaid¹ | Diagram theme. |
|
|
200
218
|
| `title` | `string` | `'Step Functions diagram'` | html only | Accessible title for the rendered iframe. |
|
|
201
219
|
|
|
202
|
-
¹
|
|
203
|
-
|
|
204
|
-
(no `history`). `format="mermaid"` diff mode (the `before` prop) is a separate
|
|
205
|
-
carve-out with its own rule — see [Diff mode](#diff-mode).
|
|
220
|
+
¹ Not applied in `format="mermaid"` diff mode (the `before` prop) — see
|
|
221
|
+
[Diff mode](#diff-mode).
|
|
206
222
|
|
|
207
223
|
When the definition is invalid the component renders `null` and (if provided) calls
|
|
208
224
|
`onError`.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { DiagramOptions, DiffOutput, ExecutionHistoryInput, ExecutionOutput, HtmlOutput, MermaidDiffOutput, MermaidExecutionOutput, MermaidOutput, SvgOutput } from "sfn-diagram";
|
|
2
|
+
import { AslDefinition, DiagramOptions, DiffOutput, ExecutionHistoryInput, ExecutionOutput, HtmlOutput, MermaidDiffOutput, MermaidExecutionOutput, MermaidOutput, SvgOutput } from "sfn-diagram";
|
|
3
3
|
interface UseSfnDiagramParams extends Pick<DiagramOptions, 'catchHandling' | 'collapse' | 'edgeOverrides' | 'edgeStyle' | 'iconPosition' | 'iconSize' | 'layout' | 'nodeOverrides' | 'showIcons' | 'showVariables' | 'theme'> {
|
|
4
4
|
/**
|
|
5
5
|
* When set, `definition` is treated as the *after* side of a diff and `before`
|
|
@@ -7,15 +7,15 @@ interface UseSfnDiagramParams extends Pick<DiagramOptions, 'catchHandling' | 'co
|
|
|
7
7
|
* removed states rather than the plain machine. Accepts an ASL object or a
|
|
8
8
|
* JSON string. Cannot be combined with `history` (core's SVG and Mermaid diff
|
|
9
9
|
* functions take no history) or with `format="html"` (core's `generateHtml`
|
|
10
|
-
* accepts a diff
|
|
10
|
+
* accepts a diff, but this hook does not wire it up yet).
|
|
11
11
|
*
|
|
12
12
|
* The Mermaid diff ignores every option in this type's `Pick<DiagramOptions, ...>`
|
|
13
13
|
* list - `layout`, `theme`, and the rest: this hook doesn't forward them to
|
|
14
|
-
* `generateMermaidDiff` yet (#393), although core accepts
|
|
15
|
-
*
|
|
14
|
+
* `generateMermaidDiff` yet (#393), although core's `generateMermaidDiff` accepts
|
|
15
|
+
* them. The SVG diff honours them.
|
|
16
16
|
*/
|
|
17
|
-
before?:
|
|
18
|
-
definition:
|
|
17
|
+
before?: AslDefinition | string;
|
|
18
|
+
definition: AslDefinition | string;
|
|
19
19
|
/**
|
|
20
20
|
* Output format. `'svg'` and `'mermaid'` render static markup; `'html'` renders
|
|
21
21
|
* the interactive pan/zoom/search viewer as a self-contained HTML document.
|
|
@@ -62,6 +62,9 @@ type SfnDiagramResult = {
|
|
|
62
62
|
* than mounted markup - for example, building a data URI for `<img src>`, a
|
|
63
63
|
* download button, or a custom render target.
|
|
64
64
|
*
|
|
65
|
+
* SVG marker ids are prefixed per hook instance from `useId()`, so diagrams on one
|
|
66
|
+
* page don't share them and server-rendered ids match the client's.
|
|
67
|
+
*
|
|
65
68
|
* @param params - The same option-bearing props `<SfnDiagram>` accepts, minus
|
|
66
69
|
* the presentational ones (`className`, `onError`, `onStateClick`, `style`,
|
|
67
70
|
* `title`).
|
|
@@ -70,7 +73,7 @@ type SfnDiagramResult = {
|
|
|
70
73
|
*
|
|
71
74
|
* @example
|
|
72
75
|
* ```tsx
|
|
73
|
-
* function DownloadSvgButton({ definition }: { definition:
|
|
76
|
+
* function DownloadSvgButton({ definition }: { definition: AslDefinition }) {
|
|
74
77
|
* const result = useSfnDiagram({ definition })
|
|
75
78
|
* if (result.type !== 'svg') return null
|
|
76
79
|
*
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from "react";
|
|
3
|
-
import { generateDiff, generateExecution,
|
|
2
|
+
import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useMemo, useRef } from "react";
|
|
3
|
+
import { generateDiff, generateExecution, generateMermaid, generateMermaidDiff, generateMermaidExecution, generateSvg } from "sfn-diagram";
|
|
4
|
+
import { generateHtml } from "sfn-diagram/html";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
// src/idPrefix.ts
|
|
7
|
+
/**
|
|
8
|
+
* Turns a `useId()` value into a core `DiagramOptions.idPrefix`, so each diagram's
|
|
9
|
+
* SVG marker ids are its own and match between the server render and hydration.
|
|
10
|
+
*
|
|
11
|
+
* React 18 ids look like `:r0:`, React 19 ids like `_r_0_`, and both embed the
|
|
12
|
+
* root's `identifierPrefix`, which the caller picks and may contain characters core
|
|
13
|
+
* rejects. Every character outside `[A-Za-z0-9_.-]` becomes `_`, `:` included, so
|
|
14
|
+
* the ids stay valid in a standalone SVG file too. The `sfn-` start keeps the
|
|
15
|
+
* prefix a valid XML name, and the trailing `-` separates it from core's id.
|
|
16
|
+
*
|
|
17
|
+
* @param params - The React id to convert.
|
|
18
|
+
* @returns The prefix core prepends to each marker id.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* toIdPrefix({ reactId: ':r0:' }) // 'sfn-_r0_-'
|
|
22
|
+
*/
|
|
23
|
+
function toIdPrefix(params) {
|
|
24
|
+
const { reactId } = params;
|
|
25
|
+
return `sfn-${reactId.replace(/[^A-Za-z0-9_.-]/g, "_")}-`;
|
|
26
|
+
}
|
|
5
27
|
// src/useSfnDiagram.ts
|
|
6
28
|
function toAslString(params) {
|
|
7
29
|
const { definition } = params;
|
|
@@ -21,6 +43,9 @@ function omitUndefinedValues(options) {
|
|
|
21
43
|
* than mounted markup - for example, building a data URI for `<img src>`, a
|
|
22
44
|
* download button, or a custom render target.
|
|
23
45
|
*
|
|
46
|
+
* SVG marker ids are prefixed per hook instance from `useId()`, so diagrams on one
|
|
47
|
+
* page don't share them and server-rendered ids match the client's.
|
|
48
|
+
*
|
|
24
49
|
* @param params - The same option-bearing props `<SfnDiagram>` accepts, minus
|
|
25
50
|
* the presentational ones (`className`, `onError`, `onStateClick`, `style`,
|
|
26
51
|
* `title`).
|
|
@@ -29,7 +54,7 @@ function omitUndefinedValues(options) {
|
|
|
29
54
|
*
|
|
30
55
|
* @example
|
|
31
56
|
* ```tsx
|
|
32
|
-
* function DownloadSvgButton({ definition }: { definition:
|
|
57
|
+
* function DownloadSvgButton({ definition }: { definition: AslDefinition }) {
|
|
33
58
|
* const result = useSfnDiagram({ definition })
|
|
34
59
|
* if (result.type !== 'svg') return null
|
|
35
60
|
*
|
|
@@ -40,6 +65,7 @@ function omitUndefinedValues(options) {
|
|
|
40
65
|
*/
|
|
41
66
|
function useSfnDiagram(params) {
|
|
42
67
|
const { before, catchHandling, collapse, definition, edgeOverrides, edgeStyle, format = "svg", history, iconPosition, iconSize, layout = "TB", nodeOverrides, showIcons, showVariables, theme = "light" } = params;
|
|
68
|
+
const idPrefix = toIdPrefix({ reactId: useId() });
|
|
43
69
|
const asl = useMemo(() => toAslString({ definition }), [definition]);
|
|
44
70
|
const beforeAsl = useMemo(() => before === void 0 ? void 0 : toAslString({ definition: before }), [before]);
|
|
45
71
|
return useMemo(() => {
|
|
@@ -57,6 +83,10 @@ function useSfnDiagram(params) {
|
|
|
57
83
|
showVariables,
|
|
58
84
|
theme
|
|
59
85
|
});
|
|
86
|
+
const svgOptions = {
|
|
87
|
+
...diagramOptions,
|
|
88
|
+
idPrefix
|
|
89
|
+
};
|
|
60
90
|
if (beforeAsl !== void 0) {
|
|
61
91
|
if (history) throw new Error("history and before cannot be combined");
|
|
62
92
|
if (format === "html") throw new Error("before and format=\"html\" cannot be combined");
|
|
@@ -74,7 +104,7 @@ function useSfnDiagram(params) {
|
|
|
74
104
|
const output = generateDiff({
|
|
75
105
|
after: asl,
|
|
76
106
|
before: beforeAsl,
|
|
77
|
-
...
|
|
107
|
+
...svgOptions
|
|
78
108
|
});
|
|
79
109
|
return {
|
|
80
110
|
height: output.height,
|
|
@@ -116,10 +146,10 @@ function useSfnDiagram(params) {
|
|
|
116
146
|
const output = history ? generateExecution({
|
|
117
147
|
aslDefinition: asl,
|
|
118
148
|
history,
|
|
119
|
-
...
|
|
149
|
+
...svgOptions
|
|
120
150
|
}) : generateSvg({
|
|
121
151
|
aslDefinition: asl,
|
|
122
|
-
...
|
|
152
|
+
...svgOptions
|
|
123
153
|
});
|
|
124
154
|
return {
|
|
125
155
|
height: output.height,
|
|
@@ -145,6 +175,7 @@ function useSfnDiagram(params) {
|
|
|
145
175
|
history,
|
|
146
176
|
iconPosition,
|
|
147
177
|
iconSize,
|
|
178
|
+
idPrefix,
|
|
148
179
|
layout,
|
|
149
180
|
nodeOverrides,
|
|
150
181
|
showIcons,
|
package/package.json
CHANGED
|
@@ -1,29 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sfn-diagram-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "React component for AWS Step Functions ASL diagrams",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
|
-
"main": "./dist/index.cjs",
|
|
8
7
|
"module": "./dist/index.js",
|
|
9
8
|
"types": "./dist/index.d.ts",
|
|
10
9
|
"exports": {
|
|
11
10
|
".": {
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
"default": "./dist/index.js"
|
|
15
|
-
},
|
|
16
|
-
"require": {
|
|
17
|
-
"types": "./dist/index.d.cts",
|
|
18
|
-
"default": "./dist/index.cjs"
|
|
19
|
-
}
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
20
13
|
}
|
|
21
14
|
},
|
|
22
15
|
"files": [
|
|
23
16
|
"dist"
|
|
24
17
|
],
|
|
25
18
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
19
|
+
"node": ">=22.12.0"
|
|
27
20
|
},
|
|
28
21
|
"scripts": {
|
|
29
22
|
"build": "tsdown",
|
|
@@ -34,7 +27,7 @@
|
|
|
34
27
|
"prepublishOnly": "pnpm run build && pnpm run validate",
|
|
35
28
|
"validate": "pnpm run validate:publint && pnpm run validate:types",
|
|
36
29
|
"validate:publint": "publint",
|
|
37
|
-
"validate:types": "attw --pack ."
|
|
30
|
+
"validate:types": "attw --pack . --profile node16 --ignore-rules cjs-resolves-to-esm"
|
|
38
31
|
},
|
|
39
32
|
"keywords": [
|
|
40
33
|
"aws",
|
|
@@ -64,7 +57,7 @@
|
|
|
64
57
|
"homepage": "https://sfn.yusufaf.dev/ecosystem/react/",
|
|
65
58
|
"peerDependencies": {
|
|
66
59
|
"react": "^18.0.0 || ^19.0.0",
|
|
67
|
-
"sfn-diagram": "^
|
|
60
|
+
"sfn-diagram": "^2.0.0"
|
|
68
61
|
},
|
|
69
62
|
"devDependencies": {
|
|
70
63
|
"@arethetypeswrong/cli": "^0.18.5",
|
package/dist/index.cjs
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
let react = require("react");
|
|
4
|
-
let sfn_diagram = require("sfn-diagram");
|
|
5
|
-
let react_jsx_runtime = require("react/jsx-runtime");
|
|
6
|
-
// src/useSfnDiagram.ts
|
|
7
|
-
function toAslString(params) {
|
|
8
|
-
const { definition } = params;
|
|
9
|
-
return typeof definition === "string" ? definition : JSON.stringify(definition);
|
|
10
|
-
}
|
|
11
|
-
function omitUndefinedValues(options) {
|
|
12
|
-
const result = {};
|
|
13
|
-
for (const key of Object.keys(options)) if (options[key] !== void 0) result[key] = options[key];
|
|
14
|
-
return result;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Generate a Step Functions diagram and return the raw output - SVG or HTML
|
|
18
|
-
* markup, Mermaid code, dimensions, and metadata - without rendering it.
|
|
19
|
-
*
|
|
20
|
-
* This is the same generation logic `<SfnDiagram>` runs internally, exposed
|
|
21
|
-
* directly for a consumer who needs the underlying string or metadata rather
|
|
22
|
-
* than mounted markup - for example, building a data URI for `<img src>`, a
|
|
23
|
-
* download button, or a custom render target.
|
|
24
|
-
*
|
|
25
|
-
* @param params - The same option-bearing props `<SfnDiagram>` accepts, minus
|
|
26
|
-
* the presentational ones (`className`, `onError`, `onStateClick`, `style`,
|
|
27
|
-
* `title`).
|
|
28
|
-
* @returns A {@link SfnDiagramResult} discriminated union. Errors are returned
|
|
29
|
-
* as `{ type: 'error', error }` rather than thrown.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```tsx
|
|
33
|
-
* function DownloadSvgButton({ definition }: { definition: object }) {
|
|
34
|
-
* const result = useSfnDiagram({ definition })
|
|
35
|
-
* if (result.type !== 'svg') return null
|
|
36
|
-
*
|
|
37
|
-
* const href = `data:image/svg+xml;base64,${btoa(result.svg)}`
|
|
38
|
-
* return <a download="diagram.svg" href={href}>Download SVG</a>
|
|
39
|
-
* }
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
function useSfnDiagram(params) {
|
|
43
|
-
const { before, catchHandling, collapse, definition, edgeOverrides, edgeStyle, format = "svg", history, iconPosition, iconSize, layout = "TB", nodeOverrides, showIcons, showVariables, theme = "light" } = params;
|
|
44
|
-
const asl = (0, react.useMemo)(() => toAslString({ definition }), [definition]);
|
|
45
|
-
const beforeAsl = (0, react.useMemo)(() => before === void 0 ? void 0 : toAslString({ definition: before }), [before]);
|
|
46
|
-
return (0, react.useMemo)(() => {
|
|
47
|
-
try {
|
|
48
|
-
const diagramOptions = omitUndefinedValues({
|
|
49
|
-
catchHandling,
|
|
50
|
-
collapse,
|
|
51
|
-
edgeOverrides,
|
|
52
|
-
edgeStyle,
|
|
53
|
-
iconPosition,
|
|
54
|
-
iconSize,
|
|
55
|
-
layout,
|
|
56
|
-
nodeOverrides,
|
|
57
|
-
showIcons,
|
|
58
|
-
showVariables,
|
|
59
|
-
theme
|
|
60
|
-
});
|
|
61
|
-
if (beforeAsl !== void 0) {
|
|
62
|
-
if (history) throw new Error("history and before cannot be combined");
|
|
63
|
-
if (format === "html") throw new Error("before and format=\"html\" cannot be combined");
|
|
64
|
-
if (format === "mermaid") {
|
|
65
|
-
const output = (0, sfn_diagram.generateMermaidDiff)({
|
|
66
|
-
after: asl,
|
|
67
|
-
before: beforeAsl
|
|
68
|
-
});
|
|
69
|
-
return {
|
|
70
|
-
code: output.code,
|
|
71
|
-
metadata: output.metadata,
|
|
72
|
-
type: "mermaid"
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
const output = (0, sfn_diagram.generateDiff)({
|
|
76
|
-
after: asl,
|
|
77
|
-
before: beforeAsl,
|
|
78
|
-
...diagramOptions
|
|
79
|
-
});
|
|
80
|
-
return {
|
|
81
|
-
height: output.height,
|
|
82
|
-
metadata: output.metadata,
|
|
83
|
-
svg: output.svg,
|
|
84
|
-
type: "svg",
|
|
85
|
-
width: output.width
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
if (format === "html") {
|
|
89
|
-
if (history) throw new Error("history and format=\"html\" cannot be combined");
|
|
90
|
-
const output = (0, sfn_diagram.generateHtml)({
|
|
91
|
-
aslDefinition: asl,
|
|
92
|
-
...diagramOptions
|
|
93
|
-
});
|
|
94
|
-
return {
|
|
95
|
-
height: output.height,
|
|
96
|
-
html: output.html,
|
|
97
|
-
metadata: output.metadata,
|
|
98
|
-
type: "html",
|
|
99
|
-
width: output.width
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
if (format === "mermaid") {
|
|
103
|
-
const output = history ? (0, sfn_diagram.generateMermaidExecution)({
|
|
104
|
-
aslDefinition: asl,
|
|
105
|
-
history,
|
|
106
|
-
...diagramOptions
|
|
107
|
-
}) : (0, sfn_diagram.generateMermaid)({
|
|
108
|
-
aslDefinition: asl,
|
|
109
|
-
...diagramOptions
|
|
110
|
-
});
|
|
111
|
-
return {
|
|
112
|
-
code: output.code,
|
|
113
|
-
metadata: output.metadata,
|
|
114
|
-
type: "mermaid"
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
const output = history ? (0, sfn_diagram.generateExecution)({
|
|
118
|
-
aslDefinition: asl,
|
|
119
|
-
history,
|
|
120
|
-
...diagramOptions
|
|
121
|
-
}) : (0, sfn_diagram.generateSvg)({
|
|
122
|
-
aslDefinition: asl,
|
|
123
|
-
...diagramOptions
|
|
124
|
-
});
|
|
125
|
-
return {
|
|
126
|
-
height: output.height,
|
|
127
|
-
metadata: output.metadata,
|
|
128
|
-
svg: output.svg,
|
|
129
|
-
type: "svg",
|
|
130
|
-
width: output.width
|
|
131
|
-
};
|
|
132
|
-
} catch (err) {
|
|
133
|
-
return {
|
|
134
|
-
error: err instanceof Error ? err : new Error(String(err)),
|
|
135
|
-
type: "error"
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
}, [
|
|
139
|
-
asl,
|
|
140
|
-
beforeAsl,
|
|
141
|
-
catchHandling,
|
|
142
|
-
collapse,
|
|
143
|
-
edgeOverrides,
|
|
144
|
-
edgeStyle,
|
|
145
|
-
format,
|
|
146
|
-
history,
|
|
147
|
-
iconPosition,
|
|
148
|
-
iconSize,
|
|
149
|
-
layout,
|
|
150
|
-
nodeOverrides,
|
|
151
|
-
showIcons,
|
|
152
|
-
showVariables,
|
|
153
|
-
theme
|
|
154
|
-
]);
|
|
155
|
-
}
|
|
156
|
-
// src/SfnDiagram.tsx
|
|
157
|
-
const SfnDiagram = (0, react.forwardRef)(function SfnDiagram({ className, onError, onStateClick, style, title = "Step Functions diagram", ...diagramParams }, ref) {
|
|
158
|
-
const result = useSfnDiagram(diagramParams);
|
|
159
|
-
(0, react.useImperativeHandle)(ref, () => ({ getSvg: () => result.type === "svg" ? result.svg : null }), [result]);
|
|
160
|
-
const handleStateClick = (0, react.useCallback)((event) => {
|
|
161
|
-
const stateId = (event.target instanceof Element ? event.target : null)?.closest("[data-state-id]")?.getAttribute("data-state-id");
|
|
162
|
-
if (stateId) onStateClick?.({
|
|
163
|
-
event,
|
|
164
|
-
stateId
|
|
165
|
-
});
|
|
166
|
-
}, [onStateClick]);
|
|
167
|
-
const reportedResult = (0, react.useRef)(null);
|
|
168
|
-
(0, react.useEffect)(() => {
|
|
169
|
-
if (result.type !== "error") {
|
|
170
|
-
reportedResult.current = null;
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
if (reportedResult.current === result) return;
|
|
174
|
-
reportedResult.current = result;
|
|
175
|
-
onError?.(result.error);
|
|
176
|
-
}, [onError, result]);
|
|
177
|
-
if (result.type === "error") return null;
|
|
178
|
-
if (result.type === "mermaid") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
179
|
-
className,
|
|
180
|
-
style,
|
|
181
|
-
children: result.code
|
|
182
|
-
});
|
|
183
|
-
if (result.type === "html") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
184
|
-
className,
|
|
185
|
-
sandbox: "allow-downloads allow-scripts",
|
|
186
|
-
srcDoc: result.html,
|
|
187
|
-
style,
|
|
188
|
-
title
|
|
189
|
-
});
|
|
190
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191
|
-
className,
|
|
192
|
-
dangerouslySetInnerHTML: { __html: result.svg },
|
|
193
|
-
onClick: onStateClick ? handleStateClick : void 0,
|
|
194
|
-
style
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
exports.SfnDiagram = SfnDiagram;
|
|
198
|
-
exports.useSfnDiagram = useSfnDiagram;
|
package/dist/index.d.cts
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { DiagramOptions, DiffOutput, ExecutionHistoryInput, ExecutionOutput, HtmlOutput, MermaidDiffOutput, MermaidExecutionOutput, MermaidOutput, SvgOutput } from "sfn-diagram";
|
|
3
|
-
interface UseSfnDiagramParams extends Pick<DiagramOptions, 'catchHandling' | 'collapse' | 'edgeOverrides' | 'edgeStyle' | 'iconPosition' | 'iconSize' | 'layout' | 'nodeOverrides' | 'showIcons' | 'showVariables' | 'theme'> {
|
|
4
|
-
/**
|
|
5
|
-
* When set, `definition` is treated as the *after* side of a diff and `before`
|
|
6
|
-
* as the *original* side: the rendered diagram highlights added, modified, and
|
|
7
|
-
* removed states rather than the plain machine. Accepts an ASL object or a
|
|
8
|
-
* JSON string. Cannot be combined with `history` (core's SVG and Mermaid diff
|
|
9
|
-
* functions take no history) or with `format="html"` (core's `generateHtml`
|
|
10
|
-
* accepts a diff since sfn-diagram 1.8, but this hook does not wire it up yet).
|
|
11
|
-
*
|
|
12
|
-
* The Mermaid diff ignores every option in this type's `Pick<DiagramOptions, ...>`
|
|
13
|
-
* list - `layout`, `theme`, and the rest: this hook doesn't forward them to
|
|
14
|
-
* `generateMermaidDiff` yet (#393), although core accepts them since sfn-diagram
|
|
15
|
-
* 1.10. The SVG diff honours them.
|
|
16
|
-
*/
|
|
17
|
-
before?: object | string;
|
|
18
|
-
definition: object | string;
|
|
19
|
-
/**
|
|
20
|
-
* Output format. `'svg'` and `'mermaid'` render static markup; `'html'` renders
|
|
21
|
-
* the interactive pan/zoom/search viewer as a self-contained HTML document.
|
|
22
|
-
* Cannot be combined with `history`.
|
|
23
|
-
* @default 'svg'
|
|
24
|
-
*/
|
|
25
|
-
format?: 'html' | 'mermaid' | 'svg';
|
|
26
|
-
/**
|
|
27
|
-
* Optional execution history. When provided, the diagram is rendered as an
|
|
28
|
-
* execution overlay: states are coloured by outcome, the taken path is
|
|
29
|
-
* emphasized, and per-state duration / retry counts are annotated.
|
|
30
|
-
* Accepts a GetExecutionHistory events array, the raw command output, or a
|
|
31
|
-
* JSON string of either. Cannot be combined with `format="html"`.
|
|
32
|
-
*/
|
|
33
|
-
history?: ExecutionHistoryInput;
|
|
34
|
-
}
|
|
35
|
-
/** Result of {@link useSfnDiagram} - the raw output of whichever core function the params select. */
|
|
36
|
-
type SfnDiagramResult = {
|
|
37
|
-
error: Error;
|
|
38
|
-
type: 'error';
|
|
39
|
-
} | {
|
|
40
|
-
height: number;
|
|
41
|
-
html: string;
|
|
42
|
-
metadata: HtmlOutput['metadata'];
|
|
43
|
-
type: 'html';
|
|
44
|
-
width: number;
|
|
45
|
-
} | {
|
|
46
|
-
code: string;
|
|
47
|
-
metadata: MermaidDiffOutput['metadata'] | MermaidExecutionOutput['metadata'] | MermaidOutput['metadata'];
|
|
48
|
-
type: 'mermaid';
|
|
49
|
-
} | {
|
|
50
|
-
height: number;
|
|
51
|
-
metadata: DiffOutput['metadata'] | ExecutionOutput['metadata'] | SvgOutput['metadata'];
|
|
52
|
-
svg: string;
|
|
53
|
-
type: 'svg';
|
|
54
|
-
width: number;
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* Generate a Step Functions diagram and return the raw output - SVG or HTML
|
|
58
|
-
* markup, Mermaid code, dimensions, and metadata - without rendering it.
|
|
59
|
-
*
|
|
60
|
-
* This is the same generation logic `<SfnDiagram>` runs internally, exposed
|
|
61
|
-
* directly for a consumer who needs the underlying string or metadata rather
|
|
62
|
-
* than mounted markup - for example, building a data URI for `<img src>`, a
|
|
63
|
-
* download button, or a custom render target.
|
|
64
|
-
*
|
|
65
|
-
* @param params - The same option-bearing props `<SfnDiagram>` accepts, minus
|
|
66
|
-
* the presentational ones (`className`, `onError`, `onStateClick`, `style`,
|
|
67
|
-
* `title`).
|
|
68
|
-
* @returns A {@link SfnDiagramResult} discriminated union. Errors are returned
|
|
69
|
-
* as `{ type: 'error', error }` rather than thrown.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```tsx
|
|
73
|
-
* function DownloadSvgButton({ definition }: { definition: object }) {
|
|
74
|
-
* const result = useSfnDiagram({ definition })
|
|
75
|
-
* if (result.type !== 'svg') return null
|
|
76
|
-
*
|
|
77
|
-
* const href = `data:image/svg+xml;base64,${btoa(result.svg)}`
|
|
78
|
-
* return <a download="diagram.svg" href={href}>Download SVG</a>
|
|
79
|
-
* }
|
|
80
|
-
* ```
|
|
81
|
-
*/
|
|
82
|
-
export declare function useSfnDiagram(params: UseSfnDiagramParams): SfnDiagramResult;
|
|
83
|
-
interface SfnDiagramProps extends UseSfnDiagramParams {
|
|
84
|
-
className?: string;
|
|
85
|
-
onError?: (error: Error) => void;
|
|
86
|
-
/**
|
|
87
|
-
* Called when a state node is clicked. SVG format only - a click inside the
|
|
88
|
-
* sandboxed `format="html"` iframe does not reach this handler, and Mermaid
|
|
89
|
-
* output has no clickable elements. `stateId` is the graph node id, which
|
|
90
|
-
* equals the state name for every state whose name is unique across the
|
|
91
|
-
* machine; for a nested state whose name repeats elsewhere in the machine the
|
|
92
|
-
* id is qualified by its scope, so read it off the rendered `data-state-id`
|
|
93
|
-
* rather than assuming the bare name.
|
|
94
|
-
*/
|
|
95
|
-
onStateClick?: (params: OnStateClickParams) => void;
|
|
96
|
-
style?: React.CSSProperties;
|
|
97
|
-
/**
|
|
98
|
-
* Accessible title for the rendered iframe when `format` is `'html'`. Ignored
|
|
99
|
-
* for every other format. Set this when a page renders more than one diagram
|
|
100
|
-
* so screen readers can distinguish between them.
|
|
101
|
-
* @default 'Step Functions diagram'
|
|
102
|
-
*/
|
|
103
|
-
title?: string;
|
|
104
|
-
}
|
|
105
|
-
/** Parameters passed to {@link SfnDiagramProps.onStateClick}. */
|
|
106
|
-
interface OnStateClickParams {
|
|
107
|
-
event: React.MouseEvent<HTMLDivElement>;
|
|
108
|
-
stateId: string;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Imperative handle exposed via `ref` on {@link SfnDiagram}. There is no
|
|
112
|
-
* programmatic zoom/pan control - core has no public API for it yet (the
|
|
113
|
-
* interactive viewer's controller is not exported from a public subpath) -
|
|
114
|
-
* this handle only surfaces the rendered markup.
|
|
115
|
-
*/
|
|
116
|
-
interface SfnDiagramHandle {
|
|
117
|
-
/** The rendered SVG markup for `format="svg"`, or `null` for every other format (including an errored render). */
|
|
118
|
-
getSvg(): string | null;
|
|
119
|
-
}
|
|
120
|
-
export declare const SfnDiagram: import("react").ForwardRefExoticComponent<SfnDiagramProps & import("react").RefAttributes<SfnDiagramHandle>>;
|
|
121
|
-
export type { OnStateClickParams, SfnDiagramHandle, SfnDiagramProps, SfnDiagramResult, UseSfnDiagramParams };
|