@hubspot/ui-extensions 0.11.0 → 0.11.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/__synced__/remoteComponents.synced.d.ts +85 -354
- package/dist/__synced__/remoteComponents.synced.js +88 -83
- package/dist/__synced__/types/components/index.synced.d.ts +38 -38
- package/dist/__synced__/types/index.synced.d.ts +7 -7
- package/dist/__synced__/types/index.synced.js +1 -9
- package/dist/__synced__/types/shared.synced.d.ts +2 -3
- package/dist/__synced__/utils/remote-component-registry.synced.d.ts +80 -0
- package/dist/__synced__/utils/remote-component-registry.synced.js +64 -0
- package/dist/experimental/testing/internal/constants.d.ts +2 -0
- package/dist/experimental/testing/internal/constants.js +1 -0
- package/dist/experimental/testing/internal/debug.d.ts +8 -0
- package/dist/experimental/testing/internal/debug.js +10 -0
- package/dist/experimental/testing/internal/element.d.ts +11 -0
- package/dist/experimental/testing/internal/element.js +67 -0
- package/dist/experimental/testing/internal/errors.d.ts +44 -0
- package/dist/experimental/testing/internal/errors.js +52 -0
- package/dist/experimental/testing/internal/fragment.d.ts +8 -0
- package/dist/experimental/testing/internal/fragment.js +44 -0
- package/dist/experimental/testing/internal/print.d.ts +6 -0
- package/dist/experimental/testing/internal/print.js +114 -0
- package/dist/experimental/testing/internal/query.d.ts +57 -0
- package/dist/experimental/testing/internal/query.js +231 -0
- package/dist/experimental/testing/internal/root.d.ts +8 -0
- package/dist/experimental/testing/internal/root.js +44 -0
- package/dist/experimental/testing/internal/text.d.ts +9 -0
- package/dist/experimental/testing/internal/text.js +16 -0
- package/dist/experimental/testing/types.d.ts +1 -1
- package/dist/hubspot.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/pages/home/index.d.ts +1 -1
- package/dist/pages/home/index.js +1 -1
- package/package.json +10 -5
- package/dist/coreComponents.d.ts +0 -848
- package/dist/coreComponents.js +0 -582
- package/dist/experimental/types.d.ts +0 -240
- package/dist/experimental/types.js +0 -5
- package/dist/types.d.ts +0 -3214
- package/dist/types.js +0 -244
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
4
|
-
export type
|
|
5
|
-
export type
|
|
6
|
-
export type
|
|
7
|
-
export type
|
|
8
|
-
export type
|
|
9
|
-
export type
|
|
10
|
-
export type
|
|
11
|
-
export type
|
|
12
|
-
export type
|
|
13
|
-
export type
|
|
14
|
-
export type
|
|
15
|
-
export type
|
|
16
|
-
export type
|
|
17
|
-
export type
|
|
18
|
-
export type
|
|
19
|
-
export type
|
|
20
|
-
export type
|
|
21
|
-
export type
|
|
22
|
-
export type
|
|
23
|
-
export type
|
|
24
|
-
export type
|
|
25
|
-
export type
|
|
26
|
-
export type
|
|
27
|
-
export type
|
|
28
|
-
export type
|
|
29
|
-
export type
|
|
30
|
-
export type
|
|
31
|
-
export type
|
|
32
|
-
export type
|
|
33
|
-
export type
|
|
34
|
-
export type
|
|
35
|
-
export type
|
|
36
|
-
export type
|
|
37
|
-
export type
|
|
38
|
-
export type
|
|
1
|
+
export type * from './accordion.synced';
|
|
2
|
+
export type * from './alert.synced';
|
|
3
|
+
export type * from './app-home-header-actions.synced';
|
|
4
|
+
export type * from './button-row.synced';
|
|
5
|
+
export type * from './button.synced';
|
|
6
|
+
export type * from './card.synced';
|
|
7
|
+
export type * from './chart.synced';
|
|
8
|
+
export type * from './description-list.synced';
|
|
9
|
+
export type * from './divider.synced';
|
|
10
|
+
export type * from './dropdown.synced';
|
|
11
|
+
export type * from './empty-state.synced';
|
|
12
|
+
export type * from './error-state.synced';
|
|
13
|
+
export type * from './form.synced';
|
|
14
|
+
export type * from './heading.synced';
|
|
15
|
+
export type * from './icon.synced';
|
|
16
|
+
export type * from './iframe.synced';
|
|
17
|
+
export type * from './illustration.synced';
|
|
18
|
+
export type * from './image.synced';
|
|
19
|
+
export type * from './inputs.synced';
|
|
20
|
+
export type * from './layouts.synced';
|
|
21
|
+
export type * from './link.synced';
|
|
22
|
+
export type * from './list.synced';
|
|
23
|
+
export type * from './loading-spinner.synced';
|
|
24
|
+
export type * from './modal.synced';
|
|
25
|
+
export type * from './panel.synced';
|
|
26
|
+
export type * from './progress-bar.synced';
|
|
27
|
+
export type * from './selects.synced';
|
|
28
|
+
export type * from './statistics.synced';
|
|
29
|
+
export type * from './status-tag.synced';
|
|
30
|
+
export type * from './step-indicator.synced';
|
|
31
|
+
export type * from './table.synced';
|
|
32
|
+
export type * from './tabs.synced';
|
|
33
|
+
export type * from './tag.synced';
|
|
34
|
+
export type * from './text.synced';
|
|
35
|
+
export type * from './tile.synced';
|
|
36
|
+
export type * from './toggle.synced';
|
|
37
|
+
export type * from './toggleInputs.synced';
|
|
38
|
+
export type * from './tooltip.synced';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export * from './components/index.synced';
|
|
2
|
-
export * from './actions.synced';
|
|
3
|
-
export * from './context.synced';
|
|
4
|
-
export * from './crm.synced';
|
|
5
|
-
export * from './extension-points.synced';
|
|
6
|
-
export * from './http-requests.synced';
|
|
7
|
-
export * from './reactions.synced';
|
|
1
|
+
export type * from './components/index.synced';
|
|
2
|
+
export type * from './actions.synced';
|
|
3
|
+
export type * from './context.synced';
|
|
4
|
+
export type * from './crm.synced';
|
|
5
|
+
export type * from './extension-points.synced';
|
|
6
|
+
export type * from './http-requests.synced';
|
|
7
|
+
export type * from './reactions.synced';
|
|
8
8
|
export * from './shared.synced';
|
|
@@ -1,9 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export * from './components/index.synced';
|
|
3
|
-
export * from './actions.synced';
|
|
4
|
-
export * from './context.synced';
|
|
5
|
-
export * from './crm.synced';
|
|
6
|
-
export * from './extension-points.synced';
|
|
7
|
-
export * from './http-requests.synced';
|
|
8
|
-
export * from './reactions.synced';
|
|
9
|
-
export * from './shared.synced';
|
|
1
|
+
export * from './shared.synced'; // NOTE: `shared.ts` has some exported classes so we can't use `export type` for now
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { ReactElement, ComponentType } from 'react';
|
|
1
|
+
import type { ReactElement, ComponentType, ReactNode } from 'react';
|
|
3
2
|
export type UnknownComponentProps = Record<string, any>;
|
|
4
3
|
/**
|
|
5
4
|
* Represents a HubSpot-provided React component.
|
|
@@ -22,7 +21,7 @@ export declare class FormSubmitExtensionEvent<V> extends ExtensionEvent {
|
|
|
22
21
|
constructor(value: V, event: Event);
|
|
23
22
|
}
|
|
24
23
|
export type OverlayComponentProps = {
|
|
25
|
-
overlay?:
|
|
24
|
+
overlay?: ReactNode;
|
|
26
25
|
};
|
|
27
26
|
export type HrefOptions = {
|
|
28
27
|
url: string;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { HubSpotReactComponent, HubSpotReactFragmentProp, UnknownComponentProps } from '../types/shared.synced';
|
|
2
|
+
/**
|
|
3
|
+
* Options for creating a remote React component.
|
|
4
|
+
*/
|
|
5
|
+
interface CreateRemoteComponentOptions<TProps extends UnknownComponentProps = UnknownComponentProps> {
|
|
6
|
+
/**
|
|
7
|
+
* An array of prop names that are allowed to be used as fragment props.
|
|
8
|
+
*/
|
|
9
|
+
fragmentProps?: ComponentFragmentPropName<TProps>[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Options for creating a remote React component.
|
|
13
|
+
*/
|
|
14
|
+
interface CreateRemoteCompoundComponentOptions<TProps extends UnknownComponentProps, TCompoundComponentProps> {
|
|
15
|
+
/**
|
|
16
|
+
* An array of prop names that are allowed to be used as fragment props.
|
|
17
|
+
*/
|
|
18
|
+
fragmentProps?: ComponentFragmentPropName<TProps>[];
|
|
19
|
+
compoundComponentProperties: TCompoundComponentProps;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Utility type for filtering out all of the prop names where the value is a ReactNode (excluding primitives).
|
|
23
|
+
* We use this to know which props are allowed to be used as fragment props.
|
|
24
|
+
*/
|
|
25
|
+
type ComponentFragmentPropName<TProps extends UnknownComponentProps> = {
|
|
26
|
+
[K in keyof TProps]: HubSpotReactFragmentProp extends Required<TProps>[K] ? K : never;
|
|
27
|
+
}[keyof TProps & string];
|
|
28
|
+
/**
|
|
29
|
+
* Represents a registry of HubSpot-provided React components that is used internally by the UI extensions SDK.
|
|
30
|
+
*/
|
|
31
|
+
export interface RemoteComponentRegistry {
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new remote React component and registers it with the registry.
|
|
34
|
+
*
|
|
35
|
+
* @param componentName The name of the component to create and register.
|
|
36
|
+
* @param options The options for the remote React component.
|
|
37
|
+
* @returns The remote React component that can be used as a React component.
|
|
38
|
+
*/
|
|
39
|
+
createAndRegisterRemoteReactComponent: <TProps extends UnknownComponentProps>(componentName: string, options?: CreateRemoteComponentOptions<TProps>) => HubSpotReactComponent<TProps>;
|
|
40
|
+
/**
|
|
41
|
+
* Creates a new remote compound React component and registers it with the registry. A compound component is a component that is
|
|
42
|
+
* composed of multiple components attached to a single component function.
|
|
43
|
+
*
|
|
44
|
+
* @param componentName The name of the component to create and register.
|
|
45
|
+
* @param options The options for the remote compound React component.
|
|
46
|
+
* @returns The remote compound React component that can be used as a React component.
|
|
47
|
+
*/
|
|
48
|
+
createAndRegisterRemoteCompoundReactComponent: <TProps extends UnknownComponentProps, TCompoundComponentProps>(componentName: string, options: CreateRemoteCompoundComponentOptions<TProps, TCompoundComponentProps>) => HubSpotReactComponent<TProps> & TCompoundComponentProps;
|
|
49
|
+
/**
|
|
50
|
+
* Returns the name of a HubSpot-provided React component.
|
|
51
|
+
*
|
|
52
|
+
* @param component The React component to get the name of.
|
|
53
|
+
* @returns The name of the HubSpot-provided React component.
|
|
54
|
+
*/
|
|
55
|
+
getComponentName: (component: HubSpotReactComponent<any>) => string | null;
|
|
56
|
+
/**
|
|
57
|
+
* Returns true if the given component name is allowed to be used in HubSpot.
|
|
58
|
+
*
|
|
59
|
+
* @param name The name of the component to check if it is allowed to be used in HubSpot.
|
|
60
|
+
* @returns `true` if the given component name is allowed to be used in HubSpot.
|
|
61
|
+
*/
|
|
62
|
+
isAllowedComponentName: (name: string) => boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Returns true if the given prop name is a fragment prop for the given component name.
|
|
65
|
+
*
|
|
66
|
+
* @param componentName The name of the component to check if the prop is a fragment prop for.
|
|
67
|
+
* @param propName The name of the prop to check if it is a fragment prop.
|
|
68
|
+
* @returns `true` if the prop name is a fragment prop for the given component name.
|
|
69
|
+
*/
|
|
70
|
+
isComponentFragmentProp: (componentName: string, propName: string) => boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Returns the names of the fragment props for a given component name.
|
|
73
|
+
*
|
|
74
|
+
* @param componentName The name of the component to get the fragment props for.
|
|
75
|
+
* @returns The names of the fragment props for the given component name.
|
|
76
|
+
*/
|
|
77
|
+
getComponentFragmentPropNames: (componentName: string) => string[];
|
|
78
|
+
}
|
|
79
|
+
export declare const createRemoteComponentRegistry: () => RemoteComponentRegistry;
|
|
80
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// Do not manually update this file, changes will be autogenerated by our scripts based on: ui-extensions-remote-renderer/static/js/utils/remote-component-registry.tsx
|
|
3
|
+
import { createRemoteReactComponent } from '@remote-ui/react';
|
|
4
|
+
export const createRemoteComponentRegistry = () => {
|
|
5
|
+
const componentMetadataLookup = new Map();
|
|
6
|
+
const componentNameByComponentMap = new Map();
|
|
7
|
+
const registerComponent = (component, componentName, fragmentProps) => {
|
|
8
|
+
componentNameByComponentMap.set(component, componentName);
|
|
9
|
+
componentMetadataLookup.set(componentName, {
|
|
10
|
+
fragmentPropsSet: new Set(fragmentProps),
|
|
11
|
+
fragmentPropsArray: fragmentProps,
|
|
12
|
+
});
|
|
13
|
+
return component;
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
getComponentName: (component) => {
|
|
17
|
+
const componentName = componentNameByComponentMap.get(component);
|
|
18
|
+
if (!componentName) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return componentName;
|
|
22
|
+
},
|
|
23
|
+
isAllowedComponentName: (componentName) => {
|
|
24
|
+
return componentMetadataLookup.has(componentName);
|
|
25
|
+
},
|
|
26
|
+
isComponentFragmentProp: (componentName, propName) => {
|
|
27
|
+
const componentMetadata = componentMetadataLookup.get(componentName);
|
|
28
|
+
if (!componentMetadata) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return componentMetadata.fragmentPropsSet.has(propName);
|
|
32
|
+
},
|
|
33
|
+
getComponentFragmentPropNames: (componentName) => {
|
|
34
|
+
const componentMetadata = componentMetadataLookup.get(componentName);
|
|
35
|
+
if (!componentMetadata) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
const { fragmentPropsArray } = componentMetadata;
|
|
39
|
+
return fragmentPropsArray;
|
|
40
|
+
},
|
|
41
|
+
createAndRegisterRemoteReactComponent: (componentName, options = {}) => {
|
|
42
|
+
const { fragmentProps = [] } = options;
|
|
43
|
+
const remoteReactComponent = createRemoteReactComponent(componentName, {
|
|
44
|
+
fragmentProps: fragmentProps,
|
|
45
|
+
});
|
|
46
|
+
return registerComponent(remoteReactComponent, componentName, fragmentProps);
|
|
47
|
+
},
|
|
48
|
+
createAndRegisterRemoteCompoundReactComponent: (componentName, options) => {
|
|
49
|
+
const { fragmentProps = [] } = options;
|
|
50
|
+
const RemoteComponentType = createRemoteReactComponent(componentName, {
|
|
51
|
+
fragmentProps,
|
|
52
|
+
});
|
|
53
|
+
// We can only attach properties to a function component type, so we need to check if the remote component type is a function.
|
|
54
|
+
// If the remote component type is not a function, we need to wrap it in a function component.
|
|
55
|
+
const CompoundFunctionComponentType = typeof RemoteComponentType === 'function'
|
|
56
|
+
? RemoteComponentType
|
|
57
|
+
: (props) => (_jsx(RemoteComponentType, { ...props }));
|
|
58
|
+
// Attach the compound component properties to the function component that we will be returning.
|
|
59
|
+
Object.assign(CompoundFunctionComponentType, options.compoundComponentProperties);
|
|
60
|
+
// Register the compound function component with the registry and return it.
|
|
61
|
+
return registerComponent(CompoundFunctionComponentType, componentName, fragmentProps);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const EMPTY_CHILDREN = [];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RenderedParentNode } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Logs a rendered node tree to the console for debugging purposes.
|
|
4
|
+
*
|
|
5
|
+
* @param parentNode The node to log.
|
|
6
|
+
* @param label Optional label to display before the node tree.
|
|
7
|
+
*/
|
|
8
|
+
export declare const debugLog: (parentNode: RenderedParentNode, label?: string) => never;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
/**
|
|
3
|
+
* Logs a rendered node tree to the console for debugging purposes.
|
|
4
|
+
*
|
|
5
|
+
* @param parentNode The node to log.
|
|
6
|
+
* @param label Optional label to display before the node tree.
|
|
7
|
+
*/
|
|
8
|
+
export const debugLog = (parentNode, label) => {
|
|
9
|
+
throw new Error('Not implemented');
|
|
10
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { UnknownComponentProps } from '../../../__synced__/types/shared.synced';
|
|
2
|
+
import type { RenderedDocumentInternal, RenderedElementNodeInternal } from './types-internal';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a rendered element node.
|
|
5
|
+
*
|
|
6
|
+
* @param document The document that the element belongs to.
|
|
7
|
+
* @param name The name of the element.
|
|
8
|
+
* @param props The props of the element.
|
|
9
|
+
* @returns A rendered element node.
|
|
10
|
+
*/
|
|
11
|
+
export declare const createElementNode: (document: RenderedDocumentInternal, name: string, props: UnknownComponentProps) => RenderedElementNodeInternal;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { RenderedNodeType } from '../types';
|
|
2
|
+
import { EMPTY_CHILDREN } from './constants';
|
|
3
|
+
import { debugLog } from './debug';
|
|
4
|
+
import { InvalidEventFunctionError, MissingEventFunctionError } from './errors';
|
|
5
|
+
import { printNode } from './print';
|
|
6
|
+
import { find, findAll, findAllChildren, findChild, maybeFind, maybeFindChild, } from './query';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a rendered element node.
|
|
9
|
+
*
|
|
10
|
+
* @param document The document that the element belongs to.
|
|
11
|
+
* @param name The name of the element.
|
|
12
|
+
* @param props The props of the element.
|
|
13
|
+
* @returns A rendered element node.
|
|
14
|
+
*/
|
|
15
|
+
export const createElementNode = (document, name, props) => {
|
|
16
|
+
const elementNode = {
|
|
17
|
+
nodeType: RenderedNodeType.Element,
|
|
18
|
+
name,
|
|
19
|
+
props,
|
|
20
|
+
text: null,
|
|
21
|
+
children: EMPTY_CHILDREN,
|
|
22
|
+
document,
|
|
23
|
+
debugLog: (label) => {
|
|
24
|
+
debugLog(elementNode, label);
|
|
25
|
+
},
|
|
26
|
+
find: (targetComponent, matcher) => {
|
|
27
|
+
return find(elementNode, targetComponent, matcher);
|
|
28
|
+
},
|
|
29
|
+
findAll: (targetComponent, matcher) => {
|
|
30
|
+
return findAll(elementNode, targetComponent, matcher);
|
|
31
|
+
},
|
|
32
|
+
findChild: (targetComponent, matcher) => {
|
|
33
|
+
return findChild(elementNode, targetComponent, matcher);
|
|
34
|
+
},
|
|
35
|
+
findAllChildren: (targetComponent, matcher) => {
|
|
36
|
+
return findAllChildren(elementNode, targetComponent, matcher);
|
|
37
|
+
},
|
|
38
|
+
maybeFind: (targetComponent, matcher) => {
|
|
39
|
+
return maybeFind(elementNode, targetComponent, matcher);
|
|
40
|
+
},
|
|
41
|
+
maybeFindChild: (targetComponent, matcher) => {
|
|
42
|
+
return maybeFindChild(elementNode, targetComponent, matcher);
|
|
43
|
+
},
|
|
44
|
+
toString: () => {
|
|
45
|
+
return printNode(elementNode);
|
|
46
|
+
},
|
|
47
|
+
trigger: (eventPropName, eventArg) => {
|
|
48
|
+
const eventFunction = elementNode.props[eventPropName];
|
|
49
|
+
if (!eventFunction) {
|
|
50
|
+
throw new MissingEventFunctionError({
|
|
51
|
+
componentName: name,
|
|
52
|
+
eventPropName,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (typeof eventFunction !== 'function') {
|
|
56
|
+
throw new InvalidEventFunctionError({
|
|
57
|
+
componentName: name,
|
|
58
|
+
eventPropName,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
document.batchUpdate(() => {
|
|
62
|
+
eventFunction(eventArg);
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
return elementNode;
|
|
67
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RenderedParentNode } from '../types';
|
|
2
|
+
import { RenderedRootNodeInternal } from './types-internal';
|
|
3
|
+
/**
|
|
4
|
+
* Thrown when trying to trigger an event that has a handler prop that is not a function.
|
|
5
|
+
*/
|
|
6
|
+
export declare class InvalidEventFunctionError extends Error {
|
|
7
|
+
constructor({ componentName, eventPropName, }: {
|
|
8
|
+
componentName: string;
|
|
9
|
+
eventPropName: string;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Thrown when trying to trigger an event that has no corresponding handler function in the props object.
|
|
14
|
+
*/
|
|
15
|
+
export declare class MissingEventFunctionError extends Error {
|
|
16
|
+
constructor({ componentName, eventPropName, }: {
|
|
17
|
+
componentName: string;
|
|
18
|
+
eventPropName: string;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Thrown when a component is not found in the rendered output.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ComponentNotFoundError extends Error {
|
|
25
|
+
constructor({ findMethodName, parentNode, componentName, }: {
|
|
26
|
+
findMethodName: string;
|
|
27
|
+
parentNode: RenderedParentNode;
|
|
28
|
+
componentName: string;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Thrown when invalid components are detected in the rendered output.
|
|
33
|
+
*/
|
|
34
|
+
export declare class InvalidComponentsError extends Error {
|
|
35
|
+
constructor(rootNode: RenderedRootNodeInternal);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Thrown when the target component passed to the find operation is not a valid HubSpot-provided React component.
|
|
39
|
+
*/
|
|
40
|
+
export declare class FindInvalidComponentError extends Error {
|
|
41
|
+
constructor({ findMethodName }: {
|
|
42
|
+
findMethodName: string;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { printNode } from './print';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when trying to trigger an event that has a handler prop that is not a function.
|
|
4
|
+
*/
|
|
5
|
+
export class InvalidEventFunctionError extends Error {
|
|
6
|
+
constructor({ componentName, eventPropName, }) {
|
|
7
|
+
super(`trigger("${String(eventPropName)}", ...) failed. Event function for prop "${String(eventPropName)}" in component "${componentName}" props is not a function`);
|
|
8
|
+
this.name = 'InvalidEventFunctionError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Thrown when trying to trigger an event that has no corresponding handler function in the props object.
|
|
13
|
+
*/
|
|
14
|
+
export class MissingEventFunctionError extends Error {
|
|
15
|
+
constructor({ componentName, eventPropName, }) {
|
|
16
|
+
super(`trigger("${String(eventPropName)}", ...) failed. Event function for prop "${String(eventPropName)}" not found in component "${componentName}" props`);
|
|
17
|
+
this.name = 'MissingEventFunctionError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Thrown when a component is not found in the rendered output.
|
|
22
|
+
*/
|
|
23
|
+
export class ComponentNotFoundError extends Error {
|
|
24
|
+
constructor({ findMethodName, parentNode, componentName, }) {
|
|
25
|
+
super(`${findMethodName}() failed. <${componentName}> not found in rendered output: ${parentNode.toString()}`);
|
|
26
|
+
this.name = 'ComponentNotFoundError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown when invalid components are detected in the rendered output.
|
|
31
|
+
*/
|
|
32
|
+
export class InvalidComponentsError extends Error {
|
|
33
|
+
constructor(rootNode) {
|
|
34
|
+
super(`Invalid rendered output. Found invalid components (${rootNode.document
|
|
35
|
+
.getInvalidComponentNames()
|
|
36
|
+
.map((name) => `"${name}"`)
|
|
37
|
+
.join(', ')}) in rendered output: ${printNode(rootNode, {
|
|
38
|
+
markInvalidComponents: true,
|
|
39
|
+
listInvalidComponents: true,
|
|
40
|
+
})}`);
|
|
41
|
+
this.name = 'InvalidComponentsError';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Thrown when the target component passed to the find operation is not a valid HubSpot-provided React component.
|
|
46
|
+
*/
|
|
47
|
+
export class FindInvalidComponentError extends Error {
|
|
48
|
+
constructor({ findMethodName }) {
|
|
49
|
+
super(`${findMethodName}() failed. The provided target component is not a HubSpot-provided React component`);
|
|
50
|
+
this.name = 'FindInvalidComponentError';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RenderedDocumentInternal, RenderedFragmentNodeInternal } from './types-internal';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a rendered fragment node.
|
|
4
|
+
*
|
|
5
|
+
* @param document The document that the fragment belongs to.
|
|
6
|
+
* @returns A rendered fragment node.
|
|
7
|
+
*/
|
|
8
|
+
export declare const createFragmentNode: (document: RenderedDocumentInternal) => RenderedFragmentNodeInternal;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RenderedNodeType } from '../types';
|
|
2
|
+
import { EMPTY_CHILDREN } from './constants';
|
|
3
|
+
import { debugLog } from './debug';
|
|
4
|
+
import { printNode } from './print';
|
|
5
|
+
import { find, findAll, findAllChildren, findChild, maybeFind, maybeFindChild, } from './query';
|
|
6
|
+
/**
|
|
7
|
+
* Creates a rendered fragment node.
|
|
8
|
+
*
|
|
9
|
+
* @param document The document that the fragment belongs to.
|
|
10
|
+
* @returns A rendered fragment node.
|
|
11
|
+
*/
|
|
12
|
+
export const createFragmentNode = (document) => {
|
|
13
|
+
const fragmentNode = {
|
|
14
|
+
nodeType: RenderedNodeType.Fragment,
|
|
15
|
+
text: null,
|
|
16
|
+
children: EMPTY_CHILDREN,
|
|
17
|
+
document,
|
|
18
|
+
debugLog: (label) => {
|
|
19
|
+
debugLog(fragmentNode, label);
|
|
20
|
+
},
|
|
21
|
+
find: (targetComponent, matcher) => {
|
|
22
|
+
return find(fragmentNode, targetComponent, matcher);
|
|
23
|
+
},
|
|
24
|
+
findAll: (targetComponent, matcher) => {
|
|
25
|
+
return findAll(fragmentNode, targetComponent, matcher);
|
|
26
|
+
},
|
|
27
|
+
findChild: (targetComponent, matcher) => {
|
|
28
|
+
return findChild(fragmentNode, targetComponent, matcher);
|
|
29
|
+
},
|
|
30
|
+
findAllChildren: (targetComponent, matcher) => {
|
|
31
|
+
return findAllChildren(fragmentNode, targetComponent, matcher);
|
|
32
|
+
},
|
|
33
|
+
maybeFind: (targetComponent, matcher) => {
|
|
34
|
+
return maybeFind(fragmentNode, targetComponent, matcher);
|
|
35
|
+
},
|
|
36
|
+
maybeFindChild: (targetComponent, matcher) => {
|
|
37
|
+
return maybeFindChild(fragmentNode, targetComponent, matcher);
|
|
38
|
+
},
|
|
39
|
+
toString: () => {
|
|
40
|
+
return printNode(fragmentNode);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
return fragmentNode;
|
|
44
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { __hubSpotComponentRegistry } from '../../../__synced__/remoteComponents.synced';
|
|
2
|
+
import { isRenderedElementNode, isRenderedFragmentNode, isRenderedRootNode, isRenderedTextNode, } from '../type-utils';
|
|
3
|
+
const INDENT_STRING = ' ';
|
|
4
|
+
const printTextNode = (node, indent, printContext) => {
|
|
5
|
+
printContext.append(`${indent}${JSON.stringify(node.text)}\n`);
|
|
6
|
+
};
|
|
7
|
+
const propValueToString = (value) => {
|
|
8
|
+
if (typeof value === 'function') {
|
|
9
|
+
return '={function}';
|
|
10
|
+
}
|
|
11
|
+
else if (typeof value === 'number') {
|
|
12
|
+
return `={${value}}`;
|
|
13
|
+
}
|
|
14
|
+
else if (typeof value === 'string') {
|
|
15
|
+
return `=${JSON.stringify(value)}`;
|
|
16
|
+
}
|
|
17
|
+
else if (typeof value === 'boolean') {
|
|
18
|
+
return value === true ? '' : '={false}';
|
|
19
|
+
}
|
|
20
|
+
return `={${JSON.stringify(value)}}`;
|
|
21
|
+
};
|
|
22
|
+
const printElementProps = (name, props, indent, printContext) => {
|
|
23
|
+
for (const [propName, propValue] of Object.entries(props)) {
|
|
24
|
+
if (__hubSpotComponentRegistry.isComponentFragmentProp(name, propName)) {
|
|
25
|
+
printContext.append(` ${propName}={`);
|
|
26
|
+
printFragmentNode(propValue, indent, printContext);
|
|
27
|
+
printContext.append(`}`);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
printContext.append(` ${propName}${propValueToString(propValue)}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const printElementStart = (node, indent, printContext) => {
|
|
35
|
+
const { name } = node;
|
|
36
|
+
printContext.append(indent);
|
|
37
|
+
printContext.append(`<${name}`);
|
|
38
|
+
if (!__hubSpotComponentRegistry.isAllowedComponentName(name)) {
|
|
39
|
+
printContext.foundInvalidComponents.add(name);
|
|
40
|
+
if (printContext.options.markInvalidComponents) {
|
|
41
|
+
printContext.append('⚠️');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const printElementNode = (node, indent, printContext) => {
|
|
46
|
+
const hasChildren = node.children.length > 0;
|
|
47
|
+
const { name, props } = node;
|
|
48
|
+
if (hasChildren) {
|
|
49
|
+
printElementStart(node, indent, printContext);
|
|
50
|
+
printElementProps(name, props, indent + INDENT_STRING, printContext);
|
|
51
|
+
printContext.append(`>\n`);
|
|
52
|
+
printChildren(node, indent + INDENT_STRING, printContext);
|
|
53
|
+
printContext.append(`${indent}</${name}>\n`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
printElementStart(node, indent, printContext);
|
|
57
|
+
printElementProps(name, props, indent + INDENT_STRING, printContext);
|
|
58
|
+
printContext.append(`/>\n`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const printChildren = (node, indent, printContext) => {
|
|
62
|
+
const { children } = node;
|
|
63
|
+
for (const child of children) {
|
|
64
|
+
if (isRenderedTextNode(child)) {
|
|
65
|
+
printTextNode(child, indent, printContext);
|
|
66
|
+
}
|
|
67
|
+
else if (isRenderedElementNode(child)) {
|
|
68
|
+
printElementNode(child, indent, printContext);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
throw new Error(`Illegal State. Invalid rendered node type: ${child.nodeType}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const DEFAULT_PRINT_OPTIONS = {
|
|
76
|
+
markInvalidComponents: true,
|
|
77
|
+
listInvalidComponents: false,
|
|
78
|
+
};
|
|
79
|
+
const printFragmentNode = (node, indent, printContext) => {
|
|
80
|
+
printContext.append(`<>\n`);
|
|
81
|
+
printChildren(node, indent + INDENT_STRING, printContext);
|
|
82
|
+
printContext.append(`${indent}</>`);
|
|
83
|
+
};
|
|
84
|
+
export const printNode = (rootNode, options = DEFAULT_PRINT_OPTIONS) => {
|
|
85
|
+
const { listInvalidComponents } = options;
|
|
86
|
+
let output = '';
|
|
87
|
+
const printContext = {
|
|
88
|
+
append: (str) => {
|
|
89
|
+
output += str;
|
|
90
|
+
},
|
|
91
|
+
options,
|
|
92
|
+
foundInvalidComponents: new Set(),
|
|
93
|
+
};
|
|
94
|
+
if (isRenderedRootNode(rootNode)) {
|
|
95
|
+
printContext.append(`<>\n`);
|
|
96
|
+
printChildren(rootNode, INDENT_STRING, printContext);
|
|
97
|
+
printContext.append(`</>`);
|
|
98
|
+
}
|
|
99
|
+
else if (isRenderedFragmentNode(rootNode)) {
|
|
100
|
+
printFragmentNode(rootNode, '', printContext);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
printElementNode(rootNode, '', printContext);
|
|
104
|
+
}
|
|
105
|
+
if (listInvalidComponents && printContext.foundInvalidComponents.size > 0) {
|
|
106
|
+
printContext.append(`\n⚠️ Invalid components:\n`);
|
|
107
|
+
const foundInvalidComponents = [...printContext.foundInvalidComponents];
|
|
108
|
+
foundInvalidComponents.sort();
|
|
109
|
+
for (const invalidComponentName of foundInvalidComponents) {
|
|
110
|
+
printContext.append(`- ${invalidComponentName}\n`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return output.replace(/\n$/, '');
|
|
114
|
+
};
|