hs-uix 2.0.0 → 2.1.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.
@@ -6,7 +6,7 @@
6
6
 
7
7
  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.
8
8
 
9
- ![Full-Featured DataTable](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/fully-featured-table.png)
9
+ ![Full-Featured DataTable](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/fully-featured-table.png)
10
10
 
11
11
  ## Why DataTable?
12
12
 
@@ -111,7 +111,7 @@ hubspot.extend(() => (
111
111
 
112
112
  ### Filters, sorting, and footer totals
113
113
 
114
- ![Active Filters](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/fully-featured-table-active-filters.png)
114
+ ![Active Filters](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/fully-featured-table-active-filters.png)
115
115
 
116
116
  When more than 2 filters are defined, the first 2 appear inline and the rest are tucked behind a **Filters** button with a funnel icon. Active filters display as removable chips with a "Clear all" option by default. Hiding the badges via `showFilterBadges={false}` also hides the "Clear all" button by default — set `showClearFiltersButton={true}` to keep the reset without chips. Footer totals are declared directly on the column — a static string or a function that receives the filtered data.
117
117
 
@@ -236,7 +236,7 @@ const FILTERS = [
236
236
 
237
237
  ### Row selection with bulk actions
238
238
 
239
- ![Row Selection with Action Bar and Per-Row Actions](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/action-bar-per-row-actions.png)
239
+ ![Row Selection with Action Bar and Per-Row Actions](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/action-bar-per-row-actions.png)
240
240
 
241
241
  Add checkboxes with a select-all header (selects current page). When rows are selected, a compact action bar appears above the table showing the selected count, a "Select all" button, "Deselect all", and any custom action buttons you define.
242
242
 
@@ -314,7 +314,7 @@ Server-side selection example:
314
314
 
315
315
  ### Row actions and full-row "Edit/Done" flow
316
316
 
317
- ![Full-Row Editing](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/full-row-editing.png)
317
+ ![Full-Row Editing](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/full-row-editing.png)
318
318
 
319
319
  Use `rowActions` to append an actions column on the right. You can pass a static action list or a row-aware function.
320
320
 
@@ -385,7 +385,7 @@ const columns = [
385
385
 
386
386
  ### Scrollable wide tables
387
387
 
388
- ![Scrollable Wide Table](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/scrollable-wide-table.png)
388
+ ![Scrollable Wide Table](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/scrollable-wide-table.png)
389
389
 
390
390
  When you have many columns, set `scrollable={true}` to allow horizontal overflow instead of squishing columns. Columns without explicit widths fall back to `"min"` width, keeping each column compact and letting the table scroll.
391
391
 
@@ -402,8 +402,8 @@ When you have many columns, set `scrollable={true}` to allow horizontal overflow
402
402
 
403
403
  ### Inline editing — discrete mode
404
404
 
405
- ![Discrete Editing - Select](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/inline-editing-discreet.png)
406
- ![Discrete Editing - Text](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/inline-editing-discreet2.png)
405
+ ![Discrete Editing - Select](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/inline-editing-discreet.png)
406
+ ![Discrete Editing - Text](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/inline-editing-discreet2.png)
407
407
 
408
408
  In discrete mode (the default), editable cells appear as dark links. Click to open the input. The cell reverts to display when you click away, keeping the last committed value. Select/date/toggle-type inputs commit and close instantly on change. Text-like inputs commit via HubSpot `onChange` (typically blur/submit), and can stream live input through `onRowEditInput`.
409
409
 
@@ -473,7 +473,7 @@ function EditableTable() {
473
473
 
474
474
  ### Inline editing — inline mode
475
475
 
476
- ![Inline Edit Mode](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/inline-editing-regular.png)
476
+ ![Inline Edit Mode](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/inline-editing-regular.png)
477
477
 
478
478
  In inline mode, all editable cells always show their input controls. This mode is also used for full-row editing when `editingRowId` is set. Set `editMode="inline"` to enable always-visible inputs.
479
479
 
@@ -511,7 +511,7 @@ Use `editProps` to pass additional props to the edit component (e.g., `{ currenc
511
511
 
512
512
  ### Row grouping with aggregations
513
513
 
514
- ![Row Grouping](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/row-grouping.png)
514
+ ![Row Grouping](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/row-grouping.png)
515
515
 
516
516
  Groups are collapsible. Click a group header to expand or collapse it. You can define aggregation functions per column, and groups start expanded by default.
517
517
 
@@ -654,7 +654,7 @@ When `title` is set, DataTable renders a simple demibold title row above the too
654
654
 
655
655
  ### useAssociations
656
656
 
657
- ![useAssociations + DataTable](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/datatable/assets/useAssociations.png)
657
+ ![useAssociations + DataTable](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/datatable/assets/useAssociations.png)
658
658
 
659
659
  Connect live CRM data to a DataTable in two lines. The `useAssociations` hook from `@hubspot/ui-extensions/crm` fetches associated records from the current CRM record — pass the results straight into DataTable.
660
660
 
@@ -30,9 +30,16 @@ export interface DataTableOption<T = unknown> {
30
30
  export interface DataTableFilterConfig<Row = Record<string, unknown>> {
31
31
  name: string;
32
32
  type?: DataTableFilterType;
33
+ label?: string;
33
34
  placeholder?: string;
34
35
  options?: DataTableOption[];
35
36
  chipLabel?: string;
37
+ includeAll?: boolean;
38
+ allValue?: unknown;
39
+ emptyValue?: unknown;
40
+ allLabel?: string;
41
+ fromLabel?: string;
42
+ toLabel?: string;
36
43
  filterFn?: (row: Row, value: unknown) => boolean;
37
44
  }
38
45
 
@@ -195,6 +202,8 @@ export interface DataTableProps<Row = Record<string, unknown>, Id = string | num
195
202
  loading?: boolean;
196
203
  error?: string | boolean;
197
204
  totalCount?: number;
205
+ /** Client-mode total when rows are lazy-loaded in batches. */
206
+ clientTotalCount?: number;
198
207
  page?: number;
199
208
  searchValue?: string;
200
209
  filterValues?: Record<string, unknown>;
@@ -232,6 +241,8 @@ export interface DataTableProps<Row = Record<string, unknown>, Id = string | num
232
241
  showSearch?: boolean; // Show/hide the search input (default true)
233
242
  showSelectionBar?: boolean; // Show/hide the selection action bar when rows are selected (default true)
234
243
  filterInlineLimit?: number; // Max filters shown inline before overflow into "Filters" button (default 2)
244
+ toolbarLeftFlex?: number; // Left toolbar column flex weight (default 3)
245
+ toolbarRightFlex?: number; // Right toolbar column flex weight (default 1)
235
246
 
236
247
  labels?: DataTableLabels; // Override hardcoded UI strings for i18n
237
248
 
@@ -89,6 +89,8 @@ Feed works out of the box with these item keys:
89
89
  | `type` | Activity type label, rendered in a `StatusTag` by default |
90
90
  | `typeLabel` | Optional display label when `type` is a machine value |
91
91
  | `typeVariant` | `StatusTag` variant: `default`, `info`, `success`, `warning`, `danger` |
92
+ | `status` / `statusLabel` / `outcome` / `severity` | Optional secondary status text rendered in its own `StatusTag` (e.g. a call outcome or task severity). `statusLabel` wins when set, then `status`, `outcome`, `severity` |
93
+ | `statusVariant` / `outcomeVariant` / `severityVariant` | `StatusTag` variant for that status text (`default`, `info`, `success`, `warning`, `danger`); defaults to `default` |
92
94
  | `iconName` / `icon` | Activity/entity icon. Use verified HubSpot icon names (`email`, `calling`, `appointment`, `comment`, `description`, etc.) |
93
95
  | `title` / `subject` | Main item heading |
94
96
  | `href` | Optional link wrapping the title |
@@ -209,7 +211,7 @@ Use `serverSide` when the parent/API owns filtering, sorting, searching, and pag
209
211
  ```
210
212
 
211
213
  - `container`: `"tile"` (default), `"none"`, or `"card"` (`card` is a Tile-backed alias)
212
- - `itemContainer`: `"none"` (default), `"tile"`, or `"card"` (`card` is a Tile-backed alias)
214
+ - `itemContainer`: `"tile"` (default), `"none"`, or `"card"` (`card` is a Tile-backed alias)
213
215
  - `showDividers`: dividers between items when `itemContainer="none"`
214
216
 
215
217
  ## Render escape hatches
@@ -104,7 +104,10 @@ export interface FeedFilterConfig<Row = FeedItem> {
104
104
  options?: FeedOption[];
105
105
  defaultValue?: unknown;
106
106
  includeAll?: boolean;
107
+ allValue?: unknown;
108
+ emptyValue?: unknown;
107
109
  allLabel?: string;
110
+ chipLabel?: string;
108
111
  fromLabel?: string;
109
112
  toLabel?: string;
110
113
  filterFn?: (item: Row, value: unknown) => boolean;
@@ -121,6 +124,8 @@ export interface FeedSortOption<Row = FeedItem> {
121
124
  export interface FeedLabels {
122
125
  search?: string;
123
126
  sort?: string;
127
+ sortButton?: string;
128
+ filtersButton?: string;
124
129
  all?: string;
125
130
  clearAll?: string;
126
131
  dateFrom?: string;
@@ -158,11 +163,13 @@ export interface FeedToolbarRenderContext {
158
163
  search: string;
159
164
  filters: Record<string, unknown>;
160
165
  sort: string | null;
166
+ activeChips?: Array<{ key: string; label: ReactNode }>;
161
167
  totalCount: number;
162
168
  visibleCount: number;
163
169
  onTabChange: (value: string | number | boolean | null) => void;
164
170
  onSearchChange: (value: string) => void;
165
171
  onFilterChange: (name: string, value: unknown) => void;
172
+ onFilterRemove: (key: string) => void;
166
173
  onSortChange: (value: string | null) => void;
167
174
  }
168
175
 
@@ -241,7 +248,18 @@ export interface FeedProps<Row = FeedItem> {
241
248
  onParamsChange?: (params: FeedParams) => void;
242
249
  serverSide?: boolean;
243
250
  showToolbar?: boolean;
251
+ /**
252
+ * When the toolbar has no left-side controls (search / filters), float its
253
+ * right-side controls (sort + item count) onto the first date-group header
254
+ * row instead of a standalone row above it. "auto" (default) applies this
255
+ * only when grouping is active; `true` forces it, `false` disables it.
256
+ */
257
+ alignToolbarWithGroups?: boolean | "auto";
244
258
  filterInlineLimit?: number;
259
+ toolbarLeftFlex?: number;
260
+ toolbarRightFlex?: number;
261
+ showFilterBadges?: boolean;
262
+ showClearFiltersButton?: boolean;
245
263
  showItemCount?: boolean;
246
264
  itemCountText?: (shown: number, total: number) => string;
247
265
  recordLabel?: FeedRecordLabel;
@@ -2,7 +2,7 @@
2
2
 
3
3
  Declarative, config-driven FormBuilder for HubSpot UI Extensions. Define fields as data, get a complete form with validation, layout, multi-step wizards, and full HubSpot component integration.
4
4
 
5
- ![Basic Form](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/form/assets/basic-form.png)
5
+ ![Basic Form](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/form/assets/basic-form.png)
6
6
 
7
7
  ```bash
8
8
  npm install hs-uix
@@ -119,7 +119,7 @@ With `columnWidth={200}`, a 400px card shows 2 columns; a 600px page shows 3. Us
119
119
 
120
120
  ### Explicit Layout
121
121
 
122
- ![Explicit Layout](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/form/assets/explicit-layout-weighted.png)
122
+ ![Explicit Layout](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/form/assets/explicit-layout-weighted.png)
123
123
 
124
124
  Define exact row structure with the `layout` prop. Each inner array is a row.
125
125
 
@@ -351,7 +351,7 @@ const fields = [
351
351
 
352
352
  ## Dependent Properties
353
353
 
354
- ![Dependent & Cascading](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/form/assets/dependent-cascading.gif)
354
+ ![Dependent & Cascading](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/form/assets/dependent-cascading.gif)
355
355
 
356
356
  Dependent fields are grouped in a HubSpot Tile container below their parent. Use `dependsOnConfig` to define the relationship and `visible` to control when the dependent field appears:
357
357
 
@@ -440,7 +440,7 @@ Each step can have per-step validation:
440
440
 
441
441
  ## Display Options
442
442
 
443
- ![Display Options](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/form/assets/display-options.png)
443
+ ![Display Options](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/form/assets/display-options.png)
444
444
 
445
445
  ### Boolean Fields
446
446
 
@@ -597,7 +597,7 @@ For any HubSpot component prop not exposed as a first-class field config, use `f
597
597
 
598
598
  ## Sections (Accordion Grouping)
599
599
 
600
- ![Sections & Groups](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/form/assets/section-and-groups.png)
600
+ ![Sections & Groups](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/form/assets/section-and-groups.png)
601
601
 
602
602
  Group fields into collapsible accordion sections:
603
603
 
@@ -745,7 +745,7 @@ Display fields can also interact with the form via `setFieldValue` and `setField
745
745
 
746
746
  ## Read-Only Mode
747
747
 
748
- ![Read-Only, Auto-Save & Dirty](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/form/assets/readonly-autosave-dirty.png)
748
+ ![Read-Only, Auto-Save & Dirty](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/form/assets/readonly-autosave-dirty.png)
749
749
 
750
750
  Lock the entire form with an optional warning message:
751
751
 
@@ -774,7 +774,7 @@ To keep specific fields editable while the rest of the form is locked, set `alwa
774
774
 
775
775
  ## Async Validation
776
776
 
777
- ![Async Validation & Side Effects](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/form/assets/async-validation-side-effects.png)
777
+ ![Async Validation & Side Effects](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/form/assets/async-validation-side-effects.png)
778
778
 
779
779
  `validate` and entries in `validators` can return a Promise. The field shows a loading indicator while validation runs:
780
780
 
@@ -930,7 +930,7 @@ Change handlers on field definitions that can update other fields:
930
930
 
931
931
  ## Repeater Fields
932
932
 
933
- ![Repeater Fields](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/form/assets/repeater-fields.png)
933
+ ![Repeater Fields](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/form/assets/repeater-fields.png)
934
934
 
935
935
  Add/remove rows for dynamic lists:
936
936
 
@@ -943,7 +943,21 @@ Add/remove rows for dynamic lists:
943
943
  min: 1, max: 5 }
944
944
  ```
945
945
 
946
- Repeater sub-fields now validate on blur/onChange like top-level fields. Optional row reordering is available via `repeaterProps.reorderable` (with customizable move controls).
946
+ Repeater sub-fields now validate on blur/onChange like top-level fields. Pass `repeaterProps` on the repeater field to customize the add/remove/reorder controls:
947
+
948
+ | `repeaterProps` key | Type | Default | Description |
949
+ |---|---|---|---|
950
+ | `addLabel` | `string` | repeater add label | Text for the add-row control |
951
+ | `removeLabel` | `string` | repeater remove label | Text for the per-row remove control |
952
+ | `renderAdd` | `({ onClick, count }) => ReactNode` | — | Replace the default add control |
953
+ | `renderRemove` | `({ index, onClick }) => ReactNode` | — | Replace the default per-row remove control |
954
+ | `reorderable` | `boolean` | `false` | Enable up/down row reordering controls |
955
+ | `moveUpLabel` | `string` | `"Up"` | Label for the move-up control |
956
+ | `moveDownLabel` | `string` | `"Down"` | Label for the move-down control |
957
+ | `renderMoveUp` | `({ index, disabled, onClick }) => ReactNode` | — | Replace the move-up control. `disabled` is `true` on the first row |
958
+ | `renderMoveDown` | `({ index, disabled, onClick }) => ReactNode` | — | Replace the move-down control. `disabled` is `true` on the last row |
959
+
960
+ When `reorderable` is set, both move controls always render so rows stay column-aligned — the first row's "up" and the last row's "down" come through disabled (and the `disabled` flag is passed to `renderMoveUp` / `renderMoveDown`).
947
961
 
948
962
  ## Field Groups (Structured)
949
963
 
@@ -975,7 +989,7 @@ Each item's sub-fields get their own top-level form values (e.g. `hours_monday_s
975
989
 
976
990
  ## Custom Field Types
977
991
 
978
- ![Custom Field Types](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/form/assets/custom-field-types.png)
992
+ ![Custom Field Types](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/form/assets/custom-field-types.png)
979
993
 
980
994
  Register custom renderers with full FormBuilder integration:
981
995
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  A stage-based board view for HubSpot UI Extensions. Share DataTable's config vocabulary (`cardFields` ≈ `columns`, filters, sort, selection) so you can offer users a table-or-board toggle without rewriting the data layer. Drag-and-drop isn't available inside HubSpot UI Extensions, so stage changes happen through an inline `Select` (or menu) on each card.
8
8
 
9
- ![Kanban — HubSpot Deals preset with metrics](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/kanban/assets/hubspot-deals-preset-with-metrics.png)
9
+ ![Kanban — HubSpot Deals preset with metrics](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/kanban/assets/hubspot-deals-preset-with-metrics.png)
10
10
 
11
11
  ## Why Kanban?
12
12
 
@@ -106,7 +106,7 @@ hubspot.extend(() => (
106
106
 
107
107
  ### HubSpot Deals preset with metrics
108
108
 
109
- ![Kanban — HubSpot Deals preset with metrics](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/kanban/assets/hubspot-deals-preset-with-metrics.png)
109
+ ![Kanban — HubSpot Deals preset with metrics](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/kanban/assets/hubspot-deals-preset-with-metrics.png)
110
110
 
111
111
  Drop-in preset shaped like HubSpot's native deals pipeline: stage-variant headers, per-stage amount totals in the column footer, and a headline metrics panel above the board. Hide the summary row with `showMetrics={false}` for dashboards that already surface totals elsewhere.
112
112
 
@@ -136,7 +136,7 @@ const metrics = useMemo(() => {
136
136
  />
137
137
  ```
138
138
 
139
- ![Kanban — HubSpot Deals preset without metrics](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/kanban/assets/hubspot-deals-preset-no-metrics.png)
139
+ ![Kanban — HubSpot Deals preset without metrics](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/kanban/assets/hubspot-deals-preset-no-metrics.png)
140
140
 
141
141
  The metrics panel is toggled via a **Metrics** button that appears in the toolbar whenever `metrics` is provided. Pass an array for the shorthand `<StatisticsItem>` rendering, or a raw `ReactNode` when you need a chart / multi-row layout:
142
142
 
@@ -163,7 +163,7 @@ Keep metrics to 4–6 items (HubSpot's own `<Statistics>` guidance caps at 4 sid
163
163
 
164
164
  ### Compact lead board
165
165
 
166
- ![Kanban — Compact lead board preset](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/kanban/assets/compact-lead-board-preset.png)
166
+ ![Kanban — Compact lead board preset](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/kanban/assets/compact-lead-board-preset.png)
167
167
 
168
168
  `cardDensity="compact"` with trimmed `cardFields` for high-volume boards (leads, tickets, tasks) where you want to fit 8–12 cards per column on a typical viewport without horizontal scrolling.
169
169
 
@@ -213,7 +213,7 @@ Every knob stays overridable per board — density only shifts the defaults.
213
213
 
214
214
  ### Per-stage "Load more" and stage controls
215
215
 
216
- ![Kanban — Select + load more preset](https://raw.githubusercontent.com/05bmckay/hs-uix/main/packages/kanban/assets/select-load-more-preset.png)
216
+ ![Kanban — Select + load more preset](https://raw.githubusercontent.com/05bmckay/hs-uix/main/src/kanban/assets/select-load-more-preset.png)
217
217
 
218
218
  Per-column pagination via an `onLoadMore` handler and `stageMeta[stage].hasMore`, plus inline `Select` stage controls on each card (`stageControl="select"`). Switch to `"menu"` for action-menu style transitions, or `"none"` for read-only boards.
219
219
 
@@ -477,7 +477,7 @@ const SORT_OPTIONS = [
477
477
  />
478
478
  ```
479
479
 
480
- When every sort option has `field` + `direction`, the toolbar renders the richer "field picker + Asc/Desc toggle" UI. Mixed or missing simple flat option list.
480
+ The toolbar renders sort options as a compact transparent `Select`, matching the Feed toolbar style. Optional `field` / `direction` metadata can still be useful when deriving board sorts from shared table config, but the visible option text comes from each option's `label`.
481
481
 
482
482
  ---
483
483
 
@@ -550,11 +550,11 @@ If your data comes from an API or you have too many records to load up-front, dr
550
550
  | `showSearch` | boolean | `true` (when `searchFields` set) | Show/hide the search input |
551
551
  | `searchFields` | string[] | `[]` | Fields to search across. Search UI only renders when non-empty. |
552
552
  | `searchPlaceholder` | string | `"Search..."` | Placeholder for the search input |
553
- | `searchDebounce` | number | `0` | Milliseconds to debounce `onSearchChange` callback |
553
+ | `searchDebounce` | number | `250` | Milliseconds to debounce `onSearchChange` callback. Pass `0` for synchronous search |
554
554
  | `fuzzySearch` | boolean | `false` | Enable fuzzy matching via Fuse.js |
555
555
  | `fuzzyOptions` | object | — | Custom Fuse.js options (threshold, distance, keys) |
556
556
  | `filters` | `KanbanFilterConfig[]` | `[]` | Filter configurations (see below) |
557
- | `filterInlineLimit` | number | `2` | Max filters shown inline before overflow into a "Filters" button |
557
+ | `filterInlineLimit` | number | `4` | Max filters shown inline before overflow into a "Filters" button |
558
558
  | `showFilterBadges` | boolean | `true` | Show active filter chips |
559
559
  | `showClearFiltersButton` | boolean | `showFilterBadges` | Show "Clear all" reset button. Defaults to the value of `showFilterBadges`, so hiding the chips hides the reset button too unless set explicitly |
560
560
  | `sortOptions` | `KanbanSortOption[]` | — | Sort options (single board-wide sort) |
@@ -562,7 +562,7 @@ If your data comes from an API or you have too many records to load up-front, dr
562
562
  | `sort` | string | — | Controlled sort option `value` |
563
563
  | `onSortChange` | `(value) => void` | — | Sort callback (controlled) |
564
564
  | `columnFooter` | `(rows, stage) => ReactNode` | — | Per-stage footer (aggregate row). Overridden by `stage.footer` when set. |
565
- | `columnWidth` | number | `280` | Min per-column width in px (AutoGrid `columnWidth`). Clamped to 280px. |
565
+ | `columnWidth` | number | `350` | Min per-column width in px (AutoGrid `columnWidth`). Clamped to a 350px minimum. |
566
566
  | `collapsedStages` | string[] | — | Controlled list of collapsed stage values |
567
567
  | `onCollapsedStagesChange` | `(stages) => void` | — | Controlled-collapse callback |
568
568
  | `metrics` | `KanbanMetricItem[] \| ReactNode` | — | Headline metrics panel. Array → `<StatisticsItem>` shorthand; ReactNode → full custom render. |
@@ -627,9 +627,9 @@ If your data comes from an API or you have too many records to load up-front, dr
627
627
  |---|---|---|
628
628
  | `value` | string | Unique sort identifier |
629
629
  | `label` | string | Display label in the sort dropdown |
630
- | `field` | string | *(Optional)* Field key for the richer "field + direction" picker UI |
631
- | `direction` | `"asc" \| "desc"` | *(Optional)* Direction for the field-picker UI |
632
- | `fieldLabel` | string | *(Optional)* Label shown in the grouped field selector |
630
+ | `field` | string | *(Optional)* Field metadata for consumers deriving shared table/board sort configs |
631
+ | `direction` | `"asc" \| "desc"` | *(Optional)* Direction metadata for shared sort configs |
632
+ | `fieldLabel` | string | *(Optional)* Display label for `field` metadata |
633
633
  | `comparator` | `(a, b) => number` | Sort comparator applied within each stage |
634
634
 
635
635
  ### Stage Meta
@@ -698,7 +698,7 @@ These come from HubSpot UI Extensions itself, not Kanban:
698
698
  | No swimlanes | Secondary grouping (e.g. by owner within stage) isn't supported. On the roadmap. |
699
699
  | No export | No built-in CSV/Excel export. Pair with a serverless function. |
700
700
 
701
- See [`packages/kanban/SPEC.md`](./SPEC.md) for the full design doc, decision log, and roadmap.
701
+ See [`src/kanban/SPEC.md`](./SPEC.md) for the full design doc, decision log, and roadmap.
702
702
 
703
703
  ---
704
704
 
@@ -18,10 +18,17 @@ export interface KanbanOption<T = string> {
18
18
  export interface KanbanFilterConfig<Row = Record<string, unknown>> {
19
19
  name: string;
20
20
  type?: KanbanFilterType;
21
+ label?: string;
21
22
  placeholder?: string;
22
23
  /** Prefix used in the active-filter chip. Defaults to `placeholder` or `name`. */
23
24
  chipLabel?: string;
24
25
  options?: KanbanOption[];
26
+ includeAll?: boolean;
27
+ allValue?: unknown;
28
+ emptyValue?: unknown;
29
+ allLabel?: string;
30
+ fromLabel?: string;
31
+ toLabel?: string;
25
32
  filterFn?: (row: Row, value: unknown) => boolean;
26
33
  }
27
34
 
@@ -104,11 +111,11 @@ export interface KanbanStageMeta {
104
111
  export interface KanbanSortOption<Row = Record<string, unknown>> {
105
112
  value: string;
106
113
  label: string;
107
- /** Optional grouping metadata for the richer "field + direction" sort picker UI. */
114
+ /** Optional field metadata for consumers that derive shared table/board sort configs. */
108
115
  field?: string;
109
- /** Optional direction used with `field` to render Asc/Desc toggle controls. */
116
+ /** Optional direction metadata for consumers that derive shared table/board sort configs. */
110
117
  direction?: "asc" | "desc";
111
- /** Optional label shown for the grouped field selector. */
118
+ /** Optional display label for `field` metadata. */
112
119
  fieldLabel?: string;
113
120
  comparator: (a: Row, b: Row) => number;
114
121
  }
@@ -303,20 +310,24 @@ export interface KanbanProps<Row = Record<string, unknown>, Id = string | number
303
310
  /** Search is only active, and the search input only renders, when this list is non-empty. */
304
311
  searchFields?: string[];
305
312
  searchPlaceholder?: string;
306
- /** ms to debounce onSearchChange callback. 0 = no debounce. */
313
+ /** ms to debounce onSearchChange callback. Default 250; 0 = no debounce. */
307
314
  searchDebounce?: number;
308
315
  /** Enable fuzzy matching via Fuse.js */
309
316
  fuzzySearch?: boolean;
310
317
  /** Custom Fuse.js options (threshold, distance, keys, etc.) */
311
318
  fuzzyOptions?: Record<string, unknown>;
312
319
  filters?: KanbanFilterConfig<Row>[];
313
- /** Number of filters shown inline before the "Filters" overflow button. Default 2. */
320
+ /** Number of filters shown inline before the "Filters" overflow button. Default 4. */
314
321
  filterInlineLimit?: number;
322
+ /** Left toolbar column flex weight. Default 3. */
323
+ toolbarLeftFlex?: number;
324
+ /** Right toolbar column flex weight. Default 1. */
325
+ toolbarRightFlex?: number;
315
326
  /** Show active filter chips with individual clear affordances. Default true. */
316
327
  showFilterBadges?: boolean;
317
328
  /** Show the "Clear all" reset button when filters are active. Defaults to `showFilterBadges` when omitted, so hiding the chips hides the clear-all button too. */
318
329
  showClearFiltersButton?: boolean;
319
- /** Supports simple options or grouped field/direction options for the richer sort picker UI. */
330
+ /** Board-wide sort options shown in the toolbar Select. */
320
331
  sortOptions?: KanbanSortOption<Row>[];
321
332
  defaultSort?: string;
322
333
  sort?: string;
@@ -327,7 +338,7 @@ export interface KanbanProps<Row = Record<string, unknown>, Id = string | number
327
338
  /**
328
339
  * Pixel width for each column, passed to AutoGrid's columnWidth. Columns
329
340
  * share available horizontal space equally with this value as the minimum.
330
- * Clamped to 280px minimum regardless of the value passed. Default 280px.
341
+ * Clamped to 350px minimum regardless of the value passed. Default 350px.
331
342
  */
332
343
  columnWidth?: number;
333
344
  collapsedStages?: string[];