@braincrew-lab/langchain-canvas 0.1.1 → 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 CHANGED
@@ -1513,34 +1513,27 @@ var TEMPLATES = {
1513
1513
  </section>`
1514
1514
  }
1515
1515
  };
1516
- function SlideView({ html, ratio, title }) {
1517
- const boxRef = useRef(null);
1516
+ var SLIDE_W = 1280;
1517
+ function useSlideFit(ratio, boxRef) {
1518
1518
  const [scale, setScale] = useState(1);
1519
- const [rw, rh] = ratio.split(/[:x/]/).map(Number);
1520
- const DESIGN_W = 1280;
1521
- const DESIGN_H = rw && rh ? Math.round(DESIGN_W * rh / rw) : 720;
1519
+ const [rw, rh] = (ratio ?? "16:9").split(/[:x/]/).map(Number);
1520
+ const height = rw && rh ? Math.round(SLIDE_W * rh / rw) : 720;
1522
1521
  useEffect(() => {
1522
+ if (!ratio) return;
1523
1523
  const el = boxRef.current;
1524
1524
  if (!el) return;
1525
- const fit = () => setScale(Math.min(1, (el.clientWidth - 32) / DESIGN_W));
1525
+ const fit = () => setScale(Math.min(1, (el.clientWidth - 40) / SLIDE_W));
1526
1526
  fit();
1527
1527
  const ro = new ResizeObserver(fit);
1528
1528
  ro.observe(el);
1529
1529
  return () => ro.disconnect();
1530
- }, [DESIGN_W]);
1531
- return /* @__PURE__ */ jsx("div", { ref: boxRef, className: "cv-slideview", children: /* @__PURE__ */ jsx("div", { className: "cv-slideview__frame", style: { width: DESIGN_W * scale, height: DESIGN_H * scale }, children: /* @__PURE__ */ jsx(
1532
- "iframe",
1533
- {
1534
- title,
1535
- srcDoc: html,
1536
- sandbox: "allow-scripts allow-popups allow-modals",
1537
- style: { width: DESIGN_W, height: DESIGN_H, border: 0, transform: `scale(${scale})`, transformOrigin: "top left" }
1538
- }
1539
- ) }) });
1530
+ }, [ratio, height]);
1531
+ return { scale, width: SLIDE_W, height };
1540
1532
  }
1541
1533
  function HtmlRenderer({ artifact: artifact2 }) {
1542
1534
  const iframeRef = useRef(null);
1543
1535
  const imgFileRef = useRef(null);
1536
+ const stageRef = useRef(null);
1544
1537
  const api = useCanvasStoreApi();
1545
1538
  const setSelections = useCanvasStore((s) => s.setSelections);
1546
1539
  const applyEvent = useCanvasStore((s) => s.applyUserEvent);
@@ -1613,9 +1606,7 @@ function HtmlRenderer({ artifact: artifact2 }) {
1613
1606
  reader.readAsDataURL(file);
1614
1607
  };
1615
1608
  const ratio = artifact2.meta?.ratio;
1616
- if (ratio) {
1617
- return /* @__PURE__ */ jsx("div", { className: "cv-html-wrap", children: /* @__PURE__ */ jsx(SlideView, { html: artifact2.data.html, ratio, title: artifact2.title }) });
1618
- }
1609
+ const slide = useSlideFit(ratio, stageRef);
1619
1610
  return /* @__PURE__ */ jsxs("div", { className: "cv-html-wrap", children: [
1620
1611
  /* @__PURE__ */ jsx("input", { ref: imgFileRef, type: "file", accept: "image/*", hidden: true, onChange: (e) => {
1621
1612
  onImgFile(e.target.files?.[0]);
@@ -1623,8 +1614,10 @@ function HtmlRenderer({ artifact: artifact2 }) {
1623
1614
  } }),
1624
1615
  /* @__PURE__ */ jsxs("div", { className: "cv-html-bar cv-chrome", children: [
1625
1616
  mode === "design" && /* @__PURE__ */ jsxs(Fragment, { children: [
1626
- /* @__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)) }),
1627
- /* @__PURE__ */ jsx("span", { className: "cv-html-bar__sep" }),
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
+ ] }),
1628
1621
  /* @__PURE__ */ jsx("span", { className: "cv-html-bar__label", children: "Add" }),
1629
1622
  BLOCKS.map((b) => /* @__PURE__ */ jsx("button", { className: "cv-html-add", onClick: () => command("insert", { block: b.tag }), children: b.label }, b.tag)),
1630
1623
  /* @__PURE__ */ jsxs(
@@ -1685,7 +1678,22 @@ function HtmlRenderer({ artifact: artifact2 }) {
1685
1678
  /* @__PURE__ */ jsx("button", { className: mode === "code" ? "is-on" : "", onClick: () => setMode("code"), children: "Code" })
1686
1679
  ] })
1687
1680
  ] }),
1688
- mode === "design" ? /* @__PURE__ */ jsx("div", { className: "cv-html-stage", children: /* @__PURE__ */ jsx(
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(
1689
1697
  "iframe",
1690
1698
  {
1691
1699
  ref: iframeRef,
package/dist/styles.css CHANGED
@@ -788,16 +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 preview (read-only, scaled to fit). */
792
- .cv-slideview {
793
- flex: 1; min-height: 0; overflow: auto; display: flex; justify-content: center; align-items: flex-start;
794
- padding: 16px; background: var(--cv-surface); border-radius: 10px;
795
- }
796
- .cv-slideview__frame {
797
- position: relative; overflow: hidden; background: #fff; border-radius: 8px;
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;
798
796
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.14);
799
797
  }
800
- .cv-slideview__frame iframe { display: block; }
798
+ .cv-html-stage--slide iframe { display: block; border: 0; }
801
799
  .cv-html-code {
802
800
  flex: 1; min-height: 0; width: 100%; resize: none;
803
801
  padding: 14px 16px; border: 1px solid var(--cv-border); border-radius: 10px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@braincrew-lab/langchain-canvas",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "A live canvas for LangChain agents — stream documents, charts, and rich artifacts into a React panel.",
5
5
  "license": "MIT",
6
6
  "type": "module",