@elementor/editor-widget-creation 4.0.0-manual → 4.0.1

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
@@ -42,40 +42,45 @@ var React = __toESM(require("react"));
42
42
  var import_react = require("react");
43
43
  var import_editor_mcp = require("@elementor/editor-mcp");
44
44
  var import_editor_ui = require("@elementor/editor-ui");
45
+ var import_events = require("@elementor/events");
45
46
  var import_icons = require("@elementor/icons");
46
47
  var import_ui = require("@elementor/ui");
47
48
  var import_i18n = require("@wordpress/i18n");
48
49
  var CREATE_WIDGET_EVENT = "elementor/editor/create-widget";
49
50
  var PROMOTION_IMAGE_URL = "https://assets.elementor.com/packages/v1/images/angie-promotion.svg";
50
- function CreateWidget() {
51
- const [open, setOpen] = (0, import_react.useState)(false);
52
- const [prompt, setPrompt] = (0, import_react.useState)();
53
- const handleShow = async (event) => {
54
- const customEvent = event;
55
- if ((0, import_editor_mcp.isAngieAvailable)()) {
56
- (0, import_editor_mcp.sendPromptToAngie)(customEvent.detail?.prompt);
51
+ var ANGIE_CTA_CLICKED_EVENT = "angie_cta_clicked";
52
+ var ANGIE_INSTALL_STARTED_EVENT = "angie_install_started";
53
+ function CreateWidgetModal({ prompt, entryPoint, onClose }) {
54
+ const [installState, setInstallState] = (0, import_react.useState)("idle");
55
+ const handleClose = () => {
56
+ if (installState === "installing") {
57
57
  return;
58
58
  }
59
- setPrompt(customEvent.detail?.prompt);
60
- setOpen(true);
59
+ onClose();
61
60
  };
62
- const handleClose = () => {
63
- setOpen(false);
64
- setPrompt(void 0);
61
+ const handleInstall = async () => {
62
+ if (!prompt) {
63
+ return;
64
+ }
65
+ setInstallState("installing");
66
+ (0, import_events.trackEvent)({
67
+ eventName: ANGIE_INSTALL_STARTED_EVENT,
68
+ trigger_source: entryPoint
69
+ });
70
+ const result = await (0, import_editor_mcp.installAngiePlugin)();
71
+ if (!result.success) {
72
+ setInstallState("error");
73
+ return;
74
+ }
75
+ (0, import_editor_mcp.redirectToAppAdmin)(prompt);
65
76
  };
66
- const handleInstall = () => {
77
+ const handleFallbackInstall = () => {
67
78
  if (!prompt) {
68
79
  return;
69
80
  }
70
81
  (0, import_editor_mcp.redirectToInstallation)(prompt);
71
82
  };
72
- (0, import_react.useEffect)(() => {
73
- window.addEventListener(CREATE_WIDGET_EVENT, handleShow);
74
- return () => {
75
- window.removeEventListener(CREATE_WIDGET_EVENT, handleShow);
76
- };
77
- }, []);
78
- return /* @__PURE__ */ React.createElement(import_editor_ui.ThemeProvider, null, /* @__PURE__ */ React.createElement(import_ui.Dialog, { fullWidth: true, maxWidth: "md", open, onClose: handleClose }, /* @__PURE__ */ React.createElement(
83
+ return /* @__PURE__ */ React.createElement(import_editor_ui.ThemeProvider, null, /* @__PURE__ */ React.createElement(import_ui.Dialog, { fullWidth: true, maxWidth: "md", open: true, onClose: handleClose }, /* @__PURE__ */ React.createElement(
79
84
  import_ui.IconButton,
80
85
  {
81
86
  "aria-label": (0, import_i18n.__)("Close", "elementor"),
@@ -99,10 +104,57 @@ function CreateWidget() {
99
104
  },
100
105
  src: PROMOTION_IMAGE_URL
101
106
  }
102
- ), /* @__PURE__ */ React.createElement(import_ui.Stack, { gap: 2, justifyContent: "center", p: 4 }, /* @__PURE__ */ React.createElement(import_ui.Typography, { variant: "h6", fontWeight: 600, whiteSpace: "nowrap" }, (0, import_i18n.__)("Install Angie to build custom widgets", "elementor")), /* @__PURE__ */ React.createElement(import_ui.Typography, { variant: "body2", color: "text.secondary" }, (0, import_i18n.__)(
107
+ ), /* @__PURE__ */ React.createElement(import_ui.Stack, { gap: 2, justifyContent: "center", p: 4 }, /* @__PURE__ */ React.createElement(import_ui.Typography, { variant: "h6", fontWeight: 600, whiteSpace: "nowrap" }, installState === "error" ? (0, import_i18n.__)("Installation failed", "elementor") : (0, import_i18n.__)("Install Angie to build custom widgets", "elementor")), /* @__PURE__ */ React.createElement(import_ui.Typography, { variant: "body2", color: "text.secondary" }, installState === "error" ? (0, import_i18n.__)(
108
+ "We couldn't install Angie automatically. Click below to install it manually.",
109
+ "elementor"
110
+ ) : (0, import_i18n.__)(
103
111
  "Angie lets you generate custom widgets, sections, and code using simple instructions.",
104
112
  "elementor"
105
- )), /* @__PURE__ */ React.createElement(import_ui.Typography, { variant: "body2", color: "text.secondary" }, (0, import_i18n.__)("Install once to start building directly inside the editor.", "elementor")), /* @__PURE__ */ React.createElement(import_ui.Stack, { direction: "row", justifyContent: "flex-end", sx: { mt: 2 } }, /* @__PURE__ */ React.createElement(import_ui.Button, { variant: "contained", color: "accent", onClick: handleInstall }, (0, import_i18n.__)("Install Angie", "elementor"))))))));
113
+ )), installState !== "error" && /* @__PURE__ */ React.createElement(import_ui.Typography, { variant: "body2", color: "text.secondary" }, (0, import_i18n.__)("Install once to start building directly inside the editor.", "elementor")), /* @__PURE__ */ React.createElement(import_ui.Stack, { direction: "row", justifyContent: "flex-end", sx: { mt: 2 } }, installState === "error" ? /* @__PURE__ */ React.createElement(import_ui.Button, { variant: "contained", color: "accent", onClick: handleFallbackInstall }, (0, import_i18n.__)("Install Manually", "elementor")) : /* @__PURE__ */ React.createElement(
114
+ import_ui.Button,
115
+ {
116
+ variant: "contained",
117
+ color: "accent",
118
+ onClick: handleInstall,
119
+ disabled: installState === "installing",
120
+ startIcon: installState === "installing" ? /* @__PURE__ */ React.createElement(import_ui.CircularProgress, { size: 18, color: "inherit" }) : void 0
121
+ },
122
+ installState === "installing" ? (0, import_i18n.__)("Installing\u2026", "elementor") : (0, import_i18n.__)("Install Angie", "elementor")
123
+ )))))));
124
+ }
125
+ function CreateWidget() {
126
+ const [modalData, setModalData] = (0, import_react.useState)(null);
127
+ (0, import_react.useEffect)(() => {
128
+ const handleShow = (event) => {
129
+ const customEvent = event;
130
+ const hasAngieInstalled = (0, import_editor_mcp.isAngieAvailable)();
131
+ (0, import_events.trackEvent)({
132
+ eventName: ANGIE_CTA_CLICKED_EVENT,
133
+ entry_point: customEvent.detail.entry_point,
134
+ has_angie_installed: hasAngieInstalled
135
+ });
136
+ if (hasAngieInstalled) {
137
+ (0, import_editor_mcp.sendPromptToAngie)(customEvent.detail?.prompt);
138
+ return;
139
+ }
140
+ setModalData(customEvent.detail);
141
+ };
142
+ window.addEventListener(CREATE_WIDGET_EVENT, handleShow);
143
+ return () => {
144
+ window.removeEventListener(CREATE_WIDGET_EVENT, handleShow);
145
+ };
146
+ }, []);
147
+ if (!modalData) {
148
+ return null;
149
+ }
150
+ return /* @__PURE__ */ React.createElement(
151
+ CreateWidgetModal,
152
+ {
153
+ prompt: modalData.prompt,
154
+ entryPoint: modalData.entry_point,
155
+ onClose: () => setModalData(null)
156
+ }
157
+ );
106
158
  }
107
159
 
108
160
  // src/init.ts
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/init.ts","../src/components/create-widget.tsx"],"sourcesContent":["export { init } from './init';\n","import { injectIntoTop } from '@elementor/editor';\n\nimport { CreateWidget } from './components/create-widget';\n\nexport function init() {\n\tinjectIntoTop( {\n\t\tid: 'create-widget',\n\t\tcomponent: CreateWidget,\n\t} );\n}\n","import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { isAngieAvailable, redirectToInstallation, sendPromptToAngie } from '@elementor/editor-mcp';\nimport { ThemeProvider } from '@elementor/editor-ui';\nimport { XIcon } from '@elementor/icons';\nimport { Button, Dialog, DialogContent, IconButton, Image, Stack, Typography } from '@elementor/ui';\nimport { __ } from '@wordpress/i18n';\n\ntype ShowModalEventDetail = {\n\tprompt?: string;\n};\n\nconst CREATE_WIDGET_EVENT = 'elementor/editor/create-widget';\nconst PROMOTION_IMAGE_URL = 'https://assets.elementor.com/packages/v1/images/angie-promotion.svg';\n\nexport function CreateWidget() {\n\tconst [ open, setOpen ] = useState( false );\n\tconst [ prompt, setPrompt ] = useState< string | undefined >();\n\n\tconst handleShow = async ( event: Event ) => {\n\t\tconst customEvent = event as CustomEvent< ShowModalEventDetail >;\n\n\t\tif ( isAngieAvailable() ) {\n\t\t\tsendPromptToAngie( customEvent.detail?.prompt );\n\n\t\t\treturn;\n\t\t}\n\n\t\tsetPrompt( customEvent.detail?.prompt );\n\t\tsetOpen( true );\n\t};\n\n\tconst handleClose = () => {\n\t\tsetOpen( false );\n\t\tsetPrompt( undefined );\n\t};\n\n\tconst handleInstall = () => {\n\t\tif ( ! prompt ) {\n\t\t\treturn;\n\t\t}\n\n\t\tredirectToInstallation( prompt );\n\t};\n\n\tuseEffect( () => {\n\t\twindow.addEventListener( CREATE_WIDGET_EVENT, handleShow );\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener( CREATE_WIDGET_EVENT, handleShow );\n\t\t};\n\t}, [] );\n\n\treturn (\n\t\t<ThemeProvider>\n\t\t\t<Dialog fullWidth maxWidth=\"md\" open={ open } onClose={ handleClose }>\n\t\t\t\t<IconButton\n\t\t\t\t\taria-label={ __( 'Close', 'elementor' ) }\n\t\t\t\t\tonClick={ handleClose }\n\t\t\t\t\tsx={ {\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\tright: 8,\n\t\t\t\t\t\ttop: 8,\n\t\t\t\t\t\tzIndex: 1,\n\t\t\t\t\t} }\n\t\t\t\t>\n\t\t\t\t\t<XIcon />\n\t\t\t\t</IconButton>\n\t\t\t\t<DialogContent sx={ { p: 0, overflow: 'hidden' } }>\n\t\t\t\t\t<Stack direction=\"row\" sx={ { height: 400 } }>\n\t\t\t\t\t\t<Image\n\t\t\t\t\t\t\tsx={ {\n\t\t\t\t\t\t\t\theight: '100%',\n\t\t\t\t\t\t\t\taspectRatio: '1 / 1',\n\t\t\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\t\t\tobjectPosition: 'right center',\n\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\tsrc={ PROMOTION_IMAGE_URL }\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Stack gap={ 2 } justifyContent=\"center\" p={ 4 }>\n\t\t\t\t\t\t\t<Typography variant=\"h6\" fontWeight={ 600 } whiteSpace=\"nowrap\">\n\t\t\t\t\t\t\t\t{ __( 'Install Angie to build custom widgets', 'elementor' ) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t\t\t{ __(\n\t\t\t\t\t\t\t\t\t'Angie lets you generate custom widgets, sections, and code using simple instructions.',\n\t\t\t\t\t\t\t\t\t'elementor'\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t\t\t{ __( 'Install once to start building directly inside the editor.', 'elementor' ) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t<Stack direction=\"row\" justifyContent=\"flex-end\" sx={ { mt: 2 } }>\n\t\t\t\t\t\t\t\t<Button variant=\"contained\" color=\"accent\" onClick={ handleInstall }>\n\t\t\t\t\t\t\t\t\t{ __( 'Install Angie', 'elementor' ) }\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t</Stack>\n\t\t\t\t</DialogContent>\n\t\t\t</Dialog>\n\t\t</ThemeProvider>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA8B;;;ACA9B,YAAuB;AACvB,mBAAoC;AACpC,wBAA4E;AAC5E,uBAA8B;AAC9B,mBAAsB;AACtB,gBAAoF;AACpF,kBAAmB;AAMnB,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAErB,SAAS,eAAe;AAC9B,QAAM,CAAE,MAAM,OAAQ,QAAI,uBAAU,KAAM;AAC1C,QAAM,CAAE,QAAQ,SAAU,QAAI,uBAA+B;AAE7D,QAAM,aAAa,OAAQ,UAAkB;AAC5C,UAAM,cAAc;AAEpB,YAAK,oCAAiB,GAAI;AACzB,+CAAmB,YAAY,QAAQ,MAAO;AAE9C;AAAA,IACD;AAEA,cAAW,YAAY,QAAQ,MAAO;AACtC,YAAS,IAAK;AAAA,EACf;AAEA,QAAM,cAAc,MAAM;AACzB,YAAS,KAAM;AACf,cAAW,MAAU;AAAA,EACtB;AAEA,QAAM,gBAAgB,MAAM;AAC3B,QAAK,CAAE,QAAS;AACf;AAAA,IACD;AAEA,kDAAwB,MAAO;AAAA,EAChC;AAEA,8BAAW,MAAM;AAChB,WAAO,iBAAkB,qBAAqB,UAAW;AAEzD,WAAO,MAAM;AACZ,aAAO,oBAAqB,qBAAqB,UAAW;AAAA,IAC7D;AAAA,EACD,GAAG,CAAC,CAAE;AAEN,SACC,oCAAC,sCACA,oCAAC,oBAAO,WAAS,MAAC,UAAS,MAAK,MAAc,SAAU,eACvD;AAAA,IAAC;AAAA;AAAA,MACA,kBAAa,gBAAI,SAAS,WAAY;AAAA,MACtC,SAAU;AAAA,MACV,IAAK;AAAA,QACJ,UAAU;AAAA,QACV,OAAO;AAAA,QACP,KAAK;AAAA,QACL,QAAQ;AAAA,MACT;AAAA;AAAA,IAEA,oCAAC,wBAAM;AAAA,EACR,GACA,oCAAC,2BAAc,IAAK,EAAE,GAAG,GAAG,UAAU,SAAS,KAC9C,oCAAC,mBAAM,WAAU,OAAM,IAAK,EAAE,QAAQ,IAAI,KACzC;AAAA,IAAC;AAAA;AAAA,MACA,IAAK;AAAA,QACJ,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,WAAW;AAAA,QACX,gBAAgB;AAAA,MACjB;AAAA,MACA,KAAM;AAAA;AAAA,EACP,GACA,oCAAC,mBAAM,KAAM,GAAI,gBAAe,UAAS,GAAI,KAC5C,oCAAC,wBAAW,SAAQ,MAAK,YAAa,KAAM,YAAW,gBACpD,gBAAI,yCAAyC,WAAY,CAC5D,GACA,oCAAC,wBAAW,SAAQ,SAAQ,OAAM,wBAC/B;AAAA,IACD;AAAA,IACA;AAAA,EACD,CACD,GACA,oCAAC,wBAAW,SAAQ,SAAQ,OAAM,wBAC/B,gBAAI,8DAA8D,WAAY,CACjF,GACA,oCAAC,mBAAM,WAAU,OAAM,gBAAe,YAAW,IAAK,EAAE,IAAI,EAAE,KAC7D,oCAAC,oBAAO,SAAQ,aAAY,OAAM,UAAS,SAAU,qBAClD,gBAAI,iBAAiB,WAAY,CACpC,CACD,CACD,CACD,CACD,CACD,CACD;AAEF;;;ADnGO,SAAS,OAAO;AACtB,mCAAe;AAAA,IACd,IAAI;AAAA,IACJ,WAAW;AAAA,EACZ,CAAE;AACH;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/init.ts","../src/components/create-widget.tsx"],"sourcesContent":["export { init } from './init';\n","import { injectIntoTop } from '@elementor/editor';\n\nimport { CreateWidget } from './components/create-widget';\n\nexport function init() {\n\tinjectIntoTop( {\n\t\tid: 'create-widget',\n\t\tcomponent: CreateWidget,\n\t} );\n}\n","import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport {\n\tinstallAngiePlugin,\n\tisAngieAvailable,\n\tredirectToAppAdmin,\n\tredirectToInstallation,\n\tsendPromptToAngie,\n} from '@elementor/editor-mcp';\nimport { ThemeProvider } from '@elementor/editor-ui';\nimport { trackEvent } from '@elementor/events';\nimport { XIcon } from '@elementor/icons';\nimport { Button, CircularProgress, Dialog, DialogContent, IconButton, Image, Stack, Typography } from '@elementor/ui';\nimport { __ } from '@wordpress/i18n';\n\ntype ShowModalEventDetail = {\n\tprompt?: string;\n\tentry_point: string;\n};\n\ntype InstallState = 'idle' | 'installing' | 'error';\n\ntype CreateWidgetModalProps = {\n\tprompt?: string;\n\tentryPoint: string;\n\tonClose: () => void;\n};\n\nconst CREATE_WIDGET_EVENT = 'elementor/editor/create-widget';\nconst PROMOTION_IMAGE_URL = 'https://assets.elementor.com/packages/v1/images/angie-promotion.svg';\nconst ANGIE_CTA_CLICKED_EVENT = 'angie_cta_clicked' as const;\nconst ANGIE_INSTALL_STARTED_EVENT = 'angie_install_started' as const;\n\nfunction CreateWidgetModal( { prompt, entryPoint, onClose }: CreateWidgetModalProps ) {\n\tconst [ installState, setInstallState ] = useState< InstallState >( 'idle' );\n\n\tconst handleClose = () => {\n\t\tif ( installState === 'installing' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tonClose();\n\t};\n\n\tconst handleInstall = async () => {\n\t\tif ( ! prompt ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetInstallState( 'installing' );\n\n\t\ttrackEvent( {\n\t\t\teventName: ANGIE_INSTALL_STARTED_EVENT,\n\t\t\ttrigger_source: entryPoint,\n\t\t} );\n\n\t\tconst result = await installAngiePlugin();\n\n\t\tif ( ! result.success ) {\n\t\t\tsetInstallState( 'error' );\n\n\t\t\treturn;\n\t\t}\n\n\t\tredirectToAppAdmin( prompt );\n\t};\n\n\tconst handleFallbackInstall = () => {\n\t\tif ( ! prompt ) {\n\t\t\treturn;\n\t\t}\n\n\t\tredirectToInstallation( prompt );\n\t};\n\n\treturn (\n\t\t<ThemeProvider>\n\t\t\t<Dialog fullWidth maxWidth=\"md\" open onClose={ handleClose }>\n\t\t\t\t<IconButton\n\t\t\t\t\taria-label={ __( 'Close', 'elementor' ) }\n\t\t\t\t\tonClick={ handleClose }\n\t\t\t\t\tsx={ {\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\tright: 8,\n\t\t\t\t\t\ttop: 8,\n\t\t\t\t\t\tzIndex: 1,\n\t\t\t\t\t} }\n\t\t\t\t>\n\t\t\t\t\t<XIcon />\n\t\t\t\t</IconButton>\n\t\t\t\t<DialogContent sx={ { p: 0, overflow: 'hidden' } }>\n\t\t\t\t\t<Stack direction=\"row\" sx={ { height: 400 } }>\n\t\t\t\t\t\t<Image\n\t\t\t\t\t\t\tsx={ {\n\t\t\t\t\t\t\t\theight: '100%',\n\t\t\t\t\t\t\t\taspectRatio: '1 / 1',\n\t\t\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\t\t\tobjectPosition: 'right center',\n\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\tsrc={ PROMOTION_IMAGE_URL }\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Stack gap={ 2 } justifyContent=\"center\" p={ 4 }>\n\t\t\t\t\t\t\t<Typography variant=\"h6\" fontWeight={ 600 } whiteSpace=\"nowrap\">\n\t\t\t\t\t\t\t\t{ installState === 'error'\n\t\t\t\t\t\t\t\t\t? __( 'Installation failed', 'elementor' )\n\t\t\t\t\t\t\t\t\t: __( 'Install Angie to build custom widgets', 'elementor' ) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t\t\t{ installState === 'error'\n\t\t\t\t\t\t\t\t\t? __(\n\t\t\t\t\t\t\t\t\t\t\t\"We couldn't install Angie automatically. Click below to install it manually.\",\n\t\t\t\t\t\t\t\t\t\t\t'elementor'\n\t\t\t\t\t\t\t\t\t )\n\t\t\t\t\t\t\t\t\t: __(\n\t\t\t\t\t\t\t\t\t\t\t'Angie lets you generate custom widgets, sections, and code using simple instructions.',\n\t\t\t\t\t\t\t\t\t\t\t'elementor'\n\t\t\t\t\t\t\t\t\t ) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t{ installState !== 'error' && (\n\t\t\t\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t\t\t\t{ __( 'Install once to start building directly inside the editor.', 'elementor' ) }\n\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t<Stack direction=\"row\" justifyContent=\"flex-end\" sx={ { mt: 2 } }>\n\t\t\t\t\t\t\t\t{ installState === 'error' ? (\n\t\t\t\t\t\t\t\t\t<Button variant=\"contained\" color=\"accent\" onClick={ handleFallbackInstall }>\n\t\t\t\t\t\t\t\t\t\t{ __( 'Install Manually', 'elementor' ) }\n\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\t\t\tcolor=\"accent\"\n\t\t\t\t\t\t\t\t\t\tonClick={ handleInstall }\n\t\t\t\t\t\t\t\t\t\tdisabled={ installState === 'installing' }\n\t\t\t\t\t\t\t\t\t\tstartIcon={\n\t\t\t\t\t\t\t\t\t\t\tinstallState === 'installing' ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<CircularProgress size={ 18 } color=\"inherit\" />\n\t\t\t\t\t\t\t\t\t\t\t) : undefined\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{ installState === 'installing'\n\t\t\t\t\t\t\t\t\t\t\t? __( 'Installing…', 'elementor' )\n\t\t\t\t\t\t\t\t\t\t\t: __( 'Install Angie', 'elementor' ) }\n\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t</Stack>\n\t\t\t\t</DialogContent>\n\t\t\t</Dialog>\n\t\t</ThemeProvider>\n\t);\n}\n\nexport function CreateWidget() {\n\tconst [ modalData, setModalData ] = useState< ShowModalEventDetail | null >( null );\n\n\tuseEffect( () => {\n\t\tconst handleShow = ( event: Event ) => {\n\t\t\tconst customEvent = event as CustomEvent< ShowModalEventDetail >;\n\t\t\tconst hasAngieInstalled = isAngieAvailable();\n\n\t\t\ttrackEvent( {\n\t\t\t\teventName: ANGIE_CTA_CLICKED_EVENT,\n\t\t\t\tentry_point: customEvent.detail.entry_point,\n\t\t\t\thas_angie_installed: hasAngieInstalled,\n\t\t\t} );\n\n\t\t\tif ( hasAngieInstalled ) {\n\t\t\t\tsendPromptToAngie( customEvent.detail?.prompt );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetModalData( customEvent.detail );\n\t\t};\n\n\t\twindow.addEventListener( CREATE_WIDGET_EVENT, handleShow );\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener( CREATE_WIDGET_EVENT, handleShow );\n\t\t};\n\t}, [] );\n\n\tif ( ! modalData ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<CreateWidgetModal\n\t\t\tprompt={ modalData.prompt }\n\t\t\tentryPoint={ modalData.entry_point }\n\t\t\tonClose={ () => setModalData( null ) }\n\t\t/>\n\t);\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -4,42 +4,53 @@ import { injectIntoTop } from "@elementor/editor";
4
4
  // src/components/create-widget.tsx
5
5
  import * as React from "react";
6
6
  import { useEffect, useState } from "react";
7
- import { isAngieAvailable, redirectToInstallation, sendPromptToAngie } from "@elementor/editor-mcp";
7
+ import {
8
+ installAngiePlugin,
9
+ isAngieAvailable,
10
+ redirectToAppAdmin,
11
+ redirectToInstallation,
12
+ sendPromptToAngie
13
+ } from "@elementor/editor-mcp";
8
14
  import { ThemeProvider } from "@elementor/editor-ui";
15
+ import { trackEvent } from "@elementor/events";
9
16
  import { XIcon } from "@elementor/icons";
10
- import { Button, Dialog, DialogContent, IconButton, Image, Stack, Typography } from "@elementor/ui";
17
+ import { Button, CircularProgress, Dialog, DialogContent, IconButton, Image, Stack, Typography } from "@elementor/ui";
11
18
  import { __ } from "@wordpress/i18n";
12
19
  var CREATE_WIDGET_EVENT = "elementor/editor/create-widget";
13
20
  var PROMOTION_IMAGE_URL = "https://assets.elementor.com/packages/v1/images/angie-promotion.svg";
14
- function CreateWidget() {
15
- const [open, setOpen] = useState(false);
16
- const [prompt, setPrompt] = useState();
17
- const handleShow = async (event) => {
18
- const customEvent = event;
19
- if (isAngieAvailable()) {
20
- sendPromptToAngie(customEvent.detail?.prompt);
21
+ var ANGIE_CTA_CLICKED_EVENT = "angie_cta_clicked";
22
+ var ANGIE_INSTALL_STARTED_EVENT = "angie_install_started";
23
+ function CreateWidgetModal({ prompt, entryPoint, onClose }) {
24
+ const [installState, setInstallState] = useState("idle");
25
+ const handleClose = () => {
26
+ if (installState === "installing") {
21
27
  return;
22
28
  }
23
- setPrompt(customEvent.detail?.prompt);
24
- setOpen(true);
29
+ onClose();
25
30
  };
26
- const handleClose = () => {
27
- setOpen(false);
28
- setPrompt(void 0);
31
+ const handleInstall = async () => {
32
+ if (!prompt) {
33
+ return;
34
+ }
35
+ setInstallState("installing");
36
+ trackEvent({
37
+ eventName: ANGIE_INSTALL_STARTED_EVENT,
38
+ trigger_source: entryPoint
39
+ });
40
+ const result = await installAngiePlugin();
41
+ if (!result.success) {
42
+ setInstallState("error");
43
+ return;
44
+ }
45
+ redirectToAppAdmin(prompt);
29
46
  };
30
- const handleInstall = () => {
47
+ const handleFallbackInstall = () => {
31
48
  if (!prompt) {
32
49
  return;
33
50
  }
34
51
  redirectToInstallation(prompt);
35
52
  };
36
- useEffect(() => {
37
- window.addEventListener(CREATE_WIDGET_EVENT, handleShow);
38
- return () => {
39
- window.removeEventListener(CREATE_WIDGET_EVENT, handleShow);
40
- };
41
- }, []);
42
- return /* @__PURE__ */ React.createElement(ThemeProvider, null, /* @__PURE__ */ React.createElement(Dialog, { fullWidth: true, maxWidth: "md", open, onClose: handleClose }, /* @__PURE__ */ React.createElement(
53
+ return /* @__PURE__ */ React.createElement(ThemeProvider, null, /* @__PURE__ */ React.createElement(Dialog, { fullWidth: true, maxWidth: "md", open: true, onClose: handleClose }, /* @__PURE__ */ React.createElement(
43
54
  IconButton,
44
55
  {
45
56
  "aria-label": __("Close", "elementor"),
@@ -63,10 +74,57 @@ function CreateWidget() {
63
74
  },
64
75
  src: PROMOTION_IMAGE_URL
65
76
  }
66
- ), /* @__PURE__ */ React.createElement(Stack, { gap: 2, justifyContent: "center", p: 4 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6", fontWeight: 600, whiteSpace: "nowrap" }, __("Install Angie to build custom widgets", "elementor")), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "text.secondary" }, __(
77
+ ), /* @__PURE__ */ React.createElement(Stack, { gap: 2, justifyContent: "center", p: 4 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6", fontWeight: 600, whiteSpace: "nowrap" }, installState === "error" ? __("Installation failed", "elementor") : __("Install Angie to build custom widgets", "elementor")), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "text.secondary" }, installState === "error" ? __(
78
+ "We couldn't install Angie automatically. Click below to install it manually.",
79
+ "elementor"
80
+ ) : __(
67
81
  "Angie lets you generate custom widgets, sections, and code using simple instructions.",
68
82
  "elementor"
69
- )), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "text.secondary" }, __("Install once to start building directly inside the editor.", "elementor")), /* @__PURE__ */ React.createElement(Stack, { direction: "row", justifyContent: "flex-end", sx: { mt: 2 } }, /* @__PURE__ */ React.createElement(Button, { variant: "contained", color: "accent", onClick: handleInstall }, __("Install Angie", "elementor"))))))));
83
+ )), installState !== "error" && /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "text.secondary" }, __("Install once to start building directly inside the editor.", "elementor")), /* @__PURE__ */ React.createElement(Stack, { direction: "row", justifyContent: "flex-end", sx: { mt: 2 } }, installState === "error" ? /* @__PURE__ */ React.createElement(Button, { variant: "contained", color: "accent", onClick: handleFallbackInstall }, __("Install Manually", "elementor")) : /* @__PURE__ */ React.createElement(
84
+ Button,
85
+ {
86
+ variant: "contained",
87
+ color: "accent",
88
+ onClick: handleInstall,
89
+ disabled: installState === "installing",
90
+ startIcon: installState === "installing" ? /* @__PURE__ */ React.createElement(CircularProgress, { size: 18, color: "inherit" }) : void 0
91
+ },
92
+ installState === "installing" ? __("Installing\u2026", "elementor") : __("Install Angie", "elementor")
93
+ )))))));
94
+ }
95
+ function CreateWidget() {
96
+ const [modalData, setModalData] = useState(null);
97
+ useEffect(() => {
98
+ const handleShow = (event) => {
99
+ const customEvent = event;
100
+ const hasAngieInstalled = isAngieAvailable();
101
+ trackEvent({
102
+ eventName: ANGIE_CTA_CLICKED_EVENT,
103
+ entry_point: customEvent.detail.entry_point,
104
+ has_angie_installed: hasAngieInstalled
105
+ });
106
+ if (hasAngieInstalled) {
107
+ sendPromptToAngie(customEvent.detail?.prompt);
108
+ return;
109
+ }
110
+ setModalData(customEvent.detail);
111
+ };
112
+ window.addEventListener(CREATE_WIDGET_EVENT, handleShow);
113
+ return () => {
114
+ window.removeEventListener(CREATE_WIDGET_EVENT, handleShow);
115
+ };
116
+ }, []);
117
+ if (!modalData) {
118
+ return null;
119
+ }
120
+ return /* @__PURE__ */ React.createElement(
121
+ CreateWidgetModal,
122
+ {
123
+ prompt: modalData.prompt,
124
+ entryPoint: modalData.entry_point,
125
+ onClose: () => setModalData(null)
126
+ }
127
+ );
70
128
  }
