@hubspot/ui-extensions 0.9.8 → 0.10.0

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.
Files changed (28) hide show
  1. package/dist/__tests__/{experimental → crm}/hooks/useAssociations.spec.js +123 -4
  2. package/dist/__tests__/{experimental → crm}/hooks/useCrmProperties.spec.js +17 -3
  3. package/dist/__tests__/{experimental/crm → crm/utils}/fetchAssociations.spec.js +1 -1
  4. package/dist/__tests__/{experimental/crm → crm/utils}/fetchCrmProperties.spec.js +1 -1
  5. package/dist/__tests__/test-d/extension-points.test-d.d.ts +1 -0
  6. package/dist/__tests__/test-d/extension-points.test-d.js +29 -0
  7. package/dist/{experimental → crm}/hooks/useAssociations.d.ts +2 -2
  8. package/dist/{experimental → crm}/hooks/useAssociations.js +4 -4
  9. package/dist/{experimental → crm}/hooks/useCrmProperties.d.ts +1 -1
  10. package/dist/{experimental → crm}/hooks/useCrmProperties.js +4 -1
  11. package/dist/crm/index.d.ts +2 -0
  12. package/dist/crm/index.js +2 -0
  13. package/dist/experimental/index.d.ts +3 -21
  14. package/dist/experimental/index.js +3 -13
  15. package/dist/experimental/types.d.ts +1 -22
  16. package/dist/experimental/types.js +4 -0
  17. package/dist/pages/home/components.d.ts +28 -0
  18. package/dist/pages/home/components.js +20 -0
  19. package/dist/types.d.ts +40 -1
  20. package/package.json +10 -4
  21. /package/dist/__tests__/{experimental → crm}/hooks/useAssociations.spec.d.ts +0 -0
  22. /package/dist/__tests__/{experimental → crm}/hooks/useCrmProperties.spec.d.ts +0 -0
  23. /package/dist/__tests__/{experimental/crm → crm/utils}/fetchAssociations.spec.d.ts +0 -0
  24. /package/dist/__tests__/{experimental/crm → crm/utils}/fetchCrmProperties.spec.d.ts +0 -0
  25. /package/dist/{experimental/crm → crm/utils}/fetchAssociations.d.ts +0 -0
  26. /package/dist/{experimental/crm → crm/utils}/fetchAssociations.js +0 -0
  27. /package/dist/{experimental/crm → crm/utils}/fetchCrmProperties.d.ts +0 -0
  28. /package/dist/{experimental/crm → crm/utils}/fetchCrmProperties.js +0 -0
@@ -1,6 +1,6 @@
1
1
  import { renderHook, waitFor } from '@testing-library/react';
2
- import { useAssociations } from '../../../experimental/hooks/useAssociations';
3
- import { fetchAssociations } from '../../../experimental/crm/fetchAssociations';
2
+ import { useAssociations } from '../../../crm/hooks/useAssociations';
3
+ import { fetchAssociations } from '../../../crm/utils/fetchAssociations';
4
4
  // Mock the logger module
