diff --git a/src/designer/designer_packages/angular-workspace/projects/component-library/src/lib/stencil-generated/components.ts b/src/designer/designer_packages/angular-workspace/projects/component-library/src/lib/stencil-generated/components.ts
index 988fd4abb..9b9bcbae4 100644
--- a/src/designer/designer_packages/angular-workspace/projects/component-library/src/lib/stencil-generated/components.ts
+++ b/src/designer/designer_packages/angular-workspace/projects/component-library/src/lib/stencil-generated/components.ts
@@ -121,14 +121,14 @@ export declare interface ElsaActivityPropertiesEditor extends Components.ElsaAct
@ProxyCmp({
- inputs: ['notification']
+ inputs: ['notification', 'showDuration']
})
@Component({
selector: 'elsa-awhile-notifications',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
- inputs: ['notification'],
+ inputs: ['notification', 'showDuration'],
})
export class ElsaAwhileNotifications {
protected el: HTMLElement;
@@ -762,6 +762,28 @@ export class ElsaMultiTextInput {
export declare interface ElsaMultiTextInput extends Components.ElsaMultiTextInput {}
+@ProxyCmp({
+ inputs: ['notification']
+})
+@Component({
+ selector: 'elsa-notification-template',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: '',
+ // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
+ inputs: ['notification'],
+})
+export class ElsaNotificationTemplate {
+ protected el: HTMLElement;
+ constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
+ c.detach();
+ this.el = r.nativeElement;
+ }
+}
+
+
+export declare interface ElsaNotificationTemplate extends Components.ElsaNotificationTemplate {}
+
+
@ProxyCmp({
inputs: ['modalState']
})
@@ -1020,6 +1042,27 @@ export class ElsaSwitchEditor {
export declare interface ElsaSwitchEditor extends Components.ElsaSwitchEditor {}
+@ProxyCmp({
+})
+@Component({
+ selector: 'elsa-toast-manager',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: '',
+ // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
+ inputs: [],
+})
+export class ElsaToastManager {
+ protected el: HTMLElement;
+ constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
+ c.detach();
+ this.el = r.nativeElement;
+ }
+}
+
+
+export declare interface ElsaToastManager extends Components.ElsaToastManager {}
+
+
@ProxyCmp({
inputs: ['tooltipContent', 'tooltipPosition']
})
diff --git a/src/designer/designer_packages/angular-workspace/projects/component-library/src/lib/stencil-generated/index.ts b/src/designer/designer_packages/angular-workspace/projects/component-library/src/lib/stencil-generated/index.ts
index 9230f65a7..47e41de80 100644
--- a/src/designer/designer_packages/angular-workspace/projects/component-library/src/lib/stencil-generated/index.ts
+++ b/src/designer/designer_packages/angular-workspace/projects/component-library/src/lib/stencil-generated/index.ts
@@ -31,6 +31,7 @@ export const DIRECTIVES = [
d.ElsaMonacoEditor,
d.ElsaMultiLineInput,
d.ElsaMultiTextInput,
+ d.ElsaNotificationTemplate,
d.ElsaNotificationsManager,
d.ElsaOutcomePickerInput,
d.ElsaOutputPickerInput,
@@ -42,6 +43,7 @@ export const DIRECTIVES = [
d.ElsaSlideOverPanel,
d.ElsaStudio,
d.ElsaSwitchEditor,
+ d.ElsaToastManager,
d.ElsaTooltip,
d.ElsaTypePickerInput,
d.ElsaVariableEditorDialogContent,
diff --git a/src/designer/designer_packages/elsa-workflows-designer/src/modules/flowchart/shapes.ts b/src/designer/designer_packages/elsa-workflows-designer/src/modules/flowchart/shapes.ts
index 1d8755393..3f11def78 100644
--- a/src/designer/designer_packages/elsa-workflows-designer/src/modules/flowchart/shapes.ts
+++ b/src/designer/designer_packages/elsa-workflows-designer/src/modules/flowchart/shapes.ts
@@ -58,12 +58,15 @@ export class ActivityNodeShape extends Shape.HTML {
return;
const wrapper = document.createElement('div');
- wrapper.className = 'w-full flex items-center pl-10 pr-2 py-2 absolute';
+ wrapper.className = 'inline-block flex items-center pl-10 pr-2 py-2 absolute';
wrapper.style.left = '-1000px';
wrapper.style.top = '-1000px';
wrapper.innerHTML = this.createHtml();
- document.body.append(wrapper);
+ // Append the temporary element to the DOM.
+ // Important: this needs to be a child of the elsa-shell element, otherwise the tailwind CSS classes will not be applied due to the "important" rule in tailwind.config.js.
+ const elsaStudioShell = document.getElementsByTagName('elsa-shell')[0];
+ elsaStudioShell.append(wrapper);
// Wait for activity element to be completely rendered.
// When using custom elements, they are rendered after they are mounted. Before then, they have a 0 width and height.
diff --git a/src/designer/designer_packages/elsa-workflows-designer/tailwind.config.js b/src/designer/designer_packages/elsa-workflows-designer/tailwind.config.js
index b082356da..3bf019e2e 100644
--- a/src/designer/designer_packages/elsa-workflows-designer/tailwind.config.js
+++ b/src/designer/designer_packages/elsa-workflows-designer/tailwind.config.js
@@ -7,6 +7,7 @@ const dev = process.argv && process.argv.indexOf('--dev') > -1;
module.exports = {
content: ['./src/**/*.tsx', './src/**/*.ts'],
darkMode: 'media',
+ important: 'elsa-shell',
theme: {
extend: {
colors: {
diff --git a/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/index.ts b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/index.ts
new file mode 100644
index 000000000..21bbfe342
--- /dev/null
+++ b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/index.ts
@@ -0,0 +1,76 @@
+/* eslint-disable */
+/* tslint:disable */
+/* auto-generated react proxies */
+import { createReactComponent } from './react-component-lib';
+
+import type { JSX } from '@elsa-workflows/elsa-workflows-designer';
+
+
+
+export const ElsaActivityInputEditorDialogContent = /*@__PURE__*/createReactComponent('elsa-activity-input-editor-dialog-content');
+export const ElsaActivityOutputEditorDialogContent = /*@__PURE__*/createReactComponent('elsa-activity-output-editor-dialog-content');
+export const ElsaActivityProperties = /*@__PURE__*/createReactComponent('elsa-activity-properties');
+export const ElsaActivityPropertiesEditor = /*@__PURE__*/createReactComponent('elsa-activity-properties-editor');
+export const ElsaAwhileNotifications = /*@__PURE__*/createReactComponent('elsa-awhile-notifications');
+export const ElsaButtonGroup = /*@__PURE__*/createReactComponent('elsa-button-group');
+export const ElsaCheckListInput = /*@__PURE__*/createReactComponent('elsa-check-list-input');
+export const ElsaCheckboxInput = /*@__PURE__*/createReactComponent('elsa-checkbox-input');
+export const ElsaCodeEditorInput = /*@__PURE__*/createReactComponent('elsa-code-editor-input');
+export const ElsaContextMenu = /*@__PURE__*/createReactComponent('elsa-context-menu');
+export const ElsaCopyButton = /*@__PURE__*/createReactComponent('elsa-copy-button');
+export const ElsaDefaultActivityTemplate = /*@__PURE__*/createReactComponent('elsa-default-activity-template');
+export const ElsaDropdownButton = /*@__PURE__*/createReactComponent('elsa-dropdown-button');
+export const ElsaDropdownInput = /*@__PURE__*/createReactComponent('elsa-dropdown-input');
+export const ElsaFlowSwitchEditor = /*@__PURE__*/createReactComponent('elsa-flow-switch-editor');
+export const ElsaFlowchart = /*@__PURE__*/createReactComponent('elsa-flowchart');
+export const ElsaFormPanel = /*@__PURE__*/createReactComponent('elsa-form-panel');
+export const ElsaHomePage = /*@__PURE__*/createReactComponent('elsa-home-page');
+export const ElsaHttpStatusCodesEditor = /*@__PURE__*/createReactComponent('elsa-http-status-codes-editor');
+export const ElsaInputControlSwitch = /*@__PURE__*/createReactComponent('elsa-input-control-switch');
+export const ElsaInputTags = /*@__PURE__*/createReactComponent('elsa-input-tags');
+export const ElsaInputTagsDropdown = /*@__PURE__*/createReactComponent('elsa-input-tags-dropdown');
+export const ElsaLabelPicker = /*@__PURE__*/createReactComponent('elsa-label-picker');
+export const ElsaLoginPage = /*@__PURE__*/createReactComponent('elsa-login-page');
+export const ElsaModalDialog = /*@__PURE__*/createReactComponent('elsa-modal-dialog');
+export const ElsaModalDialogContainer = /*@__PURE__*/createReactComponent('elsa-modal-dialog-container');
+export const ElsaMonacoEditor = /*@__PURE__*/createReactComponent('elsa-monaco-editor');
+export const ElsaMultiLineInput = /*@__PURE__*/createReactComponent('elsa-multi-line-input');
+export const ElsaMultiTextInput = /*@__PURE__*/createReactComponent('elsa-multi-text-input');
+export const ElsaNotificationTemplate = /*@__PURE__*/createReactComponent('elsa-notification-template');
+export const ElsaNotificationsManager = /*@__PURE__*/createReactComponent('elsa-notifications-manager');
+export const ElsaOutcomePickerInput = /*@__PURE__*/createReactComponent('elsa-outcome-picker-input');
+export const ElsaOutputPickerInput = /*@__PURE__*/createReactComponent('elsa-output-picker-input');
+export const ElsaPager = /*@__PURE__*/createReactComponent('elsa-pager');
+export const ElsaPanel = /*@__PURE__*/createReactComponent('elsa-panel');
+export const ElsaRadioListInput = /*@__PURE__*/createReactComponent('elsa-radio-list-input');
+export const ElsaShell = /*@__PURE__*/createReactComponent('elsa-shell');
+export const ElsaSingleLineInput = /*@__PURE__*/createReactComponent('elsa-single-line-input');
+export const ElsaSlideOverPanel = /*@__PURE__*/createReactComponent('elsa-slide-over-panel');
+export const ElsaStudio = /*@__PURE__*/createReactComponent('elsa-studio');
+export const ElsaSwitchEditor = /*@__PURE__*/createReactComponent('elsa-switch-editor');
+export const ElsaToastManager = /*@__PURE__*/createReactComponent('elsa-toast-manager');
+export const ElsaTooltip = /*@__PURE__*/createReactComponent('elsa-tooltip');
+export const ElsaTypePickerInput = /*@__PURE__*/createReactComponent('elsa-type-picker-input');
+export const ElsaVariableEditorDialogContent = /*@__PURE__*/createReactComponent('elsa-variable-editor-dialog-content');
+export const ElsaVariablePickerInput = /*@__PURE__*/createReactComponent('elsa-variable-picker-input');
+export const ElsaVariablesEditor = /*@__PURE__*/createReactComponent('elsa-variables-editor');
+export const ElsaVariablesViewer = /*@__PURE__*/createReactComponent('elsa-variables-viewer');
+export const ElsaWidgets = /*@__PURE__*/createReactComponent('elsa-widgets');
+export const ElsaWorkflowDefinitionActivityVersionSettings = /*@__PURE__*/createReactComponent('elsa-workflow-definition-activity-version-settings');
+export const ElsaWorkflowDefinitionBrowser = /*@__PURE__*/createReactComponent('elsa-workflow-definition-browser');
+export const ElsaWorkflowDefinitionEditor = /*@__PURE__*/createReactComponent('elsa-workflow-definition-editor');
+export const ElsaWorkflowDefinitionEditorToolbar = /*@__PURE__*/createReactComponent('elsa-workflow-definition-editor-toolbar');
+export const ElsaWorkflowDefinitionEditorToolbox = /*@__PURE__*/createReactComponent('elsa-workflow-definition-editor-toolbox');
+export const ElsaWorkflowDefinitionEditorToolboxActivities = /*@__PURE__*/createReactComponent('elsa-workflow-definition-editor-toolbox-activities');
+export const ElsaWorkflowDefinitionInputOutputSettings = /*@__PURE__*/createReactComponent('elsa-workflow-definition-input-output-settings');
+export const ElsaWorkflowDefinitionPickerInput = /*@__PURE__*/createReactComponent('elsa-workflow-definition-picker-input');
+export const ElsaWorkflowDefinitionPropertiesEditor = /*@__PURE__*/createReactComponent('elsa-workflow-definition-properties-editor');
+export const ElsaWorkflowDefinitionVersionHistory = /*@__PURE__*/createReactComponent('elsa-workflow-definition-version-history');
+export const ElsaWorkflowInstanceBrowser = /*@__PURE__*/createReactComponent('elsa-workflow-instance-browser');
+export const ElsaWorkflowInstanceProperties = /*@__PURE__*/createReactComponent('elsa-workflow-instance-properties');
+export const ElsaWorkflowInstanceViewer = /*@__PURE__*/createReactComponent('elsa-workflow-instance-viewer');
+export const ElsaWorkflowJournal = /*@__PURE__*/createReactComponent('elsa-workflow-journal');
+export const ElsaWorkflowNavigator = /*@__PURE__*/createReactComponent('elsa-workflow-navigator');
+export const ElsaWorkflowPublishButton = /*@__PURE__*/createReactComponent('elsa-workflow-publish-button');
+export const ElsaWorkflowToolbar = /*@__PURE__*/createReactComponent('elsa-workflow-toolbar');
+export const ElsaWorkflowToolbarMenu = /*@__PURE__*/createReactComponent('elsa-workflow-toolbar-menu');
diff --git a/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/createComponent.tsx b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/createComponent.tsx
new file mode 100644
index 000000000..7c7415a29
--- /dev/null
+++ b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/createComponent.tsx
@@ -0,0 +1,106 @@
+import React, { createElement } from 'react';
+
+import { attachProps, camelToDashCase, createForwardRef, dashToPascalCase, isCoveredByReact, mergeRefs } from './utils';
+
+export interface HTMLStencilElement extends HTMLElement {
+ componentOnReady(): Promise;
+}
+
+interface StencilReactInternalProps extends React.HTMLAttributes {
+ forwardedRef: React.RefObject;
+ ref?: React.Ref;
+}
+
+export const createReactComponent = <
+ PropType,
+ ElementType extends HTMLStencilElement,
+ ContextStateType = {},
+ ExpandedPropsTypes = {}
+>(
+ tagName: string,
+ ReactComponentContext?: React.Context,
+ manipulatePropsFunction?: (
+ originalProps: StencilReactInternalProps,
+ propsToPass: any
+ ) => ExpandedPropsTypes,
+ defineCustomElement?: () => void
+) => {
+ if (defineCustomElement !== undefined) {
+ defineCustomElement();
+ }
+
+ const displayName = dashToPascalCase(tagName);
+ const ReactComponent = class extends React.Component> {
+ componentEl!: ElementType;
+
+ setComponentElRef = (element: ElementType) => {
+ this.componentEl = element;
+ };
+
+ constructor(props: StencilReactInternalProps) {
+ super(props);
+ }
+
+ componentDidMount() {
+ this.componentDidUpdate(this.props);
+ }
+
+ componentDidUpdate(prevProps: StencilReactInternalProps) {
+ attachProps(this.componentEl, this.props, prevProps);
+ }
+
+ render() {
+ const { children, forwardedRef, style, className, ref, ...cProps } = this.props;
+
+ let propsToPass = Object.keys(cProps).reduce((acc: any, name) => {
+ const value = (cProps as any)[name];
+
+ if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
+ const eventName = name.substring(2).toLowerCase();
+ if (typeof document !== 'undefined' && isCoveredByReact(eventName)) {
+ acc[name] = value;
+ }
+ } else {
+ // we should only render strings, booleans, and numbers as attrs in html.
+ // objects, functions, arrays etc get synced via properties on mount.
+ const type = typeof value;
+
+ if (type === 'string' || type === 'boolean' || type === 'number') {
+ acc[camelToDashCase(name)] = value;
+ }
+ }
+ return acc;
+ }, {} as ExpandedPropsTypes);
+
+ if (manipulatePropsFunction) {
+ propsToPass = manipulatePropsFunction(this.props, propsToPass);
+ }
+
+ const newProps: Omit, 'forwardedRef'> = {
+ ...propsToPass,
+ ref: mergeRefs(forwardedRef, this.setComponentElRef),
+ style,
+ };
+
+ /**
+ * We use createElement here instead of
+ * React.createElement to work around a
+ * bug in Vite (https://github.com/vitejs/vite/issues/6104).
+ * React.createElement causes all elements to be rendered
+ * as instead of the actual Web Component.
+ */
+ return createElement(tagName, newProps, children);
+ }
+
+ static get displayName() {
+ return displayName;
+ }
+ };
+
+ // If context was passed to createReactComponent then conditionally add it to the Component Class
+ if (ReactComponentContext) {
+ ReactComponent.contextType = ReactComponentContext;
+ }
+
+ return createForwardRef(ReactComponent, displayName);
+};
diff --git a/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/createOverlayComponent.tsx b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/createOverlayComponent.tsx
new file mode 100644
index 000000000..288c38dd5
--- /dev/null
+++ b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/createOverlayComponent.tsx
@@ -0,0 +1,142 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+import { OverlayEventDetail } from './interfaces';
+import { StencilReactForwardedRef, attachProps, dashToPascalCase, defineCustomElement, setRef } from './utils';
+
+interface OverlayElement extends HTMLElement {
+ present: () => Promise;
+ dismiss: (data?: any, role?: string | undefined) => Promise;
+}
+
+export interface ReactOverlayProps {
+ children?: React.ReactNode;
+ isOpen: boolean;
+ onDidDismiss?: (event: CustomEvent) => void;
+ onDidPresent?: (event: CustomEvent) => void;
+ onWillDismiss?: (event: CustomEvent) => void;
+ onWillPresent?: (event: CustomEvent) => void;
+}
+
+export const createOverlayComponent = (
+ tagName: string,
+ controller: { create: (options: any) => Promise },
+ customElement?: any
+) => {
+ defineCustomElement(tagName, customElement);
+
+ const displayName = dashToPascalCase(tagName);
+ const didDismissEventName = `on${displayName}DidDismiss`;
+ const didPresentEventName = `on${displayName}DidPresent`;
+ const willDismissEventName = `on${displayName}WillDismiss`;
+ const willPresentEventName = `on${displayName}WillPresent`;
+
+ type Props = OverlayComponent &
+ ReactOverlayProps & {
+ forwardedRef?: StencilReactForwardedRef;
+ };
+
+ let isDismissing = false;
+
+ class Overlay extends React.Component {
+ overlay?: OverlayType;
+ el!: HTMLDivElement;
+
+ constructor(props: Props) {
+ super(props);
+ if (typeof document !== 'undefined') {
+ this.el = document.createElement('div');
+ }
+ this.handleDismiss = this.handleDismiss.bind(this);
+ }
+
+ static get displayName() {
+ return displayName;
+ }
+
+ componentDidMount() {
+ if (this.props.isOpen) {
+ this.present();
+ }
+ }
+
+ componentWillUnmount() {
+ if (this.overlay) {
+ this.overlay.dismiss();
+ }
+ }
+
+ handleDismiss(event: CustomEvent>) {
+ if (this.props.onDidDismiss) {
+ this.props.onDidDismiss(event);
+ }
+ setRef(this.props.forwardedRef, null);
+ }
+
+ shouldComponentUpdate(nextProps: Props) {
+ // Check if the overlay component is about to dismiss
+ if (this.overlay && nextProps.isOpen !== this.props.isOpen && nextProps.isOpen === false) {
+ isDismissing = true;
+ }
+
+ return true;
+ }
+
+ async componentDidUpdate(prevProps: Props) {
+ if (this.overlay) {
+ attachProps(this.overlay, this.props, prevProps);
+ }
+
+ if (prevProps.isOpen !== this.props.isOpen && this.props.isOpen === true) {
+ this.present(prevProps);
+ }
+ if (this.overlay && prevProps.isOpen !== this.props.isOpen && this.props.isOpen === false) {
+ await this.overlay.dismiss();
+ isDismissing = false;
+
+ /**
+ * Now that the overlay is dismissed
+ * we need to render again so that any
+ * inner components will be unmounted
+ */
+ this.forceUpdate();
+ }
+ }
+
+ async present(prevProps?: Props) {
+ const { children, isOpen, onDidDismiss, onDidPresent, onWillDismiss, onWillPresent, ...cProps } = this.props;
+ const elementProps = {
+ ...cProps,
+ ref: this.props.forwardedRef,
+ [didDismissEventName]: this.handleDismiss,
+ [didPresentEventName]: (e: CustomEvent) => this.props.onDidPresent && this.props.onDidPresent(e),
+ [willDismissEventName]: (e: CustomEvent) => this.props.onWillDismiss && this.props.onWillDismiss(e),
+ [willPresentEventName]: (e: CustomEvent) => this.props.onWillPresent && this.props.onWillPresent(e),
+ };
+
+ this.overlay = await controller.create({
+ ...elementProps,
+ component: this.el,
+ componentProps: {},
+ });
+
+ setRef(this.props.forwardedRef, this.overlay);
+ attachProps(this.overlay, elementProps, prevProps);
+
+ await this.overlay.present();
+ }
+
+ render() {
+ /**
+ * Continue to render the component even when
+ * overlay is dismissing otherwise component
+ * will be hidden before animation is done.
+ */
+ return ReactDOM.createPortal(this.props.isOpen || isDismissing ? this.props.children : null, this.el);
+ }
+ }
+
+ return React.forwardRef((props, ref) => {
+ return ;
+ });
+};
diff --git a/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/index.ts b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/index.ts
new file mode 100644
index 000000000..85e81ad19
--- /dev/null
+++ b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/index.ts
@@ -0,0 +1,2 @@
+export { createReactComponent } from './createComponent';
+export { createOverlayComponent } from './createOverlayComponent';
diff --git a/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/interfaces.ts b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/interfaces.ts
new file mode 100644
index 000000000..92e5389c8
--- /dev/null
+++ b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/interfaces.ts
@@ -0,0 +1,34 @@
+// General types important to applications using stencil built components
+export interface EventEmitter {
+ emit: (data?: T) => CustomEvent;
+}
+
+export interface StyleReactProps {
+ class?: string;
+ className?: string;
+ style?: { [key: string]: any };
+}
+
+export interface OverlayEventDetail {
+ data?: T;
+ role?: string;
+}
+
+export interface OverlayInterface {
+ el: HTMLElement;
+ animated: boolean;
+ keyboardClose: boolean;
+ overlayIndex: number;
+ presented: boolean;
+
+ enterAnimation?: any;
+ leaveAnimation?: any;
+
+ didPresent: EventEmitter;
+ willPresent: EventEmitter;
+ willDismiss: EventEmitter;
+ didDismiss: EventEmitter;
+
+ present(): Promise;
+ dismiss(data?: any, role?: string): Promise;
+}
diff --git a/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/attachProps.ts b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/attachProps.ts
new file mode 100644
index 000000000..de2cc499b
--- /dev/null
+++ b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/attachProps.ts
@@ -0,0 +1,114 @@
+import { camelToDashCase } from './case';
+
+export const attachProps = (node: HTMLElement, newProps: any, oldProps: any = {}) => {
+ // some test frameworks don't render DOM elements, so we test here to make sure we are dealing with DOM first
+ if (node instanceof Element) {
+ // add any classes in className to the class list
+ const className = getClassName(node.classList, newProps, oldProps);
+ if (className !== '') {
+ node.className = className;
+ }
+
+ Object.keys(newProps).forEach((name) => {
+ if (
+ name === 'children' ||
+ name === 'style' ||
+ name === 'ref' ||
+ name === 'class' ||
+ name === 'className' ||
+ name === 'forwardedRef'
+ ) {
+ return;
+ }
+ if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
+ const eventName = name.substring(2);
+ const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1);
+
+ if (!isCoveredByReact(eventNameLc)) {
+ syncEvent(node, eventNameLc, newProps[name]);
+ }
+ } else {
+ (node as any)[name] = newProps[name];
+ const propType = typeof newProps[name];
+ if (propType === 'string') {
+ node.setAttribute(camelToDashCase(name), newProps[name]);
+ }
+ }
+ });
+ }
+};
+
+export const getClassName = (classList: DOMTokenList, newProps: any, oldProps: any) => {
+ const newClassProp: string = newProps.className || newProps.class;
+ const oldClassProp: string = oldProps.className || oldProps.class;
+ // map the classes to Maps for performance
+ const currentClasses = arrayToMap(classList);
+ const incomingPropClasses = arrayToMap(newClassProp ? newClassProp.split(' ') : []);
+ const oldPropClasses = arrayToMap(oldClassProp ? oldClassProp.split(' ') : []);
+ const finalClassNames: string[] = [];
+ // loop through each of the current classes on the component
+ // to see if it should be a part of the classNames added
+ currentClasses.forEach((currentClass) => {
+ if (incomingPropClasses.has(currentClass)) {
+ // add it as its already included in classnames coming in from newProps
+ finalClassNames.push(currentClass);
+ incomingPropClasses.delete(currentClass);
+ } else if (!oldPropClasses.has(currentClass)) {
+ // add it as it has NOT been removed by user
+ finalClassNames.push(currentClass);
+ }
+ });
+ incomingPropClasses.forEach((s) => finalClassNames.push(s));
+ return finalClassNames.join(' ');
+};
+
+/**
+ * Checks if an event is supported in the current execution environment.
+ * @license Modernizr 3.0.0pre (Custom Build) | MIT
+ */
+export const isCoveredByReact = (eventNameSuffix: string) => {
+ if (typeof document === 'undefined') {
+ return true;
+ } else {
+ const eventName = 'on' + eventNameSuffix;
+ let isSupported = eventName in document;
+
+ if (!isSupported) {
+ const element = document.createElement('div');
+ element.setAttribute(eventName, 'return;');
+ isSupported = typeof (element as any)[eventName] === 'function';
+ }
+
+ return isSupported;
+ }
+};
+
+export const syncEvent = (
+ node: Element & { __events?: { [key: string]: ((e: Event) => any) | undefined } },
+ eventName: string,
+ newEventHandler?: (e: Event) => any
+) => {
+ const eventStore = node.__events || (node.__events = {});
+ const oldEventHandler = eventStore[eventName];
+
+ // Remove old listener so they don't double up.
+ if (oldEventHandler) {
+ node.removeEventListener(eventName, oldEventHandler);
+ }
+
+ // Bind new listener.
+ node.addEventListener(
+ eventName,
+ (eventStore[eventName] = function handler(e: Event) {
+ if (newEventHandler) {
+ newEventHandler.call(this, e);
+ }
+ })
+ );
+};
+
+const arrayToMap = (arr: string[] | DOMTokenList) => {
+ const map = new Map();
+ (arr as string[]).forEach((s: string) => map.set(s, s));
+ return map;
+};
diff --git a/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/case.ts b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/case.ts
new file mode 100644
index 000000000..786689dc9
--- /dev/null
+++ b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/case.ts
@@ -0,0 +1,7 @@
+export const dashToPascalCase = (str: string) =>
+ str
+ .toLowerCase()
+ .split('-')
+ .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
+ .join('');
+export const camelToDashCase = (str: string) => str.replace(/([A-Z])/g, (m: string) => `-${m[0].toLowerCase()}`);
diff --git a/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/dev.ts b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/dev.ts
new file mode 100644
index 000000000..cc6f9ed08
--- /dev/null
+++ b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/dev.ts
@@ -0,0 +1,14 @@
+export const isDevMode = () => {
+ return process && process.env && process.env.NODE_ENV === 'development';
+};
+
+const warnings: { [key: string]: boolean } = {};
+
+export const deprecationWarning = (key: string, message: string) => {
+ if (isDevMode()) {
+ if (!warnings[key]) {
+ console.warn(message);
+ warnings[key] = true;
+ }
+ }
+};
diff --git a/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/index.tsx b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/index.tsx
new file mode 100644
index 000000000..a66bd02de
--- /dev/null
+++ b/src/designer/designer_packages/react-wrapper/lib/components/stencil-generated/react-component-lib/utils/index.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+
+import type { StyleReactProps } from '../interfaces';
+
+export type StencilReactExternalProps = PropType &
+ Omit, 'style'> &
+ StyleReactProps;
+
+// This will be replaced with React.ForwardedRef when react-output-target is upgraded to React v17
+export type StencilReactForwardedRef = ((instance: T | null) => void) | React.MutableRefObject | null;
+
+export const setRef = (ref: StencilReactForwardedRef | React.Ref | undefined, value: any) => {
+ if (typeof ref === 'function') {
+ ref(value);
+ } else if (ref != null) {
+ // Cast as a MutableRef so we can assign current
+ (ref as React.MutableRefObject).current = value;
+ }
+};
+
+export const mergeRefs = (
+ ...refs: (StencilReactForwardedRef | React.Ref | undefined)[]
+): React.RefCallback => {
+ return (value: any) => {
+ refs.forEach((ref) => {
+ setRef(ref, value);
+ });
+ };
+};
+
+export const createForwardRef = (ReactComponent: any, displayName: string) => {
+ const forwardRef = (
+ props: StencilReactExternalProps,
+ ref: StencilReactForwardedRef
+ ) => {
+ return ;
+ };
+ forwardRef.displayName = displayName;
+
+ return React.forwardRef(forwardRef);
+};
+
+export const defineCustomElement = (tagName: string, customElement: any) => {
+ if (customElement !== undefined && typeof customElements !== 'undefined' && !customElements.get(tagName)) {
+ customElements.define(tagName, customElement);
+ }
+};
+
+export * from './attachProps';
+export * from './case';