@zenuml/core 3.32.4 → 3.32.5
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/CLAUDE.md +98 -0
- package/cy/nested-interaction-with-fragment.html +34 -0
- package/cy/nested-interaction-with-outbound.html +34 -0
- package/dist/zenuml.esm.mjs +1 -1
- package/dist/zenuml.js +1 -1
- package/package.json +10 -15
- package/playwright.config.ts +36 -0
- package/vite.config.ts +4 -0
- package/.husky/pre-commit +0 -4
- package/cypress.config.ts +0 -16
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Development Commands
|
|
6
|
+
|
|
7
|
+
- **Start development server**: `pnpm dev` (runs on port 8080)
|
|
8
|
+
- **Build library**: `pnpm build` (builds library with vite.config.lib.ts)
|
|
9
|
+
- **Build site**: `pnpm build:site` (builds demo site with vite.config.ts)
|
|
10
|
+
- **Run tests**: `pnpm test` (runs Vitest unit tests)
|
|
11
|
+
- **Run E2E tests**: `pnpm pw` (runs Playwright tests)
|
|
12
|
+
- **Run E2E tests (CI)**: `pnpm pw:ci` (runs with GitHub reporter for CI)
|
|
13
|
+
- **Open Playwright UI**: `pnpm pw:ui`
|
|
14
|
+
- **Update Playwright snapshots**: `pnpm pw:update`
|
|
15
|
+
- **Install Playwright browsers**: `pnpm pw:install`
|
|
16
|
+
- **Run smoke tests**: `pnpm pw:smoke`
|
|
17
|
+
- **Lint code**: `pnpm eslint` (runs ESLint with auto-fix)
|
|
18
|
+
- **Format code**: `pnpm prettier` (runs Prettier)
|
|
19
|
+
- **Generate ANTLR parser**: `pnpm antlr` (generates JavaScript parser from grammar)
|
|
20
|
+
|
|
21
|
+
## Project Architecture
|
|
22
|
+
|
|
23
|
+
ZenUML is a JavaScript-based diagramming library for creating sequence diagrams from text definitions. The project has two main parts:
|
|
24
|
+
|
|
25
|
+
### 1. DSL Parser (ANTLR-based)
|
|
26
|
+
|
|
27
|
+
- **Grammar files**: `src/g4/` contains ANTLR grammar definitions
|
|
28
|
+
- **Generated parser**: `src/generated-parser/` contains generated JavaScript parser
|
|
29
|
+
- **Parser enhancements**: `src/parser/` contains custom functionality layered on top of ANTLR
|
|
30
|
+
|
|
31
|
+
### 2. React-based Renderer
|
|
32
|
+
|
|
33
|
+
- **Core entry point**: `src/core.tsx` - main library export and ZenUml class
|
|
34
|
+
- **Component structure**: `src/components/` - React components for rendering diagrams
|
|
35
|
+
- **Store management**: `src/store/Store.ts` - Jotai-based state management
|
|
36
|
+
- **Positioning engine**: `src/positioning/` - algorithms for layout and positioning
|
|
37
|
+
|
|
38
|
+
### Key Components Architecture
|
|
39
|
+
|
|
40
|
+
- **DiagramFrame**: Main container component that orchestrates the entire diagram
|
|
41
|
+
- **SeqDiagram**: Core sequence diagram renderer with layers:
|
|
42
|
+
- **LifeLineLayer**: Renders participants and their lifelines
|
|
43
|
+
- **MessageLayer**: Renders messages and interactions between participants
|
|
44
|
+
- **Statement components**: Individual renderers for different UML elements (interactions, fragments, etc.)
|
|
45
|
+
|
|
46
|
+
### Parser Architecture
|
|
47
|
+
|
|
48
|
+
The parser uses a two-stage approach:
|
|
49
|
+
|
|
50
|
+
1. **ANTLR-generated parser**: Converts text to parse tree
|
|
51
|
+
2. **Custom parser layer**: Transforms parse tree into structured data for rendering
|
|
52
|
+
|
|
53
|
+
Key parser modules:
|
|
54
|
+
|
|
55
|
+
- **Participants.ts**: Manages participant detection and ordering
|
|
56
|
+
- **MessageContext.ts**: Handles message parsing and context
|
|
57
|
+
- **FrameBuilder.ts**: Builds the overall diagram structure
|
|
58
|
+
- **Fragment handling**: Support for UML fragments (alt, opt, loop, par, etc.)
|
|
59
|
+
|
|
60
|
+
## Build System
|
|
61
|
+
|
|
62
|
+
The project uses Vite with two configurations:
|
|
63
|
+
|
|
64
|
+
- **vite.config.ts**: Development server and demo site build
|
|
65
|
+
- **vite.config.lib.ts**: Library build (ESM and UMD outputs)
|
|
66
|
+
|
|
67
|
+
Output formats:
|
|
68
|
+
|
|
69
|
+
- **ESM**: `dist/zenuml.esm.mjs` for modern bundlers
|
|
70
|
+
- **UMD**: `dist/zenuml.js` for browser scripts
|
|
71
|
+
|
|
72
|
+
## Testing Strategy
|
|
73
|
+
|
|
74
|
+
- **Unit tests**: Vitest for parser and utility functions
|
|
75
|
+
- **Component tests**: React Testing Library for component logic
|
|
76
|
+
- **E2E tests**: Playwright for full integration testing with visual snapshots
|
|
77
|
+
- **Test files**: Co-located with source files using `.spec.ts` extension
|
|
78
|
+
|
|
79
|
+
## Key Dependencies
|
|
80
|
+
|
|
81
|
+
- **React 19**: UI framework
|
|
82
|
+
- **ANTLR4**: Parser generation
|
|
83
|
+
- **Jotai**: State management
|
|
84
|
+
- **Tailwind CSS**: Styling framework
|
|
85
|
+
- **html-to-image**: PNG export functionality
|
|
86
|
+
- **Vite**: Build tool and development server
|
|
87
|
+
|
|
88
|
+
## Package Management
|
|
89
|
+
|
|
90
|
+
Uses pnpm with volta for Node.js version management. Always use `npx pnpm` for the first install.
|
|
91
|
+
|
|
92
|
+
## Development Notes
|
|
93
|
+
|
|
94
|
+
- The project builds both a library and a demo site
|
|
95
|
+
- Parser generation requires Java and ANTLR4
|
|
96
|
+
- E2E tests use visual snapshots for regression testing
|
|
97
|
+
- The library is published as `@zenuml/core` to npm
|
|
98
|
+
- GitHub Pages deployment is automated via GitHub Actions
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
6
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
|
7
|
+
<title>Nested Interaction with Fragment Test</title>
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
margin: 0; /* mostly for demo on mobile */
|
|
11
|
+
}
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<div id="diagram" class="diagram">
|
|
16
|
+
<pre class="zenuml" style="margin: 0">
|
|
17
|
+
title Nested Interaction with Fragment and Self-Invocation
|
|
18
|
+
A.Read() {
|
|
19
|
+
B.Submit() {
|
|
20
|
+
Process() {
|
|
21
|
+
if (true) {
|
|
22
|
+
ProcessCallback() {
|
|
23
|
+
A.method
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}</pre
|
|
29
|
+
>
|
|
30
|
+
</div>
|
|
31
|
+
<!-- built files will be auto injected -->
|
|
32
|
+
<script type="module" src="/src/main-cy.ts"></script>
|
|
33
|
+
</body>
|
|
34
|
+
</html>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
6
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
|
7
|
+
<title>Nested Interaction with Outbound Message and Fragment Test</title>
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
margin: 0; /* mostly for demo on mobile */
|
|
11
|
+
}
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<div id="diagram" class="diagram">
|
|
16
|
+
<pre class="zenuml" style="margin: 0">
|
|
17
|
+
title Nested Interaction with Outbound Message and Fragment
|
|
18
|
+
A.Read() {
|
|
19
|
+
B.Submit() {
|
|
20
|
+
C->B.method {
|
|
21
|
+
if (true) {
|
|
22
|
+
ProcessCallback() {
|
|
23
|
+
A.method
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}</pre
|
|
29
|
+
>
|
|
30
|
+
</div>
|
|
31
|
+
<!-- built files will be auto injected -->
|
|
32
|
+
<script type="module" src="/src/main-cy.ts"></script>
|
|
33
|
+
</body>
|
|
34
|
+
</html>
|
package/dist/zenuml.esm.mjs
CHANGED
|
@@ -71096,7 +71096,7 @@ const jW = (i, e) => {
|
|
|
71096
71096
|
]
|
|
71097
71097
|
}
|
|
71098
71098
|
);
|
|
71099
|
-
}, t$ = "3.32.
|
|
71099
|
+
}, t$ = "3.32.5";
|
|
71100
71100
|
function n$(i) {
|
|
71101
71101
|
const e = Math.floor(i / 1e3), t = Math.floor(i % 1e3), n = Math.floor((i % 1e3 - t) * 1e3);
|
|
71102
71102
|
return e + "s " + t + "ms " + n + "μs";
|
package/dist/zenuml.js
CHANGED
|
@@ -3392,7 +3392,7 @@ https://github.com/highlightjs/highlight.js/issues/2277`),l4=L2,ae=b2);const B1=
|
|
|
3392
3392
|
`+d).trim(),this.textStyle={...f,...L,...p},this.classNames=[...h,..._,...m],this.commentStyle={...f,...L},this.messageStyle={...f,...p},this.commentClassNames=[...h,..._],this.messageClassNames=[...h,...m]}}const lH=i=>{const e=i.context.getComment()||"",t=new oH(e),n={className:Z2("text-left text-sm text-skin-message",{hidden:i.collapsed&&!i.context.ret()}),context:i.context,origin:i.origin,comment:e,commentObj:t,number:i.number};switch(!0){case!!i.context.loop():return S.jsx(kz,{...n});case!!i.context.alt():return S.jsx(Pz,{...n});case!!i.context.par():return S.jsx(Fz,{...n});case!!i.context.opt():return S.jsx(Uz,{...n});case!!i.context.section():return S.jsx(Bz,{...n});case!!i.context.critical():return S.jsx(Gz,{...n});case!!i.context.tcf():return S.jsx(zz,{...n});case!!i.context.ref():return S.jsx(Hz,{...n});case!!i.context.creation():return S.jsx(Kz,{...n});case!!i.context.message():return S.jsx(jz,{...n});case!!i.context.asyncMessage():return S.jsx(Jz,{...n});case!!i.context.divider():return S.jsx(rH,{...n});case!!i.context.ret():return S.jsx(aH,{...n,className:"text-left text-sm text-skin-message"})}},S3=i=>{var n;const e=((n=i.context)==null?void 0:n.stat())||[],t=s=>i.number?i.incremental?dU(i.number,s):`${i.number}.${s+1}`:String(s+1);return S.jsx("div",{className:Z2("block",i.className),style:i.style,"data-origin":i.origin,children:e.map((s,l)=>S.jsx("div",{className:Z2("statement-container my-4",l===e.length-1&&"[&>.return]:-mb-4 [&>.return]:bottom-[-1px]"),"data-origin":i.origin,children:S.jsx(lH,{origin:i.origin||"",context:s,collapsed:!!i.collapsed,number:t(l)})},l))})};var Pl=typeof document<"u"?R.useLayoutEffect:R.useEffect;const cH={...hn}.useInsertionEffect||(i=>i());function uH(i){const e=R.useRef(()=>{});return cH(()=>{e.current=i}),R.useCallback(function(){for(var t=arguments.length,n=new Array(t),s=0;s<t;s++)n[s]=arguments[s];return e.current==null?void 0:e.current(...n)},[])}const dH={...hn};let Ff=!1,LH=0;const Uf=()=>"floating-ui-"+Math.random().toString(36).slice(2,6)+LH++;function CH(){const[i,e]=R.useState(()=>Ff?Uf():void 0);return Pl(()=>{i==null&&e(Uf())},[]),R.useEffect(()=>{Ff=!0},[]),i}const _H=dH.useId||CH;function gH(){const i=new Map;return{emit(e,t){var n;(n=i.get(e))==null||n.forEach(s=>s(t))},on(e,t){i.has(e)||i.set(e,new Set),i.get(e).add(t)},off(e,t){var n;(n=i.get(e))==null||n.delete(t)}}}const pH=R.createContext(null),mH=R.createContext(null),hH=()=>{var i;return((i=R.useContext(pH))==null?void 0:i.id)||null},fH=()=>R.useContext(mH);function EH(i){const{open:e=!1,onOpenChange:t,elements:n}=i,s=_H(),l=R.useRef({}),[c]=R.useState(()=>gH()),d=hH()!=null,[L,_]=R.useState(n.reference),p=uH((h,v,b)=>{l.current.openEvent=h?v:void 0,c.emit("openchange",{open:h,event:v,reason:b,nested:d}),t==null||t(h,v,b)}),m=R.useMemo(()=>({setPositionReference:_}),[]),f=R.useMemo(()=>({reference:L||n.reference||null,floating:n.floating||null,domReference:n.reference}),[L,n.reference,n.floating]);return R.useMemo(()=>({dataRef:l,open:e,onOpenChange:p,elements:f,events:c,floatingId:s,refs:m}),[e,p,f,c,s,m])}function SH(i){i===void 0&&(i={});const{nodeId:e}=i,t=EH({...i,elements:{reference:null,floating:null,...i.elements}}),n=i.rootContext||t,s=n.elements,[l,c]=R.useState(null),[d,L]=R.useState(null),p=(s==null?void 0:s.domReference)||l,m=R.useRef(null),f=fH();Pl(()=>{p&&(m.current=p)},[p]);const h=ZP({...i,elements:{...s,...d&&{reference:d}}}),v=R.useCallback(D=>{const I=Ke(D)?{getBoundingClientRect:()=>D.getBoundingClientRect(),getClientRects:()=>D.getClientRects(),contextElement:D}:D;L(I),h.refs.setReference(I)},[h.refs]),b=R.useCallback(D=>{(Ke(D)||D===null)&&(m.current=D,c(D)),(Ke(h.refs.reference.current)||h.refs.reference.current===null||D!==null&&!Ke(D))&&h.refs.setReference(D)},[h.refs]),w=R.useMemo(()=>({...h.refs,setReference:b,setPositionReference:v,domReference:m}),[h.refs,b,v]),M=R.useMemo(()=>({...h.elements,domReference:p}),[h.elements,p]),N=R.useMemo(()=>({...h,...n,refs:w,elements:M,nodeId:e}),[h,w,M,e,n]);return Pl(()=>{n.dataRef.current.floatingContext=N;const D=f==null?void 0:f.nodesRef.current.find(I=>I.id===e);D&&(D.context=N)}),R.useMemo(()=>({...h,context:N,refs:w,elements:M}),[h,w,M,N])}function TH(i){const e=R.useRef(i);return R.useEffect(()=>{e.current=i},[i]),e}function vH(i,e,t){const n=TH(e);R.useEffect(()=>{function s(l){n.current(l)}return document.addEventListener(i,s,t),()=>document.removeEventListener(i,s,t)},[i,t,n])}const RH=(i,e)=>{vH("click",t=>{i&&(i.contains(t.target)||e(t))},{capture:!0})},bH=[{name:"bold",content:"B",class:"font-bold"},{name:"italic",content:"I",class:"italic"},{name:"underline",content:"U",class:"underline"},{name:"strikethrough",content:"S",class:"line-through"}],xH=()=>{const[i,e]=e4(Z9),t=i1(Q0),n=k0(Qi),[s,l]=R.useState(!1),[c,d]=R.useState([]),[L,_]=R.useState(""),p=b=>{e(b),t(b)},m=R.useRef({start:0,lineHead:0,prevLine:"",leadingSpaces:"",prevLineIsComment:!1,hasStyleBrackets:!1}),{refs:f,floatingStyles:h}=SH({open:s,onOpenChange:l}),v=b=>{var M;if(l(!1),!L)return;const w=m.current;if(w.prevLineIsComment){let N="";if(w.hasStyleBrackets){let D;c.includes(b)?D=c.filter(I=>I!==b):D=[...c,b],N=`${w.leadingSpaces}// [${D.filter(Boolean).join(", ")}] ${w.prevLine.slice(w.prevLine.indexOf("]")+1).trimStart()}`}else N=`${w.leadingSpaces}// [${b}] ${w.prevLine.slice((((M=w.prevLine.match(/\/\/*/))==null?void 0:M.index)||-2)+2).trimStart()}`;N.endsWith(`
|
|
3393
3393
|
`)||(N+=`
|
|
3394
3394
|
`),p(i.slice(0,kL(i,w.start))+N+i.slice(w.lineHead))}else p(i.slice(0,w.lineHead)+`${w.leadingSpaces}// [${b}]
|
|
3395
|
-
`+i.slice(w.lineHead))};return RH(f.floating.current,()=>{l(!1)}),R.useEffect(()=>{n((b,w)=>{setTimeout(()=>{var N;const M=m.current;if(M.start=b.start.start,M.lineHead=Gi(i,M.start),M.prevLine=pb(i,M.start),M.leadingSpaces=((N=i.slice(M.lineHead).match(/^\s*/))==null?void 0:N[0])||"",M.prevLineIsComment=M.prevLine.trim().startsWith("//"),M.prevLineIsComment){const D=M.prevLine.trimStart().slice(2).trimStart(),I=D.indexOf("["),Z=D.indexOf("]");M.hasStyleBrackets=!!(I===0&&Z),M.hasStyleBrackets?d(D.slice(I+1,Z).split(",").map(U=>U.trim())):d([])}f.setReference(w),_(b),l(!0)},0)})},[i,f,n]),S.jsx("div",{id:"style-panel",ref:f.setFloating,style:h,children:s&&S.jsx("div",{className:"flex bg-white shadow-md z-10 rounded-md p-1",children:bH.map(b=>S.jsx("div",{onClick:()=>v(b.class),children:S.jsx("div",{className:Z2("w-6 mx-1 py-1 rounded-md text-black text-center cursor-pointer hover:bg-gray-200",[b.class,{"bg-gray-100":c.includes(b.class)}]),children:b.content})},b.name))})})},Zf=j6.child({name:"MessageLayer"}),Bf=i=>{const e=i1(B9),t=R.useMemo(()=>{const c=Qn(e);return c.length===0?$e:c[0].from||$e},[e]),n=E4(t)+1,[s,l]=R.useState(!1);return s&&Zf.debug("MessageLayer updated"),R.useEffect(()=>{l(!0),Zf.debug("MessageLayer mounted")},[]),S.jsxs("div",{className:"message-layer relative z-30 pt-14 pb-10",style:i.style,children:[S.jsx(S3,{context:i.context,style:{paddingLeft:`${n}px`},origin:t}),S.jsx(xH,{})]})},Gf=i=>{const e=i1(G9),t=i1(I4),n=i1(B9),s=i1(at),l=k0($i),c=R.useRef(null);R.useEffect(()=>{l(c.current)}),R.useImperativeHandle(i.ref,()=>c.current);const d=R.useMemo(()=>{const _=s.orderedParticipantNames(),m=new w8(_).getFrame(n);return m?M8(m).left:0},[s,n]),L=R.useMemo(()=>Sg(n,s)-d,[n,s,d]);return S.jsx("div",{className:Z2("zenuml sequence-diagram relative box-border text-left overflow-visible px-2.5",e,i.className),style:i.style,ref:c,children:S.jsx("div",{style:{paddingLeft:`${d}px`},className:"relative z-container",children:t===F3.Dynamic?S.jsxs(S.Fragment,{children:[S.jsx(Yr,{leftGap:d,context:n==null?void 0:n.head(),renderLifeLine:!0}),S.jsx(Bf,{context:n==null?void 0:n.block(),style:{width:`${L}px`}}),S.jsx(Yr,{leftGap:d,context:n==null?void 0:n.head(),renderParticipants:!0})]}):S.jsxs(S.Fragment,{children:[S.jsx(Yr,{leftGap:d,context:n==null?void 0:n.head(),renderParticipants:!0,renderLifeLine:!0}),S.jsx(Bf,{context:n==null?void 0:n.block(),style:{width:`${L}px`}})]})})})},H8={backgroundColor:"white",filter:i=>{var e;return!((e=i==null?void 0:i.classList)!=null&&e.contains("hide-export"))}},wH=({ref:i,children:e})=>{const t=R.useRef(null),n=R.useRef(null),s=i1(B9),[l,c]=e4($L),[d,L]=e4(WL),[_,p]=e4(G9),[m,f]=e4(KL),h=i1(qL),v=i1(I4),b=s==null?void 0:s.title(),w=()=>{c(!0)},M=async()=>{if(t.current)return pC(t.current,H8)},N=async()=>{if(t.current)return gC(t.current,H8)},D=async()=>{if(t.current)return Nx(t.current,H8)},I=async()=>{if(t.current)return yx(t.current,H8)},Z=()=>{const K=Math.min(1,d+.1);L(K)},U=()=>{L(d-.1)},k=K=>{const X="zenuml-style";let r2=document.getElementById(X)||document.createElement("style");r2=document.createElement("style"),r2.id=X,document.head.append(r2),r2.textContent=K},n2=K=>{const X=new URL(K).hostname;if(X==="https://github.com"||X==="https://githubusercontent.com"){fetch(K.replace("github.com","raw.githubusercontent.com").replace("blob/","")).then(g2=>g2.text()).then(g2=>{k(g2)});return}const r2="zenuml-remote-css";let t2=document.getElementById(r2)||document.createElement("link");t2=document.createElement("link"),t2.id=r2,t2.rel="stylesheet",document.head.append(t2),t2.href=K};return R.useImperativeHandle(i,()=>({toPng:M,toSvg:N,toBlob:D,toJpeg:I,zoomIn:Z,zoomOut:U,setTheme:p,setRemoteCss:n2})),S.jsxs("div",{ref:t,className:Z2("zenuml p-1 bg-skin-canvas inline-block",_),children:[S.jsx(Ew,{}),S.jsxs("div",{className:"frame text-skin-base bg-skin-frame border-skin-frame relative m-1 origin-top-left whitespace-nowrap border rounded",children:[S.jsxs("div",{ref:n,children:[S.jsxs("div",{className:"header text-skin-title bg-skin-title border-skin-frame border-b p-1 flex justify-between rounded-t",children:[S.jsx("div",{className:"left hide-export",children:e}),S.jsxs("div",{className:"right flex-grow flex justify-between",children:[S.jsx(Tw,{context:b}),S.jsx(Sw,{className:"hide-export flex items-center"})]})]}),l&&S.jsx("div",{className:"fixed z-40 inset-0 overflow-y-auto","aria-labelledby":"modal-title",role:"dialog","aria-modal":"true",children:S.jsx(HD,{})}),S.jsx(Gf,{className:"origin-top-left",style:{transform:`scale(${d})`}})]}),S.jsx("div",{className:"footer rounded text-skin-control bg-skin-title px-4 py-1 flex justify-between items-center gap-3",children:v===F3.Dynamic&&S.jsxs(S.Fragment,{children:[S.jsxs("div",{className:"flex items-center gap-3 color-base",children:[S.jsx("button",{className:"bottom-1 flex items-center left-1 hide-export",onClick:w,children:S.jsx(Ce,{name:"tip",className:"filter grayscale w-4 h-4"})}),h&&S.jsx($F,{}),S.jsxs("div",{className:"flex items-center",children:[S.jsx("input",{type:"checkbox",id:"order-display",className:"mr-1",checked:!!m,onChange:()=>f(!m)}),S.jsx("label",{htmlFor:"order-display",title:"Numbering the diagram",className:"select-none",children:S.jsx(Ce,{name:"numbering",className:"w-6 h-6"})})]})]}),S.jsxs("div",{className:"zoom-controls flex hide-export gap-1",children:[S.jsx("button",{className:"zoom-in",onClick:Z,children:S.jsx(Ce,{name:"zoom-in",className:"w-4 h-4"})}),S.jsxs("label",{className:"w-12 block text-center",children:[Number(d*100).toFixed(0),"%"]}),S.jsx("button",{className:"zoom-out",onClick:U,children:S.jsx(Ce,{name:"zoom-out",className:"w-4 h-4"})})]}),S.jsx("a",{target:"_blank",href:"https://zenuml.com",className:"brand text-xs hover:underline",children:"ZenUML.com"})]})})]})]})},MH="3.32.
|
|
3395
|
+
`+i.slice(w.lineHead))};return RH(f.floating.current,()=>{l(!1)}),R.useEffect(()=>{n((b,w)=>{setTimeout(()=>{var N;const M=m.current;if(M.start=b.start.start,M.lineHead=Gi(i,M.start),M.prevLine=pb(i,M.start),M.leadingSpaces=((N=i.slice(M.lineHead).match(/^\s*/))==null?void 0:N[0])||"",M.prevLineIsComment=M.prevLine.trim().startsWith("//"),M.prevLineIsComment){const D=M.prevLine.trimStart().slice(2).trimStart(),I=D.indexOf("["),Z=D.indexOf("]");M.hasStyleBrackets=!!(I===0&&Z),M.hasStyleBrackets?d(D.slice(I+1,Z).split(",").map(U=>U.trim())):d([])}f.setReference(w),_(b),l(!0)},0)})},[i,f,n]),S.jsx("div",{id:"style-panel",ref:f.setFloating,style:h,children:s&&S.jsx("div",{className:"flex bg-white shadow-md z-10 rounded-md p-1",children:bH.map(b=>S.jsx("div",{onClick:()=>v(b.class),children:S.jsx("div",{className:Z2("w-6 mx-1 py-1 rounded-md text-black text-center cursor-pointer hover:bg-gray-200",[b.class,{"bg-gray-100":c.includes(b.class)}]),children:b.content})},b.name))})})},Zf=j6.child({name:"MessageLayer"}),Bf=i=>{const e=i1(B9),t=R.useMemo(()=>{const c=Qn(e);return c.length===0?$e:c[0].from||$e},[e]),n=E4(t)+1,[s,l]=R.useState(!1);return s&&Zf.debug("MessageLayer updated"),R.useEffect(()=>{l(!0),Zf.debug("MessageLayer mounted")},[]),S.jsxs("div",{className:"message-layer relative z-30 pt-14 pb-10",style:i.style,children:[S.jsx(S3,{context:i.context,style:{paddingLeft:`${n}px`},origin:t}),S.jsx(xH,{})]})},Gf=i=>{const e=i1(G9),t=i1(I4),n=i1(B9),s=i1(at),l=k0($i),c=R.useRef(null);R.useEffect(()=>{l(c.current)}),R.useImperativeHandle(i.ref,()=>c.current);const d=R.useMemo(()=>{const _=s.orderedParticipantNames(),m=new w8(_).getFrame(n);return m?M8(m).left:0},[s,n]),L=R.useMemo(()=>Sg(n,s)-d,[n,s,d]);return S.jsx("div",{className:Z2("zenuml sequence-diagram relative box-border text-left overflow-visible px-2.5",e,i.className),style:i.style,ref:c,children:S.jsx("div",{style:{paddingLeft:`${d}px`},className:"relative z-container",children:t===F3.Dynamic?S.jsxs(S.Fragment,{children:[S.jsx(Yr,{leftGap:d,context:n==null?void 0:n.head(),renderLifeLine:!0}),S.jsx(Bf,{context:n==null?void 0:n.block(),style:{width:`${L}px`}}),S.jsx(Yr,{leftGap:d,context:n==null?void 0:n.head(),renderParticipants:!0})]}):S.jsxs(S.Fragment,{children:[S.jsx(Yr,{leftGap:d,context:n==null?void 0:n.head(),renderParticipants:!0,renderLifeLine:!0}),S.jsx(Bf,{context:n==null?void 0:n.block(),style:{width:`${L}px`}})]})})})},H8={backgroundColor:"white",filter:i=>{var e;return!((e=i==null?void 0:i.classList)!=null&&e.contains("hide-export"))}},wH=({ref:i,children:e})=>{const t=R.useRef(null),n=R.useRef(null),s=i1(B9),[l,c]=e4($L),[d,L]=e4(WL),[_,p]=e4(G9),[m,f]=e4(KL),h=i1(qL),v=i1(I4),b=s==null?void 0:s.title(),w=()=>{c(!0)},M=async()=>{if(t.current)return pC(t.current,H8)},N=async()=>{if(t.current)return gC(t.current,H8)},D=async()=>{if(t.current)return Nx(t.current,H8)},I=async()=>{if(t.current)return yx(t.current,H8)},Z=()=>{const K=Math.min(1,d+.1);L(K)},U=()=>{L(d-.1)},k=K=>{const X="zenuml-style";let r2=document.getElementById(X)||document.createElement("style");r2=document.createElement("style"),r2.id=X,document.head.append(r2),r2.textContent=K},n2=K=>{const X=new URL(K).hostname;if(X==="https://github.com"||X==="https://githubusercontent.com"){fetch(K.replace("github.com","raw.githubusercontent.com").replace("blob/","")).then(g2=>g2.text()).then(g2=>{k(g2)});return}const r2="zenuml-remote-css";let t2=document.getElementById(r2)||document.createElement("link");t2=document.createElement("link"),t2.id=r2,t2.rel="stylesheet",document.head.append(t2),t2.href=K};return R.useImperativeHandle(i,()=>({toPng:M,toSvg:N,toBlob:D,toJpeg:I,zoomIn:Z,zoomOut:U,setTheme:p,setRemoteCss:n2})),S.jsxs("div",{ref:t,className:Z2("zenuml p-1 bg-skin-canvas inline-block",_),children:[S.jsx(Ew,{}),S.jsxs("div",{className:"frame text-skin-base bg-skin-frame border-skin-frame relative m-1 origin-top-left whitespace-nowrap border rounded",children:[S.jsxs("div",{ref:n,children:[S.jsxs("div",{className:"header text-skin-title bg-skin-title border-skin-frame border-b p-1 flex justify-between rounded-t",children:[S.jsx("div",{className:"left hide-export",children:e}),S.jsxs("div",{className:"right flex-grow flex justify-between",children:[S.jsx(Tw,{context:b}),S.jsx(Sw,{className:"hide-export flex items-center"})]})]}),l&&S.jsx("div",{className:"fixed z-40 inset-0 overflow-y-auto","aria-labelledby":"modal-title",role:"dialog","aria-modal":"true",children:S.jsx(HD,{})}),S.jsx(Gf,{className:"origin-top-left",style:{transform:`scale(${d})`}})]}),S.jsx("div",{className:"footer rounded text-skin-control bg-skin-title px-4 py-1 flex justify-between items-center gap-3",children:v===F3.Dynamic&&S.jsxs(S.Fragment,{children:[S.jsxs("div",{className:"flex items-center gap-3 color-base",children:[S.jsx("button",{className:"bottom-1 flex items-center left-1 hide-export",onClick:w,children:S.jsx(Ce,{name:"tip",className:"filter grayscale w-4 h-4"})}),h&&S.jsx($F,{}),S.jsxs("div",{className:"flex items-center",children:[S.jsx("input",{type:"checkbox",id:"order-display",className:"mr-1",checked:!!m,onChange:()=>f(!m)}),S.jsx("label",{htmlFor:"order-display",title:"Numbering the diagram",className:"select-none",children:S.jsx(Ce,{name:"numbering",className:"w-6 h-6"})})]})]}),S.jsxs("div",{className:"zoom-controls flex hide-export gap-1",children:[S.jsx("button",{className:"zoom-in",onClick:Z,children:S.jsx(Ce,{name:"zoom-in",className:"w-4 h-4"})}),S.jsxs("label",{className:"w-12 block text-center",children:[Number(d*100).toFixed(0),"%"]}),S.jsx("button",{className:"zoom-out",onClick:U,children:S.jsx(Ce,{name:"zoom-out",className:"w-4 h-4"})})]}),S.jsx("a",{target:"_blank",href:"https://zenuml.com",className:"brand text-xs hover:underline",children:"ZenUML.com"})]})})]})]})},MH="3.32.5";function AH(i){const e=Math.floor(i/1e3),t=Math.floor(i%1e3),n=Math.floor((i%1e3-t)*1e3);return e+"s "+t+"ms "+n+"μs"}const yH=(i,e)=>{const n=zf()-e;return console.debug(i+" cost: "+AH(n)),n},zf=()=>performance.now();var Fl={exports:{}},E5={},Ul={exports:{}},Zl={};/**
|
|
3396
3396
|
* @license React
|
|
3397
3397
|
* scheduler.production.js
|
|
3398
3398
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenuml/core",
|
|
3
|
-
"version": "3.32.
|
|
3
|
+
"version": "3.32.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -13,10 +13,13 @@
|
|
|
13
13
|
"build:gh-pages": "vite build --mode gh-pages",
|
|
14
14
|
"build": "vite build -c vite.config.lib.ts",
|
|
15
15
|
"test": "vitest",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
16
|
+
"pw": "playwright test",
|
|
17
|
+
"pw:ci": "playwright test --reporter=github",
|
|
18
|
+
"pw:update": "playwright test --update-snapshots",
|
|
19
|
+
"pw:update-ci": "playwright test --update-snapshots --reporter=github",
|
|
20
|
+
"pw:ui": "playwright test --ui",
|
|
21
|
+
"pw:smoke": "playwright test smoke",
|
|
22
|
+
"pw:install": "playwright install",
|
|
20
23
|
"antlr:setup": "python3 -m pip install antlr4-tools",
|
|
21
24
|
"antlr:generate": "pwd && cd ./src/g4-units/hello-world && antlr4 Hello.g4",
|
|
22
25
|
"antlr:javac": "pwd && cd ./src/g4-units/hello-world && CLASSPATH=\"../../../antlr/antlr-4.11.1-complete.jar:$CLASSPATH\" javac *.java",
|
|
@@ -31,16 +34,11 @@
|
|
|
31
34
|
"git:branch:clean:merged": "git branch --merged|egrep -v \"(\\*|master|main|dev|skip_branch_name)\" | xargs git branch -d",
|
|
32
35
|
"git:branch:safe-delete": "echo '> git log --graph --left-right --cherry --oneline another-branch...main'",
|
|
33
36
|
"git:forget": "git rm -r --cached . && git add . && git commit -m \"Forget all ignored files\"",
|
|
34
|
-
"test:specs": "echo \"Error: test:specs is not supported\""
|
|
35
|
-
"prepare": "husky install"
|
|
37
|
+
"test:specs": "echo \"Error: test:specs is not supported\""
|
|
36
38
|
},
|
|
37
39
|
"main": "./dist/zenuml.js",
|
|
38
40
|
"module": "./dist/zenuml.esm.mjs",
|
|
39
41
|
"types": "./types/index.d.ts",
|
|
40
|
-
"lint-staged": {
|
|
41
|
-
"**/*": "prettier --write --ignore-unknown",
|
|
42
|
-
"*.{js,ts,tsx,jsx,json,htm,html}": "eslint --fix"
|
|
43
|
-
},
|
|
44
42
|
"engines": {
|
|
45
43
|
"node": ">=20"
|
|
46
44
|
},
|
|
@@ -80,6 +78,7 @@
|
|
|
80
78
|
},
|
|
81
79
|
"devDependencies": {
|
|
82
80
|
"@eslint/js": "^9.21.0",
|
|
81
|
+
"@playwright/test": "^1.54.1",
|
|
83
82
|
"@testing-library/jest-dom": "^6.6.3",
|
|
84
83
|
"@testing-library/react": "^16.3.0",
|
|
85
84
|
"@types/antlr4": "~4.11.2",
|
|
@@ -93,17 +92,13 @@
|
|
|
93
92
|
"@types/react-dom": "^19.0.4",
|
|
94
93
|
"@vitejs/plugin-react": "^4.3.4",
|
|
95
94
|
"autoprefixer": "^10.4.21",
|
|
96
|
-
"cypress": "^14.3.2",
|
|
97
|
-
"cypress-plugin-snapshots": "^1.4.4",
|
|
98
95
|
"eslint": "^9.21.0",
|
|
99
96
|
"eslint-config-prettier": "^10.1.1",
|
|
100
97
|
"eslint-plugin-react-hooks": "^5.1.0",
|
|
101
98
|
"eslint-plugin-react-refresh": "^0.4.19",
|
|
102
99
|
"globals": "^15.15.0",
|
|
103
|
-
"husky": "^9.1.7",
|
|
104
100
|
"jsdom": "^26.1.0",
|
|
105
101
|
"less": "^4.3.0",
|
|
106
|
-
"lint-staged": "^15.5.1",
|
|
107
102
|
"postcss": "^8.5.3",
|
|
108
103
|
"prettier": "3.5.3",
|
|
109
104
|
"sass": "^1.86.3",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { defineConfig, devices } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
testDir: "./tests",
|
|
5
|
+
fullyParallel: true,
|
|
6
|
+
forbidOnly: !!process.env.CI,
|
|
7
|
+
retries: process.env.CI ? 2 : 0,
|
|
8
|
+
workers: process.env.CI ? 1 : undefined,
|
|
9
|
+
reporter: process.env.CI
|
|
10
|
+
? [["github"], ["html", { open: "never" }]]
|
|
11
|
+
: [["html"]],
|
|
12
|
+
use: {
|
|
13
|
+
baseURL: "http://127.0.0.1:8080",
|
|
14
|
+
trace: "on-first-retry",
|
|
15
|
+
screenshot: "only-on-failure",
|
|
16
|
+
},
|
|
17
|
+
projects: [
|
|
18
|
+
{
|
|
19
|
+
name: "chromium",
|
|
20
|
+
use: {
|
|
21
|
+
...devices["Desktop Chrome"],
|
|
22
|
+
viewport: { width: 1200, height: 800 },
|
|
23
|
+
// Force color profile like Cypress config
|
|
24
|
+
launchOptions: {
|
|
25
|
+
args: ["--force-color-profile=srgb"],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
webServer: {
|
|
31
|
+
command: "pnpm preview",
|
|
32
|
+
url: "http://127.0.0.1:8080",
|
|
33
|
+
reuseExistingServer: !process.env.CI,
|
|
34
|
+
timeout: 120 * 1000,
|
|
35
|
+
},
|
|
36
|
+
});
|
package/vite.config.ts
CHANGED
package/.husky/pre-commit
DELETED
package/cypress.config.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "cypress";
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
projectId: "srixxa",
|
|
5
|
-
e2e: {
|
|
6
|
-
viewportWidth: 1200,
|
|
7
|
-
viewportHeight: 800,
|
|
8
|
-
// We've imported your old cypress plugins here.
|
|
9
|
-
// You may want to clean this up later by importing these.
|
|
10
|
-
setupNodeEvents(on, config) {
|
|
11
|
-
return require("./cypress/plugins/index.js")(on, config);
|
|
12
|
-
},
|
|
13
|
-
excludeSpecPattern: ["**/__snapshots__/*", "**/__image_snapshots__/*"],
|
|
14
|
-
specPattern: "cypress/e2e/**/*.{js,jsx,ts,tsx}",
|
|
15
|
-
},
|
|
16
|
-
});
|