@braincrew-lab/langchain-canvas 0.1.0 → 0.1.2
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/dist/index.js +40 -3
- package/dist/styles.css +8 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1513,9 +1513,27 @@ var TEMPLATES = {
|
|
|
1513
1513
|
</section>`
|
|
1514
1514
|
}
|
|
1515
1515
|
};
|
|
1516
|
+
var SLIDE_W = 1280;
|
|
1517
|
+
function useSlideFit(ratio, boxRef) {
|
|
1518
|
+
const [scale, setScale] = useState(1);
|
|
1519
|
+
const [rw, rh] = (ratio ?? "16:9").split(/[:x/]/).map(Number);
|
|
1520
|
+
const height = rw && rh ? Math.round(SLIDE_W * rh / rw) : 720;
|
|
1521
|
+
useEffect(() => {
|
|
1522
|
+
if (!ratio) return;
|
|
1523
|
+
const el = boxRef.current;
|
|
1524
|
+
if (!el) return;
|
|
1525
|
+
const fit = () => setScale(Math.min(1, (el.clientWidth - 40) / SLIDE_W));
|
|
1526
|
+
fit();
|
|
1527
|
+
const ro = new ResizeObserver(fit);
|
|
1528
|
+
ro.observe(el);
|
|
1529
|
+
return () => ro.disconnect();
|
|
1530
|
+
}, [ratio, height]);
|
|
1531
|
+
return { scale, width: SLIDE_W, height };
|
|
1532
|
+
}
|
|
1516
1533
|
function HtmlRenderer({ artifact: artifact2 }) {
|
|
1517
1534
|
const iframeRef = useRef(null);
|
|
1518
1535
|
const imgFileRef = useRef(null);
|
|
1536
|
+
const stageRef = useRef(null);
|
|
1519
1537
|
const api = useCanvasStoreApi();
|
|
1520
1538
|
const setSelections = useCanvasStore((s) => s.setSelections);
|
|
1521
1539
|
const applyEvent = useCanvasStore((s) => s.applyUserEvent);
|
|
@@ -1587,6 +1605,8 @@ function HtmlRenderer({ artifact: artifact2 }) {
|
|
|
1587
1605
|
reader.onload = () => sendIframeCommand({ artifactId: artifact2.id, type: "set_src", cid: single.cid, value: String(reader.result) });
|
|
1588
1606
|
reader.readAsDataURL(file);
|
|
1589
1607
|
};
|
|
1608
|
+
const ratio = artifact2.meta?.ratio;
|
|
1609
|
+
const slide = useSlideFit(ratio, stageRef);
|
|
1590
1610
|
return /* @__PURE__ */ jsxs("div", { className: "cv-html-wrap", children: [
|
|
1591
1611
|
/* @__PURE__ */ jsx("input", { ref: imgFileRef, type: "file", accept: "image/*", hidden: true, onChange: (e) => {
|
|
1592
1612
|
onImgFile(e.target.files?.[0]);
|
|
@@ -1594,8 +1614,10 @@ function HtmlRenderer({ artifact: artifact2 }) {
|
|
|
1594
1614
|
} }),
|
|
1595
1615
|
/* @__PURE__ */ jsxs("div", { className: "cv-html-bar cv-chrome", children: [
|
|
1596
1616
|
mode === "design" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1597
|
-
|
|
1598
|
-
|
|
1617
|
+
!ratio && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1618
|
+
/* @__PURE__ */ jsx("div", { className: "cv-html-seg", role: "group", "aria-label": "Preview width", children: DEVICES.map((d) => /* @__PURE__ */ jsx("button", { className: device === d.id ? "is-on" : "", onClick: () => setDevice(d.id), children: d.label }, d.id)) }),
|
|
1619
|
+
/* @__PURE__ */ jsx("span", { className: "cv-html-bar__sep" })
|
|
1620
|
+
] }),
|
|
1599
1621
|
/* @__PURE__ */ jsx("span", { className: "cv-html-bar__label", children: "Add" }),
|
|
1600
1622
|
BLOCKS.map((b) => /* @__PURE__ */ jsx("button", { className: "cv-html-add", onClick: () => command("insert", { block: b.tag }), children: b.label }, b.tag)),
|
|
1601
1623
|
/* @__PURE__ */ jsxs(
|
|
@@ -1656,7 +1678,22 @@ function HtmlRenderer({ artifact: artifact2 }) {
|
|
|
1656
1678
|
/* @__PURE__ */ jsx("button", { className: mode === "code" ? "is-on" : "", onClick: () => setMode("code"), children: "Code" })
|
|
1657
1679
|
] })
|
|
1658
1680
|
] }),
|
|
1659
|
-
mode === "design" ? /* @__PURE__ */ jsx("div", { className: "cv-html-stage", children:
|
|
1681
|
+
mode === "design" ? /* @__PURE__ */ jsx("div", { className: `cv-html-stage${ratio ? " cv-html-stage--slide" : ""}`, ref: stageRef, children: ratio ? (
|
|
1682
|
+
// Scaled slide: the iframe lays out at its full design size, then a
|
|
1683
|
+
// transform shrinks it to fit; a sized wrapper reserves the scaled box
|
|
1684
|
+
// so the stage scrolls correctly. Clicks still hit the right elements.
|
|
1685
|
+
/* @__PURE__ */ jsx("div", { style: { width: slide.width * slide.scale, height: slide.height * slide.scale, flex: "0 0 auto" }, children: /* @__PURE__ */ jsx(
|
|
1686
|
+
"iframe",
|
|
1687
|
+
{
|
|
1688
|
+
ref: iframeRef,
|
|
1689
|
+
className: "cv-html",
|
|
1690
|
+
title: artifact2.title,
|
|
1691
|
+
srcDoc,
|
|
1692
|
+
sandbox: "allow-scripts allow-popups allow-modals",
|
|
1693
|
+
style: { width: slide.width, height: slide.height, transform: `scale(${slide.scale})`, transformOrigin: "top left" }
|
|
1694
|
+
}
|
|
1695
|
+
) })
|
|
1696
|
+
) : /* @__PURE__ */ jsx(
|
|
1660
1697
|
"iframe",
|
|
1661
1698
|
{
|
|
1662
1699
|
ref: iframeRef,
|
package/dist/styles.css
CHANGED
|
@@ -788,6 +788,14 @@
|
|
|
788
788
|
flex: 1; min-height: 0; overflow: auto; display: flex; justify-content: center;
|
|
789
789
|
padding: 10px; background: var(--cv-surface); border-radius: 10px;
|
|
790
790
|
}
|
|
791
|
+
/* Fixed-aspect slide stage — the scaled iframe box sits centered at the top,
|
|
792
|
+
with a card-like frame around it. Still fully editable. */
|
|
793
|
+
.cv-html-stage--slide { align-items: flex-start; padding: 16px; }
|
|
794
|
+
.cv-html-stage--slide > div {
|
|
795
|
+
overflow: hidden; background: #fff; border-radius: 8px;
|
|
796
|
+
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.14);
|
|
797
|
+
}
|
|
798
|
+
.cv-html-stage--slide iframe { display: block; border: 0; }
|
|
791
799
|
.cv-html-code {
|
|
792
800
|
flex: 1; min-height: 0; width: 100%; resize: none;
|
|
793
801
|
padding: 14px 16px; border: 1px solid var(--cv-border); border-radius: 10px;
|
package/package.json
CHANGED