@puckeditor/plugin-ai 0.4.0-canary.fb6e09c3 → 0.4.1-canary.07ea2d1a

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.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as react from 'react';
1
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
3
  import { LanguageModelUsage, UIMessage, DataUIPart, ChatStatus } from 'ai';
3
4
  import { PuckAction, Data } from '@measured/puck';
@@ -70,7 +71,6 @@ type JSONSchema = {
70
71
 
71
72
  type ComponentAiParams = {
72
73
  instructions?: string;
73
- schema?: JSONSchema;
74
74
  defaultZone?: { allow?: string[]; disallow?: string[]; disabled?: boolean };
75
75
  };
76
76
 
@@ -184,6 +184,7 @@ type AiPluginProps = {
184
184
  onClick?: () => void;
185
185
  }[];
186
186
  };
187
+ scrollTracking?: boolean;
187
188
  };
188
189
  declare global {
189
190
  interface Window {
@@ -201,6 +202,11 @@ declare function createAiPlugin(opts?: AiPluginProps): {
201
202
  render: () => react_jsx_runtime.JSX.Element;
202
203
  icon: react_jsx_runtime.JSX.Element;
203
204
  mobilePanelHeight: "min-content";
205
+ overrides: {
206
+ preview: ({ children }: {
207
+ children: react.ReactNode;
208
+ }) => react_jsx_runtime.JSX.Element;
209
+ };
204
210
  };
205
211
 
206
212
  export { createAiPlugin };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as react from 'react';
1
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
3
  import { LanguageModelUsage, UIMessage, DataUIPart, ChatStatus } from 'ai';
3
4
  import { PuckAction, Data } from '@measured/puck';
@@ -70,7 +71,6 @@ type JSONSchema = {
70
71
 
71
72
  type ComponentAiParams = {
72
73
  instructions?: string;
73
- schema?: JSONSchema;
74
74
  defaultZone?: { allow?: string[]; disallow?: string[]; disabled?: boolean };
75
75
  };
76
76
 
@@ -184,6 +184,7 @@ type AiPluginProps = {
184
184
  onClick?: () => void;
185
185
  }[];
186
186
  };
187
+ scrollTracking?: boolean;
187
188
  };
188
189
  declare global {
189
190
  interface Window {
@@ -201,6 +202,11 @@ declare function createAiPlugin(opts?: AiPluginProps): {
201
202
  render: () => react_jsx_runtime.JSX.Element;
202
203
  icon: react_jsx_runtime.JSX.Element;
203
204
  mobilePanelHeight: "min-content";
205
+ overrides: {
206
+ preview: ({ children }: {
207
+ children: react.ReactNode;
208
+ }) => react_jsx_runtime.JSX.Element;
209
+ };
204
210
  };
205
211
 
206
212
  export { createAiPlugin };
package/dist/index.js CHANGED
@@ -1750,7 +1750,7 @@ function Placeholder({
1750
1750
  };
1751
1751
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: getClassName17("placeholder"), children: [
1752
1752
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Bot, { size: "24" }),
1753
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { children: "Use AI to build a page using your own components" }),
1753
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { children: "Use AI to build a page using the available blocks" }),
1754
1754
  /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: getClassName17("actions"), children: [
1755
1755
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1756
1756
  "button",
@@ -1783,15 +1783,111 @@ function isScrolledIntoView(el) {
1783
1783
  return elemTop >= 0 && elemBottom <= window.innerHeight;
1784
1784
  }
1785
1785
 
1786
+ // src/components/ScrollTracking/ScrollTracking.tsx
1787
+ init_react_import();
1788
+ var import_react24 = require("react");
1789
+
1790
+ // src/lib/scroll-into-view-local.ts
1791
+ init_react_import();
1792
+ function scrollIntoViewLocal(el, win, behavior = "smooth") {
1793
+ const scroller = el.ownerDocument?.scrollingElement || el.ownerDocument?.documentElement;
1794
+ const rect = el.getBoundingClientRect();
1795
+ const vpH = win.innerHeight;
1796
+ const current = scroller.scrollTop;
1797
+ const offset = win.innerHeight / 2;
1798
+ let targetTop = current;
1799
+ if (rect.top < 0) {
1800
+ targetTop = current + rect.top;
1801
+ } else if (rect.bottom > vpH) {
1802
+ targetTop = current + (rect.bottom - vpH);
1803
+ }
1804
+ if (targetTop !== current) {
1805
+ scroller.scrollTo({ top: targetTop + offset, behavior });
1806
+ }
1807
+ }
1808
+
1809
+ // src/lib/use-frame-mutation-observer.ts
1810
+ init_react_import();
1811
+ var import_react23 = require("react");
1812
+ function useFrameMutationObserver(callback) {
1813
+ return (0, import_react23.useCallback)(() => {
1814
+ const frame = document?.getElementById(
1815
+ "preview-frame"
1816
+ );
1817
+ if (!frame) return;
1818
+ let observer = null;
1819
+ const win = frame.contentWindow;
1820
+ let enabled = true;
1821
+ const disable = () => {
1822
+ enabled = false;
1823
+ };
1824
+ const attachObserver = () => {
1825
+ const win2 = frame.contentWindow;
1826
+ const doc = frame.contentDocument || win2?.document;
1827
+ if (!win2 || !doc) return;
1828
+ const target = doc.querySelector("#frame-root > div");
1829
+ if (!target) return;
1830
+ observer = new MutationObserver((entries) => {
1831
+ if (enabled) {
1832
+ callback(entries, win2);
1833
+ }
1834
+ });
1835
+ observer?.observe(target, { childList: true, subtree: true });
1836
+ win2.addEventListener("pointerdown", disable);
1837
+ win2.addEventListener("mousewheel", disable);
1838
+ };
1839
+ if (frame.contentDocument?.readyState === "complete") {
1840
+ attachObserver();
1841
+ } else {
1842
+ frame.addEventListener("load", attachObserver, { once: true });
1843
+ }
1844
+ return () => {
1845
+ frame.removeEventListener("load", attachObserver);
1846
+ win?.removeEventListener("pointerdown", disable);
1847
+ win?.removeEventListener("mousewheel", disable);
1848
+ observer?.disconnect();
1849
+ };
1850
+ }, [callback]);
1851
+ }
1852
+
1853
+ // src/components/ScrollTracking/ScrollTracking.tsx
1854
+ var ScrollTracking = ({ children }) => {
1855
+ const followedRefs = (0, import_react24.useRef)([]);
1856
+ const follow = useFrameMutationObserver((records, win) => {
1857
+ if (records.length > 0) {
1858
+ const lastRecord = records[records.length - 1];
1859
+ if (followedRefs.current.includes(lastRecord.target)) return;
1860
+ followedRefs.current.push(lastRecord.target);
1861
+ requestAnimationFrame(() => {
1862
+ const el = lastRecord.target;
1863
+ scrollIntoViewLocal(el, win);
1864
+ });
1865
+ }
1866
+ });
1867
+ (0, import_react24.useEffect)(() => {
1868
+ follow();
1869
+ }, [follow]);
1870
+ return children;
1871
+ };
1872
+
1786
1873
  // src/index.tsx
1787
1874
  var import_jsx_runtime28 = require("react/jsx-runtime");
1788
1875
  function createAiPlugin(opts) {
1876
+ const { scrollTracking = true, ...rest } = opts || {};
1789
1877
  return {
1790
1878
  label: "AI",
1791
1879
  name: "ai",
1792
- render: () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Chat2, { ...opts }),
1880
+ render: () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Chat2, { ...rest }),
1793
1881
  icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Bot, {}),
1794
- mobilePanelHeight: "min-content"
1882
+ mobilePanelHeight: "min-content",
1883
+ overrides: {
1884
+ preview: ({ children }) => {
1885
+ if (scrollTracking) {
1886
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ScrollTracking, { children });
1887
+ }
1888
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children });
1889
+ }
1890
+ }
1795
1891
  };
