ng-hub-ui-paginable 22.1.3 → 22.4.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.
package/README.md CHANGED
@@ -119,6 +119,31 @@ import { TableComponent } from 'ng-hub-ui-paginable';
119
119
 
120
120
  ---
121
121
 
122
+ ## Form-controls synergy (optional, agnostic)
123
+
124
+ The table renders its primitive controls (global **search** input and the
125
+ **rows-per-page** selector) as native `<input>` / `<select>` by default — `ng-hub-ui-paginable`
126
+ has **no hard dependency** on a forms library. Provide the adapter shipped by
127
+ `ng-hub-ui-forms` once and those controls upgrade to `hub-input` / `hub-select`
128
+ automatically (dynamic component creation under the hood), with no template
129
+ changes:
130
+
131
+ ```ts
132
+ import { provideHubPaginableFormControls } from 'ng-hub-ui-paginable';
133
+ import { hubFormControlAdapter } from 'ng-hub-ui-forms';
134
+
135
+ export const appConfig: ApplicationConfig = {
136
+ providers: [provideHubPaginableFormControls(hubFormControlAdapter)]
137
+ };
138
+ ```
139
+
140
+ To limit it to one table, provide the `HUB_PAGINABLE_FORM_CONTROLS` token in that
141
+ component's `providers` instead. Remove it and the table falls back to native
142
+ controls. See the ecosystem-wide
143
+ [Synergies & agnosticism](../../README.md#synergies--agnosticism) section.
144
+
145
+ ---
146
+
122
147
  ## ✨ Inspiration
123
148
 
124
149
  This library arises from the need to offer highly configurable, accessible, and modern data visualization components for Angular applications, enabling integrated lists, tables, and pagination with full support for signals, reactive forms, and complete render customization.
@@ -150,7 +175,7 @@ All components are built as standalone Angular components with full Angular Sign
150
175
  - **📋 Smart Sorting**: Ascending/descending column sorting with visual indicators
151
176
  - **☑️ Row Selection**: Single or multiple row selection with batch operations and ControlValueAccessor support
152
177
  - **📈 Expandable Content**: Collapsible row content for detailed views with custom templates
153
- - **📄 Dual Pagination**: Support for both local and remote pagination strategies
178
+ - **📄 Dual Pagination**: Automatic **client-side** pagination for plain arrays (in-memory search, filter, sort & slice) or **server-side** via `PaginationState` / `totalItems`
154
179
  - **🎨 Template Customization**: Extensive custom templates for headers, cells, filters, states (empty, loading, error)
155
180
  - **📱 Responsive Design**: Configurable responsive breakpoints for optimal mobile experience
156
181
  - **♿ Accessibility Ready**: Built-in ARIA support and keyboard navigation
@@ -1012,11 +1037,11 @@ filters = signal({
1012
1037
  | Name | Type | Default | Description |
1013
1038
  | -------------------- | --------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------- |
1014
1039
  | `headers` | `PaginableTableHeader[]` | `[]` | Column definitions with titles, sorting, filtering, and actions. |
1015
- | `data` / `rows` | `T[]` or `PaginationState<T>` | `[]` | Table data - can be flat array or paginated object with metadata. |
1016
- | `page` | `number` | `null` | Current page number (1-based, model signal). |
1017
- | `perPage` | `number` | `null` | Number of items per page. |
1018
- | `perPageOptions` | `number[]` | `[20, 50, 100]` | Available options for items per page. |
1019
- | `totalItems` | `number` | `null` | Total number of items across all pages. |
1040
+ | `data` / `rows` | `T[]` or `PaginationState<T>` | `[]` | Table data. A plain array → client-side mode (in-memory pagination); a `PaginationState` → server mode. |
1041
+ | `page` | `number` | `null` | Current page number (1-based, model signal). Defaulted to `1` automatically in client-side mode. |
1042
+ | `perPage` | `number` | `10` | Number of items per page (model signal). |
1043
+ | `perPageOptions` | `number[]` | `[10, 20, 50, 100]` | Available options for items per page. |
1044
+ | `totalItems` | `number` | `null` | Total items across all pages. Setting it selects **server mode** (the table renders `data` as-is). |
1020
1045
  | `searchable` | `boolean` | `true` | Whether to show the global search input. |
1021
1046
  | `searchTerm` | `string` | `''` | Current search term (model signal). |
1022
1047
  | `searchFn` | `(a: T, b: T) => boolean` | `null` | Custom search function for filtering. |
@@ -1027,7 +1052,7 @@ filters = signal({
1027
1052
  | `filters` | `Record<string, any>` | `{}` | Active column filters (model signal). |
1028
1053
  | `debounce` | `number` | `0` | Debounce time in ms for search and filter inputs. |
1029
1054
  | `loading` | `boolean` | `false` | Loading state indicator (model signal). |
1030
- | `paginate` | `boolean` | `true` | Whether to enable pagination. |
1055
+ | `paginate` | `boolean` | `true` | Enables pagination. With a plain array and no `totalItems`, this turns on automatic client-side mode. `false` renders the whole array unpaginated. |
1031
1056
  | `paginationPosition` | `'top' \| 'bottom' \| 'both'` | `'bottom'` | Where to display pagination controls. |
1032
1057
  | `paginationInfo` | `boolean` | `true` | Whether to show pagination info (e.g., "Showing 1 to 10 of 100"). |
1033
1058
  | `stickyActions` | `boolean` | `false` | Whether action buttons should stick during scrolling. |
@@ -1078,6 +1103,7 @@ interface TableRowEvent<T> {
1078
1103
  | `batchActions` | `Array<PaginableTableDropdown \| PaginableActionButton>` | `[]` | Actions for selected items. |
1079
1104
  | `clickFn` | `(event: ListClickEvent<T>) => void` | `null` | Handler for item click events. |
1080
1105
  | `rowClass` | `string \| ((item: T) => string)` | `null` | Custom CSS class for a list item. Can be a fixed string or a function that returns a class based on item data. |
1106
+ | `connected` | `boolean` | `false` | Draws a vertical connector between consecutive items for a timeline / pipeline look (list display only, skipped in cards). Themed via `--hub-list-connector-color` / `-width` / `-style` / `-offset`. |
1081
1107
 
1082
1108
  **List Click Event (`ListClickEvent<T>`):**
1083
1109
 
@@ -1207,7 +1233,7 @@ You can also use `tableRowTpt` with expandable components.
1207
1233
  The `ng-hub-ui-paginable` library is fully style-configurable through **CSS custom properties (CSS variables)** for **Table**, **List**, and **Paginator**.
1208
1234
 
1209
1235
  For a complete and up-to-date token catalog, see [CSS Variables Reference](./docs/css-variables-reference.md).
1210
- Table and List also expose context pagination tokens (`--hub-table-pagination-*`, `--hub-list-pagination-*`) so embedded paginators follow component themes by default.
1236
+ The paginator embedded in Table and List is themed through the shared `--hub-paginator-*` tokens — override them on the host component to re-theme it in context.
1211
1237
 
1212
1238
  ### 🔗 Import styles
1213
1239
 
@@ -1236,6 +1262,45 @@ Table and List also expose context pagination tokens (`--hub-table-pagination-*`
1236
1262
  }
1237
1263
  ```
1238
1264
 
1265
+ ### 🧩 SCSS mixins — one-call theming
1266
+
1267
+ Instead of setting the `--hub-*` tokens by hand, you can theme the table or the list in a single `@include`. Every parameter is optional and defaults to `null`, so only the ones you pass are emitted (the rest keep the component defaults). Import the mixin you need from the distributed styles:
1268
+
1269
+ ```scss
1270
+ @use 'ng-hub-ui-paginable/styles/mixins/table-theme' as *;
1271
+ @use 'ng-hub-ui-paginable/styles/mixins/list-theme' as *;
1272
+ ```
1273
+
1274
+ #### `hub-table-theme(…)` — theme `<hub-table>`
1275
+
1276
+ Colour (`$accent`, `$bg`, `$color`, `$border-color`, `$hover-bg`, `$hover-color`, `$selected-bg`, `$selected-color`, `$striped-bg`, `$striped-color`), border (`$border-width`, `$border-radius`), density (`$cell-padding-x`, `$cell-padding-y`) and footer / bottom-bar (`$footer-gap`, `$footer-justify`, `$footer-align`, `$footer-wrap`).
1277
+
1278
+ ```scss
1279
+ .invoices-table {
1280
+ @include hub-table-theme(
1281
+ $accent: var(--hub-sys-color-success),
1282
+ $border-radius: 0.5rem,
1283
+ $cell-padding-y: 0.375rem,
1284
+ $footer-justify: end
1285
+ );
1286
+ }
1287
+ ```
1288
+
1289
+ #### `hub-list-theme(…)` — theme `<hub-list>` (list & cards)
1290
+
1291
+ Colour (`$accent`, `$bg`, `$item-bg`, `$item-color`, `$item-border-color`, `$hover-bg`, `$selected-bg`, `$selected-color`), border/radius (`$border-radius`, `$item-border-radius`), density (`$item-padding-x`, `$item-padding-y`, `$gap`), the cards layout (`$cards-bg`, `$cards-border-color`, `$cards-border-radius`, `$cards-padding-x`, `$cards-padding-y`, `$cards-min-column-width`, `$cards-gap`) and footer (`$footer-gap`, `$footer-justify`, `$footer-align`, `$footer-wrap`).
1292
+
1293
+ ```scss
1294
+ .team-list {
1295
+ @include hub-list-theme(
1296
+ $accent: var(--hub-sys-color-success),
1297
+ $item-border-radius: 0.75rem,
1298
+ $gap: 0.5rem,
1299
+ $cards-min-column-width: 16rem
1300
+ );
1301
+ }
1302
+ ```
1303
+
1239
1304
  ### Dynamic Row Styling (`rowClass`)
1240
1305
 
1241
1306
  The `rowClass` input allows you to dynamically assign custom CSS classes to each row in both the table and list components. This is useful for visually highlighting rows based on their data. It accepts either a static `string` (to apply the same class to all rows) or a `function` that receives the item data and returns a class string.
@@ -1949,9 +2014,9 @@ headers = [
1949
2014
 
1950
2015
  ```scss
1951
2016
  .hub-table {
1952
- --hub-body-bg: #f8f9fa;
1953
- --hub-body-color: #212529;
1954
- --hub-border-color: #dee2e6;
2017
+ --hub-table-bg: #f8f9fa;
2018
+ --hub-table-color: #212529;
2019
+ --hub-table-border-color: #dee2e6;
1955
2020
  }
1956
2021
  ```
1957
2022
 
@@ -2069,11 +2134,21 @@ This allows you to adapt any type of visual filter (date-range, boolean, dropdow
2069
2134
 
2070
2135
  ## 🧠 Pagination and Data Handling
2071
2136
 
2072
- The `hub-ui-table` component can receive data in two different ways:
2137
+ The `hub-ui-table` component supports **three** data / pagination modes:
2138
+
2139
+ #### 1. Client-side (automatic) — pass a plain array
2140
+
2141
+ Hand the table the **full array** and let it paginate, search, sort and filter **entirely in memory** — no parent wiring required. This is the default whenever `[data]` is a plain array, `paginate` is `true` (its default) and you do **not** provide `totalItems`; the table computes the total itself. It mirrors the client-side behaviour of `<hub-ui-list>`.
2142
+
2143
+ ```html
2144
+ <hub-ui-table [data]="allRows()" [headers]="headers" [(page)]="page" [perPage]="20" [searchable]="true"></hub-ui-table>
2145
+ ```
2146
+
2147
+ > The global search box, sortable headers and every per-column filter (inline "row" filters and the advanced "menu" rule engine) all resolve client-side, and the current page resets/clamps automatically as the result set changes. Set `[paginate]="false"` to render the whole array without any pagination.
2073
2148
 
2074
- #### 1. Grouped form (`PaginationState<T>`)
2149
+ #### 2. Grouped form (`PaginationState<T>`) — server-side
2075
2150
 
2076
- Ideal if you manage pagination outside the component. The `data` input can directly accept an object with the full pagination structure:
2151
+ Ideal if you manage pagination outside the component (a service, store or `computed()`). Passing a `PaginationState` keeps the table in **server mode**: it renders `data` as-is and reads `page` / `perPage` / `totalItems` from the object. The `data` input accepts it directly:
2077
2152
 
2078
2153
  ```html
2079
2154
  <hub-ui-table
@@ -2088,17 +2163,17 @@ Ideal if you manage pagination outside the component. The `data` input can direc
2088
2163
 
2089
2164
  > This form is useful when you manage `PaginationState` in a single place (for example, from a service, `computed()`, or store).
2090
2165
 
2091
- #### 2. Split form (individual inputs)
2166
+ #### 3. Split form (individual inputs) — server-side
2092
2167
 
2093
- You can also pass each value separately:
2168
+ You can also pass each value separately, holding only the current page's rows in `data`:
2094
2169
 
2095
2170
  ```html
2096
- <hub-ui-table [data]="data()" [page]="page()" [perPage]="perPage()" [totalItems]="totalItems()"></hub-ui-table>
2171
+ <hub-ui-table [data]="pageRows()" [page]="page()" [perPage]="perPage()" [totalItems]="totalItems()"></hub-ui-table>
2097
2172
  ```
2098
2173
 
2099
- > It is important that if you choose this form, **all inputs are present**. If `page`, `perPage`, or `totalItems` are missing, the component will show an error in the console.
2174
+ > Set **`totalItems`** to opt into server mode — it tells the table you are managing the total yourself, so it renders `data` as-is instead of paginating it in memory. (If you pass a plain array **without** `totalItems`, the table assumes client-side mode #1 and paginates it for you.)
2100
2175
 
2101
- Both forms are compatible with Signals and can be easily integrated with `model()` and `computed()`.
2176
+ All three modes are compatible with Signals and integrate cleanly with `model()` and `computed()`.
2102
2177
 
2103
2178
  ### Advanced Pagination Example
2104
2179