71
129
 
72
130
  // src/init.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/init.ts","../src/components/create-widget.tsx"],"sourcesContent":["import { injectIntoTop } from '@elementor/editor';\n\nimport { CreateWidget } from './components/create-widget';\n\nexport function init() {\n\tinjectIntoTop( {\n\t\tid: 'create-widget',\n\t\tcomponent: CreateWidget,\n\t} );\n}\n","import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { isAngieAvailable, redirectToInstallation, sendPromptToAngie } from '@elementor/editor-mcp';\nimport { ThemeProvider } from '@elementor/editor-ui';\nimport { XIcon } from '@elementor/icons';\nimport { Button, Dialog, DialogContent, IconButton, Image, Stack, Typography } from '@elementor/ui';\nimport { __ } from '@wordpress/i18n';\n\ntype ShowModalEventDetail = {\n\tprompt?: string;\n};\n\nconst CREATE_WIDGET_EVENT = 'elementor/editor/create-widget';\nconst PROMOTION_IMAGE_URL = 'https://assets.elementor.com/packages/v1/images/angie-promotion.svg';\n\nexport function CreateWidget() {\n\tconst [ open, setOpen ] = useState( false );\n\tconst [ prompt, setPrompt ] = useState< string | undefined >();\n\n\tconst handleShow = async ( event: Event ) => {\n\t\tconst customEvent = event as CustomEvent< ShowModalEventDetail >;\n\n\t\tif ( isAngieAvailable() ) {\n\t\t\tsendPromptToAngie( customEvent.detail?.prompt );\n\n\t\t\treturn;\n\t\t}\n\n\t\tsetPrompt( customEvent.detail?.prompt );\n\t\tsetOpen( true );\n\t};\n\n\tconst handleClose = () => {\n\t\tsetOpen( false );\n\t\tsetPrompt( undefined );\n\t};\n\n\tconst handleInstall = () => {\n\t\tif ( ! prompt ) {\n\t\t\treturn;\n\t\t}\n\n\t\tredirectToInstallation( prompt );\n\t};\n\n\tuseEffect( () => {\n\t\twindow.addEventListener( CREATE_WIDGET_EVENT, handleShow );\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener( CREATE_WIDGET_EVENT, handleShow );\n\t\t};\n\t}, [] );\n\n\treturn (\n\t\t<ThemeProvider>\n\t\t\t<Dialog fullWidth maxWidth=\"md\" open={ open } onClose={ handleClose }>\n\t\t\t\t<IconButton\n\t\t\t\t\taria-label={ __( 'Close', 'elementor' ) }\n\t\t\t\t\tonClick={ handleClose }\n\t\t\t\t\tsx={ {\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\tright: 8,\n\t\t\t\t\t\ttop: 8,\n\t\t\t\t\t\tzIndex: 1,\n\t\t\t\t\t} }\n\t\t\t\t>\n\t\t\t\t\t<XIcon />\n\t\t\t\t</IconButton>\n\t\t\t\t<DialogContent sx={ { p: 0, overflow: 'hidden' } }>\n\t\t\t\t\t<Stack direction=\"row\" sx={ { height: 400 } }>\n\t\t\t\t\t\t<Image\n\t\t\t\t\t\t\tsx={ {\n\t\t\t\t\t\t\t\theight: '100%',\n\t\t\t\t\t\t\t\taspectRatio: '1 / 1',\n\t\t\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\t\t\tobjectPosition: 'right center',\n\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\tsrc={ PROMOTION_IMAGE_URL }\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Stack gap={ 2 } justifyContent=\"center\" p={ 4 }>\n\t\t\t\t\t\t\t<Typography variant=\"h6\" fontWeight={ 600 } whiteSpace=\"nowrap\">\n\t\t\t\t\t\t\t\t{ __( 'Install Angie to build custom widgets', 'elementor' ) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t\t\t{ __(\n\t\t\t\t\t\t\t\t\t'Angie lets you generate custom widgets, sections, and code using simple instructions.',\n\t\t\t\t\t\t\t\t\t'elementor'\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t\t\t{ __( 'Install once to start building directly inside the editor.', 'elementor' ) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t<Stack direction=\"row\" justifyContent=\"flex-end\" sx={ { mt: 2 } }>\n\t\t\t\t\t\t\t\t<Button variant=\"contained\" color=\"accent\" onClick={ handleInstall }>\n\t\t\t\t\t\t\t\t\t{ __( 'Install Angie', 'elementor' ) }\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t</Stack>\n\t\t\t\t</DialogContent>\n\t\t\t</Dialog>\n\t\t</ThemeProvider>\n\t);\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;;;ACA9B,YAAY,WAAW;AACvB,SAAS,WAAW,gBAAgB;AACpC,SAAS,kBAAkB,wBAAwB,yBAAyB;AAC5E,SAAS,qBAAqB;AAC9B,SAAS,aAAa;AACtB,SAAS,QAAQ,QAAQ,eAAe,YAAY,OAAO,OAAO,kBAAkB;AACpF,SAAS,UAAU;AAMnB,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAErB,SAAS,eAAe;AAC9B,QAAM,CAAE,MAAM,OAAQ,IAAI,SAAU,KAAM;AAC1C,QAAM,CAAE,QAAQ,SAAU,IAAI,SAA+B;AAE7D,QAAM,aAAa,OAAQ,UAAkB;AAC5C,UAAM,cAAc;AAEpB,QAAK,iBAAiB,GAAI;AACzB,wBAAmB,YAAY,QAAQ,MAAO;AAE9C;AAAA,IACD;AAEA,cAAW,YAAY,QAAQ,MAAO;AACtC,YAAS,IAAK;AAAA,EACf;AAEA,QAAM,cAAc,MAAM;AACzB,YAAS,KAAM;AACf,cAAW,MAAU;AAAA,EACtB;AAEA,QAAM,gBAAgB,MAAM;AAC3B,QAAK,CAAE,QAAS;AACf;AAAA,IACD;AAEA,2BAAwB,MAAO;AAAA,EAChC;AAEA,YAAW,MAAM;AAChB,WAAO,iBAAkB,qBAAqB,UAAW;AAEzD,WAAO,MAAM;AACZ,aAAO,oBAAqB,qBAAqB,UAAW;AAAA,IAC7D;AAAA,EACD,GAAG,CAAC,CAAE;AAEN,SACC,oCAAC,qBACA,oCAAC,UAAO,WAAS,MAAC,UAAS,MAAK,MAAc,SAAU,eACvD;AAAA,IAAC;AAAA;AAAA,MACA,cAAa,GAAI,SAAS,WAAY;AAAA,MACtC,SAAU;AAAA,MACV,IAAK;AAAA,QACJ,UAAU;AAAA,QACV,OAAO;AAAA,QACP,KAAK;AAAA,QACL,QAAQ;AAAA,MACT;AAAA;AAAA,IAEA,oCAAC,WAAM;AAAA,EACR,GACA,oCAAC,iBAAc,IAAK,EAAE,GAAG,GAAG,UAAU,SAAS,KAC9C,oCAAC,SAAM,WAAU,OAAM,IAAK,EAAE,QAAQ,IAAI,KACzC;AAAA,IAAC;AAAA;AAAA,MACA,IAAK;AAAA,QACJ,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,WAAW;AAAA,QACX,gBAAgB;AAAA,MACjB;AAAA,MACA,KAAM;AAAA;AAAA,EACP,GACA,oCAAC,SAAM,KAAM,GAAI,gBAAe,UAAS,GAAI,KAC5C,oCAAC,cAAW,SAAQ,MAAK,YAAa,KAAM,YAAW,YACpD,GAAI,yCAAyC,WAAY,CAC5D,GACA,oCAAC,cAAW,SAAQ,SAAQ,OAAM,oBAC/B;AAAA,IACD;AAAA,IACA;AAAA,EACD,CACD,GACA,oCAAC,cAAW,SAAQ,SAAQ,OAAM,oBAC/B,GAAI,8DAA8D,WAAY,CACjF,GACA,oCAAC,SAAM,WAAU,OAAM,gBAAe,YAAW,IAAK,EAAE,IAAI,EAAE,KAC7D,oCAAC,UAAO,SAAQ,aAAY,OAAM,UAAS,SAAU,iBAClD,GAAI,iBAAiB,WAAY,CACpC,CACD,CACD,CACD,CACD,CACD,CACD;AAEF;;;ADnGO,SAAS,OAAO;AACtB,gBAAe;AAAA,IACd,IAAI;AAAA,IACJ,WAAW;AAAA,EACZ,CAAE;AACH;","names":[]}