1796
1892
  }
1797
1893
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.mjs CHANGED
@@ -1748,7 +1748,7 @@ function Placeholder({
1748
1748
  };
1749
1749
  return /* @__PURE__ */ jsxs14("div", { className: getClassName17("placeholder"), children: [
1750
1750
  /* @__PURE__ */ jsx27(Bot, { size: "24" }),
1751
- /* @__PURE__ */ jsx27("div", { children: "Use AI to build a page using your own components" }),
1751
+ /* @__PURE__ */ jsx27("div", { children: "Use AI to build a page using the available blocks" }),
1752
1752
  /* @__PURE__ */ jsxs14("div", { className: getClassName17("actions"), children: [
1753
1753
  /* @__PURE__ */ jsx27(
1754
1754
  "button",
@@ -1781,15 +1781,111 @@ function isScrolledIntoView(el) {
1781
1781
  return elemTop >= 0 && elemBottom <= window.innerHeight;
1782
1782
  }
1783
1783
 
1784
+ // src/components/ScrollTracking/ScrollTracking.tsx
1785
+ init_react_import();
1786
+ import { useEffect as useEffect10, useRef as useRef9 } from "react";
1787
+
1788
+ // src/lib/scroll-into-view-local.ts
1789
+ init_react_import();
1790
+ function scrollIntoViewLocal(el, win, behavior = "smooth") {
1791
+ const scroller = el.ownerDocument?.scrollingElement || el.ownerDocument?.documentElement;
1792
+ const rect = el.getBoundingClientRect();
1793
+ const vpH = win.innerHeight;
1794
+ const current = scroller.scrollTop;
1795
+ const offset = win.innerHeight / 2;
1796
+ let targetTop = current;
1797
+ if (rect.top < 0) {
1798
+ targetTop = current + rect.top;
1799
+ } else if (rect.bottom > vpH) {
1800
+ targetTop = current + (rect.bottom - vpH);
1801
+ }
1802
+ if (targetTop !== current) {
1803
+ scroller.scrollTo({ top: targetTop + offset, behavior });
1804
+ }
1805
+ }
1806
+
1807
+ // src/lib/use-frame-mutation-observer.ts
1808
+ init_react_import();
1809
+ import { useCallback as useCallback5 } from "react";
1810
+ function useFrameMutationObserver(callback) {
1811
+ return useCallback5(() => {
1812
+ const frame = document?.getElementById(
1813
+ "preview-frame"
1814
+ );
1815
+ if (!frame) return;
1816
+ let observer = null;
1817
+ const win = frame.contentWindow;
1818
+ let enabled = true;
1819
+ const disable = () => {
1820
+ enabled = false;
1821
+ };
1822
+ const attachObserver = () => {
1823
+ const win2 = frame.contentWindow;
1824
+ const doc = frame.contentDocument || win2?.document;
1825
+ if (!win2 || !doc) return;
1826
+ const target = doc.querySelector("#frame-root > div");
1827
+ if (!target) return;
1828
+ observer = new MutationObserver((entries) => {
1829
+ if (enabled) {
1830
+ callback(entries, win2);
1831
+ }
1832
+ });
1833
+ observer?.observe(target, { childList: true, subtree: true });
1834
+ win2.addEventListener("pointerdown", disable);
1835
+ win2.addEventListener("mousewheel", disable);
1836
+ };
1837
+ if (frame.contentDocument?.readyState === "complete") {
1838
+ attachObserver();
1839
+ } else {
1840
+ frame.addEventListener("load", attachObserver, { once: true });
1841
+ }
1842
+ return () => {
1843
+ frame.removeEventListener("load", attachObserver);
1844
+ win?.removeEventListener("pointerdown", disable);
1845
+ win?.removeEventListener("mousewheel", disable);
1846
+ observer?.disconnect();
1847
+ };
1848
+ }, [callback]);
1849
+ }
1850
+
1851
+ // src/components/ScrollTracking/ScrollTracking.tsx
1852
+ var ScrollTracking = ({ children }) => {
1853
+ const followedRefs = useRef9([]);
1854
+ const follow = useFrameMutationObserver((records, win) => {
1855
+ if (records.length > 0) {
1856
+ const lastRecord = records[records.length - 1];
1857
+ if (followedRefs.current.includes(lastRecord.target)) return;
1858
+ followedRefs.current.push(lastRecord.target);
1859
+ requestAnimationFrame(() => {
1860
+ const el = lastRecord.target;
1861
+ scrollIntoViewLocal(el, win);
1862
+ });
1863
+ }
1864
+ });
1865
+ useEffect10(() => {
1866
+ follow();
1867
+ }, [follow]);
1868
+ return children;
1869
+ };
1870
+
1784
1871
  // src/index.tsx
1785
- import { jsx as jsx28 } from "react/jsx-runtime";
1872
+ import { Fragment as Fragment3, jsx as jsx28 } from "react/jsx-runtime";
1786
1873
  function createAiPlugin(opts) {
1874
+ const { scrollTracking = true, ...rest } = opts || {};
1787
1875
  return {
1788
1876
  label: "AI",
1789
1877
  name: "ai",
1790
- render: () => /* @__PURE__ */ jsx28(Chat2, { ...opts }),
1878
+ render: () => /* @__PURE__ */ jsx28(Chat2, { ...rest }),
1791
1879
  icon: /* @__PURE__ */ jsx28(Bot, {}),
1792
- mobilePanelHeight: "min-content"
1880
+ mobilePanelHeight: "min-content",
1881
+ overrides: {
1882
+ preview: ({ children }) => {
1883
+ if (scrollTracking) {
1884
+ return /* @__PURE__ */ jsx28(ScrollTracking, { children });
1885
+ }
1886
+ return /* @__PURE__ */ jsx28(Fragment3, { children });
1887
+ }
1888
+ }
1793
1889
  };
1794
1890
  }
1795
1891
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@puckeditor/plugin-ai",
3
- "version": "0.4.0-canary.fb6e09c3",
3
+ "version": "0.4.1-canary.07ea2d1a",
4
4
  "author": "Chris Villa <chris@puckeditor.com>",
5
5
  "repository": "puckeditor/puck",
6
6
  "bugs": "https://github.com/puckeditor/puck/issues",
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "devDependencies": {
39
39
  "@ai-sdk/react": "^2.0.29",
40
- "@measured/puck": "0.21.0-canary.17395b2c",
40
+ "@measured/puck": "0.21.0-canary.ed351ce5",
41
41
  "@puckeditor/ai-types": "workspace:*",
42
42
  "@puckeditor/platform-types": "workspace:*",
43
43
  "@types/jest": "^30.0.0",
@@ -54,7 +54,7 @@
54
54
  "typescript": "^5.5.4"
55
55
  },
56
56
  "peerDependencies": {
57
- "@measured/puck": "0.21.0-canary.17395b2c",
57
+ "@measured/puck": "0.21.0-canary.ed351ce5",
58
58
  "react": "^18.0.0 || ^19.0.0"
59
59
  }
60
60
  }