@hubspot/ui-extensions 0.0.1-prealpha.5 → 0.0.1-prealpha.7

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/README.md CHANGED
@@ -13,6 +13,7 @@
13
13
  - [Heading](#heading)
14
14
  - [Image](#image)
15
15
  - [Input](#input)
16
+ - [Link](#link)
16
17
  - [LoadingSpinner](#loadingspinner)
17
18
  - [ProgressBar](#progressbar)
18
19
  - [Select](#select)
@@ -29,6 +30,7 @@
29
30
  - [TableRow](#tablerow)
30
31
  - [Tag](#tag)
31
32
  - [Text](#text)
33
+ - [Textarea](#textarea)
32
34
  - [Tile](#tile)
33
35
 
34
36
  ## Components
@@ -115,8 +117,8 @@ interface ButtonProps {
115
117
  | `onClick` | `() => void` `(optional)` | `N/A` | A function that will be invoked when the button is clicked. It receives no arguments and it's return value is ignored|
116
118
  | `href` | `string(optional)`| `N/A` | A URL that will be opened when the button is clicked. If the value is a URL external to HubSpot it will be opened in a new tab. |
117
119
  | `disabled` | `boolean(optional)` | `N/A` | Determines if the button should be disabled or not.|
118
- | `variant` | ` 'primary' | 'secondary' | 'destructive'` `(optional)` |`'secondary'`| Sets the color variation of the button |
119
- | `type` | `'button' \| 'reset' \| 'submit'` `(optional)` | `'button'`| Sets the HTML attribute "role" of the button |
120
+ | `variant` | `'primary' \| 'secondary' \| 'destructive'` `(optional)` | `'secondary'` | Sets the color variation of the button |
121
+ | `type` | `'button' \| 'reset' \| 'submit'` `(optional)` | `'button'` | Sets the HTML attribute "role" of the button |
120
122
 
121
123
  ##### Usage
122
124
  ```javascript
@@ -332,14 +334,14 @@ import { Form } from '@hubspot/ui-extensions';
332
334
  ```typescript
333
335
  interface FormProps {
334
336
  children: ReactNode;
335
- onSubmit?: () => void;
337
+ onSubmit?: (event: RemoteEvent<FormInputValues>) => void;
336
338
  preventDefault?: boolean;
337
339
  }
338
340
  ```
339
341
  | Prop | Type | Default | Description |
340
342
  | - | - | - | - |
341
343
  | `children` | `ReactNode` | `N/A`| Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
342
- | `onSubmit` | `function(optional)` | `N/A`| A function that will be called when the form is submitted. It will receive no arguments and it's return value will be ignored. |
344
+ | `onSubmit` | `function(optional)` | `N/A`| A function that will be called when the form is submitted. It will receive a `RemoteEvent` as argument and it's return value will be ignored. |
343
345
  | `preventDefault` | `boolean(optional)` | `false`| If set to `true` `event.preventDefault()` will be invoked before your `onSubmit` function is called, preventing the default html form behavior. |
344
346
 
345
347
  ##### Usage
@@ -362,6 +364,95 @@ const Extension = () => {
362
364
  }
363
365
  ```
364
366
 
367
+ ### EmptyState
368
+
369
+ ##### Import
370
+ ```javascript
371
+ import { EmptyState } from '@hubspot/ui-extensions';
372
+ ```
373
+
374
+ ##### Props
375
+ ```typescript
376
+ interface EmptyStateProps {
377
+ children: ReactNode;
378
+ flush?: boolean;
379
+ imageWidth?: number;
380
+ layout?: 'horizontal' | 'vertical';
381
+ reverseOrder?: boolean;
382
+ title?: string;
383
+ }
384
+ ```
385
+ | Prop | Type | Default | Description |
386
+ | - | - | - | - |
387
+ | `children` | `ReactNode` | `N/A` | Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
388
+ | `flush` | `boolean(optional)` | `false` | Removes the default vertical margins for the component. |
389
+ | `imageWidth` | `number(optional)` | `250`| The max-width for the image container. |
390
+ | `layout` | `'horizontal' \| 'vertical'` `(optional)` | `'horizontal'` | Sets the layout direction for the content. |
391
+ | `reverseOrder` | `boolean(optional)` | `false` | Swaps the visual order of the text (primary) and image (secondary) content. This ensures the primary content is still presented first to assistive technology. |
392
+ | `title` | `string(optional)` | `Intl("All is not lost.")` | The text for the title header rendered above the `children`. |
393
+
394
+ ##### Usage
395
+ ```javascript
396
+ const Extension = ({ data }) => {
397
+ if (!data || !data.length) {
398
+ return (
399
+ <EmptyState title="Nothing here yet" layout="vertical" reverseOrder={true}>
400
+ <Text text="Go out there and get some leads!" />
401
+ </EmptyState>
402
+ )
403
+ }
404
+
405
+ return (
406
+ <Stack>
407
+ {data.map(...)}
408
+ </Stack>
409
+ );
410
+ }
411
+ ```
412
+
413
+ ### ErrorState
414
+
415
+ ##### Import
416
+ ```javascript
417
+ import { ErrorState } from '@hubspot/ui-extensions';
418
+ ```
419
+
420
+ ##### Props
421
+ ```typescript
422
+ interface ErrorStateProps {
423
+ children: ReactNode;
424
+ title?: string;
425
+ type?: 'error' | 'support' | 'lock';
426
+ }
427
+ ```
428
+ | Prop | Type | Default | Description |
429
+ | - | - | - | - |
430
+ | `children` | `ReactNode` | `N/A` | Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
431
+ | `title` | `string(optional)` | `Intl("All is not lost.")` | The text for the title header rendered above the `children`. |
432
+ | `type` | `'error' \| 'support' \| 'lock'` `(optional)` | `'error'` | Sets the type of error image that will be shown. |
433
+
434
+ ##### Usage
435
+ ```javascript
436
+ const Extension = ({ data, error, fetchData }) => {
437
+ if (error) {
438
+ return (
439
+ <ErrorState title="Trouble fetching properties." layout="vertical" reverseOrder={true}>
440
+ <Stack>
441
+ <Text text="Please try again in a few moments." />
442
+ <Button text="Try again" onClick={fetchData} />
443
+ </Stack>
444
+ </ErrorState>
445
+ )
446
+ }
447
+
448
+ return (
449
+ <Stack>
450
+ {data.map(...)}
451
+ </Stack>
452
+ );
453
+ }
454
+ ```
455
+
365
456
  ### Heading
366
457
 
367
458
  ##### Import
@@ -467,14 +558,16 @@ interface InputProps {
467
558
  name: string;
468
559
  value?: string;
469
560
  required?: boolean;
470
- readonly?: boolean;
561
+ readOnly?: boolean;
471
562
  description?: string;
472
563
  tooltip?: string;
473
564
  placeholder?: string;
474
565
  error?: boolean;
475
- errorMessage?: string;
476
- onChange: (value: string) => void;
477
- onInput: (value: string) => void;
566
+ validationMessage?: string;
567
+ onChange?: (value: string) => void;
568
+ onInput?: (value: string) => void;
569
+ onBlur?: (value: string) => void;
570
+ onFocus?: (value: string) => void;
478
571
  }
479
572
  ```
480
573
  | Prop | Type | Default | Description |
@@ -483,14 +576,16 @@ interface InputProps {
483
576
  | `name` | `string` | `N/A`| The unique identifier for the input element, this could be thought of as the HTML5 [Input element's name attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#name) |
484
577
  | `value` | `string(optional)` | `''`| The value of the input |
485
578
  | `required` | `boolean(optional)` | `false`| Determines if the required indicator should be displayed |
486
- | `readonly` | `boolean(optional)` | `false`| Determines if the field is editable or not. |
579
+ | `readOnly` | `boolean(optional)` | `false`| Determines if the field is editable or not. |
487
580
  | `description` | `string(optional)` | `N/A`| Instructional message to display to the user to help understand the purpose of the input. |
488
581
  | `tooltip` | `string(optional)` | `N/A`| Text that will appear in a tooltip next to the input label. |
489
582
  | `placeholder` | `string(optional)` | `N/A`| Text that appears in the input when it has no value set. |
490
583
  | `error` | `boolean(optional)` | `false`| If set to true, `validationMessage` is displayed as an error message, if it was provided. The input will also render it's error state to let the user know there is an error. If false, `validationMessage` is displayed as a success message. |
491
584
  | `validationMessage` | `string(optional)` | `''`| The text to show if the input has an error. |
492
- | `onChange` | `(value: string) => void` | `N/A`| A callback function that is invoked when the value is committed. Currently these times are `onBlur` of the input and when the user stops typing. |
493
- | `onInput` | `(value: string) => void` | `N/A`| A function that is called and passed the value every time the field is edited by the user. It is recommended that you do not use this value to update state, that is what `onChange` should be used for. Instead this should be used for validation. |
585
+ | `onChange` | `(value: string) => void(optional)` | `N/A`| A callback function that is invoked when the value is committed. Currently these times are `onBlur` of the input and when the user submits the form. |
586
+ | `onInput` | `(value: string) => void(optional)` | `N/A`| A function that is called and passed the value every time the field is edited by the user. It is recommended that you do not use this value to update state, that is what `onChange` should be used for. Instead this should be used for validation. |
587
+ | `onBlur` | `(value: string) => void(optional)` | `N/A`| A function that is called and passed the value every time the field loses focus. |
588
+ | `onFocus` | `(value: string) => void(optional)` | `N/A`| A function that is called and passed the value every time the field gets focused. |
494
589
 
495
590
  ##### Usage
496
591
  ```javascript
@@ -533,6 +628,33 @@ const Extension = () => {
533
628
  }
534
629
  ```
535
630
 
631
+ ### Link
632
+
633
+ ##### Import
634
+ ```javascript
635
+ import { Link } from '@hubspot/ui-extensions';
636
+ ```
637
+
638
+ ##### Props
639
+ ```typescript
640
+ export interface LinkProps {
641
+ href: string;
642
+ variant?: 'primary' | 'destructive' | 'light' | 'dark';
643
+ children: ReactNode;
644
+ }
645
+ ```
646
+ | Prop | Type | Default | Description |
647
+ | --- | --- | --- | --- |
648
+ | `href` | `string`| `N/A` | A URL that will be opened when the link is clicked. If the value is a URL external to HubSpot it will be opened in a new tab. |
649
+ | `variant` | `'primary' \| 'light' \| 'dark' \| 'destructive'` `(optional)` | `'primary'` | Sets the color variation of the link |
650
+ | `children` | `ReactNode` | `N/A`| Sets the content that will render inside the component. |
651
+
652
+ ##### Usage
653
+ ```javascript
654
+ const Extension = () => {
655
+ return <Link href="https://app.hubspot.com/">HubSpot</Link>
656
+ }
657
+ ```
536
658
  ### LoadingSpinner
537
659
 
538
660
  ##### Import
@@ -619,7 +741,7 @@ interface SelectProps {
619
741
  name: string;
620
742
  value?: string | number | boolean;
621
743
  required?: boolean;
622
- readonly?: boolean;
744
+ readOnly?: boolean;
623
745
  description?: string;
624
746
  tooltip?: string;
625
747
  placeholder?: string;
@@ -639,7 +761,7 @@ interface SelectProps {
639
761
  | `name` | `string` | `N/A`| The unique identifier for the select element. |
640
762
  | `value` | `string \| number \| boolean` | `''`| The value of the select input. |
641
763
  | `required` | `boolean` | `false`| Determines if the required indicator should be displayed |
642
- | `readonly` | `boolean` | `false`| Determines if the field is editable or not. |
764
+ | `readOnly` | `boolean` | `false`| Determines if the field is editable or not. |
643
765
  | `description` | `string` | `N/A`| Instructional message to display to the user to help understand the purpose of the input. |
644
766
  | `tooltip` | `string` | `N/A`| Text that will appear in a tooltip next to the input label. |
645
767
  | `placeholder` | `string` | `N/A`| Text that appears in the input when it has no value set. |
@@ -698,13 +820,15 @@ import { Stack } from '@hubspot/ui-extensions';
698
820
  ##### Props
699
821
  ```typescript
700
822
  interface StackProps {
701
- distance?: 'flush' | 'small';
823
+ distance?: 'flush' | 'small' | 'extra-small' | 'medium' | 'large';
824
+ direction?: 'row' | 'column';
702
825
  children?: ReactNode;
703
826
  }
704
827
  ```
705
828
  | Prop | Type | Default | Description |
706
829
  | - | - | - | - |
707
- | `distance` | `'flush' \| 'small'` | `'small'`| Amount of padding between each child component passed as children |
830
+ | `distance` | `'flush' \| 'extra-small' \| 'small' \| 'medium' \| 'large'` | `'small'`| Amount of space between each child component passed as children |
831
+ | `direction` | `'row' \| 'column'` | `'column'`| Stacks elements in the vertical or horizontal direction. |
708
832
  | `children` | `ReactNode` | `N/A`| Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
709
833
 
710
834
  ##### Usage
@@ -833,6 +957,14 @@ interface TableProps {
833
957
  children: ReactNode;
834
958
  flush?: boolean;
835
959
  bordered?: boolean;
960
+ paginated?: boolean;
961
+ // if paginated=true
962
+ pageCount: number;
963
+ onPageChange: (pageNumber: number) => void;
964
+ showButtonLabels?: boolean;
965
+ showFirstLastButtons?: boolean;
966
+ maxVisiblePageButtons?: number;
967
+ page?: number;
836
968
  }
837
969
  ```
838
970
  | Prop | Type | Default | Description |
@@ -840,6 +972,19 @@ interface TableProps {
840
972
  | `children` | `ReactNode` | `N/A`| Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. These children should be [TableHead](#tablehead), [TableFooter](#tablefooter), or [TableBody](#tablebody) |
841
973
  | `flush` | `boolean(optional)` | `false`| If true the table will not have bottom margin. |
842
974
  | `bordered` | `boolean(optional)` | `true`| If false the table will not haver borders around its content. |
975
+ | `paginated` | `boolean(optional)` | `false`| If true, the table will display the paginator component and consumer will have to provide extra pagination props. |
976
+
977
+ **Props for paginated=true**
978
+
979
+ | Prop | Type | Default | Description |
980
+ | - | - | - | - |
981
+ | `pageCount` | `number` | `N/A`| The total number of pages available |
982
+ | `onPageChange` | `onPageChange: (pageNumber: number) => void` |`N/A`| A function that will be invoked when the pagination button is clicked. It receives the new page number as argument. |
983
+ | `showButtonLabels` | `boolean(optional)` | `true` | if `false`, it hides the text labels for the First/Prev/Next/Last buttons. The button labels will still be accessible for screen readers. |
984
+ | `showFirstLastButtons` | `boolean(optional)` | `false` | if `true`, it displays the First page and Last page buttons. |
985
+ | `maxVisiblePageButtons` | `number(optional)` | `5` | Changes how many page buttons are shown. |
986
+ | `page` | `number(optional)` | `N/A` | Denotes the current page. |
987
+
843
988
 
844
989
  ##### Usage
845
990
  ```javascript
@@ -861,6 +1006,64 @@ const Extension = () => {
861
1006
  </Table>
862
1007
  );
863
1008
  }
1009
+
1010
+
1011
+ // Paginated example
1012
+
1013
+ function generateData(count = 15) {
1014
+ const result = [];
1015
+
1016
+ for (let index = 0; index < count; index++) {
1017
+ result.push({
1018
+ name: `Jane Doe ${index}`,
1019
+ email: `janedoemail${index}@hubspot.com`,
1020
+ });
1021
+ }
1022
+
1023
+ return result;
1024
+ }
1025
+
1026
+ function PaginatedTable() {
1027
+ const ITEMS_PER_PAGE = 10;
1028
+ const data = generateData(30);
1029
+
1030
+ const [currentPage, setCurrentPage] = useState(1);
1031
+ const pageCount = data.length / ITEMS_PER_PAGE;
1032
+
1033
+ const dataToDisplay = data.slice(
1034
+ (currentPage - 1) * ITEMS_PER_PAGE,
1035
+ currentPage * ITEMS_PER_PAGE
1036
+ );
1037
+
1038
+ return (
1039
+ <Table
1040
+ paginated={true}
1041
+ pageCount={pageCount}
1042
+ page={currentPage}
1043
+ onPageChange={(nextPageNumber: number) => {
1044
+ setCurrentPage(nextPageNumber);
1045
+ }}
1046
+ >
1047
+ <TableHead>
1048
+ <TableRow>
1049
+ <TableHeader>Name</TableHeader>
1050
+ <TableHeader>Email</TableHeader>
1051
+ </TableRow>
1052
+ </TableHead>
1053
+ <TableBody>
1054
+ {dataToDisplay.map(({ name, email }) => {
1055
+ console.log(name, email);
1056
+ return (
1057
+ <TableRow key={email}>
1058
+ <TableCell>{name}</TableCell>
1059
+ <TableCell>{email}</TableCell>
1060
+ </TableRow>
1061
+ );
1062
+ })}
1063
+ </TableBody>
1064
+ </Table>
1065
+ );
1066
+ }
864
1067
  ```
865
1068
  ### TableBody
866
1069
 
@@ -1160,13 +1363,17 @@ interface TextProps {
1160
1363
  format?: 'plaintext' | 'markdown';
1161
1364
  text: string;
1162
1365
  variant?: 'bodytext' | 'microcopy';
1366
+ children: ReactNode;
1367
+ tagName?: 'p' | 'span' | 'small';
1163
1368
  }
1164
1369
  ```
1165
1370
  | Prop | Type | Default | Description |
1166
1371
  | - | - | - | - |
1167
1372
  | `format` | `'plaintext' \| 'markdown'` `(optional)`| `'plaintext'`| Type of formatting for the display text. |
1168
- | `text` | `string` | `N/A`| Text to be displayed as body text. If format is `"markdown"`, inline markdown elements (i.e. bold, italics, code, links) are supported |
1373
+ | `text` | `string` | `N/A`| Text to be displayed as body text iff format is `"markdown"`. Inline markdown elements (i.e. bold, italics, code, links) are supported |
1374
+ | `children` | `string` | `N/A`| Text to be displayed as body text iff format is `"plaintext"`. |
1169
1375
  | `variant` | `'bodytext' \| 'microcopy'` | `'bodytext`| Type of text to display |
1376
+ | `tagName` | `'p' \| 'small' \| 'span'` | `'bodytext`| Type of text element(tag) to display. |
1170
1377
 
1171
1378
  #### Markdown
1172
1379
  Markdown syntax supported in the component:
@@ -1190,6 +1397,96 @@ const Extension = () => {
1190
1397
  }
1191
1398
  ```
1192
1399
 
1400
+ ### Textarea
1401
+
1402
+ ##### Import
1403
+ ```javascript
1404
+ import { Textarea } from '@hubspot/ui-extensions';
1405
+ ```
1406
+
1407
+ ##### Props
1408
+ ```typescript
1409
+ interface TextareaProps {
1410
+ label: string;
1411
+ name: string;
1412
+ value?: string;
1413
+ required?: boolean;
1414
+ readOnly?: boolean;
1415
+ description?: string;
1416
+ tooltip?: string;
1417
+ placeholder?: string;
1418
+ error?: boolean;
1419
+ validationMessage?: string;
1420
+ onChange?: (value: string) => void;
1421
+ onInput?: (value: string) => void;
1422
+ onBlur?: (value: string) => void;
1423
+ onFocus?: (value: string) => void;
1424
+ cols?: number;
1425
+ maxLength?: number;
1426
+ rows?: number;
1427
+ resize?: 'vertical' | 'horizontal' | 'both' | 'none';
1428
+ }
1429
+ ```
1430
+ | Prop | Type | Default | Description |
1431
+ | - | - | - | - |
1432
+ | `label` | `string` | `N/A`| The label text to display for the textarea element |
1433
+ | `name` | `string` | `N/A`| The unique identifier for the textarea element, this could be thought of as the HTML5 [Textarea element's name attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#name) |
1434
+ | `value` | `string(optional)` | `''`| The value of the textarea |
1435
+ | `required` | `boolean(optional)` | `false`| Determines if the required indicator should be displayed |
1436
+ | `readOnly` | `boolean(optional)` | `false`| Determines if the field is editable or not. |
1437
+ | `description` | `string(optional)` | `N/A`| Instructional message to display to the user to help understand the purpose of the textarea. |
1438
+ | `tooltip` | `string(optional)` | `N/A`| Text that will appear in a tooltip next to the textarea label. |
1439
+ | `placeholder` | `string(optional)` | `N/A`| Text that appears in the textarea when it has no value set. |
1440
+ | `error` | `boolean(optional)` | `false`| If set to true, `validationMessage` is displayed as an error message, if it was provided. The textarea will also render it's error state to let the user know there is an error. If false, `validationMessage` is displayed as a success message. |
1441
+ | `validationMessage` | `string(optional)` | `''`| The text to show if the textarea has an error. |
1442
+ | `onChange` | `(value: string) => void(optional)` | `N/A` | A callback function that is invoked when the value is committed. Currently these times are `onBlur` of the textarea and when the user submits the form. |
1443
+ | `onInput` | `(value: string) => void(optional)` | `N/A`| A function that is called and passed the value every time the field is edited by the user. It is recommended that you do not use this value to update state, that is what `onChange` should be used for. Instead this should be used for validation. |
1444
+ | `onBlur` | `(value: string) => void(optional)` | `N/A`| A function that is called and passed the value every time the field loses focus. |
1445
+ | `onFocus` | `(value: string) => void(optional)` | `N/A`| A function that is called and passed the value every time the field gets focused. |
1446
+ | `cols` | `number(optional)` | `N/A` | The visible width of the text control, in average character widths. |
1447
+ | `rows` | `number(optional)` | `N/A` | The number of visible text lines for the control. |
1448
+ | `maxLength` | `number(optional)` | `N/A` | The maximum number of characters (UTF-16 code units) that the user can enter. If this value isn't specified, the user can enter an unlimited number of characters. |
1449
+ | `resize` | `'vertical' \| 'horizontal' \| 'both' \| 'none'` `(optional)`| `'vertical'` | Sets whether an element is resizable, and if so, in which directions. |
1450
+
1451
+ ##### Usage
1452
+ ```javascript
1453
+ import { useState } from 'react';
1454
+
1455
+ const Extension = () => {
1456
+ const [ desciptiption, setDescription ] = useState('');
1457
+ const [ validationMessage, setValidationMessage ] = useState('');
1458
+ const [ isValid, setIsValid ] = useState(true);
1459
+
1460
+ return (
1461
+ <Form>
1462
+ <Textarea
1463
+ label="Description"
1464
+ name="description"
1465
+ tooltip="Provide as much detail as possible"
1466
+ description="Please include a link"
1467
+ placeholder="My desription"
1468
+ required={true}
1469
+ error={!isValid}
1470
+ validationMessage={validationMessage}
1471
+ onChange={(value) => {
1472
+ setDescription(value)
1473
+ }}
1474
+ onInput={(value) => {
1475
+ if (!value.includes('http')) {
1476
+ setValidationMessage('A link must be included.');
1477
+ setIsValid(false);
1478
+ } else {
1479
+ setValidationMessage('Valid description!')
1480
+ setIsValid(true);
1481
+ }
1482
+ }}
1483
+ />
1484
+ </Form>
1485
+ );
1486
+ }
1487
+ ```
1488
+
1489
+
1193
1490
  ### Tile
1194
1491
 
1195
1492
  ##### Import
@@ -1,4 +1,4 @@
1
- import type { AlertProps, ButtonProps, ButtonRowProps, CardProps, DescriptionListProps, DescriptionListItemProps, DividerProps, FormProps, HeadingProps, ImageProps, InputProps, LoadingSpinnerProps, ProgressBarProps, SelectProps, TagProps, TextProps, TileProps, StackProps, StatisticsProps, StatisticsItemProps, StatisticsTrendProps, TableProps, TableElementProps } from './types';
1
+ import type { AlertProps, ButtonProps, ButtonRowProps, CardProps, DescriptionListProps, DescriptionListItemProps, DividerProps, EmptyStateProps, ErrorStateProps, FormProps, HeadingProps, ImageProps, InputProps, TextareaProps, LoadingSpinnerProps, ProgressBarProps, SelectProps, TagProps, TextProps, TileProps, StackProps, StatisticsProps, StatisticsItemProps, StatisticsTrendProps, TableProps, TableElementProps, LinkProps } from './types';
2
2
  declare const Alert: "Alert" & {
3
3
  readonly type?: "Alert" | undefined;
4
4
  readonly props?: AlertProps | undefined;
@@ -34,6 +34,16 @@ declare const Divider: "Divider" & {
34
34
  readonly props?: DividerProps | undefined;
35
35
  readonly children?: true | undefined;
36
36
  } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"Divider", DividerProps, true>>;
37
+ declare const EmptyState: "EmptyState" & {
38
+ readonly type?: "EmptyState" | undefined;
39
+ readonly props?: EmptyStateProps | undefined;
40
+ readonly children?: true | undefined;
41
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"EmptyState", EmptyStateProps, true>>;
42
+ declare const ErrorState: "ErrorState" & {
43
+ readonly type?: "ErrorState" | undefined;
44
+ readonly props?: ErrorStateProps | undefined;
45
+ readonly children?: true | undefined;
46
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"ErrorState", ErrorStateProps, true>>;
37
47
  declare const Form: "Form" & {
38
48
  readonly type?: "Form" | undefined;
39
49
  readonly props?: FormProps | undefined;
@@ -54,6 +64,11 @@ declare const Input: "Input" & {
54
64
  readonly props?: InputProps | undefined;
55
65
  readonly children?: true | undefined;
56
66
  } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"Input", InputProps, true>>;
67
+ declare const Textarea: "Textarea" & {
68
+ readonly type?: "Textarea" | undefined;
69
+ readonly props?: TextareaProps | undefined;
70
+ readonly children?: true | undefined;
71
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"Textarea", TextareaProps, true>>;
57
72
  declare const LoadingSpinner: "LoadingSpinner" & {
58
73
  readonly type?: "LoadingSpinner" | undefined;
59
74
  readonly props?: LoadingSpinnerProps | undefined;
@@ -139,4 +154,9 @@ declare const TableHead: "TableHead" & {
139
154
  readonly props?: TableElementProps | undefined;
140
155
  readonly children?: true | undefined;
141
156
  } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"TableHead", TableElementProps, true>>;
142
- export { Alert, Button, ButtonRow, Card, DescriptionList, DescriptionListItem, Divider, Form, Heading, Image, Input, LoadingSpinner, ProgressBar, Select, Stack, Statistics, StatisticsItem, StatisticsTrend, Table, TableFooter, TableCell, TableRow, TableBody, TableHeader, TableHead, Tag, Text, Tile, };
157
+ declare const Link: "Link" & {
158
+ readonly type?: "Link" | undefined;
159
+ readonly props?: LinkProps | undefined;
160
+ readonly children?: true | undefined;
161
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"Link", LinkProps, true>>;
162
+ export { Alert, Button, ButtonRow, Card, DescriptionList, DescriptionListItem, Divider, EmptyState, ErrorState, Form, Heading, Image, Input, Textarea, LoadingSpinner, Link, ProgressBar, Select, Stack, Statistics, StatisticsItem, StatisticsTrend, Table, TableFooter, TableCell, TableRow, TableBody, TableHeader, TableHead, Tag, Text, Tile, };
@@ -6,10 +6,13 @@ const Card = createRemoteReactComponent('Card');
6
6
  const DescriptionList = createRemoteReactComponent('DescriptionList');
7
7
  const DescriptionListItem = createRemoteReactComponent('DescriptionListItem');
8
8
  const Divider = createRemoteReactComponent('Divider');
9
+ const EmptyState = createRemoteReactComponent('EmptyState');
10
+ const ErrorState = createRemoteReactComponent('ErrorState');
9
11
  const Form = createRemoteReactComponent('Form');
10
12
  const Heading = createRemoteReactComponent('Heading');
11
13
  const Image = createRemoteReactComponent('Image');
12
14
  const Input = createRemoteReactComponent('Input');
15
+ const Textarea = createRemoteReactComponent('Textarea');
13
16
  const LoadingSpinner = createRemoteReactComponent('LoadingSpinner');
14
17
  const ProgressBar = createRemoteReactComponent('ProgressBar');
15
18
  const Select = createRemoteReactComponent('Select');
@@ -27,4 +30,5 @@ const TableRow = createRemoteReactComponent('TableRow');
27
30
  const TableBody = createRemoteReactComponent('TableBody');
28
31
  const TableHeader = createRemoteReactComponent('TableHeader');
29
32
  const TableHead = createRemoteReactComponent('TableHead');
30
- export { Alert, Button, ButtonRow, Card, DescriptionList, DescriptionListItem, Divider, Form, Heading, Image, Input, LoadingSpinner, ProgressBar, Select, Stack, Statistics, StatisticsItem, StatisticsTrend, Table, TableFooter, TableCell, TableRow, TableBody, TableHeader, TableHead, Tag, Text, Tile, };
33
+ const Link = createRemoteReactComponent('Link');
34
+ export { Alert, Button, ButtonRow, Card, DescriptionList, DescriptionListItem, Divider, EmptyState, ErrorState, Form, Heading, Image, Input, Textarea, LoadingSpinner, Link, ProgressBar, Select, Stack, Statistics, StatisticsItem, StatisticsTrend, Table, TableFooter, TableCell, TableRow, TableBody, TableHeader, TableHead, Tag, Text, Tile, };
@@ -1,7 +1,12 @@
1
- import { CrmPropertyListProps } from '../types';
1
+ import { CrmAssociationTableProps, CrmPropertyListProps } from '../types';
2
2
  declare const CrmPropertyList: "CrmPropertyList" & {
3
3
  readonly type?: "CrmPropertyList" | undefined;
4
4
  readonly props?: CrmPropertyListProps | undefined;
5
5
  readonly children?: true | undefined;
6
6
  } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"CrmPropertyList", CrmPropertyListProps, true>>;
7
- export { CrmPropertyList };
7
+ declare const CrmAssociationTable: "CrmAssociationTable" & {
8
+ readonly type?: "CrmAssociationTable" | undefined;
9
+ readonly props?: CrmAssociationTableProps | undefined;
10
+ readonly children?: true | undefined;
11
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"CrmAssociationTable", CrmAssociationTableProps, true>>;
12
+ export { CrmPropertyList, CrmAssociationTable };
@@ -1,3 +1,4 @@
1
1
  import { createExtensionComponent } from '../utils/createExtensionComponent';
2
2
  const CrmPropertyList = createExtensionComponent('CrmPropertyList');
3
- export { CrmPropertyList };
3
+ const CrmAssociationTable = createExtensionComponent('CrmAssociationTable');
4
+ export { CrmPropertyList, CrmAssociationTable };
@@ -1,2 +1,2 @@
1
- import { CrmPropertyList } from './components';
2
- export { CrmPropertyList };
1
+ import { CrmPropertyList, CrmAssociationTable } from './components';
2
+ export { CrmPropertyList, CrmAssociationTable };
package/dist/crm/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { CrmPropertyList } from './components';
2
- export { CrmPropertyList };
1
+ import { CrmPropertyList, CrmAssociationTable } from './components';
2
+ export { CrmPropertyList, CrmAssociationTable };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { Alert, Button, ButtonRow, Card, DescriptionList, DescriptionListItem, Divider, Form, Heading, Image, Input, LoadingSpinner, ProgressBar, Select, Stack, Statistics, StatisticsItem, StatisticsTrend, Table, TableFooter, TableCell, TableRow, TableBody, TableHeader, TableHead, Tag, Text, Tile, } from './coreComponents';
1
+ export { Alert, Button, ButtonRow, Card, DescriptionList, DescriptionListItem, Divider, EmptyState, ErrorState, Form, Heading, Image, Input, LoadingSpinner, ProgressBar, Select, Stack, Statistics, StatisticsItem, StatisticsTrend, Table, TableFooter, TableCell, TableRow, TableBody, TableHeader, TableHead, Tag, Text, Textarea, Tile, Link, } from './coreComponents';
2
2
  export { hubspot } from './hubspot';
3
3
  export * from './types';
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { Alert, Button, ButtonRow, Card, DescriptionList, DescriptionListItem, Divider, Form, Heading, Image, Input, LoadingSpinner, ProgressBar, Select, Stack, Statistics, StatisticsItem, StatisticsTrend, Table, TableFooter, TableCell, TableRow, TableBody, TableHeader, TableHead, Tag, Text, Tile, } from './coreComponents';
1
+ export { Alert, Button, ButtonRow, Card, DescriptionList, DescriptionListItem, Divider, EmptyState, ErrorState, Form, Heading, Image, Input, LoadingSpinner, ProgressBar, Select, Stack, Statistics, StatisticsItem, StatisticsTrend, Table, TableFooter, TableCell, TableRow, TableBody, TableHeader, TableHead, Tag, Text, Textarea, Tile, Link, } from './coreComponents';
2
2
  export { hubspot } from './hubspot';
3
3
  export * from './types';
package/dist/types.d.ts CHANGED
@@ -6,12 +6,12 @@ export interface AlertProps {
6
6
  variant?: 'info' | 'warning' | 'success' | 'error' | 'danger';
7
7
  }
8
8
  export interface ButtonProps {
9
- text: string;
10
9
  onClick?: () => void;
11
10
  href?: string;
12
11
  disabled?: boolean;
13
12
  variant?: 'primary' | 'secondary' | 'destructive';
14
13
  type?: 'button' | 'reset' | 'submit';
14
+ children: ReactNode;
15
15
  }
16
16
  export interface ButtonRowProps {
17
17
  children: ReactNode;
@@ -31,9 +31,23 @@ export interface DescriptionListProps {
31
31
  export interface DividerProps {
32
32
  distance?: 'flush' | 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large';
33
33
  }
34
+ export interface EmptyStateProps {
35
+ flush?: boolean;
36
+ children: ReactNode;
37
+ title?: string;
38
+ layout?: 'horizontal' | 'vertical';
39
+ reverseOrder?: boolean;
40
+ imageWidth?: number;
41
+ }
42
+ export interface ErrorStateProps {
43
+ children: ReactNode;
44
+ title?: string;
45
+ type?: 'error' | 'support' | 'lock';
46
+ }
47
+ export type FormInputValues = Record<string, string | number>;
34
48
  export interface FormProps {
35
49
  children: ReactNode;
36
- onSubmit?: () => void;
50
+ onSubmit?: (event: RemoteEvent<FormInputValues>) => void;
37
51
  preventDefault?: boolean;
38
52
  }
39
53
  export interface HeadingProps {
@@ -52,14 +66,22 @@ export interface InputProps {
52
66
  name: string;
53
67
  value?: string;
54
68
  required?: boolean;
55
- readonly?: boolean;
69
+ readOnly?: boolean;
56
70
  description?: string;
57
71
  tooltip?: string;
58
72
  placeholder?: string;
59
73
  error?: boolean;
60
74
  validationMessage?: string;
61
- onChange: (value: string) => void;
62
- onInput: (value: string) => void;
75
+ onChange?: (value: string) => void;
76
+ onInput?: (value: string) => void;
77
+ onBlur?: (value: string) => void;
78
+ onFocus?: (value: string) => void;
79
+ }
80
+ export interface TextareaProps extends InputProps {
81
+ cols?: number;
82
+ maxLength?: number;
83
+ rows?: number;
84
+ resize?: 'vertical' | 'horizontal' | 'both' | 'none';
63
85
  }
64
86
  export interface ProgressBarProps {
65
87
  title?: string;
@@ -72,9 +94,9 @@ export interface ProgressBarProps {
72
94
  export interface SelectProps {
73
95
  label: string;
74
96
  name: string;
75
- value?: string | number | boolean;
97
+ value?: string | number;
76
98
  required?: boolean;
77
- readonly?: boolean;
99
+ readOnly?: boolean;
78
100
  description?: string;
79
101
  tooltip?: string;
80
102
  placeholder?: string;
@@ -83,7 +105,7 @@ export interface SelectProps {
83
105
  onChange?: (value: SelectProps['value']) => void;
84
106
  options: {
85
107
  label: string;
86
- value: string | number | boolean;
108
+ value: string | number;
87
109
  }[];
88
110
  }
89
111
  export interface TagProps {
@@ -91,11 +113,17 @@ export interface TagProps {
91
113
  onClick?: () => void;
92
114
  variant?: 'default' | 'warning' | 'success' | 'error';
93
115
  }
94
- export interface TextProps {
95
- format?: 'plaintext' | 'markdown';
96
- text: string;
97
- variant?: 'bodytext' | 'microcopy';
116
+ export interface TextFormatOptions {
117
+ fontWeight?: 'regular' | 'bold' | 'demibold';
118
+ italic?: boolean;
119
+ lineDecoration?: 'none' | 'underline' | 'strikethrough';
98
120
  }
121
+ export type TextProps = {
122
+ variant?: 'bodytext' | 'microcopy';
123
+ inline?: boolean;
124
+ children: ReactNode;
125
+ format?: TextFormatOptions;
126
+ };
99
127
  export interface TileProps {
100
128
  children: ReactNode;
101
129
  flush?: boolean;
@@ -123,10 +151,10 @@ export interface Context {
123
151
  user: UserContext;
124
152
  portal: PortalContext;
125
153
  }
126
- type distanceOptions = 'flush' | 'small';
127
154
  export interface StackProps {
128
- distance?: distanceOptions;
155
+ distance?: 'flush' | 'small' | 'extra-small' | 'medium' | 'large';
129
156
  children?: React.ReactNode;
157
+ direction?: 'row' | 'column';
130
158
  }
131
159
  export interface StatisticsTrendProps {
132
160
  value: string;
@@ -141,26 +169,56 @@ export interface StatisticsItemProps {
141
169
  export interface StatisticsProps {
142
170
  children: ReactNode;
143
171
  }
144
- export interface CrmPropertyListProps {
145
- properties: string[];
146
- direction?: string;
147
- }
148
172
  export interface ServerlessRunnerParams {
173
+ /**
174
+ * Name of the serverless function
175
+ */
149
176
  name: string;
150
- payload: Record<string, unknown>;
151
- onError?: () => void;
177
+ /**
178
+ * Names of CRM object properties to be retrieved and supplied to the function as `context.propertiesToSend`
179
+ */
180
+ propertiesToSend?: string[];
181
+ /**
182
+ * Additional parameters to be supplied to the function as `context.parameters`
183
+ */
184
+ parameters?: JsonValue;
185
+ /**
186
+ * @deprecated Optional payload supplied to the function as `context.event.payload`.
187
+ * Support for this param may be removed in the future. Use `parameters` instead.
188
+ */
189
+ payload?: JsonValue;
190
+ }
191
+ export declare enum ServerlessExecutionStatus {
192
+ Success = "SUCCESS",
193
+ Error = "ERROR"
194
+ }
195
+ export type ServerlessExecutionResult = {
196
+ status: ServerlessExecutionStatus.Success;
197
+ response: JsonValue;
198
+ } | {
199
+ status: ServerlessExecutionStatus.Error;
200
+ message: string;
201
+ };
202
+ export type ServerlessFuncRunner = (params: ServerlessRunnerParams) => Promise<ServerlessExecutionResult>;
203
+ export interface ServerlessExecutionRequest {
204
+ appId: number;
205
+ extensibleCardId: number;
206
+ serverlessFunction: string;
207
+ location: keyof ExtensionPoints;
208
+ objectQuery?: {
209
+ objectId: number;
210
+ objectTypeId: string;
211
+ objectPropertyNames: string[];
212
+ };
213
+ parameters?: JsonValue;
214
+ event?: {
215
+ type: 'SERVERLESS_ACTION_HOOK';
216
+ payload: JsonValue;
217
+ };
152
218
  }
153
- export type ServerlessFuncRunner = (params: ServerlessRunnerParams) => Promise<any>;
154
- export interface ServerlessSuccessResponse {
219
+ export interface ServerlessExecutionResponse {
155
220
  logId: string;
156
- response: {
157
- message?: {
158
- type: 'SUCCESS' | 'ERROR';
159
- body: string;
160
- } | string;
161
- context?: Record<string, unknown>;
162
- section?: Record<string, unknown>;
163
- };
221
+ response?: JsonValue;
164
222
  }
165
223
  export interface ServerlessErrorResponse {
166
224
  responseJSON?: {
@@ -195,10 +253,7 @@ export type AddAlertAction = (args: {
195
253
  message: string;
196
254
  }) => void;
197
255
  export type ReloadPageAction = () => void;
198
- export type FetchCrmObjectPropertiesAction = (properties: string[]) => Promise<{
199
- name: string;
200
- value: string;
201
- }[]>;
256
+ export type FetchCrmObjectPropertiesAction = (properties: string[]) => Promise<Record<string, string>>;
202
257
  export type OpenIframeModalAction = (action: OpenIframeActionPayload) => void;
203
258
  export interface CrmMiddleExtensionPoint extends ExtensionPointContract {
204
259
  actions: {
@@ -208,9 +263,34 @@ export interface CrmMiddleExtensionPoint extends ExtensionPointContract {
208
263
  openIframeModal: OpenIframeModalAction;
209
264
  };
210
265
  customComponents: {
211
- CrmPropertyList?: ComponentType<CrmPropertyListProps>;
266
+ CrmPropertyList: ComponentType<CrmPropertyListProps>;
267
+ CrmAssociationTable: ComponentType<CrmAssociationTableProps>;
212
268
  };
213
269
  }
270
+ export interface CrmPropertyListProps {
271
+ properties: string[];
272
+ direction?: string;
273
+ }
274
+ type CrmSortDescriptor = {
275
+ columnName: string;
276
+ direction: 1 | -1;
277
+ };
278
+ interface CrmSearchFilter {
279
+ operator: 'EQ' | 'NEQ' | 'LT' | 'LTE' | 'GT' | 'GTE' | 'BETWEEN' | 'IN' | 'NOT_IN' | 'HAS_PROPERTY' | 'NOT_HAS_PROPERTY' | 'ROLLING_DATE_RANGE' | 'TIME_UNIT_TO_DATE';
280
+ value?: string | number;
281
+ highValue?: string | number;
282
+ property: string;
283
+ }
284
+ export interface CrmAssociationTableProps {
285
+ objectTypeId: string;
286
+ propertyColumns: Array<string>;
287
+ quickFilterProperties?: Array<string>;
288
+ searchable?: boolean;
289
+ pagination?: boolean;
290
+ pageSize?: number;
291
+ preFilters?: Array<CrmSearchFilter>;
292
+ sort?: Array<CrmSortDescriptor>;
293
+ }
214
294
  interface CrmSidebarExtensionPoint extends ExtensionPointContract {
215
295
  actions: {
216
296
  reloadPage: ReloadPageAction;
@@ -256,8 +336,37 @@ export interface LoadingSpinnerProps {
256
336
  export interface TableElementProps {
257
337
  children: React.ReactNode;
258
338
  }
259
- export interface TableProps extends TableElementProps {
260
- flush?: boolean;
339
+ interface BaseTableProps {
261
340
  bordered?: boolean;
341
+ flush?: boolean;
342
+ children: React.ReactNode;
343
+ }
344
+ export interface TableNoPaginatedProps extends BaseTableProps {
345
+ paginated?: false;
346
+ }
347
+ export interface TablePaginatedProps extends BaseTableProps {
348
+ paginated: true;
349
+ pageCount: number;
350
+ onPageChange: (pageNumber: number) => void;
351
+ showButtonLabels?: boolean;
352
+ showFirstLastButtons?: boolean;
353
+ maxVisiblePageButtons?: number;
354
+ page?: number;
355
+ }
356
+ export type TableProps = TableNoPaginatedProps | TablePaginatedProps;
357
+ export declare class RemoteEvent<V> {
358
+ type: string;
359
+ bubbles: boolean;
360
+ timeStamp: number;
361
+ targetValue: V;
362
+ constructor(value: V, event: Event);
363
+ }
364
+ export interface LinkProps {
365
+ children: ReactNode;
366
+ href: string;
367
+ variant?: 'primary' | 'destructive' | 'light' | 'dark';
262
368
  }
369
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
370
+ [key: string]: JsonValue;
371
+ };
263
372
  export {};
package/dist/types.js CHANGED
@@ -1 +1,17 @@
1
- export {};
1
+ export var ServerlessExecutionStatus;
2
+ (function (ServerlessExecutionStatus) {
3
+ ServerlessExecutionStatus["Success"] = "SUCCESS";
4
+ ServerlessExecutionStatus["Error"] = "ERROR";
5
+ })(ServerlessExecutionStatus || (ServerlessExecutionStatus = {}));
6
+ export class RemoteEvent {
7
+ type;
8
+ bubbles;
9
+ timeStamp;
10
+ targetValue;
11
+ constructor(value, event) {
12
+ this.bubbles = event.bubbles;
13
+ this.type = event.type;
14
+ this.timeStamp = event.timeStamp;
15
+ this.targetValue = value;
16
+ }
17
+ }
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions",
3
- "version": "0.0.1-prealpha.5",
3
+ "version": "0.0.1-prealpha.7",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "scripts": {
9
9
  "clean": "rm -rf dist/",
10
- "prepare": "npm run clean && tsc",
11
- "watch": "npm run clean && tsc --watch"
10
+ "build": "npm run clean && tsc",
11
+ "watch": "npm run clean && tsc --watch",
12
+ "prepare": "npm run build"
12
13
  },
13
14
  "files": [
14
15
  "dist/**/*"
@@ -47,5 +48,5 @@
47
48
  "devDependencies": {
48
49
  "typescript": "5.0.4"
49
50
  },
50
- "gitHead": "a4652eb58cbde813dbebc8b7127c36102b9b6ed6"
51
+ "gitHead": "b5968f431fe29ee9977e6aacdd9b9ab3aa08af0c"
51
52
  }