1
+ {"version":3,"sources":["../src/init.ts","../src/components/create-widget.tsx"],"sourcesContent":["import { injectIntoTop } from '@elementor/editor';\n\nimport { CreateWidget } from './components/create-widget';\n\nexport function init() {\n\tinjectIntoTop( {\n\t\tid: 'create-widget',\n\t\tcomponent: CreateWidget,\n\t} );\n}\n","import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport {\n\tinstallAngiePlugin,\n\tisAngieAvailable,\n\tredirectToAppAdmin,\n\tredirectToInstallation,\n\tsendPromptToAngie,\n} from '@elementor/editor-mcp';\nimport { ThemeProvider } from '@elementor/editor-ui';\nimport { trackEvent } from '@elementor/events';\nimport { XIcon } from '@elementor/icons';\nimport { Button, CircularProgress, Dialog, DialogContent, IconButton, Image, Stack, Typography } from '@elementor/ui';\nimport { __ } from '@wordpress/i18n';\n\ntype ShowModalEventDetail = {\n\tprompt?: string;\n\tentry_point: string;\n};\n\ntype InstallState = 'idle' | 'installing' | 'error';\n\ntype CreateWidgetModalProps = {\n\tprompt?: string;\n\tentryPoint: string;\n\tonClose: () => void;\n};\n\nconst CREATE_WIDGET_EVENT = 'elementor/editor/create-widget';\nconst PROMOTION_IMAGE_URL = 'https://assets.elementor.com/packages/v1/images/angie-promotion.svg';\nconst ANGIE_CTA_CLICKED_EVENT = 'angie_cta_clicked' as const;\nconst ANGIE_INSTALL_STARTED_EVENT = 'angie_install_started' as const;\n\nfunction CreateWidgetModal( { prompt, entryPoint, onClose }: CreateWidgetModalProps ) {\n\tconst [ installState, setInstallState ] = useState< InstallState >( 'idle' );\n\n\tconst handleClose = () => {\n\t\tif ( installState === 'installing' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tonClose();\n\t};\n\n\tconst handleInstall = async () => {\n\t\tif ( ! prompt ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetInstallState( 'installing' );\n\n\t\ttrackEvent( {\n\t\t\teventName: ANGIE_INSTALL_STARTED_EVENT,\n\t\t\ttrigger_source: entryPoint,\n\t\t} );\n\n\t\tconst result = await installAngiePlugin();\n\n\t\tif ( ! result.success ) {\n\t\t\tsetInstallState( 'error' );\n\n\t\t\treturn;\n\t\t}\n\n\t\tredirectToAppAdmin( prompt );\n\t};\n\n\tconst handleFallbackInstall = () => {\n\t\tif ( ! prompt ) {\n\t\t\treturn;\n\t\t}\n\n\t\tredirectToInstallation( prompt );\n\t};\n\n\treturn (\n\t\t<ThemeProvider>\n\t\t\t<Dialog fullWidth maxWidth=\"md\" open onClose={ handleClose }>\n\t\t\t\t<IconButton\n\t\t\t\t\taria-label={ __( 'Close', 'elementor' ) }\n\t\t\t\t\tonClick={ handleClose }\n\t\t\t\t\tsx={ {\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\tright: 8,\n\t\t\t\t\t\ttop: 8,\n\t\t\t\t\t\tzIndex: 1,\n\t\t\t\t\t} }\n\t\t\t\t>\n\t\t\t\t\t<XIcon />\n\t\t\t\t</IconButton>\n\t\t\t\t<DialogContent sx={ { p: 0, overflow: 'hidden' } }>\n\t\t\t\t\t<Stack direction=\"row\" sx={ { height: 400 } }>\n\t\t\t\t\t\t<Image\n\t\t\t\t\t\t\tsx={ {\n\t\t\t\t\t\t\t\theight: '100%',\n\t\t\t\t\t\t\t\taspectRatio: '1 / 1',\n\t\t\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\t\t\tobjectPosition: 'right center',\n\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\tsrc={ PROMOTION_IMAGE_URL }\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Stack gap={ 2 } justifyContent=\"center\" p={ 4 }>\n\t\t\t\t\t\t\t<Typography variant=\"h6\" fontWeight={ 600 } whiteSpace=\"nowrap\">\n\t\t\t\t\t\t\t\t{ installState === 'error'\n\t\t\t\t\t\t\t\t\t? __( 'Installation failed', 'elementor' )\n\t\t\t\t\t\t\t\t\t: __( 'Install Angie to build custom widgets', 'elementor' ) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t\t\t{ installState === 'error'\n\t\t\t\t\t\t\t\t\t? __(\n\t\t\t\t\t\t\t\t\t\t\t\"We couldn't install Angie automatically. Click below to install it manually.\",\n\t\t\t\t\t\t\t\t\t\t\t'elementor'\n\t\t\t\t\t\t\t\t\t )\n\t\t\t\t\t\t\t\t\t: __(\n\t\t\t\t\t\t\t\t\t\t\t'Angie lets you generate custom widgets, sections, and code using simple instructions.',\n\t\t\t\t\t\t\t\t\t\t\t'elementor'\n\t\t\t\t\t\t\t\t\t ) }\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t{ installState !== 'error' && (\n\t\t\t\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t\t\t\t{ __( 'Install once to start building directly inside the editor.', 'elementor' ) }\n\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t<Stack direction=\"row\" justifyContent=\"flex-end\" sx={ { mt: 2 } }>\n\t\t\t\t\t\t\t\t{ installState === 'error' ? (\n\t\t\t\t\t\t\t\t\t<Button variant=\"contained\" color=\"accent\" onClick={ handleFallbackInstall }>\n\t\t\t\t\t\t\t\t\t\t{ __( 'Install Manually', 'elementor' ) }\n\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\t\t\tcolor=\"accent\"\n\t\t\t\t\t\t\t\t\t\tonClick={ handleInstall }\n\t\t\t\t\t\t\t\t\t\tdisabled={ installState === 'installing' }\n\t\t\t\t\t\t\t\t\t\tstartIcon={\n\t\t\t\t\t\t\t\t\t\t\tinstallState === 'installing' ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<CircularProgress size={ 18 } color=\"inherit\" />\n\t\t\t\t\t\t\t\t\t\t\t) : undefined\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{ installState === 'installing'\n\t\t\t\t\t\t\t\t\t\t\t? __( 'Installing…', 'elementor' )\n\t\t\t\t\t\t\t\t\t\t\t: __( 'Install Angie', 'elementor' ) }\n\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t</Stack>\n\t\t\t\t</DialogContent>\n\t\t\t</Dialog>\n\t\t</ThemeProvider>\n\t);\n}\n\nexport function CreateWidget() {\n\tconst [ modalData, setModalData ] = useState< ShowModalEventDetail | null >( null );\n\n\tuseEffect( () => {\n\t\tconst handleShow = ( event: Event ) => {\n\t\t\tconst customEvent = event as CustomEvent< ShowModalEventDetail >;\n\t\t\tconst hasAngieInstalled = isAngieAvailable();\n\n\t\t\ttrackEvent( {\n\t\t\t\teventName: ANGIE_CTA_CLICKED_EVENT,\n\t\t\t\tentry_point: customEvent.detail.entry_point,\n\t\t\t\thas_angie_installed: hasAngieInstalled,\n\t\t\t} );\n\n\t\t\tif ( hasAngieInstalled ) {\n\t\t\t\tsendPromptToAngie( customEvent.detail?.prompt );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetModalData( customEvent.detail );\n\t\t};\n\n\t\twindow.addEventListener( CREATE_WIDGET_EVENT, handleShow );\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener( CREATE_WIDGET_EVENT, handleShow );\n\t\t};\n\t}, [] );\n\n\tif ( ! modalData ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<CreateWidgetModal\n\t\t\tprompt={ modalData.prompt }\n\t\t\tentryPoint={ modalData.entry_point }\n\t\t\tonClose={ () => setModalData( null ) }\n\t\t/>\n\t);\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-widget-creation",
3
- "version": "4.0.0-manual",
3
+ "version": "4.0.1",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,12 +39,12 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "4.0.0-manual",
43
- "@elementor/editor-mcp": "4.0.0-manual",
44
- "@elementor/editor-ui": "4.0.0-manual",
42
+ "@elementor/editor": "4.0.1",
43
+ "@elementor/editor-mcp": "4.0.1",
44
+ "@elementor/editor-ui": "4.0.1",
45
+ "@elementor/events": "4.0.1",
45
46
  "@elementor/icons": "^1.63.0",
46
47
  "@elementor/ui": "1.36.17",
47
- "@wordpress/api-fetch": "^6.42.0",
48
48
  "@wordpress/i18n": "^5.13.0"
49
49
  },
50
50
  "peerDependencies": {
@@ -1,41 +1,71 @@
1
1
  import * as React from 'react';
2
2
  import { useEffect, useState } from 'react';
3
- import { isAngieAvailable, redirectToInstallation, sendPromptToAngie } from '@elementor/editor-mcp';
3
+ import {
4
+ installAngiePlugin,
5
+ isAngieAvailable,
6
+ redirectToAppAdmin,
7
+ redirectToInstallation,
8
+ sendPromptToAngie,
9
+ } from '@elementor/editor-mcp';
4
10
  import { ThemeProvider } from '@elementor/editor-ui';
11
+ import { trackEvent } from '@elementor/events';
5
12
  import { XIcon } from '@elementor/icons';
6
- import { Button, Dialog, DialogContent, IconButton, Image, Stack, Typography } from '@elementor/ui';
13
+ import { Button, CircularProgress, Dialog, DialogContent, IconButton, Image, Stack, Typography } from '@elementor/ui';
7
14
  import { __ } from '@wordpress/i18n';
8
15
 
9
16
  type ShowModalEventDetail = {
10
17
  prompt?: string;
18
+ entry_point: string;
19
+ };
20
+
21
+ type InstallState = 'idle' | 'installing' | 'error';
22
+
23
+ type CreateWidgetModalProps = {
24
+ prompt?: string;
25
+ entryPoint: string;
26
+ onClose: () => void;
11
27
  };
12
28
 
13
29
  const CREATE_WIDGET_EVENT = 'elementor/editor/create-widget';
14
30
  const PROMOTION_IMAGE_URL = 'https://assets.elementor.com/packages/v1/images/angie-promotion.svg';
31
+ const ANGIE_CTA_CLICKED_EVENT = 'angie_cta_clicked' as const;
32
+ const ANGIE_INSTALL_STARTED_EVENT = 'angie_install_started' as const;
15
33
 
16
- export function CreateWidget() {
17
- const [ open, setOpen ] = useState( false );
18
- const [ prompt, setPrompt ] = useState< string | undefined >();
34
+ function CreateWidgetModal( { prompt, entryPoint, onClose }: CreateWidgetModalProps ) {
35
+ const [ installState, setInstallState ] = useState< InstallState >( 'idle' );
19
36
 
20
- const handleShow = async ( event: Event ) => {
21
- const customEvent = event as CustomEvent< ShowModalEventDetail >;
37
+ const handleClose = () => {
38
+ if ( installState === 'installing' ) {
39
+ return;
40
+ }
22
41
 
23
- if ( isAngieAvailable() ) {
24
- sendPromptToAngie( customEvent.detail?.prompt );
42
+ onClose();
43
+ };
25
44
 
45
+ const handleInstall = async () => {
46
+ if ( ! prompt ) {
26
47
  return;
27
48
  }
28
49
 
29
- setPrompt( customEvent.detail?.prompt );
30
- setOpen( true );
31
- };
50
+ setInstallState( 'installing' );
32
51
 
33
- const handleClose = () => {
34
- setOpen( false );
35
- setPrompt( undefined );
52
+ trackEvent( {
53
+ eventName: ANGIE_INSTALL_STARTED_EVENT,
54
+ trigger_source: entryPoint,
55
+ } );
56
+
57
+ const result = await installAngiePlugin();
58
+
59
+ if ( ! result.success ) {
60
+ setInstallState( 'error' );
61
+
62
+ return;
63
+ }
64
+
65
+ redirectToAppAdmin( prompt );
36
66
  };
37
67
 
38
- const handleInstall = () => {
68
+ const handleFallbackInstall = () => {
39
69
  if ( ! prompt ) {
40
70
  return;
41
71
  }
@@ -43,17 +73,9 @@ export function CreateWidget() {
43
73
  redirectToInstallation( prompt );
44
74
  };
45
75
 
46
- useEffect( () => {
47
- window.addEventListener( CREATE_WIDGET_EVENT, handleShow );
48
-
49
- return () => {
50
- window.removeEventListener( CREATE_WIDGET_EVENT, handleShow );
51
- };
52
- }, [] );
53
-
54
76
  return (
55
77
  <ThemeProvider>
56
- <Dialog fullWidth maxWidth="md" open={ open } onClose={ handleClose }>
78
+ <Dialog fullWidth maxWidth="md" open onClose={ handleClose }>
57
79
  <IconButton
58
80
  aria-label={ __( 'Close', 'elementor' ) }
59
81
  onClick={ handleClose }
@@ -79,21 +101,48 @@ export function CreateWidget() {
79
101
  />
80
102
  <Stack gap={ 2 } justifyContent="center" p={ 4 }>
81
103
  <Typography variant="h6" fontWeight={ 600 } whiteSpace="nowrap">
82
- { __( 'Install Angie to build custom widgets', 'elementor' ) }
104
+ { installState === 'error'
105
+ ? __( 'Installation failed', 'elementor' )
106
+ : __( 'Install Angie to build custom widgets', 'elementor' ) }
83
107
  </Typography>
84
108
  <Typography variant="body2" color="text.secondary">
85
- { __(
86
- 'Angie lets you generate custom widgets, sections, and code using simple instructions.',
87
- 'elementor'
88
- ) }
89
- </Typography>
90
- <Typography variant="body2" color="text.secondary">
91
- { __( 'Install once to start building directly inside the editor.', 'elementor' ) }
109
+ { installState === 'error'
110
+ ? __(
111
+ "We couldn't install Angie automatically. Click below to install it manually.",
112
+ 'elementor'
113
+ )
114
+ : __(
115
+ 'Angie lets you generate custom widgets, sections, and code using simple instructions.',
116
+ 'elementor'
117
+ ) }
92
118
  </Typography>
119
+ { installState !== 'error' && (
120
+ <Typography variant="body2" color="text.secondary">
121
+ { __( 'Install once to start building directly inside the editor.', 'elementor' ) }
122
+ </Typography>
123
+ ) }
93
124
  <Stack direction="row" justifyContent="flex-end" sx={ { mt: 2 } }>
94
- <Button variant="contained" color="accent" onClick={ handleInstall }>
95
- { __( 'Install Angie', 'elementor' ) }
96
- </Button>
125
+ { installState === 'error' ? (
126
+ <Button variant="contained" color="accent" onClick={ handleFallbackInstall }>
127
+ { __( 'Install Manually', 'elementor' ) }
128
+ </Button>
129
+ ) : (
130
+ <Button
131
+ variant="contained"
132
+ color="accent"
133
+ onClick={ handleInstall }
134
+ disabled={ installState === 'installing' }
135
+ startIcon={
136
+ installState === 'installing' ? (
137
+ <CircularProgress size={ 18 } color="inherit" />
138
+ ) : undefined
139
+ }
140
+ >
141
+ { installState === 'installing'
142
+ ? __( 'Installing…', 'elementor' )
143
+ : __( 'Install Angie', 'elementor' ) }
144
+ </Button>
145
+ ) }
97
146
  </Stack>
98
147
  </Stack>
99
148
  </Stack>
@@ -102,3 +151,46 @@ export function CreateWidget() {
102
151
  </ThemeProvider>
103
152
  );
104
153
  }
154
+
155
+ export function CreateWidget() {
156
+ const [ modalData, setModalData ] = useState< ShowModalEventDetail | null >( null );
157
+
158
+ useEffect( () => {
159
+ const handleShow = ( event: Event ) => {
160
+ const customEvent = event as CustomEvent< ShowModalEventDetail >;
161
+ const hasAngieInstalled = isAngieAvailable();
162
+
163
+ trackEvent( {
164
+ eventName: ANGIE_CTA_CLICKED_EVENT,
165
+ entry_point: customEvent.detail.entry_point,
166
+ has_angie_installed: hasAngieInstalled,
167
+ } );
168
+
169
+ if ( hasAngieInstalled ) {
170
+ sendPromptToAngie( customEvent.detail?.prompt );
171
+
172
+ return;
173
+ }
174
+
175
+ setModalData( customEvent.detail );
176
+ };
177
+
178
+ window.addEventListener( CREATE_WIDGET_EVENT, handleShow );
179
+
180
+ return () => {
181
+ window.removeEventListener( CREATE_WIDGET_EVENT, handleShow );
182
+ };
183
+ }, [] );
184
+
185
+ if ( ! modalData ) {
186
+ return null;
187
+ }
188
+
189
+ return (
190
+ <CreateWidgetModal
191
+ prompt={ modalData.prompt }
192
+ entryPoint={ modalData.entry_point }
193
+ onClose={ () => setModalData( null ) }
194
+ />
195
+ );
196
+ }