@elementor/editor-app-bar 4.1.0-838 → 4.1.0-beta2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-app-bar",
3
3
  "description": "App Bar extension for @elementor/editor",
4
- "version": "4.1.0-838",
4
+ "version": "4.1.0-beta2",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -40,17 +40,18 @@
40
40
  "dev": "tsup --config=../../tsup.dev.ts"
41
41
  },
42
42
  "dependencies": {
43
- "@elementor/editor-ui": "4.1.0-838",
44
- "@elementor/http-client": "4.1.0-838",
45
- "@elementor/editor": "4.1.0-838",
46
- "@elementor/editor-documents": "4.1.0-838",
47
- "@elementor/editor-mcp": "4.1.0-838",
48
- "@elementor/editor-responsive": "4.1.0-838",
49
- "@elementor/editor-v1-adapters": "4.1.0-838",
43
+ "@elementor/editor-current-user": "4.1.0-beta2",
44
+ "@elementor/editor-ui": "4.1.0-beta2",
45
+ "@elementor/http-client": "4.1.0-beta2",
46
+ "@elementor/editor": "4.1.0-beta2",
47
+ "@elementor/editor-documents": "4.1.0-beta2",
48
+ "@elementor/editor-mcp": "4.1.0-beta2",
49
+ "@elementor/editor-responsive": "4.1.0-beta2",
50
+ "@elementor/editor-v1-adapters": "4.1.0-beta2",
50
51
  "@elementor/icons": "~1.75.1",
51
- "@elementor/locations": "4.1.0-838",
52
- "@elementor/menus": "4.1.0-838",
53
- "@elementor/events": "4.1.0-838",
52
+ "@elementor/locations": "4.1.0-beta2",
53
+ "@elementor/menus": "4.1.0-beta2",
54
+ "@elementor/events": "4.1.0-beta2",
54
55
  "@elementor/ui": "1.37.5",
55
56
  "@wordpress/i18n": "^5.13.0"
56
57
  },
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
 
3
+ import { AngieGuideLocation } from '../../extensions/angie/components/angie-guide-location';
3
4
  import { toolsMenu } from '../../locations';
4
5
  import ToolbarMenu from '../ui/toolbar-menu';
5
6
  import ToolbarMenuMore from '../ui/toolbar-menu-more';
