@calca/canvas-ui 0.0.0-stage → 0.7.3
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 +8 -2
- package/dist/index.d.mts +64 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +280 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +48 -4
package/README.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @calca/canvas-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Headless canvas UI components for Calca — presentational React pieces for canvas surfaces: `DesignFrame` (generated-frame chrome), `DesignCard`, `PipelineStatusOverlay`, `RubberBandOverlay` (marquee selection), `useMountEffect`. No React Flow or document-model dependency — pair with `@calca/canvas-flow` for the full surface.
|
|
4
|
+
|
|
5
|
+
Part of [Calca](https://calca.illo.fyi) — open source.
|
|
6
|
+
|
|
7
|
+
## License
|
|
8
|
+
|
|
9
|
+
Apache-2.0
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Comment, DesignIteration, PipelineStatus, Point } from "@calca/shared";
|
|
2
|
+
//#region src/components/DesignFrame.d.ts
|
|
3
|
+
export declare const DEFAULT_FRAME_WIDTH = 480;
|
|
4
|
+
interface DesignFrameProps {
|
|
5
|
+
iteration: DesignIteration;
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: React.CSSProperties;
|
|
10
|
+
isCommentMode?: boolean;
|
|
11
|
+
isSelectMode?: boolean;
|
|
12
|
+
isSelected?: boolean;
|
|
13
|
+
isDragging?: boolean;
|
|
14
|
+
scale?: number;
|
|
15
|
+
onClick?: (e: React.MouseEvent) => void;
|
|
16
|
+
onMouseDown?: (e: React.MouseEvent) => void;
|
|
17
|
+
onAddComment?: (iterationId: string, position: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
}, screenX: number, screenY: number) => void;
|
|
21
|
+
onClickComment?: (comment: Comment, iterationId: string) => void;
|
|
22
|
+
}
|
|
23
|
+
export declare function DesignFrame({ iteration, width, height: _height, className, style, isCommentMode, isSelectMode, isSelected, isDragging, scale, onClick, onMouseDown, onAddComment, onClickComment }: DesignFrameProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/components/DesignCard.d.ts
|
|
26
|
+
interface DesignCardProps {
|
|
27
|
+
iteration: DesignIteration;
|
|
28
|
+
isCommentMode: boolean;
|
|
29
|
+
isSelectMode: boolean;
|
|
30
|
+
isDragging: boolean;
|
|
31
|
+
isSelected?: boolean;
|
|
32
|
+
onSelect?: (e?: React.MouseEvent) => void;
|
|
33
|
+
onAddComment: (iterationId: string, position: Point, screenX: number, screenY: number) => void;
|
|
34
|
+
onClickComment: (comment: Comment, iterationId: string) => void;
|
|
35
|
+
onDragStart: (e: React.MouseEvent) => void;
|
|
36
|
+
scale: number;
|
|
37
|
+
}
|
|
38
|
+
export declare function DesignCard({ iteration, isCommentMode, isSelectMode, isDragging, isSelected, onSelect, onAddComment, onClickComment, onDragStart, scale }: DesignCardProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/components/PipelineStatusOverlay.d.ts
|
|
41
|
+
interface PipelineStatusBarProps {
|
|
42
|
+
status: PipelineStatus;
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
width: number;
|
|
46
|
+
frameHeight: number;
|
|
47
|
+
}
|
|
48
|
+
export declare function PipelineStatusOverlay({ status, x, y, width, frameHeight }: PipelineStatusBarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/components/RubberBandOverlay.d.ts
|
|
51
|
+
interface RubberBandOverlayProps {
|
|
52
|
+
rubberBand: {
|
|
53
|
+
startX: number;
|
|
54
|
+
startY: number;
|
|
55
|
+
currentX: number;
|
|
56
|
+
currentY: number;
|
|
57
|
+
} | null;
|
|
58
|
+
}
|
|
59
|
+
export declare function RubberBandOverlay({ rubberBand }: RubberBandOverlayProps): import("react/jsx-runtime").JSX.Element | null;
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/utils/use-mount-effect.d.ts
|
|
62
|
+
export declare function useMountEffect(effect: () => void | (() => void)): void;
|
|
63
|
+
//#endregion
|
|
64
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":["CommentType","CommentType"],"sources":["../src/components/DesignFrame.tsx","../src/components/DesignCard.tsx","../src/components/PipelineStatusOverlay.tsx","../src/components/RubberBandOverlay.tsx","../src/utils/use-mount-effect.ts"],"mappings":";;qBAgBa;UAIH;EACR,WAAW;EACX;EACA;EACA;EACA,QAAQ,MAAM;EACd;EACA;EACA;EACA;EACA;EACA,WAAW,GAAG,MAAM;EACpB,eAAe,GAAG,MAAM;EACxB,gBACE,qBACA;IAAY;IAAW;KACvB,iBACA;EAEF,kBAAkB,SAASA,SAAa;;wBAG1B,cACd,WACA,OACA,QAAQ,SACR,WACA,OACA,eACA,cACA,YACA,YACA,OACA,SACA,aACA,cACA,kBACC,+CAAgB,IAAA;;;UCnDT;EACR,WAAW;EACX;EACA;EACA;EACA;EACA,YAAY,IAAI,MAAM;EACtB,eAAe,qBAAqB,UAAU,OAAO,iBAAiB;EACtE,iBAAiB,SAASC,SAAa;EACvC,cAAc,GAAG,MAAM;EACvB;;wBAGc,aACd,WACA,eACA,cACA,YACA,YACA,UACA,cACA,gBACA,aACA,SACC,8CAAe,IAAA;;;UC5BR;EACR,QAAQ;EACR;EACA;EACA;EACA;;wBAGc,wBACd,QACA,GACA,GACA,OACA,eACC,qDAAsB,IAAA;;;UChBf;EACR;IACE;IACA;IACA;IACA;;;wBAIY,oBAAoB,cAAc,qDAAsB,IAAA;;;wBCNxD,eAAe"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { Loader } from "lucide-react";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { STAGE_CONFIG } from "@calca/shared";
|
|
5
|
+
|
|
6
|
+
//#region src/utils/use-mount-effect.ts
|
|
7
|
+
function useMountEffect(effect) {
|
|
8
|
+
useEffect(effect, []);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/components/DesignFrame.tsx
|
|
13
|
+
const getTailwindScriptSrc = () => {
|
|
14
|
+
if (typeof window !== "undefined" && window.__CALCA_DESKTOP__) return `${window.location.origin}/tailwindcss.js`;
|
|
15
|
+
return "https://cdn.tailwindcss.com";
|
|
16
|
+
};
|
|
17
|
+
const DEFAULT_FRAME_WIDTH = 480;
|
|
18
|
+
const FRAME_WIDTH = 480;
|
|
19
|
+
const INITIAL_IFRAME_HEIGHT = 2e3;
|
|
20
|
+
function DesignFrame({ iteration, width, height: _height, className = "", style, isCommentMode, isSelectMode, isSelected, isDragging, scale = 1, onClick, onMouseDown, onAddComment, onClickComment }) {
|
|
21
|
+
const iframeRef = useRef(null);
|
|
22
|
+
const wrapperRef = useRef(null);
|
|
23
|
+
const [contentHeight, setContentHeight] = useState(320);
|
|
24
|
+
const measuredRef = useRef(false);
|
|
25
|
+
const measurementGenRef = useRef(0);
|
|
26
|
+
const frameW = width || iteration.width || FRAME_WIDTH;
|
|
27
|
+
const srcdoc = iteration.html && !iteration.isLoading ? `<!DOCTYPE html>
|
|
28
|
+
<html style="height:auto;overflow:hidden;"><head>
|
|
29
|
+
<meta charset="utf-8">
|
|
30
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
31
|
+
<script src="${getTailwindScriptSrc()}"><\/script>
|
|
32
|
+
<style>
|
|
33
|
+
html, body { margin: 0; padding: 0; height: auto !important; min-height: 0 !important; max-height: none !important; overflow: hidden; }
|
|
34
|
+
body { background: white; width: ${frameW}px; }
|
|
35
|
+
#calca-measure { width: ${frameW}px; overflow: hidden; }
|
|
36
|
+
img, video, svg { max-width: 100%; height: auto; display: block; object-fit: cover; }
|
|
37
|
+
* { animation: none !important; transition: none !important; }
|
|
38
|
+
[style*="100vh"], [style*="min-height: 100vh"], [style*="height: 100vh"] { height: auto !important; min-height: 0 !important; }
|
|
39
|
+
</style>
|
|
40
|
+
</head><body><div id="calca-measure" data-gen="${measurementGenRef.current}">${iteration.html}</div>
|
|
41
|
+
<script>
|
|
42
|
+
var GEN = ${measurementGenRef.current};
|
|
43
|
+
function reportHeight() {
|
|
44
|
+
var el = document.getElementById('calca-measure');
|
|
45
|
+
if (!el) return;
|
|
46
|
+
var h = el.offsetHeight || el.scrollHeight || 100;
|
|
47
|
+
parent.postMessage({ type: 'calca-frame-height', id: '${iteration.id}', height: h, gen: GEN }, '*');
|
|
48
|
+
}
|
|
49
|
+
setTimeout(reportHeight, 300);
|
|
50
|
+
setTimeout(reportHeight, 800);
|
|
51
|
+
setTimeout(reportHeight, 2000);
|
|
52
|
+
<\/script></body></html>` : void 0;
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!iteration.html || iteration.isLoading) return;
|
|
55
|
+
measuredRef.current = false;
|
|
56
|
+
measurementGenRef.current += 1;
|
|
57
|
+
const currentGen = measurementGenRef.current;
|
|
58
|
+
if (iteration.height) setContentHeight(iteration.height);
|
|
59
|
+
const onMessage = (e) => {
|
|
60
|
+
if (e.data?.type === "calca-frame-height" && e.data.id === iteration.id && e.data.gen === currentGen) {
|
|
61
|
+
const h = Math.min(Math.max(e.data.height, 50), 12e3);
|
|
62
|
+
if (!iteration.height || iteration.height === 0 || Math.abs(h - iteration.height) > 30) {
|
|
63
|
+
setContentHeight(h);
|
|
64
|
+
measuredRef.current = true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
window.addEventListener("message", onMessage);
|
|
69
|
+
return () => window.removeEventListener("message", onMessage);
|
|
70
|
+
}, [
|
|
71
|
+
iteration.html,
|
|
72
|
+
iteration.isLoading,
|
|
73
|
+
iteration.id,
|
|
74
|
+
iteration.height
|
|
75
|
+
]);
|
|
76
|
+
const handleClick = (e) => {
|
|
77
|
+
if (isCommentMode && onAddComment && wrapperRef.current) {
|
|
78
|
+
e.stopPropagation();
|
|
79
|
+
const rect = wrapperRef.current.getBoundingClientRect();
|
|
80
|
+
const x = (e.clientX - rect.left) / scale;
|
|
81
|
+
const y = (e.clientY - rect.top) / scale;
|
|
82
|
+
onAddComment(iteration.id, {
|
|
83
|
+
x,
|
|
84
|
+
y
|
|
85
|
+
}, e.clientX, e.clientY);
|
|
86
|
+
}
|
|
87
|
+
onClick?.(e);
|
|
88
|
+
};
|
|
89
|
+
const frameHeight = iteration.isLoading ? 320 : contentHeight;
|
|
90
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
91
|
+
ref: wrapperRef,
|
|
92
|
+
"data-tour": "design-frame",
|
|
93
|
+
onClick: handleClick,
|
|
94
|
+
onMouseDown,
|
|
95
|
+
className: `relative bg-white rounded-xl shadow-md border overflow-hidden transition-shadow ${isSelected ? "ring-2 ring-blue-500 border-blue-400/50 shadow-lg" : "border-gray-200/80"} ${isCommentMode ? "cursor-crosshair ring-2 ring-blue-400/20 hover:ring-blue-400/40" : isSelectMode ? isDragging ? "cursor-grabbing shadow-xl ring-2 ring-blue-400/30" : "cursor-grab hover:shadow-lg" : ""} ${className}`,
|
|
96
|
+
style: {
|
|
97
|
+
...style,
|
|
98
|
+
height: frameHeight,
|
|
99
|
+
width: frameW
|
|
100
|
+
},
|
|
101
|
+
children: [iteration.isLoading ? /* @__PURE__ */ jsxs("div", {
|
|
102
|
+
className: "w-full h-full flex flex-col items-center justify-center gap-4",
|
|
103
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
104
|
+
className: "relative w-10 h-10",
|
|
105
|
+
children: /* @__PURE__ */ jsx(Loader, { className: "w-10 h-10 animate-spin" })
|
|
106
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
107
|
+
className: "text-[12px] font-medium text-gray-400",
|
|
108
|
+
children: "Generating…"
|
|
109
|
+
})]
|
|
110
|
+
}) : /* @__PURE__ */ jsx("iframe", {
|
|
111
|
+
ref: iframeRef,
|
|
112
|
+
title: iteration.label,
|
|
113
|
+
sandbox: "allow-scripts",
|
|
114
|
+
srcDoc: srcdoc,
|
|
115
|
+
style: {
|
|
116
|
+
border: "none",
|
|
117
|
+
display: "block",
|
|
118
|
+
height: measuredRef.current ? contentHeight : iteration.height || INITIAL_IFRAME_HEIGHT,
|
|
119
|
+
pointerEvents: "none",
|
|
120
|
+
width: frameW
|
|
121
|
+
}
|
|
122
|
+
}), isCommentMode && onClickComment && onAddComment && iteration.comments.map((comment) => /* @__PURE__ */ jsx(CommentPin, {
|
|
123
|
+
comment,
|
|
124
|
+
onClick: () => onClickComment(comment, iteration.id)
|
|
125
|
+
}, comment.id))]
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const STATUS_COLORS = {
|
|
129
|
+
done: {
|
|
130
|
+
bg: "bg-emerald-500",
|
|
131
|
+
shadow: "rgba(16,185,129,0.4)",
|
|
132
|
+
anchor: "bg-emerald-400/60",
|
|
133
|
+
ping: "bg-emerald-400/30"
|
|
134
|
+
},
|
|
135
|
+
waiting: {
|
|
136
|
+
bg: "bg-gray-400",
|
|
137
|
+
shadow: "rgba(156,163,175,0.4)",
|
|
138
|
+
anchor: "bg-gray-400/60",
|
|
139
|
+
ping: "bg-gray-400/30"
|
|
140
|
+
},
|
|
141
|
+
working: {
|
|
142
|
+
bg: "bg-amber-500",
|
|
143
|
+
shadow: "rgba(245,158,11,0.4)",
|
|
144
|
+
anchor: "bg-amber-400/60",
|
|
145
|
+
ping: "bg-amber-400/30"
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
function CommentPin({ comment, onClick }) {
|
|
149
|
+
const [isNew, setIsNew] = useState(true);
|
|
150
|
+
useMountEffect(() => {
|
|
151
|
+
const timer = setTimeout(() => setIsNew(false), 2e3);
|
|
152
|
+
return () => clearTimeout(timer);
|
|
153
|
+
});
|
|
154
|
+
const status = comment.status || "waiting";
|
|
155
|
+
const colors = STATUS_COLORS[status];
|
|
156
|
+
const isWorking = status === "working";
|
|
157
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
158
|
+
className: "absolute z-20",
|
|
159
|
+
style: {
|
|
160
|
+
left: comment.position.x - 14,
|
|
161
|
+
top: comment.position.y - 14
|
|
162
|
+
},
|
|
163
|
+
children: [
|
|
164
|
+
(isNew || isWorking) && /* @__PURE__ */ jsx("span", { className: `absolute inset-0 rounded-full ${colors.ping} animate-ping` }),
|
|
165
|
+
/* @__PURE__ */ jsx("span", { className: `absolute left-1/2 -translate-x-1/2 top-full w-0.5 h-2 ${colors.anchor}` }),
|
|
166
|
+
/* @__PURE__ */ jsx("button", {
|
|
167
|
+
className: `relative w-7 h-7 rounded-full ${colors.bg} text-white text-[11px] font-bold flex items-center justify-center hover:scale-110 transition-all cursor-pointer border-2 border-white`,
|
|
168
|
+
style: { boxShadow: `0 2px 8px ${colors.shadow}` },
|
|
169
|
+
onClick: (e) => {
|
|
170
|
+
e.stopPropagation();
|
|
171
|
+
onClick();
|
|
172
|
+
},
|
|
173
|
+
title: comment.aiResponse || comment.text,
|
|
174
|
+
children: status === "done" ? "✓" : comment.number
|
|
175
|
+
})
|
|
176
|
+
]
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/components/DesignCard.tsx
|
|
182
|
+
function DesignCard({ iteration, isCommentMode, isSelectMode, isDragging, isSelected, onSelect, onAddComment, onClickComment, onDragStart, scale }) {
|
|
183
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
184
|
+
className: `absolute ${isDragging ? "z-50" : ""}`,
|
|
185
|
+
style: {
|
|
186
|
+
left: iteration.position.x,
|
|
187
|
+
top: iteration.position.y,
|
|
188
|
+
width: iteration.width || 480
|
|
189
|
+
},
|
|
190
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
191
|
+
className: "mb-2 flex items-center gap-2 group/label",
|
|
192
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
193
|
+
className: "text-xs font-medium text-gray-500/80 bg-white/60 backdrop-blur-sm px-2.5 py-0.5 rounded-lg border border-white/40",
|
|
194
|
+
children: iteration.label
|
|
195
|
+
})
|
|
196
|
+
}), /* @__PURE__ */ jsx(DesignFrame, {
|
|
197
|
+
iteration,
|
|
198
|
+
isCommentMode,
|
|
199
|
+
isSelectMode,
|
|
200
|
+
isSelected,
|
|
201
|
+
isDragging,
|
|
202
|
+
scale,
|
|
203
|
+
onClick: (e) => {
|
|
204
|
+
if (isSelectMode && onSelect) {
|
|
205
|
+
e.stopPropagation();
|
|
206
|
+
onSelect(e);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
onMouseDown: (e) => {
|
|
210
|
+
if (isSelectMode) {
|
|
211
|
+
e.stopPropagation();
|
|
212
|
+
onDragStart(e);
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
onAddComment: (iterationId, position, screenX, screenY) => onAddComment(iterationId, position, screenX, screenY),
|
|
216
|
+
onClickComment
|
|
217
|
+
})]
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/components/PipelineStatusOverlay.tsx
|
|
223
|
+
function PipelineStatusOverlay({ status, x, y, width, frameHeight }) {
|
|
224
|
+
const config = STAGE_CONFIG[status.stage];
|
|
225
|
+
const isDone = status.stage === "done";
|
|
226
|
+
const isError = status.stage === "error";
|
|
227
|
+
const isQueued = status.stage === "queued";
|
|
228
|
+
if (isDone) return null;
|
|
229
|
+
const topOffset = y + frameHeight + 8;
|
|
230
|
+
const value = Math.max(status.progress * 100, 5);
|
|
231
|
+
const indicatorClass = isError ? "bg-destructive" : "bg-gradient-to-r from-primary to-secondary";
|
|
232
|
+
const pulseClass = status.stage === "layout" || status.stage === "images" ? "animate-pulse" : "";
|
|
233
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
234
|
+
className: "absolute pointer-events-none",
|
|
235
|
+
style: {
|
|
236
|
+
left: x,
|
|
237
|
+
top: topOffset,
|
|
238
|
+
width
|
|
239
|
+
},
|
|
240
|
+
children: [!isQueued && /* @__PURE__ */ jsx("div", {
|
|
241
|
+
className: "h-1 w-full overflow-hidden rounded-full bg-primary/20",
|
|
242
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
243
|
+
className: `h-full transition-all ${indicatorClass} ${pulseClass}`,
|
|
244
|
+
style: { width: `${value}%` }
|
|
245
|
+
})
|
|
246
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
247
|
+
className: "flex items-center justify-between mt-1.5",
|
|
248
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
249
|
+
className: "text-[10px] font-medium text-muted-foreground whitespace-nowrap",
|
|
250
|
+
children: [
|
|
251
|
+
config.icon,
|
|
252
|
+
" ",
|
|
253
|
+
config.label
|
|
254
|
+
]
|
|
255
|
+
}), status.skipped && /* @__PURE__ */ jsxs("span", {
|
|
256
|
+
className: "text-[10px] font-medium text-destructive/80 whitespace-nowrap",
|
|
257
|
+
children: ["⏭ ", status.reason || "Skipped"]
|
|
258
|
+
})]
|
|
259
|
+
})]
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region src/components/RubberBandOverlay.tsx
|
|
265
|
+
function RubberBandOverlay({ rubberBand }) {
|
|
266
|
+
if (!rubberBand) return null;
|
|
267
|
+
return /* @__PURE__ */ jsx("div", {
|
|
268
|
+
className: "fixed pointer-events-none z-[60] border border-blue-400/50 bg-blue-400/10 rounded-sm",
|
|
269
|
+
style: {
|
|
270
|
+
height: Math.abs(rubberBand.currentY - rubberBand.startY),
|
|
271
|
+
left: Math.min(rubberBand.startX, rubberBand.currentX),
|
|
272
|
+
top: Math.min(rubberBand.startY, rubberBand.currentY),
|
|
273
|
+
width: Math.abs(rubberBand.currentX - rubberBand.startX)
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
//#endregion
|
|
279
|
+
export { DEFAULT_FRAME_WIDTH, DesignCard, DesignFrame, PipelineStatusOverlay, RubberBandOverlay, useMountEffect };
|
|
280
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/utils/use-mount-effect.ts","../src/components/DesignFrame.tsx","../src/components/DesignCard.tsx","../src/components/PipelineStatusOverlay.tsx","../src/components/RubberBandOverlay.tsx"],"sourcesContent":["import { useEffect } from \"react\";\n\n// oxlint-disable-next-line\nexport function useMountEffect(effect: () => void | (() => void)) {\n useEffect(effect, []);\n}\n","import type { Comment as CommentType, DesignIteration } from \"@calca/shared\";\nimport { Loader } from \"lucide-react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { useMountEffect } from \"../utils/use-mount-effect\";\n\nconst getTailwindScriptSrc = (): string => {\n if (\n typeof window !== \"undefined\" &&\n (window as unknown as { __CALCA_DESKTOP__?: boolean }).__CALCA_DESKTOP__\n ) {\n return `${window.location.origin}/tailwindcss.js`;\n }\n return \"https://cdn.tailwindcss.com\";\n};\n\nexport const DEFAULT_FRAME_WIDTH = 480;\nconst FRAME_WIDTH = DEFAULT_FRAME_WIDTH;\nconst INITIAL_IFRAME_HEIGHT = 2000;\n\ninterface DesignFrameProps {\n iteration: DesignIteration;\n width?: number;\n height?: number;\n className?: string;\n style?: React.CSSProperties;\n isCommentMode?: boolean;\n isSelectMode?: boolean;\n isSelected?: boolean;\n isDragging?: boolean;\n scale?: number;\n onClick?: (e: React.MouseEvent) => void;\n onMouseDown?: (e: React.MouseEvent) => void;\n onAddComment?: (\n iterationId: string,\n position: { x: number; y: number },\n screenX: number,\n screenY: number,\n ) => void;\n onClickComment?: (comment: CommentType, iterationId: string) => void;\n}\n\nexport function DesignFrame({\n iteration,\n width,\n height: _height,\n className = \"\",\n style,\n isCommentMode,\n isSelectMode,\n isSelected,\n isDragging,\n scale = 1,\n onClick,\n onMouseDown,\n onAddComment,\n onClickComment,\n}: DesignFrameProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const [contentHeight, setContentHeight] = useState(320);\n const measuredRef = useRef(false);\n const measurementGenRef = useRef(0);\n\n const frameW = width || iteration.width || FRAME_WIDTH;\n const srcdoc =\n iteration.html && !iteration.isLoading\n ? `<!DOCTYPE html>\n<html style=\"height:auto;overflow:hidden;\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script src=\"${getTailwindScriptSrc()}\"></script>\n <style>\n html, body { margin: 0; padding: 0; height: auto !important; min-height: 0 !important; max-height: none !important; overflow: hidden; }\n body { background: white; width: ${frameW}px; }\n #calca-measure { width: ${frameW}px; overflow: hidden; }\n img, video, svg { max-width: 100%; height: auto; display: block; object-fit: cover; }\n * { animation: none !important; transition: none !important; }\n [style*=\"100vh\"], [style*=\"min-height: 100vh\"], [style*=\"height: 100vh\"] { height: auto !important; min-height: 0 !important; }\n </style>\n</head><body><div id=\"calca-measure\" data-gen=\"${measurementGenRef.current}\">${iteration.html}</div>\n<script>\nvar GEN = ${measurementGenRef.current};\nfunction reportHeight() {\n var el = document.getElementById('calca-measure');\n if (!el) return;\n var h = el.offsetHeight || el.scrollHeight || 100;\n parent.postMessage({ type: 'calca-frame-height', id: '${iteration.id}', height: h, gen: GEN }, '*');\n}\nsetTimeout(reportHeight, 300);\nsetTimeout(reportHeight, 800);\nsetTimeout(reportHeight, 2000);\n</script></body></html>`\n : undefined;\n\n // oxlint-disable-next-line\n useEffect(() => {\n if (!iteration.html || iteration.isLoading) {\n return;\n }\n measuredRef.current = false;\n measurementGenRef.current += 1;\n const currentGen = measurementGenRef.current;\n\n if (iteration.height) {\n setContentHeight(iteration.height);\n }\n\n const onMessage = (e: MessageEvent) => {\n if (\n e.data?.type === \"calca-frame-height\" &&\n e.data.id === iteration.id &&\n e.data.gen === currentGen\n ) {\n const h = Math.min(Math.max(e.data.height, 50), 12_000);\n if (!iteration.height || iteration.height === 0 || Math.abs(h - iteration.height) > 30) {\n setContentHeight(h);\n measuredRef.current = true;\n }\n }\n };\n window.addEventListener(\"message\", onMessage);\n return () => window.removeEventListener(\"message\", onMessage);\n }, [iteration.html, iteration.isLoading, iteration.id, iteration.height]);\n\n const handleClick = (e: React.MouseEvent) => {\n if (isCommentMode && onAddComment && wrapperRef.current) {\n e.stopPropagation();\n const rect = wrapperRef.current.getBoundingClientRect();\n const x = (e.clientX - rect.left) / scale;\n const y = (e.clientY - rect.top) / scale;\n onAddComment(iteration.id, { x, y }, e.clientX, e.clientY);\n }\n onClick?.(e);\n };\n\n const frameHeight = iteration.isLoading ? 320 : contentHeight;\n\n return (\n <div\n ref={wrapperRef}\n data-tour=\"design-frame\"\n onClick={handleClick}\n onMouseDown={onMouseDown}\n className={`relative bg-white rounded-xl shadow-md border overflow-hidden transition-shadow ${\n isSelected ? \"ring-2 ring-blue-500 border-blue-400/50 shadow-lg\" : \"border-gray-200/80\"\n } ${\n isCommentMode\n ? \"cursor-crosshair ring-2 ring-blue-400/20 hover:ring-blue-400/40\"\n : isSelectMode\n ? isDragging\n ? \"cursor-grabbing shadow-xl ring-2 ring-blue-400/30\"\n : \"cursor-grab hover:shadow-lg\"\n : \"\"\n } ${className}`}\n style={{ ...style, height: frameHeight, width: frameW }}\n >\n {iteration.isLoading ? (\n <div className=\"w-full h-full flex flex-col items-center justify-center gap-4\">\n <div className=\"relative w-10 h-10\">\n <Loader className=\"w-10 h-10 animate-spin\" />\n </div>\n <span className=\"text-[12px] font-medium text-gray-400\">Generating…</span>\n </div>\n ) : (\n <iframe\n ref={iframeRef}\n title={iteration.label}\n sandbox=\"allow-scripts\"\n srcDoc={srcdoc}\n style={{\n border: \"none\",\n display: \"block\",\n height: measuredRef.current ? contentHeight : iteration.height || INITIAL_IFRAME_HEIGHT,\n pointerEvents: \"none\",\n width: frameW,\n }}\n />\n )}\n\n {isCommentMode &&\n onClickComment &&\n onAddComment &&\n iteration.comments.map((comment) => (\n <CommentPin\n key={comment.id}\n comment={comment}\n onClick={() => onClickComment(comment, iteration.id)}\n />\n ))}\n </div>\n );\n}\n\nconst STATUS_COLORS = {\n done: {\n bg: \"bg-emerald-500\",\n shadow: \"rgba(16,185,129,0.4)\",\n anchor: \"bg-emerald-400/60\",\n ping: \"bg-emerald-400/30\",\n },\n waiting: {\n bg: \"bg-gray-400\",\n shadow: \"rgba(156,163,175,0.4)\",\n anchor: \"bg-gray-400/60\",\n ping: \"bg-gray-400/30\",\n },\n working: {\n bg: \"bg-amber-500\",\n shadow: \"rgba(245,158,11,0.4)\",\n anchor: \"bg-amber-400/60\",\n ping: \"bg-amber-400/30\",\n },\n} as const;\n\nfunction CommentPin({ comment, onClick }: { comment: CommentType; onClick: () => void }) {\n const [isNew, setIsNew] = useState(true);\n\n useMountEffect(() => {\n const timer = setTimeout(() => setIsNew(false), 2000);\n return () => clearTimeout(timer);\n });\n\n const status = comment.status || \"waiting\";\n const colors = STATUS_COLORS[status];\n const isWorking = status === \"working\";\n\n return (\n <div\n className=\"absolute z-20\"\n style={{\n left: comment.position.x - 14,\n top: comment.position.y - 14,\n }}\n >\n {(isNew || isWorking) && (\n <span className={`absolute inset-0 rounded-full ${colors.ping} animate-ping`} />\n )}\n <span className={`absolute left-1/2 -translate-x-1/2 top-full w-0.5 h-2 ${colors.anchor}`} />\n <button\n className={`relative w-7 h-7 rounded-full ${colors.bg} text-white text-[11px] font-bold flex items-center justify-center hover:scale-110 transition-all cursor-pointer border-2 border-white`}\n style={{ boxShadow: `0 2px 8px ${colors.shadow}` }}\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n title={comment.aiResponse || comment.text}\n >\n {status === \"done\" ? \"✓\" : comment.number}\n </button>\n </div>\n );\n}\n","import type { Comment as CommentType, DesignIteration, Point } from \"@calca/shared\";\n\nimport { DesignFrame, DEFAULT_FRAME_WIDTH } from \"./DesignFrame\";\n\nexport { DEFAULT_FRAME_WIDTH } from \"./DesignFrame\";\n\ninterface DesignCardProps {\n iteration: DesignIteration;\n isCommentMode: boolean;\n isSelectMode: boolean;\n isDragging: boolean;\n isSelected?: boolean;\n onSelect?: (e?: React.MouseEvent) => void;\n onAddComment: (iterationId: string, position: Point, screenX: number, screenY: number) => void;\n onClickComment: (comment: CommentType, iterationId: string) => void;\n onDragStart: (e: React.MouseEvent) => void;\n scale: number;\n}\n\nexport function DesignCard({\n iteration,\n isCommentMode,\n isSelectMode,\n isDragging,\n isSelected,\n onSelect,\n onAddComment,\n onClickComment,\n onDragStart,\n scale,\n}: DesignCardProps) {\n return (\n <div\n className={`absolute ${isDragging ? \"z-50\" : \"\"}`}\n style={{\n left: iteration.position.x,\n top: iteration.position.y,\n width: iteration.width || DEFAULT_FRAME_WIDTH,\n }}\n >\n <div className=\"mb-2 flex items-center gap-2 group/label\">\n <span className=\"text-xs font-medium text-gray-500/80 bg-white/60 backdrop-blur-sm px-2.5 py-0.5 rounded-lg border border-white/40\">\n {iteration.label}\n </span>\n </div>\n\n <DesignFrame\n iteration={iteration}\n isCommentMode={isCommentMode}\n isSelectMode={isSelectMode}\n isSelected={isSelected}\n isDragging={isDragging}\n scale={scale}\n onClick={(e) => {\n if (isSelectMode && onSelect) {\n e.stopPropagation();\n onSelect(e);\n }\n }}\n onMouseDown={(e) => {\n if (isSelectMode) {\n e.stopPropagation();\n onDragStart(e);\n }\n }}\n onAddComment={(iterationId, position, screenX, screenY) =>\n onAddComment(iterationId, position, screenX, screenY)\n }\n onClickComment={onClickComment}\n />\n </div>\n );\n}\n","import { type PipelineStatus, STAGE_CONFIG } from \"@calca/shared\";\n\ninterface PipelineStatusBarProps {\n status: PipelineStatus;\n x: number;\n y: number;\n width: number;\n frameHeight: number;\n}\n\nexport function PipelineStatusOverlay({\n status,\n x,\n y,\n width,\n frameHeight,\n}: PipelineStatusBarProps) {\n const config = STAGE_CONFIG[status.stage];\n const isDone = status.stage === \"done\";\n const isError = status.stage === \"error\";\n const isQueued = status.stage === \"queued\";\n\n if (isDone) {\n return null;\n }\n\n const topOffset = y + frameHeight + 8;\n const value = Math.max(status.progress * 100, 5);\n\n const indicatorClass = isError ? \"bg-destructive\" : \"bg-gradient-to-r from-primary to-secondary\";\n const pulseClass = status.stage === \"layout\" || status.stage === \"images\" ? \"animate-pulse\" : \"\";\n\n return (\n <div className=\"absolute pointer-events-none\" style={{ left: x, top: topOffset, width }}>\n {!isQueued && (\n <div className=\"h-1 w-full overflow-hidden rounded-full bg-primary/20\">\n <div\n className={`h-full transition-all ${indicatorClass} ${pulseClass}`}\n style={{ width: `${value}%` }}\n />\n </div>\n )}\n <div className=\"flex items-center justify-between mt-1.5\">\n <span className=\"text-[10px] font-medium text-muted-foreground whitespace-nowrap\">\n {config.icon} {config.label}\n </span>\n {status.skipped && (\n <span className=\"text-[10px] font-medium text-destructive/80 whitespace-nowrap\">\n ⏭ {status.reason || \"Skipped\"}\n </span>\n )}\n </div>\n </div>\n );\n}\n","interface RubberBandOverlayProps {\n rubberBand: {\n startX: number;\n startY: number;\n currentX: number;\n currentY: number;\n } | null;\n}\n\nexport function RubberBandOverlay({ rubberBand }: RubberBandOverlayProps) {\n if (!rubberBand) {\n return null;\n }\n\n return (\n <div\n className=\"fixed pointer-events-none z-[60] border border-blue-400/50 bg-blue-400/10 rounded-sm\"\n style={{\n height: Math.abs(rubberBand.currentY - rubberBand.startY),\n left: Math.min(rubberBand.startX, rubberBand.currentX),\n top: Math.min(rubberBand.startY, rubberBand.currentY),\n width: Math.abs(rubberBand.currentX - rubberBand.startX),\n }}\n />\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@calca/canvas-ui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.7.3",
|
|
4
|
+
"private": false,
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.mts",
|
|
14
|
+
"import": "./dist/index.mjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsdown",
|
|
22
|
+
"typecheck": "bunx tsc --noEmit",
|
|
23
|
+
"lint": "oxlint --fix .",
|
|
24
|
+
"format": "oxfmt --write .",
|
|
25
|
+
"test": "vitest run --passWithNoTests",
|
|
26
|
+
"clean": "rm -rf dist",
|
|
27
|
+
"validate": "bun ../../scripts/validate.ts --cwd $INIT_CWD",
|
|
28
|
+
"check:pack": "publint && attw --pack . --profile esm-only"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@calca/shared": "0.7.3",
|
|
32
|
+
"lucide-react": "^1.8.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
36
|
+
"@types/react": "^19.2.14",
|
|
37
|
+
"@types/react-dom": "^19.2.3",
|
|
38
|
+
"publint": "^0.3.25",
|
|
39
|
+
"react": "^19.2.4",
|
|
40
|
+
"react-dom": "^19.2.4",
|
|
41
|
+
"tsdown": "^0.23.0",
|
|
42
|
+
"typescript": "^6.0.3",
|
|
43
|
+
"vitest": "^4.1.5"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"lucide-react": "^1.8.0",
|
|
47
|
+
"react": "^19.2.4",
|
|
48
|
+
"react-dom": "^19.2.4"
|
|
49
|
+
}
|
|
50
|
+
}
|