ng-hub-ui-panels 21.2.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 +378 -0
- package/fesm2022/ng-hub-ui-panels.mjs +1080 -0
- package/fesm2022/ng-hub-ui-panels.mjs.map +1 -0
- package/ng-hub-ui-panels-21.2.0.tgz +0 -0
- package/package.json +48 -0
- package/types/ng-hub-ui-panels.d.ts +399 -0
package/README.md
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
# ng-hub-ui-panels
|
|
2
|
+
|
|
3
|
+
[EspaΓ±ol](./README.es.md) | **English**
|
|
4
|
+
|
|
5
|
+
A versatile, accessible **content-panels** container for Angular that renders as
|
|
6
|
+
**tabs**, **pills**, an **accordion** or plain **cards** from a single API β with
|
|
7
|
+
routing, reactive forms, keyboard navigation and CSS-variable theming. Built as
|
|
8
|
+
standalone Angular components on top of Signals.
|
|
9
|
+
|
|
10
|
+
> `ng-hub-ui-panels` supersedes [`ng-hub-ui-accordion`](https://www.npmjs.com/package/ng-hub-ui-accordion). Its accordion view is a drop-in, more capable replacement.
|
|
11
|
+
|
|
12
|
+
## Documentation and Live Examples
|
|
13
|
+
|
|
14
|
+
This package is part of [Hub UI](https://hubui.dev/), a collection of Angular component libraries for standalone apps.
|
|
15
|
+
|
|
16
|
+
- Docs: https://hubui.dev/panels/overview/
|
|
17
|
+
- Live examples: https://hubui.dev/panels/examples/
|
|
18
|
+
- Hub UI: https://hubui.dev/
|
|
19
|
+
|
|
20
|
+
## π§© Library Family `ng-hub-ui`
|
|
21
|
+
|
|
22
|
+
This library is part of the **ng-hub-ui** ecosystem:
|
|
23
|
+
|
|
24
|
+
- [**ng-hub-ui-accordion**](https://www.npmjs.com/package/ng-hub-ui-accordion) _(deprecated β use panels)_
|
|
25
|
+
- [**ng-hub-ui-action-sheet**](https://www.npmjs.com/package/ng-hub-ui-action-sheet)
|
|
26
|
+
- [**ng-hub-ui-avatar**](https://www.npmjs.com/package/ng-hub-ui-avatar)
|
|
27
|
+
- [**ng-hub-ui-board**](https://www.npmjs.com/package/ng-hub-ui-board)
|
|
28
|
+
- [**ng-hub-ui-breadcrumbs**](https://www.npmjs.com/package/ng-hub-ui-breadcrumbs)
|
|
29
|
+
- [**ng-hub-ui-calendar**](https://www.npmjs.com/package/ng-hub-ui-calendar)
|
|
30
|
+
- [**ng-hub-ui-dropdown**](https://www.npmjs.com/package/ng-hub-ui-dropdown)
|
|
31
|
+
- [**ng-hub-ui-history**](https://www.npmjs.com/package/ng-hub-ui-history)
|
|
32
|
+
- [**ng-hub-ui-modal**](https://www.npmjs.com/package/ng-hub-ui-modal)
|
|
33
|
+
- [**ng-hub-ui-nav**](https://www.npmjs.com/package/ng-hub-ui-nav)
|
|
34
|
+
- [**ng-hub-ui-paginable**](https://www.npmjs.com/package/ng-hub-ui-paginable)
|
|
35
|
+
- [**ng-hub-ui-panels**](https://www.npmjs.com/package/ng-hub-ui-panels) β You are here
|
|
36
|
+
- [**ng-hub-ui-portal**](https://www.npmjs.com/package/ng-hub-ui-portal)
|
|
37
|
+
- [**ng-hub-ui-sortable**](https://www.npmjs.com/package/ng-hub-ui-sortable)
|
|
38
|
+
- [**ng-hub-ui-stepper**](https://www.npmjs.com/package/ng-hub-ui-stepper)
|
|
39
|
+
- [**ng-hub-ui-utils**](https://www.npmjs.com/package/ng-hub-ui-utils)
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## π Quick Start
|
|
44
|
+
|
|
45
|
+
### 1. Install
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install ng-hub-ui-panels
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Import
|
|
52
|
+
|
|
53
|
+
The components are standalone β import them directly where you use them:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import {
|
|
57
|
+
PanelsComponent,
|
|
58
|
+
PanelComponent,
|
|
59
|
+
PanelHeadingDirective,
|
|
60
|
+
PanelHeaderDirective,
|
|
61
|
+
PanelFooterDirective
|
|
62
|
+
} from 'ng-hub-ui-panels';
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. Use
|
|
66
|
+
|
|
67
|
+
```html
|
|
68
|
+
<hub-panels>
|
|
69
|
+
<hub-panel heading="Overview">First panel content</hub-panel>
|
|
70
|
+
<hub-panel heading="Details">Second panel content</hub-panel>
|
|
71
|
+
<hub-panel heading="Settings">Third panel content</hub-panel>
|
|
72
|
+
</hub-panels>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## π¦ Description
|
|
78
|
+
|
|
79
|
+
`ng-hub-ui-panels` unifies the most common content-switching patterns β **tabs**,
|
|
80
|
+
**pills** and **accordion** β plus a chromeless **card** layout, behind one
|
|
81
|
+
declarative component. Drop `<hub-panel>` panes inside `<hub-panels>` and pick a
|
|
82
|
+
`type`; everything else (keyboard navigation, ARIA wiring, animated collapse,
|
|
83
|
+
routed panels and form binding) works the same across views. A `<hub-panel>` can
|
|
84
|
+
also be used **standalone**, outside any container, where it renders as a card on
|
|
85
|
+
its own.
|
|
86
|
+
|
|
87
|
+
## π― Features
|
|
88
|
+
|
|
89
|
+
- **Four visualizations** β `tabs`, `pills`, `accordion` and `card`, switched with a single `type` input.
|
|
90
|
+
- **Card layout & standalone** β `type="card"` renders every panel as an always-visible card; a single `<hub-panel>` also works on its own, outside any container.
|
|
91
|
+
- **Content header/footer slots** β `hubPanelHeader` and `hubPanelFooter` mark header/footer bands that render in every view (distinct from the `hubPanelHeading` nav label).
|
|
92
|
+
- **Forms** β implements `ControlValueAccessor`; bind the active panel(s) to a `FormControl` or `ngModel` (single or `multiple`), with `bindValue` and `compareWith`.
|
|
93
|
+
- **Routing** β a panel with a `routerLink` turns the content area into a `<router-outlet>` that follows the URL.
|
|
94
|
+
- **Keyboard & a11y** β roving tabindex, Arrow/Home/End/Delete keys, and correct `role="tablist"`/`tab`/`tabpanel` and accordion `aria-expanded`/`aria-controls` semantics.
|
|
95
|
+
- **Strip layout** β `vertical`, `justified` and `scrollable` header strips.
|
|
96
|
+
- **Accordion options** β `multiple` expansion and edge-to-edge `flush` layout, with an animated grid-based collapse.
|
|
97
|
+
- **Custom headers** β project any markup with the `hubPanelHeading` directive.
|
|
98
|
+
- **Removable panels** β opt-in `removable` panels close with a β button or the Delete key.
|
|
99
|
+
- **Theming** β every token is a `--hub-panels-*` CSS custom property; the accordion view also honours the `--hub-accordion-*` contract.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## π¦ Installation
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npm install ng-hub-ui-panels
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Peer Dependencies
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"@angular/common": ">=21.0.0",
|
|
114
|
+
"@angular/core": ">=21.0.0",
|
|
115
|
+
"@angular/forms": ">=21.0.0",
|
|
116
|
+
"@angular/router": ">=21.0.0"
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## βοΈ Usage
|
|
123
|
+
|
|
124
|
+
### Tabs (default)
|
|
125
|
+
|
|
126
|
+
```html
|
|
127
|
+
<hub-panels>
|
|
128
|
+
<hub-panel heading="One">First</hub-panel>
|
|
129
|
+
<hub-panel heading="Two">Second</hub-panel>
|
|
130
|
+
</hub-panels>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Pills
|
|
134
|
+
|
|
135
|
+
```html
|
|
136
|
+
<hub-panels type="pills"> β¦ </hub-panels>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Accordion
|
|
140
|
+
|
|
141
|
+
```html
|
|
142
|
+
<hub-panels type="accordion" multiple flush>
|
|
143
|
+
<hub-panel heading="Shipping">β¦</hub-panel>
|
|
144
|
+
<hub-panel heading="Returns">β¦</hub-panel>
|
|
145
|
+
</hub-panels>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Cards
|
|
149
|
+
|
|
150
|
+
`type="card"` drops the navigation strip entirely: every panel is always visible
|
|
151
|
+
and rendered as a card. Use the `hubPanelHeader` / `hubPanelFooter` slots for the
|
|
152
|
+
card's header and footer bands.
|
|
153
|
+
|
|
154
|
+
```html
|
|
155
|
+
<hub-panels type="card">
|
|
156
|
+
<hub-panel>
|
|
157
|
+
<div hubPanelHeader>Project summary</div>
|
|
158
|
+
Every panel is always visible and styled as a card.
|
|
159
|
+
<div hubPanelFooter>Updated 2 hours ago</div>
|
|
160
|
+
</hub-panel>
|
|
161
|
+
<hub-panel>
|
|
162
|
+
<div hubPanelHeader>Team</div>
|
|
163
|
+
The same header/footer slots work in tabs, pills and accordion too.
|
|
164
|
+
</hub-panel>
|
|
165
|
+
</hub-panels>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
A single `<hub-panel>` can be used on its own, with no container β it renders as a
|
|
169
|
+
card by itself:
|
|
170
|
+
|
|
171
|
+
```html
|
|
172
|
+
<hub-panel>
|
|
173
|
+
<div hubPanelHeader>Standalone card</div>
|
|
174
|
+
Dropped on its own, a hub-panel renders as a card.
|
|
175
|
+
<div hubPanelFooter>
|
|
176
|
+
<button class="btn btn-sm btn-primary">Action</button>
|
|
177
|
+
</div>
|
|
178
|
+
</hub-panel>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
> `hubPanelHeader` / `hubPanelFooter` are content bands inside the panel body and
|
|
182
|
+
> render in **every** view. They are different from `hubPanelHeading`, which is the
|
|
183
|
+
> navigational tab label / accordion disclosure button.
|
|
184
|
+
|
|
185
|
+
### Vertical / Justified / Scrollable
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<hub-panels vertical> β¦ </hub-panels>
|
|
189
|
+
<hub-panels justified> β¦ </hub-panels>
|
|
190
|
+
<div style="max-width: 360px">
|
|
191
|
+
<hub-panels scrollable> β¦ many panels β¦ </hub-panels>
|
|
192
|
+
</div>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Reactive forms
|
|
196
|
+
|
|
197
|
+
```html
|
|
198
|
+
<hub-panels [formControl]="selected">
|
|
199
|
+
<hub-panel heading="Light" value="light">β¦</hub-panel>
|
|
200
|
+
<hub-panel heading="Dark" value="dark">β¦</hub-panel>
|
|
201
|
+
</hub-panels>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
selected = new FormControl<string>('dark');
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
With `multiple`, the form value is an array. Use `bindValue="meta.key"` to map
|
|
209
|
+
each panel's `value` object to a primitive, and `compareWith` for custom equality.
|
|
210
|
+
|
|
211
|
+
### Multiple selection
|
|
212
|
+
|
|
213
|
+
Add `multiple` to let several panels be open at once. In the `tabs` / `pills`
|
|
214
|
+
views the open panes render side by side (or stacked, when `vertical`), each at
|
|
215
|
+
least `--hub-panels-pane-min-width` wide; the content area scrolls when they
|
|
216
|
+
overflow. In the `accordion` view every selected panel expands.
|
|
217
|
+
|
|
218
|
+
```html
|
|
219
|
+
<hub-panels multiple [formControl]="open">
|
|
220
|
+
<hub-panel heading="Summary" value="summary">β¦</hub-panel>
|
|
221
|
+
<hub-panel heading="Stats" value="stats">β¦</hub-panel>
|
|
222
|
+
<hub-panel heading="Activity" value="activity">β¦</hub-panel>
|
|
223
|
+
</hub-panels>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
open = new FormControl<string[]>(['summary', 'stats']);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Routed panels
|
|
231
|
+
|
|
232
|
+
```html
|
|
233
|
+
<hub-panels>
|
|
234
|
+
<hub-panel heading="Profile" routerLink="/account/profile">Loaded via router-outlet</hub-panel>
|
|
235
|
+
<hub-panel heading="Billing" routerLink="/account/billing">Loaded via router-outlet</hub-panel>
|
|
236
|
+
</hub-panels>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
When the active panel is routed, the content area renders a `<router-outlet>` and
|
|
240
|
+
the active panel follows the current URL (`tabs` / `pills` views only).
|
|
241
|
+
|
|
242
|
+
### Custom headers
|
|
243
|
+
|
|
244
|
+
```html
|
|
245
|
+
<hub-panel>
|
|
246
|
+
<ng-template hubPanelHeading>
|
|
247
|
+
<i class="fa-solid fa-gear"></i> Settings <span class="badge text-bg-primary">3</span>
|
|
248
|
+
</ng-template>
|
|
249
|
+
Panel content
|
|
250
|
+
</hub-panel>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## πͺ API Reference
|
|
256
|
+
|
|
257
|
+
### `<hub-panels>` inputs
|
|
258
|
+
|
|
259
|
+
| Input | Type | Default | Description |
|
|
260
|
+
| --- | --- | --- | --- |
|
|
261
|
+
| `type` | `'tabs' \| 'pills' \| 'accordion' \| 'card'` | `'tabs'` | Visualization of the container. `card` removes the strip and shows every panel as a card. |
|
|
262
|
+
| `vertical` | `boolean` | `false` | Stacks the strip beside the content (tabs / pills). |
|
|
263
|
+
| `justified` | `boolean` | `false` | Stretches headers to equal width. |
|
|
264
|
+
| `scrollable` | `boolean` | `false` | Adds scroll buttons when the strip overflows. |
|
|
265
|
+
| `isKeysAllowed` | `boolean` | `true` | Enables keyboard navigation. |
|
|
266
|
+
| `multiple` | `boolean` | `false` | Accordion: allow several panels expanded at once. |
|
|
267
|
+
| `flush` | `boolean` | `false` | Accordion: edge-to-edge layout without outer chrome. |
|
|
268
|
+
| `bindValue` | `string` | `undefined` | Dot-notation path applied to each panel value. |
|
|
269
|
+
| `compareWith` | `(a, b) => boolean` | `===` | Equality used to match form values. |
|
|
270
|
+
|
|
271
|
+
### `<hub-panels>` outputs
|
|
272
|
+
|
|
273
|
+
| Output | Payload | Description |
|
|
274
|
+
| --- | --- | --- |
|
|
275
|
+
| `panelChange` | `PanelChangeEvent` | Emitted when a different panel is opened (`{ current, prev }`). |
|
|
276
|
+
|
|
277
|
+
### `<hub-panel>` inputs
|
|
278
|
+
|
|
279
|
+
| Input | Type | Default | Description |
|
|
280
|
+
| --- | --- | --- | --- |
|
|
281
|
+
| `heading` | `string` | `undefined` | Plain-text header (ignored when a `hubPanelHeading` template is present). |
|
|
282
|
+
| `id` | `string` | auto | ARIA pairing id. |
|
|
283
|
+
| `value` | `unknown` | `id` | Value contributed to the form control. |
|
|
284
|
+
| `active` | `boolean` (model) | `false` | Two-way active/expanded state. |
|
|
285
|
+
| `disabled` | `boolean` | `false` | Prevents activation. |
|
|
286
|
+
| `removable` | `boolean` | `false` | Shows a β and enables the Delete key. |
|
|
287
|
+
| `routerLink` | `string \| string[]` | `undefined` | Turns the panel into a routed panel. |
|
|
288
|
+
| `queryParams` | `Params` | `undefined` | Query params for `routerLink`. |
|
|
289
|
+
| `pathMatch` | `'route' \| 'full'` | `'route'` | URL comparison for routed panels. |
|
|
290
|
+
| `customClass` | `string` | `undefined` | Extra classes on the nav item and pane. |
|
|
291
|
+
|
|
292
|
+
### `<hub-panel>` outputs
|
|
293
|
+
|
|
294
|
+
| Output | Payload | Description |
|
|
295
|
+
| --- | --- | --- |
|
|
296
|
+
| `selectPanel` | `PanelComponent` | Emitted when the panel becomes active. |
|
|
297
|
+
| `deselectPanel` | `PanelComponent` | Emitted when the panel stops being active. |
|
|
298
|
+
| `removed` | `PanelComponent` | Emitted on removal (β or Delete). |
|
|
299
|
+
|
|
300
|
+
### Directives
|
|
301
|
+
|
|
302
|
+
- `hubPanelHeading` β marks an `<ng-template>` inside a `hub-panel` as its custom **navigational** header (tab/pill link or accordion disclosure button).
|
|
303
|
+
- `hubPanelHeader` β marks an element inside a `hub-panel` as the content **header** band, rendered at the top of the panel body in every view.
|
|
304
|
+
- `hubPanelFooter` β marks an element inside a `hub-panel` as the content **footer** band, rendered at the bottom of the panel body in every view.
|
|
305
|
+
|
|
306
|
+
### Configuration
|
|
307
|
+
|
|
308
|
+
Provide `PanelsConfig` to change defaults application-wide:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
providers: [{ provide: PanelsConfig, useValue: { ...new PanelsConfig(), type: 'pills' } }];
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## π¨ Styling
|
|
317
|
+
|
|
318
|
+
Everything is themed through `--hub-panels-*` CSS custom properties. See
|
|
319
|
+
[`docs/css-variables-reference.md`](./docs/css-variables-reference.md) for the full list.
|
|
320
|
+
|
|
321
|
+
```css
|
|
322
|
+
hub-panels {
|
|
323
|
+
--hub-panels-tab-color-active: #198754;
|
|
324
|
+
--hub-panels-pill-bg-active: #198754;
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
The `card` view and the header/footer bands have their own tokens
|
|
329
|
+
(`--hub-panels-card-*`, `--hub-panels-card-gap`, `--hub-panels-panel-header-*`).
|
|
330
|
+
Because a standalone `<hub-panel>` has no `.hub-panels` ancestor, target the panel
|
|
331
|
+
itself when theming standalone cards:
|
|
332
|
+
|
|
333
|
+
```css
|
|
334
|
+
hub-panel {
|
|
335
|
+
--hub-panels-card-border-radius: 0.75rem;
|
|
336
|
+
--hub-panels-panel-header-bg: #eef2ff;
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
The accordion view also reads the `--hub-accordion-*` contract, so themes written
|
|
341
|
+
for `ng-hub-ui-accordion` keep working.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## βΏ Accessibility
|
|
346
|
+
|
|
347
|
+
- `tabs` / `pills`: `role="tablist"`, `role="tab"`, `role="tabpanel"`, roving tabindex and `aria-selected`.
|
|
348
|
+
- `accordion`: a disclosure button per panel with `aria-expanded` / `aria-controls` and an inert collapsed region.
|
|
349
|
+
- Keyboard: Arrow keys, Home, End move focus; Delete removes a `removable` panel; Enter/Space toggle accordion headers.
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## π Migration from `ng-hub-ui-accordion`
|
|
354
|
+
|
|
355
|
+
`ng-hub-ui-panels` replaces `ng-hub-ui-accordion`. Map the markup as follows:
|
|
356
|
+
|
|
357
|
+
| Accordion | Panels |
|
|
358
|
+
| --- | --- |
|
|
359
|
+
| `<hub-accordion [multiple]="true">` | `<hub-panels type="accordion" multiple>` |
|
|
360
|
+
| `<hub-accordion [options]="{ flush: true }">` | `<hub-panels type="accordion" flush>` |
|
|
361
|
+
| `<hub-accordion-panel title="β¦">` | `<hub-panel heading="β¦">` |
|
|
362
|
+
| `<ng-template hubAccordionPanelHeader>` | `<ng-template hubPanelHeading>` |
|
|
363
|
+
| `(collapsedChange)` | `(panelChange)` |
|
|
364
|
+
|
|
365
|
+
Form binding (`formControl` / `ngModel`, `value`, `bindValue`, `compareWith`) works
|
|
366
|
+
the same. Existing `--hub-accordion-*` theme overrides keep applying.
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## π Changelog
|
|
371
|
+
|
|
372
|
+
See [CHANGELOG.md](./CHANGELOG.md).
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## π License
|
|
377
|
+
|
|
378
|
+
MIT Β© Carlos Morcillo
|