@@ -21,6 +22,7 @@ export default function ToolsMenuLocation() {
21
22
  { toolbarMenuItems.map( ( { MenuItem, id } ) => (
22
23
  <MenuItem key={ id } />
23
24
  ) ) }
25
+ <AngieGuideLocation />
24
26
  <SendFeedbackPopupLocation />
25
27
  <IntegrationsMenuLocation />
26
28
  { popoverMenuItems.length > 0 && (
@@ -0,0 +1,20 @@
1
+ import { __ } from '@wordpress/i18n';
2
+
3
+ export const ANGIE_GUIDE_TOGGLE_EVENT = 'elementor/editor/toggle-angie-guide';
4
+ export const CREATE_WIDGET_EVENT = 'elementor/editor/create-widget';
5
+
6
+ export const ANGIE_BUTTON_ARIA_LABEL = __( 'Angie', 'elementor' );
7
+
8
+ export const ANGIE_PROMOTION_IMAGE_URL = 'https://assets.elementor.com/packages/v1/images/angie-promotion.svg';
9
+
10
+ export const ANGIE_LEARN_MORE_URL = 'https://go.elementor.com/angie-learn-more';
11
+
12
+ export const ANGIE_DESCRIPTION = __(
13
+ 'Angie lets you generate custom widgets, sections, and code using simple instructions.',
14
+ 'elementor'
15
+ );
16
+
17
+ export const AI_WIDGET_CTA_VIEWED_EVENT = 'ai_widget_cta_viewed' as const;
18
+ export const ANGIE_TOP_BAR_PROMOTION_IMAGE_URL =
19
+ 'https://assets.elementor.com/packages/v1/images/angie-top-bar-promotion.svg';
20
+ export const ANGIE_TOP_BAR_DESCRIPTION = __( 'Build custom widgets using simple instructions.', 'elementor' );
@@ -0,0 +1,54 @@
1
+ import * as React from 'react';
2
+ import { Button, Chip, ClickAwayListener, CloseButton, Image, Stack, Typography } from '@elementor/ui';
3
+ import { __ } from '@wordpress/i18n';
4
+
5
+ type Props = {
6
+ imageUrl: string;
7
+ description: string;
8
+ learnMoreUrl: string;
9
+ onInstall?: () => void;
10
+ onClose: () => void;
11
+ };
12
+
13
+ export function AngieGuideCard( { imageUrl, description, learnMoreUrl, onInstall, onClose }: Props ) {
14
+ return (
15
+ <ClickAwayListener onClickAway={ onClose }>
16
+ <Stack sx={ { width: 296 } } data-testid="e-angie-guide-card">
17
+ <Stack direction="row" alignItems="center" gap={ 1 } py={ 1 } px={ 2 }>
18
+ <Typography variant="subtitle2">{ __( 'Meet Angie', 'elementor' ) }</Typography>
19
+ <Chip label={ __( 'New', 'elementor' ) } size="small" color="info" variant="standard" />
20
+ <CloseButton
21
+ edge="end"
22
+ sx={ { ml: 'auto' } }
23
+ slotProps={ { icon: { fontSize: 'small' } } }
24
+ onClick={ onClose }
25
+ />
26
+ </Stack>
27
+ <Image src={ imageUrl } alt={ __( 'Angie', 'elementor' ) } sx={ { height: 150, width: '100%' } } />
28
+ <Stack px={ 2 } pt={ 1.5 } pb={ 1 }>
29
+ <Typography variant="body2" color="secondary">
30
+ { description }
31
+ </Typography>
32
+ </Stack>
33
+ <Stack direction="row" justifyContent="flex-end" gap={ 1 } pt={ 1 } pb={ 1.5 } px={ 2 }>
34
+ <Button
35
+ variant="text"
36
+ size="small"
37
+ color="secondary"
38
+ onClick={ () => {
39
+ window.open( learnMoreUrl, '_blank', 'noopener,noreferrer' );
40
+ onClose();
41
+ } }
42
+ >
43
+ { __( 'Learn More', 'elementor' ) }
44
+ </Button>
45
+ { onInstall && (
46
+ <Button variant="contained" size="small" color="accent" onClick={ onInstall }>
47
+ { __( 'Try for free', 'elementor' ) }
48
+ </Button>
49
+ ) }
50
+ </Stack>
51
+ </Stack>
52
+ </ClickAwayListener>
53
+ );
54
+ }
@@ -0,0 +1,91 @@
1
+ import * as React from 'react';
2
+ import { useEffect, useState } from 'react';
3
+ import { useCurrentUserCapabilities } from '@elementor/editor-current-user';
4
+ import { ThemeProvider } from '@elementor/editor-ui';
5
+ import { useMixpanel } from '@elementor/events';
6
+ import { Infotip } from '@elementor/ui';
7
+
8
+ import {
9
+ AI_WIDGET_CTA_VIEWED_EVENT,
10
+ ANGIE_BUTTON_ARIA_LABEL,
11
+ ANGIE_GUIDE_TOGGLE_EVENT,
12
+ ANGIE_LEARN_MORE_URL,
13
+ ANGIE_TOP_BAR_DESCRIPTION,
14
+ ANGIE_TOP_BAR_PROMOTION_IMAGE_URL,
15
+ CREATE_WIDGET_EVENT,
16
+ } from '../angie-consts';
17
+ import { AngieGuideCard } from '../components/angie-guide-card';
18
+ import { useAutoShow } from '../hooks/use-auto-show';
19
+
20
+ export function AngieGuideLocation() {
21
+ useAutoShow();
22
+ const [ anchorEl, setAnchorEl ] = useState< Element | null >( null );
23
+ const { dispatchEvent } = useMixpanel();
24
+ const { isAdmin } = useCurrentUserCapabilities();
25
+
26
+ const isOpen = Boolean( anchorEl );
27
+
28
+ useEffect( () => {
29
+ const handleToggle = () => {
30
+ setAnchorEl( ( prev ) => {
31
+ if ( prev ) {
32
+ return null;
33
+ }
34
+
35
+ return document.querySelector( `[aria-label="${ ANGIE_BUTTON_ARIA_LABEL }"]` );
36
+ } );
37
+ };
38
+
39
+ window.addEventListener( ANGIE_GUIDE_TOGGLE_EVENT, handleToggle );
40
+
41
+ return () => {
42
+ window.removeEventListener( ANGIE_GUIDE_TOGGLE_EVENT, handleToggle );
43
+ };
44
+ }, [] );
45
+
46
+ const handleClose = () => setAnchorEl( null );
47
+
48
+ const handleInstall = async () => {
49
+ dispatchEvent?.( AI_WIDGET_CTA_VIEWED_EVENT, {
50
+ entry_point: 'top_bar_icon',
51
+ } );
52
+ window.dispatchEvent(
53
+ new CustomEvent( CREATE_WIDGET_EVENT, {
54
+ detail: {
55
+ entry_point: 'top_bar_icon',
56
+ },
57
+ } )
58
+ );
59
+ handleClose();
60
+ };
61
+
62
+ return (
63
+ <ThemeProvider>
64
+ <Infotip
65
+ content={
66
+ <AngieGuideCard
67
+ imageUrl={ ANGIE_TOP_BAR_PROMOTION_IMAGE_URL }
68
+ description={ ANGIE_TOP_BAR_DESCRIPTION }
69
+ learnMoreUrl={ ANGIE_LEARN_MORE_URL }
70
+ onInstall={ isAdmin ? handleInstall : undefined }
71
+ onClose={ handleClose }
72
+ />
73
+ }
74
+ placement="bottom-start"
75
+ open={ isOpen }
76
+ disableHoverListener={ true }
77
+ PopperProps={ {
78
+ anchorEl,
79
+ modifiers: [
80
+ {
81
+ name: 'offset',
82
+ options: { offset: [ -4, -4 ] },
83
+ },
84
+ ],
85
+ } }
86
+ >
87
+ <span />
88
+ </Infotip>
89
+ </ThemeProvider>
90
+ );
91
+ }
@@ -1,29 +1,34 @@
1
+ import { useEffect } from 'react';
1
2
  import { isAngieAvailable } from '@elementor/editor-mcp';
3
+ import { trackEvent } from '@elementor/events';
2
4
  import { AngieIcon } from '@elementor/icons';
3
5
  import { __ } from '@wordpress/i18n';
4
6
 
5
- const CREATE_WIDGET_EVENT = 'elementor/editor/create-widget';
7
+ import { AI_WIDGET_CTA_VIEWED_EVENT, ANGIE_GUIDE_TOGGLE_EVENT } from '../angie-consts';
6
8
 
7
- const CREATE_WIDGET_PROMPT = `Create a widget for me.
8
- Goal: [What should this widget help me accomplish?]
9
- Placement: [Where will I see it in the editor/UI?]
10
- How it should work: `;
9
+ export function useActionProps() {
10
+ const hasAngieInstalled = isAngieAvailable();
11
+ const visible = ! hasAngieInstalled;
12
+
13
+ useEffect( () => {
14
+ if ( ! visible ) {
15
+ return;
16
+ }
17
+
18
+ trackEvent( {
19
+ eventName: AI_WIDGET_CTA_VIEWED_EVENT,
20
+ entry_point: 'top_bar_icon',
21
+ has_angie_installed: false,
22
+ } );
23
+ }, [ visible ] );
11
24
 
12
- export default function useActionProps() {
13
25
  return {
14
26
  title: __( 'Angie', 'elementor' ),
15
27
  icon: AngieIcon,
16
28
  onClick: () => {
17
- window.dispatchEvent(
18
- new CustomEvent( CREATE_WIDGET_EVENT, {
19
- detail: {
20
- prompt: CREATE_WIDGET_PROMPT,
21
- entry_point: 'top_bar',
22
- },
23
- } )
24
- );
29
+ window.dispatchEvent( new CustomEvent( ANGIE_GUIDE_TOGGLE_EVENT ) );
25
30
  },
26
31
  selected: false,
27
- visible: ! isAngieAvailable(),
32
+ visible,
28
33
  };
29
34
  }
@@ -0,0 +1,17 @@
1
+ import { useEffect } from 'react';
2
+
3
+ import { ANGIE_GUIDE_TOGGLE_EVENT } from '../angie-consts';
4
+
5
+ export function useAutoShow() {
6
+ useEffect( () => {
7
+ if ( ! window.elementor?.config?.angie?.autoShow ) {
8
+ return;
9
+ }
10
+
11
+ const id = setTimeout( () => {
12
+ window.dispatchEvent( new CustomEvent( ANGIE_GUIDE_TOGGLE_EVENT ) );
13
+ }, 0 );
14
+
15
+ return () => clearTimeout( id );
16
+ }, [] );
17
+ }
@@ -1,5 +1,5 @@
1
1
  import { toolsMenu } from '../../locations';
2
- import useActionProps from './hooks/use-action-props';
2
+ import { useActionProps } from './hooks/use-action-props';
3
3
 
4
4
  export function init() {
5
5
  toolsMenu.registerToggleAction( {