5
5
  jest.mock('../../../logger', () => ({
6
6
  logger: {
@@ -11,8 +11,8 @@ jest.mock('../../../logger', () => ({
11
11
  },
12
12
  }));
13
13
  // Mock the fetchAssociations function, keep utility functions
14
- jest.mock('../../../experimental/crm/fetchAssociations', () => ({
15
- ...jest.requireActual('../../../experimental/crm/fetchAssociations'),
14
+ jest.mock('../../../crm/utils/fetchAssociations', () => ({
15
+ ...jest.requireActual('../../../crm/utils/fetchAssociations'),
16
16
  fetchAssociations: jest.fn(),
17
17
  }));
18
18
  // Get reference to the mocked function
@@ -313,6 +313,125 @@ describe('useAssociations with Pagination', () => {
313
313
  expect(result.current.isLoading).toBe(false);
314
314
  });
315
315
  });
316
+ it('should handle null config gracefully', async () => {
317
+ mockFetchAssociations.mockResolvedValue({
318
+ data: {
319
+ results: [],
320
+ hasMore: false,
321
+ nextOffset: 0,
322
+ },
323
+ cleanup: jest.fn(),
324
+ });
325
+ // @ts-expect-error - intentional type issue to check the failure state
326
+ const { result } = renderHook(() => useAssociations(null));
327
+ await waitFor(() => {
328
+ expect(result.current.isLoading).toBe(false);
329
+ expect(result.current.results).toEqual([]);
330
+ expect(result.current.pagination.pageSize).toBe(10); // DEFAULT_PAGE_SIZE
331
+ });
332
+ expect(mockFetchAssociations).toHaveBeenCalledWith(expect.objectContaining({
333
+ toObjectType: undefined,
334
+ properties: undefined,
335
+ pageLength: 10,
336
+ offset: undefined,
337
+ }), expect.any(Object));
338
+ });
339
+ it('should handle undefined config gracefully', async () => {
340
+ mockFetchAssociations.mockResolvedValue({
341
+ data: {
342
+ results: [],
343
+ hasMore: false,
344
+ nextOffset: 0,
345
+ },
346
+ cleanup: jest.fn(),
347
+ });
348
+ // @ts-expect-error - intentional type issue to check the failure state
349
+ const { result } = renderHook(() => useAssociations(undefined));
350
+ await waitFor(() => {
351
+ expect(result.current.isLoading).toBe(false);
352
+ expect(result.current.results).toEqual([]);
353
+ expect(result.current.pagination.pageSize).toBe(10); // DEFAULT_PAGE_SIZE
354
+ });
355
+ expect(mockFetchAssociations).toHaveBeenCalledWith(expect.objectContaining({
356
+ toObjectType: undefined,
357
+ properties: undefined,
358
+ pageLength: 10,
359
+ offset: undefined,
360
+ }), expect.any(Object));
361
+ });
362
+ it('should handle empty config object gracefully', async () => {
363
+ mockFetchAssociations.mockResolvedValue({
364
+ data: {
365
+ results: [],
366
+ hasMore: false,
367
+ nextOffset: 0,
368
+ },
369
+ cleanup: jest.fn(),
370
+ });
371
+ // @ts-expect-error - intentional type issue to check the failure state
372
+ const { result } = renderHook(() => useAssociations({}));
373
+ await waitFor(() => {
374
+ expect(result.current.isLoading).toBe(false);
375
+ expect(result.current.results).toEqual([]);
376
+ expect(result.current.pagination.pageSize).toBe(10); // DEFAULT_PAGE_SIZE
377
+ });
378
+ expect(mockFetchAssociations).toHaveBeenCalledWith(expect.objectContaining({
379
+ toObjectType: undefined,
380
+ properties: undefined,
381
+ pageLength: 10,
382
+ offset: undefined,
383
+ }), expect.any(Object));
384
+ });
385
+ it('should handle config with missing toObjectType', async () => {
386
+ mockFetchAssociations.mockResolvedValue({
387
+ data: {
388
+ results: [],
389
+ hasMore: false,
390
+ nextOffset: 0,
391
+ },
392
+ cleanup: jest.fn(),
393
+ });
394
+ const { result } = renderHook(() =>
395
+ // @ts-expect-error - intentional type issue to check the failure state
396
+ useAssociations({
397
+ properties: ['firstname'],
398
+ pageLength: 5,
399
+ }));
400
+ await waitFor(() => {
401
+ expect(result.current.isLoading).toBe(false);
402
+ expect(result.current.pagination.pageSize).toBe(5);
403
+ });
404
+ expect(mockFetchAssociations).toHaveBeenCalledWith(expect.objectContaining({
405
+ toObjectType: undefined,
406
+ properties: ['firstname'],
407
+ pageLength: 5,
408
+ offset: undefined,
409
+ }), expect.any(Object));
410
+ });
411
+ it('should handle config with missing properties', async () => {
412
+ mockFetchAssociations.mockResolvedValue({
413
+ data: {
414
+ results: [],
415
+ hasMore: false,
416
+ nextOffset: 0,
417
+ },
418
+ cleanup: jest.fn(),
419
+ });
420
+ const { result } = renderHook(() => useAssociations({
421
+ toObjectType: '0-1',
422
+ pageLength: 8,
423
+ }));
424
+ await waitFor(() => {
425
+ expect(result.current.isLoading).toBe(false);
426
+ expect(result.current.pagination.pageSize).toBe(8);
427
+ });
428
+ expect(mockFetchAssociations).toHaveBeenCalledWith(expect.objectContaining({
429
+ toObjectType: '0-1',
430
+ properties: undefined,
431
+ pageLength: 8,
432
+ offset: undefined,
433
+ }), expect.any(Object));
434
+ });
316
435
  });
317
436
  describe('options handling', () => {
318
437
  it('should pass formatting options to fetchAssociations', async () => {
@@ -1,5 +1,5 @@
1
1
  import { renderHook, waitFor } from '@testing-library/react';
2
- import { useCrmProperties } from '../../../experimental/hooks/useCrmProperties';
2
+ import { useCrmProperties } from '../../../crm/hooks/useCrmProperties';
3
3
  // Mock the logger module
4
4
  jest.mock('../../../logger', () => ({
5
5
  logger: {
@@ -10,9 +10,9 @@ jest.mock('../../../logger', () => ({
10
10
  },
11
11
  }));
12
12
  // Mock the fetchCrmProperties module
13
- jest.mock('../../../experimental/crm/fetchCrmProperties');
13
+ jest.mock('../../../crm/utils/fetchCrmProperties');
14
14
  const mockFetchCrmProperties = jest.fn();
15
- import * as fetchCrmPropertiesModule from '../../../experimental/crm/fetchCrmProperties';
15
+ import * as fetchCrmPropertiesModule from '../../../crm/utils/fetchCrmProperties';
16
16
  fetchCrmPropertiesModule.fetchCrmProperties = mockFetchCrmProperties;
17
17
  describe('useCrmProperties', () => {
18
18
  let originalError;
@@ -239,4 +239,18 @@ describe('useCrmProperties', () => {
239
239
  expect(mockCleanup1).toHaveBeenCalledTimes(1);
240
240
  });
241
241
  });
242
+ it('should handle non-array propertyNames without crashing during stabilization', async () => {
243
+ const errorMessage = 'Properties must be an array of strings';
244
+ mockFetchCrmProperties.mockRejectedValue(new Error(errorMessage));
245
+ const nonArrayPropertyNames = 2;
246
+ const { result } = renderHook(() =>
247
+ // @ts-expect-error - we are deliberately testing a bad type
248
+ useCrmProperties(nonArrayPropertyNames));
249
+ await waitFor(() => {
250
+ expect(result.current.error).toBeInstanceOf(Error);
251
+ expect(result.current.error?.message).toBe(errorMessage);
252
+ expect(result.current.isLoading).toBe(false);
253
+ });
254
+ expect(mockFetchCrmProperties).toHaveBeenCalledWith(2, expect.any(Function), {});
255
+ });
242
256
  });
@@ -8,7 +8,7 @@ Object.defineProperty(global, 'self', {
8
8
  value: mockSelf,
9
9
  writable: true,
10
10
  });
11
- import { fetchAssociations, calculatePaginationFlags, } from '../../../experimental/crm/fetchAssociations';
11
+ import { fetchAssociations, calculatePaginationFlags, } from '../../../crm/utils/fetchAssociations';
12
12
  describe('fetchAssociations', () => {
13
13
  // Helper functions
14
14
  const createMockResponse = (data, overrides = {}) => ({
@@ -8,7 +8,7 @@ Object.defineProperty(global, 'self', {
8
8
  value: mockSelf,
9
9
  writable: true,
10
10
  });
11
- import { fetchCrmProperties } from '../../../experimental/crm/fetchCrmProperties';
11
+ import { fetchCrmProperties } from '../../../crm/utils/fetchCrmProperties';
12
12
  const DEFAULT_OPTIONS = {};
13
13
  describe('fetchCrmProperties', () => {
14
14
  beforeEach(() => {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ import { expectAssignable } from 'tsd';
2
+ // Test app home extension point
3
+ expectAssignable({
4
+ actions: {
5
+ addAlert: () => { },
6
+ copyTextToClipboard: async () => { },
7
+ closeOverlay: () => { },
8
+ reloadPage: () => { },
9
+ openIframeModal: () => { },
10
+ },
11
+ context: {
12
+ user: {
13
+ id: 123,
14
+ emails: ['test@example.com'],
15
+ email: 'test@example.com',
16
+ firstName: 'John',
17
+ lastName: 'Doe',
18
+ roles: [],
19
+ teams: [],
20
+ permissions: [],
21
+ },
22
+ portal: {
23
+ id: 456,
24
+ timezone: 'America/New_York',
25
+ },
26
+ location: 'home',
27
+ },
28
+ customComponents: {},
29
+ });
@@ -1,5 +1,5 @@
1
- import { type FetchAssociationsRequest, type AssociationResult } from '../crm/fetchAssociations';
2
- import { type FetchCrmPropertiesOptions } from '../crm/fetchCrmProperties';
1
+ import { type FetchAssociationsRequest, type AssociationResult } from '../utils/fetchAssociations';
2
+ import { type FetchCrmPropertiesOptions } from '../utils/fetchCrmProperties';
3
3
  export interface UseAssociationsOptions {
4
4
  propertiesToFormat?: 'all' | string[];
5
5
  formattingOptions?: FetchCrmPropertiesOptions['formattingOptions'];
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useReducer, useMemo, useRef, useCallback } from 'react';
2
2
  import { logger } from '../../logger';
3
- import { fetchAssociations, DEFAULT_PAGE_SIZE, calculatePaginationFlags, } from '../crm/fetchAssociations';
3
+ import { fetchAssociations, DEFAULT_PAGE_SIZE, calculatePaginationFlags, } from '../utils/fetchAssociations';
4
4
  function createInitialState(pageSize) {
5
5
  return {
6
6
  results: [],
@@ -81,7 +81,7 @@ function associationsReducer(state, action) {
81
81
  }
82
82
  const DEFAULT_OPTIONS = {};
83
83
  export function useAssociations(config, options = DEFAULT_OPTIONS) {
84
- const pageSize = config.pageLength ?? DEFAULT_PAGE_SIZE;
84
+ const pageSize = config?.pageLength ?? DEFAULT_PAGE_SIZE;
85
85
  const [state, dispatch] = useReducer(associationsReducer, useMemo(() => createInitialState(pageSize), [pageSize]));
86
86
  // Log experimental warning once on mount
87
87
  useEffect(() => {
@@ -141,8 +141,8 @@ export function useAssociations(config, options = DEFAULT_OPTIONS) {
141
141
  dispatch({ type: 'FETCH_START' });
142
142
  // Build request using current offset token
143
143
  const request = {
144
- toObjectType: stableConfig.toObjectType,
145
- properties: stableConfig.properties,
144
+ toObjectType: stableConfig?.toObjectType,
145
+ properties: stableConfig?.properties,
146
146
  pageLength: pageSize,
147
147
  offset: state.currentOffset,
148
148
  };
@@ -1,4 +1,4 @@
1
- import { type FetchCrmPropertiesOptions } from '../crm/fetchCrmProperties';
1
+ import { type FetchCrmPropertiesOptions } from '../utils/fetchCrmProperties';
2
2
  export interface CrmPropertiesState {
3
3
  properties: Record<string, string | null>;
4
4
  error: Error | null;
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useReducer, useMemo, useRef } from 'react';
2
2
  import { logger } from '../../logger';
3
- import { fetchCrmProperties, } from '../crm/fetchCrmProperties';
3
+ import { fetchCrmProperties, } from '../utils/fetchCrmProperties';
4
4
  const initialState = {
5
5
  properties: {},
6
6
  error: null,
@@ -56,6 +56,9 @@ export function useCrmProperties(propertyNames, options = DEFAULT_OPTIONS) {
56
56
  const lastOptionsRef = useRef();
57
57
  const lastOptionsKeyRef = useRef();
58
58
  const stablePropertyNames = useMemo(() => {
59
+ if (!Array.isArray(propertyNames)) {
60
+ return propertyNames;
61
+ }
59
62
  const sortedNames = [...propertyNames].sort();
60
63
  const propertyNamesKey = JSON.stringify(sortedNames);
61
64
  if (propertyNamesKey === lastPropertyNamesKeyRef.current) {
@@ -1,2 +1,4 @@
1
1
  import { CrmPropertyList, CrmAssociationTable, CrmDataHighlight, CrmReport, CrmAssociationPivot, CrmAssociationPropertyList, CrmAssociationStageTracker, CrmSimpleDeadline, CrmStageTracker, CrmStatistics, CrmActionButton, CrmActionLink, CrmCardActions } from './components';
2
2
  export { CrmPropertyList, CrmAssociationTable, CrmDataHighlight, CrmReport, CrmAssociationPivot, CrmAssociationPropertyList, CrmAssociationStageTracker, CrmSimpleDeadline, CrmStageTracker, CrmStatistics, CrmActionButton, CrmActionLink, CrmCardActions, };
3
+ export { useCrmProperties } from './hooks/useCrmProperties';
4
+ export { useAssociations } from './hooks/useAssociations';
package/dist/crm/index.js CHANGED
@@ -1,2 +1,4 @@
1
1
  import { CrmPropertyList, CrmAssociationTable, CrmDataHighlight, CrmReport, CrmAssociationPivot, CrmAssociationPropertyList, CrmAssociationStageTracker, CrmSimpleDeadline, CrmStageTracker, CrmStatistics, CrmActionButton, CrmActionLink, CrmCardActions, } from './components';
2
2
  export { CrmPropertyList, CrmAssociationTable, CrmDataHighlight, CrmReport, CrmAssociationPivot, CrmAssociationPropertyList, CrmAssociationStageTracker, CrmSimpleDeadline, CrmStageTracker, CrmStatistics, CrmActionButton, CrmActionLink, CrmCardActions, };
3
+ export { useCrmProperties } from './hooks/useCrmProperties';
4
+ export { useAssociations } from './hooks/useAssociations';
@@ -1,7 +1,7 @@
1
1
  import type * as types from '../types';
2
2
  import type * as experimentalTypes from './types';
3
- export { useCrmProperties } from './hooks/useCrmProperties';
4
- export { useAssociations } from './hooks/useAssociations';
3
+ export { useCrmProperties } from '../crm/hooks/useCrmProperties';
4
+ export { useAssociations } from '../crm/hooks/useAssociations';
5
5
  /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
6
6
  declare const Iframe: "Iframe" & {
7
7
  readonly type?: "Iframe" | undefined;
@@ -78,22 +78,4 @@ declare const FileInput: "FileInput" & {
78
78
  readonly props?: experimentalTypes.FileInputProps | undefined;
79
79
  readonly children?: true | undefined;
80
80
  } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"FileInput", experimentalTypes.FileInputProps, true>>;
81
- /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
82
- declare const HeaderActions: "HeaderActions" & {
83
- readonly type?: "HeaderActions" | undefined;
84
- readonly props?: experimentalTypes.HeaderActionsProps | undefined;
85
- readonly children?: true | undefined;
86
- } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"HeaderActions", experimentalTypes.HeaderActionsProps, true>>;
87
- /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
88
- declare const PrimaryHeaderActionButton: "PrimaryHeaderActionButton" & {
89
- readonly type?: "PrimaryHeaderActionButton" | undefined;
90
- readonly props?: experimentalTypes.HeaderActionButtonProps | undefined;
91
- readonly children?: true | undefined;
92
- } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"PrimaryHeaderActionButton", experimentalTypes.HeaderActionButtonProps, true>>;
93
- /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
94
- declare const SecondaryHeaderActionButton: "SecondaryHeaderActionButton" & {
95
- readonly type?: "SecondaryHeaderActionButton" | undefined;
96
- readonly props?: experimentalTypes.HeaderActionButtonProps | undefined;
97
- readonly children?: true | undefined;
98
- } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"SecondaryHeaderActionButton", experimentalTypes.HeaderActionButtonProps, true>>;
99
- export { Iframe, MediaObject, Stack2, Center, SimpleGrid, GridItem, Grid, SettingsView, ExpandableText, Popover, FileInput, HeaderActions, PrimaryHeaderActionButton, SecondaryHeaderActionButton, };
81
+ export { Iframe, MediaObject, Stack2, Center, SimpleGrid, GridItem, Grid, SettingsView, ExpandableText, Popover, FileInput, };
@@ -1,6 +1,6 @@
1
1
  import { createRemoteReactComponent } from '@remote-ui/react';
2
- export { useCrmProperties } from './hooks/useCrmProperties';
3
- export { useAssociations } from './hooks/useAssociations';
2
+ export { useCrmProperties } from '../crm/hooks/useCrmProperties';
3
+ export { useAssociations } from '../crm/hooks/useAssociations';
4
4
  /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
5
5
  const Iframe = createRemoteReactComponent('Iframe');
6
6
  /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
@@ -35,14 +35,4 @@ const ExpandableText = createRemoteReactComponent('ExpandableText');
35
35
  */
36
36
  const Popover = createRemoteReactComponent('Popover');
37
37
  const FileInput = createRemoteReactComponent('FileInput');
38
- /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
39
- const HeaderActions = createRemoteReactComponent('HeaderActions');
40
- /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
41
- const PrimaryHeaderActionButton = createRemoteReactComponent('PrimaryHeaderActionButton', {
42
- fragmentProps: ['overlay'],
43
- });
44
- /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
45
- const SecondaryHeaderActionButton = createRemoteReactComponent('SecondaryHeaderActionButton', {
46
- fragmentProps: ['overlay'],
47
- });
48
- export { Iframe, MediaObject, Stack2, Center, SimpleGrid, GridItem, Grid, SettingsView, ExpandableText, Popover, FileInput, HeaderActions, PrimaryHeaderActionButton, SecondaryHeaderActionButton, };
38
+ export { Iframe, MediaObject, Stack2, Center, SimpleGrid, GridItem, Grid, SettingsView, ExpandableText, Popover, FileInput, };
@@ -238,29 +238,8 @@ export interface BaseInputProps<T = string, V = string> {
238
238
  */
239
239
  onFocus?: (value: V) => void;
240
240
  }
241
+ export {};
241
242
  /**
242
243
  * @ignore
243
244
  * @experimental do not use in production
244
245
  */
245
- /**
246
- * @ignore
247
- * @experimental do not use in production
248
- */
249
- export interface HeaderActionsProps {
250
- children: ReactNode;
251
- }
252
- /**
253
- * @ignore
254
- * @experimental do not use in production
255
- */
256
- export interface HeaderActionButtonProps {
257
- onClick?: ReactionsHandler<ExtensionEvent>;
258
- href?: string | {
259
- url: string;
260
- external?: boolean;
261
- };
262
- disabled?: boolean;
263
- children: ReactNode;
264
- overlay?: RemoteFragment;
265
- }
266
- export {};
@@ -1 +1,5 @@
1
1
  export {};
2
+ /**
3
+ * @ignore
4
+ * @experimental do not use in production
5
+ */
@@ -0,0 +1,28 @@
1
+ import type * as types from '../../types';
2
+ /**
3
+ * The `HeaderActions` component renders a container for action buttons in the app home header. It accepts `PrimaryHeaderActionButton` and `SecondaryHeaderActionButton` as children.
4
+ *
5
+ */
6
+ export declare const HeaderActions: "HeaderActions" & {
7
+ readonly type?: "HeaderActions" | undefined;
8
+ readonly props?: types.HeaderActionsProps | undefined;
9
+ readonly children?: true | undefined;
10
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"HeaderActions", types.HeaderActionsProps, true>>;
11
+ /**
12
+ * The `PrimaryHeaderActionButton` component renders a primary action button in the app home header. This button is styled as the main call-to-action and only one should be used per `HeaderActions` container.
13
+ *
14
+ */
15
+ export declare const PrimaryHeaderActionButton: "PrimaryHeaderActionButton" & {
16
+ readonly type?: "PrimaryHeaderActionButton" | undefined;
17
+ readonly props?: types.HeaderActionButtonProps | undefined;
18
+ readonly children?: true | undefined;
19
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"PrimaryHeaderActionButton", types.HeaderActionButtonProps, true>>;
20
+ /**
21
+ * The `SecondaryHeaderActionButton` component renders a secondary action button in the app home header. Multiple secondary actions can be used and they will be grouped appropriately in the header.
22
+ *
23
+ */
24
+ export declare const SecondaryHeaderActionButton: "SecondaryHeaderActionButton" & {
25
+ readonly type?: "SecondaryHeaderActionButton" | undefined;
26
+ readonly props?: types.HeaderActionButtonProps | undefined;
27
+ readonly children?: true | undefined;
28
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"SecondaryHeaderActionButton", types.HeaderActionButtonProps, true>>;
@@ -0,0 +1,20 @@
1
+ import { createRemoteReactComponent } from '@remote-ui/react';
2
+ /**
3
+ * The `HeaderActions` component renders a container for action buttons in the app home header. It accepts `PrimaryHeaderActionButton` and `SecondaryHeaderActionButton` as children.
4
+ *
5
+ */
6
+ export const HeaderActions = createRemoteReactComponent('HeaderActions');
7
+ /**
8
+ * The `PrimaryHeaderActionButton` component renders a primary action button in the app home header. This button is styled as the main call-to-action and only one should be used per `HeaderActions` container.
9
+ *
10
+ */
11
+ export const PrimaryHeaderActionButton = createRemoteReactComponent('PrimaryHeaderActionButton', {
12
+ fragmentProps: ['overlay'],
13
+ });
14
+ /**
15
+ * The `SecondaryHeaderActionButton` component renders a secondary action button in the app home header. Multiple secondary actions can be used and they will be grouped appropriately in the header.
16
+ *
17
+ */
18
+ export const SecondaryHeaderActionButton = createRemoteReactComponent('SecondaryHeaderActionButton', {
19
+ fragmentProps: ['overlay'],
20
+ });
package/dist/types.d.ts CHANGED
@@ -239,6 +239,7 @@ export interface UiePlatformActions {
239
239
  copyTextToClipboard: Clipboard['writeText'];
240
240
  closeOverlay: CloseOverlayAction;
241
241
  reloadPage: ReloadPageAction;
242
+ openIframeModal: OpenIframeModalAction;
242
243
  }
243
244
  /**
244
245
  * The props type for {@link !components.Accordion}.
@@ -309,6 +310,42 @@ export interface AlertProps {
309
310
  */
310
311
  variant?: 'info' | 'warning' | 'success' | 'error' | 'danger' | 'tip';
311
312
  }
313
+ /**
314
+ * The props type for {@link !components.HeaderActions}.
315
+ *
316
+ * @category Component Props
317
+ */
318
+ export interface HeaderActionsProps {
319
+ /**
320
+ * Sets the content that will render inside the HeaderActions. This prop is passed implicitly by providing sub-components.
321
+ */
322
+ children: ReactNode;
323
+ }
324
+ /**
325
+ * The props type for {@link !components.HeaderActions}.
326
+ *
327
+ * @category Component Props
328
+ */
329
+ export interface HeaderActionButtonProps extends OverlayComponentProps {
330
+ /**
331
+ * A function that will be invoked when the button is clicked. Do not use this function for submitting a form; use Form's `onSubmit` function instead.
332
+ *
333
+ * @event
334
+ */
335
+ onClick?: ReactionsHandler<ExtensionEvent>;
336
+ /**
337
+ * A URL that will be opened when the button is clicked. If the value is a URL external to `hubspot.com` it will be opened in a new tab.
338
+ */
339
+ href?: HrefProp;
340
+ /**
341
+ * Determines whether or not the button should be disabled.
342
+ */
343
+ disabled?: boolean;
344
+ /**
345
+ * Sets the content that will render inside the HeaderActionButton. This prop is passed implicitly by providing sub-components.
346
+ */
347
+ children: ReactNode;
348
+ }
312
349
  /**
313
350
  * The props type for {@link !components.ButtonRow}.
314
351
  *
@@ -2569,10 +2606,12 @@ export interface AppContext {
2569
2606
  appName?: string;
2570
2607
  cardTitle?: string;
2571
2608
  }
2609
+ type ProfileVariableValue = string | number | bigint | boolean;
2572
2610
  /** @ignore */
2573
2611
  export interface BaseContext {
2574
2612
  user: UserContext;
2575
2613
  portal: PortalContext;
2614
+ variables?: Record<string, ProfileVariableValue>;
2576
2615
  }
2577
2616
  /** @ignore */
2578
2617
  export interface CrmContext extends BaseContext {
@@ -2923,7 +2962,7 @@ export interface SettingsExtensionPoint extends ExtensionPointContract {
2923
2962
  }
2924
2963
  /** @ignore */
2925
2964
  export interface AppHomeExtensionPoint extends ExtensionPointContract {
2926
- actions: AppHomeActions;
2965
+ actions: AppHomeActions & UiePlatformActions;
2927
2966
  context: AppHomeContext;
2928
2967
  }
2929
2968
  export interface ExampleCrmComponentProps {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions",
3
- "version": "0.9.8",
3
+ "version": "0.10.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -11,8 +11,9 @@
11
11
  "watch": "npm run clean && tsc --watch",
12
12
  "prepare": "npm run build",
13
13
  "lint": "echo 'No linter configured for @hubspot/ui-extensions'",
14
- "test": "jest",
15
- "jest": "jest --watch"
14
+ "test": "jest && tsd",
15
+ "jest": "jest --watch",
16
+ "test:types": "tsd"
16
17
  },
17
18
  "files": [
18
19
  "dist"
@@ -23,6 +24,7 @@
23
24
  "exports": {
24
25
  ".": "./dist/index.js",
25
26
  "./crm": "./dist/crm/index.js",
27
+ "./pages/home": "./dist/pages/home/components.js",
26
28
  "./experimental": "./dist/experimental/index.js",
27
29
  "./experimental/testing": "./dist/experimental/testing/index.js",
28
30
  "./experimental/testing/jest-matchers": "./dist/experimental/testing/jest/matchers/index.js"
@@ -64,7 +66,11 @@
64
66
  "react-dom": "^18.2.0",
65
67
  "react-reconciler": "^0.29.0",
66
68
  "ts-jest": "^29.1.1",
69
+ "tsd": "^0.33.0",
67
70
  "typescript": "5.0.4"
68
71
  },
69
- "gitHead": "68d176099343d6d202421ec241c131f1d07562a8"
72
+ "tsd": {
73
+ "directory": "src/__tests__/test-d"
74
+ },
75
+ "gitHead": "34ce86d7cfaa1f163bf67838bbb56c054d0f72cc"
70
76
  }