hs-uix 1.0.1 → 1.0.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.
- package/README.md +151 -41
- package/dist/form.js +2 -2
- package/dist/form.mjs +2 -2
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,81 +5,191 @@
|
|
|
5
5
|
|
|
6
6
|
Production-ready UI components for [HubSpot UI Extensions](https://developers.hubspot.com/docs/apps/developer-platform/add-features/ui-extensions/overview). Built entirely on HubSpot's native primitives — no custom HTML, no CSS, no iframes.
|
|
7
7
|
|
|
8
|
-
## Components
|
|
9
|
-
|
|
10
|
-
| Component | Description | Docs |
|
|
11
|
-
|-----------|-------------|------|
|
|
12
|
-
| **DataTable** | Filterable, sortable, paginated table with auto-sized columns, inline editing, row grouping, and more | [Full documentation](./packages/datatable/README.md) |
|
|
13
|
-
| **FormBuilder** | Declarative, config-driven form with validation, multi-step wizards, and 20+ field types | [Full documentation](./packages/form/README.md) |
|
|
14
|
-
|
|
15
8
|
## Install
|
|
16
9
|
|
|
17
10
|
```bash
|
|
18
11
|
npm install hs-uix
|
|
19
12
|
```
|
|
20
13
|
|
|
21
|
-
|
|
14
|
+
```jsx
|
|
15
|
+
import { DataTable } from "hs-uix/datatable";
|
|
16
|
+
import { FormBuilder } from "hs-uix/form";
|
|
17
|
+
|
|
18
|
+
// or import everything from the root
|
|
19
|
+
import { DataTable, FormBuilder } from "hs-uix";
|
|
20
|
+
```
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
Requires `react` >= 18.0.0 and `@hubspot/ui-extensions` >= 0.12.0 as peer dependencies (already present in any HubSpot UI Extensions project).
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# DataTable
|
|
27
|
+
|
|
28
|
+
A drop-in table component for HubSpot UI Extensions. Define your columns, pass your data, and you get search, filtering, sorting, pagination, inline editing, row grouping, and auto-sized columns out of the box.
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
24
33
|
|
|
25
34
|
```jsx
|
|
26
35
|
import { DataTable } from "hs-uix/datatable";
|
|
27
36
|
|
|
28
|
-
const
|
|
29
|
-
{ field: "name", label: "
|
|
30
|
-
{ field: "status", label: "Status" },
|
|
31
|
-
{ field: "amount", label: "Amount", sortable: true },
|
|
37
|
+
const COLUMNS = [
|
|
38
|
+
{ field: "name", label: "Company", sortable: true, renderCell: (val) => val },
|
|
39
|
+
{ field: "status", label: "Status", renderCell: (val) => <StatusTag>{val}</StatusTag> },
|
|
40
|
+
{ field: "amount", label: "Amount", sortable: true, renderCell: (val) => formatCurrency(val) },
|
|
32
41
|
];
|
|
33
42
|
|
|
34
|
-
<DataTable data={deals} columns={
|
|
43
|
+
<DataTable data={deals} columns={COLUMNS} searchFields={["name"]} pageSize={10} />
|
|
35
44
|
```
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
That's a searchable, sortable, paginated table with auto-sized columns in 5 lines of config.
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- Full-text search with optional fuzzy matching via Fuse.js
|
|
51
|
+
- Select, multi-select, and date range filters with active badges and clear/reset controls
|
|
52
|
+
- Click-to-sort headers with three-state cycling
|
|
53
|
+
- Client-side or server-side pagination
|
|
54
|
+
- Collapsible row groups with per-column aggregation
|
|
55
|
+
- Row selection with bulk action bar
|
|
56
|
+
- Per-row actions via `rowActions`
|
|
57
|
+
- Two edit modes (discrete click-to-edit and inline always-visible) supporting 12 input types with validation
|
|
58
|
+
- Auto-width column sizing based on data analysis
|
|
59
|
+
- Column-level footer for totals rows
|
|
60
|
+
- Works with `useAssociations` for live CRM data
|
|
61
|
+
- Server-side mode with loading/error states, search debounce, and unified `onParamsChange` callback
|
|
62
|
+
|
|
63
|
+
## Highlights
|
|
64
|
+
|
|
65
|
+
### Filters & Footer Totals
|
|
66
|
+
|
|
67
|
+

|
|
68
|
+
|
|
69
|
+
### Row Selection & Bulk Actions
|
|
70
|
+
|
|
71
|
+

|
|
72
|
+
|
|
73
|
+
### Inline Editing
|
|
74
|
+
|
|
75
|
+

|
|
76
|
+
|
|
77
|
+
Two edit modes: **discrete** (click-to-edit, default) and **inline** (always-visible inputs). Supports `text`, `textarea`, `number`, `currency`, `stepper`, `select`, `multiselect`, `date`, `time`, `datetime`, `toggle`, and `checkbox`.
|
|
78
|
+
|
|
79
|
+
### Row Grouping
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
|
|
83
|
+
### Full-Row Editing
|
|
84
|
+
|
|
85
|
+

|
|
86
|
+
|
|
87
|
+
### useAssociations
|
|
88
|
+
|
|
89
|
+

|
|
90
|
+
|
|
91
|
+
Connect live CRM data (contacts, deals, tickets, etc.) to a DataTable with `useAssociations` from `@hubspot/ui-extensions/crm`.
|
|
92
|
+
|
|
93
|
+
> **Full documentation:** [DataTable README](./packages/datatable/README.md) — includes full API reference, all examples, server-side mode, and more.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
# FormBuilder
|
|
98
|
+
|
|
99
|
+
Declarative, config-driven forms for HubSpot UI Extensions. Define fields as data, get a complete form with validation, layout, multi-step wizards, and full HubSpot component integration.
|
|
100
|
+
|
|
101
|
+

|
|
102
|
+
|
|
103
|
+
## Quick Start
|
|
38
104
|
|
|
39
105
|
```jsx
|
|
40
106
|
import { FormBuilder } from "hs-uix/form";
|
|
41
107
|
|
|
42
108
|
const fields = [
|
|
43
|
-
{ name: "
|
|
44
|
-
{ name: "
|
|
45
|
-
|
|
46
|
-
{ label: "User", value: "user" },
|
|
47
|
-
]},
|
|
109
|
+
{ name: "firstName", type: "text", label: "First name", required: true },
|
|
110
|
+
{ name: "lastName", type: "text", label: "Last name", required: true },
|
|
111
|
+
{ name: "email", type: "text", label: "Email", pattern: /^[^\s@]+@[^\s@]+$/, patternMessage: "Enter a valid email" },
|
|
48
112
|
];
|
|
49
113
|
|
|
50
|
-
<FormBuilder
|
|
114
|
+
<FormBuilder
|
|
115
|
+
columns={2}
|
|
116
|
+
fields={fields}
|
|
117
|
+
onSubmit={(values) => console.log(values)}
|
|
118
|
+
/>
|
|
51
119
|
```
|
|
52
120
|
|
|
53
|
-
|
|
121
|
+
## Features
|
|
54
122
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
123
|
+
- 20+ field types mapping to native HubSpot components (`text`, `number`, `select`, `date`, `toggle`, `repeater`, `crmPropertyList`, and more)
|
|
124
|
+
- Four layout modes: fixed columns, responsive AutoGrid, explicit row layout, and legacy half-width
|
|
125
|
+
- Built-in validation chain: required, pattern, length/range, custom sync, and custom async with loading indicators
|
|
126
|
+
- Conditional visibility and dependent property grouping
|
|
127
|
+
- Multi-step wizards with per-step validation
|
|
128
|
+
- Repeater fields for dynamic add/remove rows
|
|
129
|
+
- Accordion sections and field group dividers
|
|
130
|
+
- Custom field type plugin registry
|
|
131
|
+
- Controlled and uncontrolled modes
|
|
132
|
+
- Ref API for imperative access (`submit`, `validate`, `reset`, `getValues`, `setFieldValue`, etc.)
|
|
133
|
+
- Submit lifecycle hooks (`transformValues`, `onBeforeSubmit`, `onSubmitSuccess`, `onSubmitError`)
|
|
134
|
+
- Auto-save, dirty tracking, read-only mode, and form-level alerts
|
|
58
135
|
|
|
59
|
-
##
|
|
136
|
+
## Highlights
|
|
60
137
|
|
|
61
|
-
|
|
62
|
-
# Install dependencies
|
|
63
|
-
npm install
|
|
138
|
+
### Layout
|
|
64
139
|
|
|
65
|
-
|
|
66
|
-
npm run build
|
|
140
|
+

|
|
67
141
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
142
|
+
### Conditional Visibility & Dependent Properties
|
|
143
|
+
|
|
144
|
+

|
|
145
|
+
|
|
146
|
+
### Async Validation
|
|
147
|
+
|
|
148
|
+

|
|
149
|
+
|
|
150
|
+
### Repeater Fields
|
|
151
|
+
|
|
152
|
+

|
|
71
153
|
|
|
72
|
-
|
|
154
|
+
### Sections & Groups
|
|
73
155
|
|
|
156
|
+

|
|
157
|
+
|
|
158
|
+
### Custom Field Types
|
|
159
|
+
|
|
160
|
+

|
|
161
|
+
|
|
162
|
+
### Display Options
|
|
163
|
+
|
|
164
|
+

|
|
165
|
+
|
|
166
|
+
### Read-Only Mode
|
|
167
|
+
|
|
168
|
+

|
|
169
|
+
|
|
170
|
+
> **Full documentation:** [FormBuilder README](./packages/form/README.md) — includes full API reference, all field types, validation details, props tables, and more.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Migrating from `@hs-uix/datatable` or `@hs-uix/form`
|
|
175
|
+
|
|
176
|
+
Both packages have been merged into `hs-uix`. Update your imports:
|
|
177
|
+
|
|
178
|
+
```diff
|
|
179
|
+
- import { DataTable } from "@hs-uix/datatable";
|
|
180
|
+
+ import { DataTable } from "hs-uix/datatable";
|
|
181
|
+
|
|
182
|
+
- import { FormBuilder } from "@hs-uix/form";
|
|
183
|
+
+ import { FormBuilder } from "hs-uix/form";
|
|
74
184
|
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
├── src/ ← unified package entry points
|
|
80
|
-
└── package.json
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm uninstall @hs-uix/datatable @hs-uix/form
|
|
188
|
+
npm install hs-uix
|
|
81
189
|
```
|
|
82
190
|
|
|
191
|
+
---
|
|
192
|
+
|
|
83
193
|
## License
|
|
84
194
|
|
|
85
195
|
MIT
|
package/dist/form.js
CHANGED
|
@@ -945,14 +945,14 @@ var FormBuilder = (0, import_react.forwardRef)(function FormBuilder2(props, ref)
|
|
|
945
945
|
const handleFieldBlur = (0, import_react.useCallback)(
|
|
946
946
|
(name, value) => {
|
|
947
947
|
if (!validateOnBlur) return;
|
|
948
|
-
const resolvedValue = value != null ? value :
|
|
948
|
+
const resolvedValue = value != null ? value : formValuesRef.current[name];
|
|
949
949
|
const err = validateField(name, resolvedValue);
|
|
950
950
|
updateErrors({ [name]: err });
|
|
951
951
|
if (!err) {
|
|
952
952
|
triggerAsyncValidation(name, resolvedValue);
|
|
953
953
|
}
|
|
954
954
|
},
|
|
955
|
-
[validateOnBlur, validateField, updateErrors,
|
|
955
|
+
[validateOnBlur, validateField, updateErrors, triggerAsyncValidation]
|
|
956
956
|
);
|
|
957
957
|
const handleSubmit = (0, import_react.useCallback)(
|
|
958
958
|
async (e) => {
|
package/dist/form.mjs
CHANGED
|
@@ -949,14 +949,14 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
949
949
|
const handleFieldBlur = useCallback(
|
|
950
950
|
(name, value) => {
|
|
951
951
|
if (!validateOnBlur) return;
|
|
952
|
-
const resolvedValue = value != null ? value :
|
|
952
|
+
const resolvedValue = value != null ? value : formValuesRef.current[name];
|
|
953
953
|
const err = validateField(name, resolvedValue);
|
|
954
954
|
updateErrors({ [name]: err });
|
|
955
955
|
if (!err) {
|
|
956
956
|
triggerAsyncValidation(name, resolvedValue);
|
|
957
957
|
}
|
|
958
958
|
},
|
|
959
|
-
[validateOnBlur, validateField, updateErrors,
|
|
959
|
+
[validateOnBlur, validateField, updateErrors, triggerAsyncValidation]
|
|
960
960
|
);
|
|
961
961
|
const handleSubmit = useCallback(
|
|
962
962
|
async (e) => {
|
package/dist/index.js
CHANGED
|
@@ -1948,14 +1948,14 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
|
|
|
1948
1948
|
const handleFieldBlur = (0, import_react2.useCallback)(
|
|
1949
1949
|
(name, value) => {
|
|
1950
1950
|
if (!validateOnBlur) return;
|
|
1951
|
-
const resolvedValue = value != null ? value :
|
|
1951
|
+
const resolvedValue = value != null ? value : formValuesRef.current[name];
|
|
1952
1952
|
const err = validateField(name, resolvedValue);
|
|
1953
1953
|
updateErrors({ [name]: err });
|
|
1954
1954
|
if (!err) {
|
|
1955
1955
|
triggerAsyncValidation(name, resolvedValue);
|
|
1956
1956
|
}
|
|
1957
1957
|
},
|
|
1958
|
-
[validateOnBlur, validateField, updateErrors,
|
|
1958
|
+
[validateOnBlur, validateField, updateErrors, triggerAsyncValidation]
|
|
1959
1959
|
);
|
|
1960
1960
|
const handleSubmit = (0, import_react2.useCallback)(
|
|
1961
1961
|
async (e) => {
|
package/dist/index.mjs
CHANGED
|
@@ -1981,14 +1981,14 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1981
1981
|
const handleFieldBlur = useCallback2(
|
|
1982
1982
|
(name, value) => {
|
|
1983
1983
|
if (!validateOnBlur) return;
|
|
1984
|
-
const resolvedValue = value != null ? value :
|
|
1984
|
+
const resolvedValue = value != null ? value : formValuesRef.current[name];
|
|
1985
1985
|
const err = validateField(name, resolvedValue);
|
|
1986
1986
|
updateErrors({ [name]: err });
|
|
1987
1987
|
if (!err) {
|
|
1988
1988
|
triggerAsyncValidation(name, resolvedValue);
|
|
1989
1989
|
}
|
|
1990
1990
|
},
|
|
1991
|
-
[validateOnBlur, validateField, updateErrors,
|
|
1991
|
+
[validateOnBlur, validateField, updateErrors, triggerAsyncValidation]
|
|
1992
1992
|
);
|
|
1993
1993
|
const handleSubmit = useCallback2(
|
|
1994
1994
|
async (e) => {
|