@hubspot/ui-extensions 0.0.1-prealpha.1 → 0.0.1-prealpha.3

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.
@@ -1,5 +1,5 @@
1
1
  /* Hello! To create your first component, uncomment the code below and replace
2
- * the entrie with your props and component name
2
+ * the entry with your props and component name
3
3
  * import { createExtensionComponent } from '../utils/createExtensionComponent';
4
4
  * import type { ExampleCrmComponentProps } from '../types';
5
5
 
package/README.md ADDED
@@ -0,0 +1,870 @@
1
+ # ui-extensions-components
2
+
3
+ ## Overview
4
+
5
+ ## Components
6
+
7
+ ### Alert
8
+
9
+ ##### Import
10
+
11
+ ```javascript
12
+ import { Alert } from '@hubspot/ui-extensions';
13
+ ```
14
+
15
+ ##### Props
16
+
17
+ The Alert component accepts the following props:
18
+
19
+ ```typescript
20
+ export interface AlertProps {
21
+ title: string;
22
+ body?: string;
23
+ children?: ReactNode;
24
+ variant?: 'info' | 'warning' | 'success' | 'error' | 'danger';
25
+ }
26
+ ```
27
+
28
+ | Prop | Type | Default | Description |
29
+ | --- | --- | --- | --- |
30
+ | `title` | `string` | `N/A` | The title text for the alert message. |
31
+ | `body` | `string(optional)` | `N/A` | The main content of the alert message. If not provided, the children prop is used. |
32
+ | `children` | `ReactNode(optional)` | `N/A` | The main content of the alert message when the body prop is not provided. |
33
+ | `variant` | `'info' \| 'warning' \| 'success' \|'error' \| 'danger'` `(optional)` | `'info'` | Sets the color variation of the alert |
34
+
35
+ ##### Usage
36
+
37
+ ```javascript
38
+ const Extension = () => {
39
+ return (
40
+ <>
41
+ <Alert title="Important Info" variant="info">
42
+ This is an informative message.
43
+ </Alert>
44
+ <Alert
45
+ title="Success"
46
+ body="Operation completed successfully."
47
+ variant="success"
48
+ />
49
+ <Alert title="Warning" body="Proceed with caution." variant="warning" />
50
+ <Alert
51
+ title="Error"
52
+ body="Something went wrong. Please try again."
53
+ variant="error"
54
+ />
55
+ <Alert
56
+ title="Danger"
57
+ body="This action cannot be undone. Be careful."
58
+ variant="danger"
59
+ />
60
+ </>
61
+ );
62
+ };
63
+ ```
64
+
65
+ ### Button
66
+
67
+ ##### Import
68
+ ```javascript
69
+ import { Button } from '@hubspot/ui-extensions';
70
+ ```
71
+
72
+ ##### Props
73
+ ```typescript
74
+ interface ButtonProps {
75
+ text: string;
76
+ onClick?: () => void;
77
+ href?: string;
78
+ disabled?: boolean;
79
+ variant?: 'primary' | 'secondary' | 'destructive';
80
+ type?: 'button' | 'reset' | 'submit';
81
+ }
82
+ ```
83
+ | Prop | Type | Default | Description |
84
+ | - | - | - | - |
85
+ | `text` | `string` | `N/A` | The displayable text for the Button |
86
+ | `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|
87
+ | `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. |
88
+ | `disabled` | `boolean(optional)` | `N/A` | Determines if the button should be disabled or not.|
89
+ | `variant` | ` 'primary' | 'secondary' | 'destructive'` `(optional)` |`'secondary'`| Sets the color variation of the button |
90
+ | `type` | `'button' \| 'reset' \| 'submit'` `(optional)` | `'button'`| Sets the HTML attribute "role" of the button |
91
+
92
+ ##### Usage
93
+ ```javascript
94
+ const Extension = () => {
95
+ return (
96
+ <Button
97
+ text="Click me!"
98
+ onClick={() => {
99
+ console.log('Someone clicked on the button!');
100
+ }}
101
+ href="https://hubspot.com"
102
+ variant="destructive"
103
+ type="button"
104
+ />
105
+ );
106
+ }
107
+ ```
108
+
109
+ ### ButtonRow
110
+
111
+ ##### Import
112
+ ```javascript
113
+ import { ButtonRow } from '@hubspot/ui-extensions';
114
+ ```
115
+
116
+ ##### Props
117
+ ```typescript
118
+ interface ButtonRowProps {
119
+ children: ReactNode;
120
+ disableDropdown?: boolean;
121
+ }
122
+ ```
123
+ | Prop | Type | Default | Description |
124
+ | - | - | - | - |
125
+ | `children` | `ReactNode` | `N/A` | Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
126
+ | `disableDropdown` | `boolean(optional)` | `false` | Disables the dropdown list of buttons that appears the the children expand beyond the horizontal space |
127
+
128
+ ##### Usage
129
+ ```javascript
130
+ const Extension = () => {
131
+ return (
132
+ <ButtonRow disableDropdown={false}>
133
+ <Button
134
+ text="Regular Button"
135
+ onClick={() => {
136
+ console.log('Regular button clicked');
137
+ }}
138
+ />
139
+ <Button
140
+ text="Reset"
141
+ onClick={() => {
142
+ console.log('Reset button clicked');
143
+ }}
144
+ variant="destructive"
145
+ type="reset"
146
+ />
147
+ <Button
148
+ text="Submit"
149
+ onClick={() => {
150
+ console.log('Submit button clicked');
151
+ }}
152
+ variant="primary"
153
+ type="submit"
154
+ />
155
+ </ButtonRow>
156
+ );
157
+ }
158
+ ```
159
+
160
+ ### Card
161
+
162
+ ##### Import
163
+ ```javascript
164
+ import { Card } from '@hubspot/ui-extensions';
165
+ ```
166
+
167
+ ##### Props
168
+ ```typescript
169
+ interface CardProps {
170
+ children: ReactNode;
171
+ }
172
+ ```
173
+ | Prop | Type | Default | Description |
174
+ | - | - | - | - |
175
+ | `children` | `ReactNode`| `N/A`| Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
176
+
177
+ ##### Usage
178
+ ```javascript
179
+ const Extension = () => {
180
+ return (
181
+ <Card>
182
+ <Button
183
+ text="Regular Button"
184
+ onClick={() => {
185
+ console.log('Regular button clicked');
186
+ }}
187
+ />
188
+ </Card>
189
+ );
190
+ }
191
+ ```
192
+
193
+ ### DescriptionList
194
+
195
+ ##### Import
196
+ ```javascript
197
+ import { DescriptionList } from '@hubspot/ui-extensions';
198
+ ```
199
+
200
+ ##### Props
201
+ ```typescript
202
+ interface DescriptionListProps {
203
+ children: ReactNode;
204
+ direction?: 'row' | 'column';
205
+ }
206
+ ```
207
+ | Prop | Type | Default | Description |
208
+ | - | - | - | - |
209
+ | `children` | `ReactNode` | `N/A`| Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. The children should be [DescriptionListItem](#descriptionlistitem) |
210
+ | `direction` | `'row' \| 'column'` `(optional)` | `'column'`| The direction the label/value pairs are placed in the description list container. |
211
+
212
+ ##### Usage
213
+ ```javascript
214
+ const Extension = () => {
215
+ return (
216
+ <DescriptionList direction="row">
217
+ <DescriptionListItem label={"First Name"}>
218
+ <Text text="Alan" />
219
+ </DescriptionListItem>
220
+ <DescriptionListItem label={"Last Name"}>
221
+ <Text text="Turing" />
222
+ </DescriptionListItem>
223
+ </DescriptionList>
224
+ );
225
+ }
226
+ ```
227
+
228
+ #### DescriptionListItem
229
+
230
+ ##### Import
231
+ ```javascript
232
+ import { DescriptionListItem } from '@hubspot/ui-extensions';
233
+ ```
234
+
235
+ ##### Props
236
+ ```typescript
237
+ interface DescriptionListItemProps {
238
+ children: ReactNode;
239
+ label: string;
240
+ }
241
+ ```
242
+ | Prop | Type | Default | Description |
243
+ | - | - | - | - |
244
+ | `children` | `ReactNode`| `N/A`| Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
245
+ | `label` | `string` | `N/A` | Text to be displayed as the label |
246
+
247
+ ##### Usage
248
+ ```javascript
249
+ const Extension = () => {
250
+ return (
251
+ <DescriptionList direction="row">
252
+ <DescriptionListItem label={"First Name"}>
253
+ <Text text="Alan" />
254
+ </DescriptionListItem>
255
+ <DescriptionListItem label={"Last Name"}>
256
+ <Text text="Turing" />
257
+ </DescriptionListItem>
258
+ </DescriptionList>
259
+ );
260
+ }
261
+ ```
262
+
263
+ ### Divider
264
+
265
+ ##### Import
266
+ ```javascript
267
+ import { Divider } from '@hubspot/ui-extensions';
268
+ ```
269
+
270
+ ##### Props
271
+ ```typescript
272
+ interface DividerProps {
273
+ distance?:
274
+ | 'flush'
275
+ | 'extra-small'
276
+ | 'small'
277
+ | 'medium'
278
+ | 'large'
279
+ | 'extra-large';
280
+ }
281
+ ```
282
+ | Prop | Type | Default | Description |
283
+ | - | - | - | - |
284
+ | `distance` | `'flush'\| 'extra-small' \| 'small' \| 'medium' \| 'large'\| 'extra-large'` `(optional)`| `'small'` | The size of the padding above and below the divider. |
285
+
286
+ ##### Usage
287
+ ```javascript
288
+ const Extension = () => {
289
+ return (
290
+ <Divider distance="extra-large"/>
291
+ );
292
+ }
293
+ ```
294
+
295
+ ### Form
296
+
297
+ ##### Import
298
+ ```javascript
299
+ import { Form } from '@hubspot/ui-extensions';
300
+ ```
301
+
302
+ ##### Props
303
+ ```typescript
304
+ interface FormProps {
305
+ children: ReactNode;
306
+ onSubmit?: () => void;
307
+ preventDefault?: boolean;
308
+ }
309
+ ```
310
+ | Prop | Type | Default | Description |
311
+ | - | - | - | - |
312
+ | `children` | `ReactNode` | `N/A`| Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
313
+ | `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. |
314
+ | `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. |
315
+
316
+ ##### Usage
317
+ ```javascript
318
+ const Extension = () => {
319
+ return (
320
+ <Form onSubmit={() => { console.log('Form submitted!')}} preventDefault={true}>
321
+ <Input {...} />
322
+ <Select {...} />
323
+ <Button
324
+ text="Submit"
325
+ onClick={() => {
326
+ console.log('Submit button clicked');
327
+ }}
328
+ variant="primary"
329
+ type="submit"
330
+ />
331
+ </Form>
332
+ );
333
+ }
334
+ ```
335
+
336
+ ### Heading
337
+
338
+ ##### Import
339
+ ```javascript
340
+ import { Heading } from '@hubspot/ui-extensions';
341
+ ```
342
+
343
+ ##### Props
344
+ ```typescript
345
+ interface HeadingProps {
346
+ text: string;
347
+ format?: 'plaintext' | 'markdown';
348
+ }
349
+ ```
350
+ | Prop | Type | Default | Description |
351
+ | - | - | - | - |
352
+ | `text` | `string` | `N/A`| Text to be displayed as heading text. If format is `"markdown"`, inline markdown elements (i.e. bold, italics, code, links) are supported|
353
+ | `format` | `'plaintext' \| 'markdown'` `(optional)` | `'plaintext'`| Type of formatting for the display text. |
354
+
355
+ #### Markdown
356
+ Markdown syntax supported in the component:
357
+
358
+ - bold text: `**like this**` or `__like this__`
359
+ - italicized text: `*like this*` or `_like this_`
360
+ - inline code: `` `like this` ``
361
+ - links: `[visible anchor text](https://www.hubspot.com/)`
362
+
363
+ ##### Usage
364
+ ```javascript
365
+ const Extension = () => {
366
+ return (
367
+ <>
368
+ <Heading text="Plain text, nothing special here"/>
369
+ <Heading text="**It's a Bold Strategy Cotton, lets see if it pays off for them.**" format="markdown"/>
370
+ </>
371
+ );
372
+ }
373
+ ```
374
+
375
+ ### Image
376
+ ##### Import
377
+
378
+
379
+ ```javascript
380
+ import { Image } from '@hubspot/ui-extensions';
381
+ ```
382
+
383
+ ##### Props
384
+ ```typescript
385
+ interface ImageProps {
386
+ alt?: string;
387
+ href?: string;
388
+ onClick?: () => void;
389
+ src: string;
390
+ width?: number;
391
+ }
392
+ ```
393
+
394
+ | Prop | Type | Description |
395
+ | - | - | - |
396
+ | `alt` | `string(optional)` | The alt text for the image, similar to the `alt` attribute for the html [img tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attributes) |
397
+ | `href` | `string(optional)` | If provided, it will be used as a href that will be opened in a new tag when the image is clicked |
398
+ | `onClick` | `function(optional)` | A function that will be called when the image is clicked on. This function will receive no arguments any returned values will be ignored. |
399
+ | `src` | | `string` | The url to the image to display, similar to [img tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attributes)|
400
+ | `width` | `number(optional)` | The pixel width of the image |
401
+
402
+ | Prop | Type | Description |
403
+ | - | - | - |
404
+ | `alt` | `string(optional)` | The alt text for the image, similar to the `alt` attribute for the html [img tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attributes) |
405
+ | `href` | `string(optional)` | If provided, it will be used as a href that will be opened in a new tag when the image is clicked |
406
+ | `onClick` | `function(optional)` | A function that will be called when the image is clicked on. This function will receive no arguments any returned values will be ignored. |
407
+ | `src` | | `string` | The url to the image to display, similar to [img tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attributes)|
408
+ | `width` | `number(optional)` | The pixel width of the image |
409
+
410
+ ##### Usage
411
+ ```javascript
412
+ const Extension = () => {
413
+ return (
414
+ <Image
415
+ alt="A picture of an adorable black lab puppy, click on me to see in a new tab"
416
+ src="https://picsum.photos/id/237/200/300"
417
+ href="https://picsum.photos/id/237"
418
+ onClick={() => {
419
+ console.log('Someone clicked on the image!')
420
+ }}
421
+ width={200}
422
+ />
423
+ );
424
+ }
425
+ ```
426
+
427
+ ### Input
428
+
429
+ ##### Import
430
+ ```javascript
431
+ import { Input } from '@hubspot/ui-extensions';
432
+ ```
433
+
434
+ ##### Props
435
+ ```typescript
436
+ interface InputProps {
437
+ label: string;
438
+ name: string;
439
+ value?: string;
440
+ required?: boolean;
441
+ readonly?: boolean;
442
+ description?: string;
443
+ tooltip?: string;
444
+ placeholder?: string;
445
+ error?: boolean;
446
+ errorMessage?: string;
447
+ onChange: (value: string) => void;
448
+ onInput: (value: string) => void;
449
+ }
450
+ ```
451
+ | Prop | Type | Default | Description |
452
+ | - | - | - | - |
453
+ | `label` | `string` | `N/A`| The label text to display for the form input element |
454
+ | `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) |
455
+ | `value` | `string(optional)` | `''`| The value of the input |
456
+ | `required` | `boolean(optional)` | `false`| Determines if the required indicator should be displayed |
457
+ | `readonly` | `boolean(optional)` | `false`| Determines if the field is editable or not. |
458
+ | `description` | `string(optional)` | `N/A`| Instructional message to display to the user to help understand the purpose of the input. |
459
+ | `tooltip` | `string(optional)` | `N/A`| Text that will appear in a tooltip next to the input label. |
460
+ | `placeholder` | `string(optional)` | `N/A`| Text that appears in the input when it has no value set. |
461
+ | `error` | `boolean(optional)` | `false`| If set to true, displays an `errorMessage` if provided and renders the error state for the input. |
462
+ | `errorMessage` | `string(optional)` | `''`| The text to show if the input has an error. |
463
+ | `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. |
464
+ | `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. |
465
+
466
+ ##### Usage
467
+ ```javascript
468
+ import { useState } from 'react';
469
+
470
+ const Extension = () => {
471
+ const [ name, setName ] = useState('');
472
+ const [ errorMessage, setErrorMessage ] = useState('');
473
+
474
+ return (
475
+ <Form>
476
+ <Input
477
+ label="First Name"
478
+ name="first-name"
479
+ tooltip="Please enter your first name"
480
+ description="Please enter your first name"
481
+ placeholder="First name"
482
+ required={true}
483
+ error={errorMessage !== ''}
484
+ errorMessage={errorMessage}
485
+ onChange={(value) => {
486
+ setName(value)
487
+ }}
488
+ onInput={(value) => {
489
+ if(value !== 'Bill') {
490
+ setErrorMessage('This form only works for people named Bill');
491
+ } else if (value === '') {
492
+ setErrorMessage('First name is required')
493
+ } else {
494
+ setErrorMessage('')
495
+ }
496
+ }}
497
+ />
498
+ </Form>
499
+ );
500
+ }
501
+ ```
502
+
503
+ ### ProgressBar
504
+
505
+ ##### Import
506
+ ```javascript
507
+ import { ProgressBar } from '@hubspot/ui-extensions';
508
+ ```
509
+
510
+ ##### Props
511
+ ```typescript
512
+ export interface ProgressBarProps {
513
+ title?: string;
514
+ showPercentage?: boolean;
515
+ value?: number;
516
+ valueMax?: number;
517
+ valueDescription?: string;
518
+ variant?: 'success' | 'danger' | 'warning';
519
+ }
520
+ ```
521
+ | Prop | Type | Default | Description |
522
+ | --- | --- | --- | --- |
523
+ | `title` | `string(optional)` | `N/A` | Text to be displayed in the progressbar title. |
524
+ | `showPercentage` | `boolean(optional)` | `false` | Toggles the display of the completion percentage. |
525
+ | `value` | `number(optional)` | `0` | The value of the progress indicator.
526
+ | `valueMax` | `number(optional)` | `100` | The maximum value of the progress.
527
+ | `valueDescription` | `string(optional)` | `N/A` | Text that explains the current state of the `value` prop. Renders to the right of `title`. **Example: "10,000 of 7,500"**
528
+ | `variant` | `'success' \| 'danger' \| 'warning'` | `'success'` | The type of progressbar to display. Defaults to success.
529
+
530
+ ##### Usage
531
+ ```javascript
532
+ const Extension = () => {
533
+ return (
534
+ <ProgressBar
535
+ variant="warning"
536
+ value={50}
537
+ valueMax={200}
538
+ showPercentage={true}
539
+ />
540
+ );
541
+ }
542
+ ```
543
+
544
+ ### Select
545
+
546
+ ##### Import
547
+ ```javascript
548
+ import { Select } from '@hubspot/ui-extensions';
549
+ ```
550
+
551
+ ##### Props
552
+ ```typescript
553
+ interface SelectProps {
554
+ label: string;
555
+ name: string;
556
+ value?: string | number | boolean;
557
+ required?: boolean;
558
+ readonly?: boolean;
559
+ description?: string;
560
+ tooltip?: string;
561
+ placeholder?: string;
562
+ error?: boolean;
563
+ errorMessage?: string;
564
+ onChange: (value: string) => void;
565
+ options: {
566
+ label: string;
567
+ value: string | number | boolean;
568
+ }[];
569
+ }
570
+
571
+ ```
572
+ | Prop | Type | Default | Description |
573
+ | - | - | - | - |
574
+ | `label` | `string` | `N/A`| The label text to display for the select element |
575
+ | `name` | `string` | `N/A`| The unique identifier for the select element. |
576
+ | `value` | `string \| number \| boolean` | `''`| The value of the select input. |
577
+ | `required` | `boolean` | `false`| Determines if the required indicator should be displayed |
578
+ | `readonly` | `boolean` | `false`| Determines if the field is editable or not. |
579
+ | `description` | `string` | `N/A`| Instructional message to display to the user to help understand the purpose of the input. |
580
+ | `tooltip` | `string` | `N/A`| Text that will appear in a tooltip next to the input label. |
581
+ | `placeholder` | `string` | `N/A`| Text that appears in the input when it has no value set. |
582
+ | `error` | `boolean` | `false`| If set to true, displays an `errorMessage` if provided and renders the error state for the input. |
583
+ | `errorMessage` | `string` | `''`| The text to show if the input has an error. |
584
+ | `onChange` | `(value: string) => void` | `N/A`| Function that is called with the new value when it is updated. |
585
+ | `options` | `Array<{label: string; value: string \| number \| boolean}>` | `N/A`| Array of options to be displayed in the select. `label` will be used as the display text in the dropdown list and `value` should be a **unique** identifier. `value` is the data that will be submitted with the form. |
586
+
587
+ ##### Usage
588
+ ```javascript
589
+ const Extension = () => {
590
+ const [ name, setName ] = useState(null);
591
+ const [ errorMessage, setErrorMessage ] = useState('');
592
+
593
+ const options = [
594
+ {label: 'Bill', value: 42},
595
+ {label: 'Ted', value: 43}
596
+ ];
597
+
598
+ return (
599
+ <Form>
600
+ <Input
601
+ label="Best Bill & Ted Character?"
602
+ name="best-char"
603
+ tooltip="Please choose"
604
+ description="Please choose"
605
+ placeholder="Bill or Ted?"
606
+ required={true}
607
+ error={errorMessage !== ''}
608
+ errorMessage={errorMessage}
609
+ onChange={(value) => {
610
+ setName(value)
611
+ if(!value) {
612
+ setErrorMessage('This is required');
613
+ } else {
614
+ setErrorMessage('');
615
+ }
616
+ }}
617
+ options={options}
618
+ />
619
+ </Form>
620
+ );
621
+ }
622
+ ```
623
+
624
+ ### Stack
625
+
626
+ ##### Import
627
+ ```javascript
628
+ import { Stack } from '@hubspot/ui-extensions';
629
+ ```
630
+
631
+ ##### Props
632
+ ```typescript
633
+ interface StackProps {
634
+ distance?: 'flush' | 'small';
635
+ children?: ReactNode;
636
+ }
637
+ ```
638
+ | Prop | Type | Default | Description |
639
+ | - | - | - | - |
640
+ | `distance` | `'flush' \| 'small'` | `'small'`| Amount of padding between each child component passed as children |
641
+ | `children` | `ReactNode` | `N/A`| Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
642
+
643
+ ##### Usage
644
+ ```javascript
645
+ const Extension = () => {
646
+ return (
647
+ <Stack>
648
+ <Image {...} />
649
+ <Text {...} />
650
+ </Stack>
651
+ );
652
+ }
653
+ ```
654
+
655
+ ### Statistics
656
+
657
+ ##### Import
658
+ ```javascript
659
+ import { Statistics } from '@hubspot/ui-extensions';
660
+ ```
661
+
662
+ ##### Props
663
+ ```typescript
664
+ interface StatisticsProps {
665
+ children: ReactNode;
666
+ }
667
+ ```
668
+ | Prop | Type | Default | Description |
669
+ | - | - | - | - |
670
+ | `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 [StatisticsItem](#statisticsitem) or [StatisticsTrend](#statisticstrend) |
671
+
672
+ ##### Usage
673
+ ```javascript
674
+ const Extension = () => {
675
+ return (
676
+ <Statistics>
677
+ <StatisticsItem {...} />
678
+ <StatisticsTrend {...} />
679
+ </Statistics>
680
+ );
681
+ }
682
+ ```
683
+
684
+ #### StatisticsItem
685
+
686
+ ##### Import
687
+ ```javascript
688
+ import { StatisticsItem } from '@hubspot/ui-extensions';
689
+ ```
690
+
691
+ ##### Props
692
+ ```typescript
693
+ interface StatisticsItemProps {
694
+ id?: string;
695
+ label: string;
696
+ number: string;
697
+ children: ReactNode;
698
+ }
699
+ ```
700
+ | Prop | Type | Default | Description |
701
+ | - | - | - | - |
702
+ | `id` | `string(optional)` | `N/A`| The unique identifier |
703
+ | `label` | `string` | `N/A`| The text to be used as a label |
704
+ | `number` | `string` | `N/A`| Fully formatted string to be displayed as the item's primary number |
705
+ | `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 [Text](#text) or [StatisticsTrend](#statisticstrend) |
706
+
707
+ ##### Usage
708
+ ```javascript
709
+ const Extension = () => {
710
+ return (
711
+ <Statistics>
712
+ <StatisticsItem label="Sales" number={'30000'}>
713
+ <Text text="Big Numbers" />
714
+ </StatisticsItem>
715
+ </Statistics>
716
+ );
717
+ }
718
+ ```
719
+
720
+ #### StatisticsTrend
721
+
722
+ ##### Import
723
+ ```javascript
724
+ import { StatisticsTrend } from '@hubspot/ui-extensions';
725
+ ```
726
+
727
+ ##### Props
728
+ ```typescript
729
+ interface StatisticsTrendProps {
730
+ value: string;
731
+ direction: 'increase' | 'decrease';
732
+ }
733
+ ```
734
+ | Prop | Type | Default | Description |
735
+ | - | - | - | - |
736
+ | `value` | `string` | `N/A`| Formatted string to be displayed as trend value |
737
+ | `direction` | `'increase' \| 'decrease'` | `N/A`| Direction in which the trend arrow should be displayed |
738
+
739
+ ##### Usage
740
+ ```javascript
741
+ const Extension = () => {
742
+ return (
743
+ <Statistics>
744
+ <StatisticsItem label="Item A Sales" number="10000">
745
+ <StatisticsTrend direction="decrease" value="200%" />
746
+ </StatisticsItem>
747
+ <StatisticsItem label="Item B Sales" number="100000">
748
+ <StatisticsTrend direction="increase" value="100%" />
749
+ </StatisticsItem>
750
+ </Statistics>
751
+ );
752
+ }
753
+ ```
754
+
755
+
756
+ ### Tag
757
+
758
+ ##### Import
759
+ ```javascript
760
+ import { Tag } from '@hubspot/ui-extensions';
761
+ ```
762
+
763
+ ##### Props
764
+ ```typescript
765
+ interface TagProps {
766
+ text: string;
767
+ onClick?: () => void;
768
+ variant?: 'default' | 'warning' | 'success' | 'error';
769
+ }
770
+ ```
771
+ | Prop | Type | Default | Description |
772
+ | - | - | - | - |
773
+ | `text` | `string` | `N/A`| Text to be displayed in the tag. |
774
+ | `onClick` | `() => void` `(optional)` | `N/A` | A function that will be invoked when the `Tag` is clicked. It receives no arguments and it's return value is ignored. |
775
+ | `variant` | `'default' \| 'warning' \| 'success' \| 'error'` `(optional)` | `'default'`| The color variation of the tag to display |
776
+
777
+ ##### Usage
778
+ ```javascript
779
+ const Extension = () => {
780
+ return (
781
+ <Tag
782
+ text="Success"
783
+ variant='success'
784
+ onClick={() => {
785
+ console.log('Tag clicked!');
786
+ }}
787
+ />
788
+ );
789
+ }
790
+ ```
791
+
792
+ ### Text
793
+
794
+ ##### Import
795
+ ```javascript
796
+ import { Text } from '@hubspot/ui-extensions';
797
+ ```
798
+
799
+ ##### Props
800
+ ```typescript
801
+ interface TextProps {
802
+ format?: 'plaintext' | 'markdown';
803
+ text: string;
804
+ variant?: 'bodytext' | 'microcopy';
805
+ }
806
+ ```
807
+ | Prop | Type | Default | Description |
808
+ | - | - | - | - |
809
+ | `format` | `'plaintext' \| 'markdown'` `(optional)`| `'plaintext'`| Type of formatting for the display text. |
810
+ | `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 |
811
+ | `variant` | `'bodytext' \| 'microcopy'` | `'bodytext`| Type of text to display |
812
+
813
+ #### Markdown
814
+ Markdown syntax supported in the component:
815
+
816
+ - bold text: `**like this**` or `__like this__`
817
+ - italicized text: `*like this*` or `_like this_`
818
+ - inline code: `` `like this` ``
819
+ - links: `[visible anchor text](https://www.hubspot.com/)`
820
+
821
+ ##### Usage
822
+ ```javascript
823
+ const Extension = () => {
824
+ return (
825
+ <>
826
+ <Text text="**Bold**" format="markdown"/>
827
+ <Text text="*Italics*" format="markdown"/>
828
+ <Text text="**Not Bold because format isn't markdown**"/>
829
+ <Text text="This is going to be small" variant="microcopy"/>
830
+ </>
831
+ );
832
+ }
833
+ ```
834
+
835
+ ### Tile
836
+
837
+ ##### Import
838
+ ```javascript
839
+ import { Tile } from '@hubspot/ui-extensions';
840
+ ```
841
+
842
+ ##### Props
843
+ ```typescript
844
+ interface TileProps {
845
+ children: ReactNode;
846
+ flush?: boolean;
847
+ }
848
+ ```
849
+ | Prop | Type | Default | Description |
850
+ | - | - | - | - |
851
+ | `children` | `ReactNode` | `N/A`| Sets the content that will render inside the component. This prop is passed implicitly by providing sub-components. |
852
+ | `flush` | `boolean(optional)` | `false`| If true the content of the Tile will have no left or right padding. |
853
+
854
+ ##### Usage
855
+ ```javascript
856
+ const Extension = () => {
857
+ return (
858
+ <>
859
+ <Tile flush={true}>
860
+ <Text text="No left padding" />
861
+ </Tile>
862
+ <Tile>
863
+ <Text text="Small amount of left padding" />
864
+ </Tile>
865
+ </>
866
+ );
867
+ }
868
+
869
+
870
+ ```
package/coreComponents.ts CHANGED
@@ -11,6 +11,7 @@ import type {
11
11
  HeadingProps,
12
12
  ImageProps,
13
13
  InputProps,
14
+ LoadingSpinnerProps,
14
15
  ProgressBarProps,
15
16
  SelectProps,
16
17
  TagProps,
@@ -41,6 +42,10 @@ const Form = createRemoteReactComponent<'Form', FormProps>('Form');
41
42
  const Heading = createRemoteReactComponent<'Heading', HeadingProps>('Heading');
42
43
  const Image = createRemoteReactComponent<'Image', ImageProps>('Image');
43
44
  const Input = createRemoteReactComponent<'Input', InputProps>('Input');
45
+ const LoadingSpinner = createRemoteReactComponent<
46
+ 'LoadingSpinner',
47
+ LoadingSpinnerProps
48
+ >('LoadingSpinner');
44
49
  const ProgressBar = createRemoteReactComponent<'ProgressBar', ProgressBarProps>(
45
50
  'ProgressBar'
46
51
  );
@@ -76,6 +81,7 @@ export {
76
81
  Heading,
77
82
  Image,
78
83
  Input,
84
+ LoadingSpinner,
79
85
  ProgressBar,
80
86
  Select,
81
87
  Stack,
package/index.ts CHANGED
@@ -10,6 +10,7 @@ export {
10
10
  Heading,
11
11
  Image,
12
12
  Input,
13
+ LoadingSpinner,
13
14
  ProgressBar,
14
15
  Select,
15
16
  Stack,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions",
3
- "version": "0.0.1-prealpha.1",
3
+ "version": "0.0.1-prealpha.3",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -13,5 +13,5 @@
13
13
  "@remote-ui/react": "^5.0.0",
14
14
  "react": "^18.2.0"
15
15
  },
16
- "gitHead": "d9459af4e3027da7ae3fa9a9d91c48c1f612677b"
16
+ "gitHead": "74dbffa7fe6e4ad7d5029897801c11dc5d5edae1"
17
17
  }
package/types.ts CHANGED
@@ -14,6 +14,7 @@ export interface ButtonProps {
14
14
  href?: string;
15
15
  disabled?: boolean;
16
16
  variant?: 'primary' | 'secondary' | 'destructive';
17
+ type?: 'button' | 'reset' | 'submit';
17
18
  }
18
19
 
19
20
  export interface ButtonRowProps {
@@ -47,7 +48,8 @@ export interface DividerProps {
47
48
 
48
49
  export interface FormProps {
49
50
  children: ReactNode;
50
- onSubmit: () => void;
51
+ onSubmit?: () => void;
52
+ preventDefault?: boolean;
51
53
  }
52
54
 
53
55
  export interface HeadingProps {
@@ -238,7 +240,7 @@ interface CrmMiddleExtensionPoint extends ExtensionPointContract {
238
240
  addAlert: AddAlertAction;
239
241
  reloadPage: ReloadPageAction;
240
242
  fetchCrmObjectProperties: FetchCrmObjectPropertiesAction;
241
- openIframeModal?: (action: OpenIframeActionPayload) => void;
243
+ openIframeModal: (action: OpenIframeActionPayload) => void;
242
244
  };
243
245
  }
244
246
 
@@ -285,3 +287,11 @@ interface OpenIframeActionPayload {
285
287
  width: number;
286
288
  associatedObjectProperties?: string[];
287
289
  }
290
+
291
+ export interface LoadingSpinnerProps {
292
+ label: string;
293
+ showLabel?: boolean;
294
+ size?: 'xs' | 'sm' | 'md';
295
+ layout?: 'inline' | 'centered';
296
+ grow?: boolean;
297
+ }