ng-hub-ui-skeleton 22.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 ADDED
@@ -0,0 +1,397 @@
1
+ # ng-hub-ui-skeleton
2
+
3
+ [EspaΓ±ol](./README.es.md) | **English**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/ng-hub-ui-skeleton.svg)](https://www.npmjs.com/package/ng-hub-ui-skeleton)
6
+ [![license](https://img.shields.io/npm/l/ng-hub-ui-skeleton.svg)](https://github.com/carlos-morcillo/ng-hub-ui/blob/main/LICENSE)
7
+
8
+ Dynamic Angular skeleton placeholders driven by a compact Emmet-like DSL, reusable presets, responsive values, variants, and programmatic preset registration.
9
+
10
+ ## Documentation and Live Examples
11
+
12
+ This package is part of [Hub UI](https://hubui.dev/), a collection of Angular component libraries for standalone apps.
13
+
14
+ - Docs: https://hubui.dev/skeleton/overview/
15
+ - Live examples: https://hubui.dev/skeleton/examples/
16
+ - Hub UI: https://hubui.dev/
17
+
18
+ ## 🧩 Library Family `ng-hub-ui`
19
+
20
+ This library is part of the **Hub UI** ecosystem:
21
+
22
+ - [**ng-hub-ui-accordion**](https://www.npmjs.com/package/ng-hub-ui-accordion) (deprecated β€” use ng-hub-ui-panels)
23
+ - [**ng-hub-ui-action-sheet**](https://www.npmjs.com/package/ng-hub-ui-action-sheet)
24
+ - [**ng-hub-ui-avatar**](https://www.npmjs.com/package/ng-hub-ui-avatar)
25
+ - [**ng-hub-ui-board**](https://www.npmjs.com/package/ng-hub-ui-board)
26
+ - [**ng-hub-ui-breadcrumbs**](https://www.npmjs.com/package/ng-hub-ui-breadcrumbs)
27
+ - [**ng-hub-ui-calendar**](https://www.npmjs.com/package/ng-hub-ui-calendar)
28
+ - [**ng-hub-ui-dropdown**](https://www.npmjs.com/package/ng-hub-ui-dropdown)
29
+ - [**ng-hub-ui-ds**](https://www.npmjs.com/package/ng-hub-ui-ds)
30
+ - [**ng-hub-ui-forms**](https://www.npmjs.com/package/ng-hub-ui-forms)
31
+ - [**ng-hub-ui-history**](https://www.npmjs.com/package/ng-hub-ui-history)
32
+ - [**ng-hub-ui-milestones**](https://www.npmjs.com/package/ng-hub-ui-milestones)
33
+ - [**ng-hub-ui-modal**](https://www.npmjs.com/package/ng-hub-ui-modal)
34
+ - [**ng-hub-ui-nav**](https://www.npmjs.com/package/ng-hub-ui-nav)
35
+ - [**ng-hub-ui-paginable**](https://www.npmjs.com/package/ng-hub-ui-paginable)
36
+ - [**ng-hub-ui-panels**](https://www.npmjs.com/package/ng-hub-ui-panels)
37
+ - [**ng-hub-ui-portal**](https://www.npmjs.com/package/ng-hub-ui-portal)
38
+ - [**ng-hub-ui-skeleton**](https://www.npmjs.com/package/ng-hub-ui-skeleton) ← You are here
39
+ - [**ng-hub-ui-sortable**](https://www.npmjs.com/package/ng-hub-ui-sortable)
40
+ - [**ng-hub-ui-stepper**](https://www.npmjs.com/package/ng-hub-ui-stepper)
41
+ - [**ng-hub-ui-utils**](https://www.npmjs.com/package/ng-hub-ui-utils)
42
+
43
+ ## πŸ“‘ Table of Contents
44
+
45
+ - [πŸ“¦ Description](#-description)
46
+ - [✨ Features](#-features)
47
+ - [πŸ“¦ Installation](#-installation)
48
+ - [πŸš€ Usage](#-usage)
49
+ - [Render a bundled preset](#render-a-bundled-preset)
50
+ - [Render an inline DSL template](#render-an-inline-dsl-template)
51
+ - [Parameterized presets](#parameterized-presets)
52
+ - [Variants](#variants)
53
+ - [Responsive templates](#responsive-templates)
54
+ - [Register custom presets](#register-custom-presets)
55
+ - [✍️ The Template DSL](#️-the-template-dsl)
56
+ - [πŸ“– API Reference](#-api-reference)
57
+ - [🎨 Styling / CSS Variables](#-styling--css-variables)
58
+ - [πŸ“Š Changelog](#-changelog)
59
+ - [🀝 Contribution](#-contribution)
60
+ - [β˜• Support](#-support)
61
+ - [πŸ“„ License](#-license)
62
+
63
+ ## πŸ“¦ Description
64
+
65
+ `ng-hub-ui-skeleton` renders loading placeholders for Angular standalone apps. Instead of hand-crafting a markup tree per loading state, you describe the placeholder with a single compact string β€” a small Emmet-inspired DSL β€” or you pick one of the bundled presets. Skeletons are fully responsive (values can change per breakpoint), support visual variants, and can be extended at the application level with your own preset catalogue.
66
+
67
+ The `<hub-skeleton>` component resolves the active breakpoint from the viewport width, expands presets and aliases recursively, interpolates any `{{param}}` placeholders, and paints animated shimmer surfaces with CSS β€” no external dependencies.
68
+
69
+ ## ✨ Features
70
+
71
+ - **Compact DSL**: Describe entire placeholder trees with a single Emmet-like string.
72
+ - **Bundled presets**: Ready-made layouts for cards, lists, tables, forms, dashboards, charts, profiles, feeds, and empty states.
73
+ - **Preset composition**: Reference any preset by name inside the DSL as an alias (e.g. `list-item*4`).
74
+ - **Responsive values**: Per-breakpoint tokens (`base`, `sm`, `md`, `lg`, `xl`) resolved from the viewport width.
75
+ - **Variants**: Named preset variants (such as `compact`) selected with the `variant` input or inline `name@variant`.
76
+ - **Parameters**: Inject runtime values via `{{param}}` interpolation and the `params` input.
77
+ - **Programmatic registration**: Add custom presets app-wide with `provideHubSkeletonPresets`.
78
+ - **Appearance presets**: `default`, `subtle`, and `contrast` tones.
79
+ - **CSS shimmer animation**: Toggleable, fully CSS-driven, no JavaScript animation loop.
80
+ - **Standalone & SSR-aware**: Standalone component, `OnPush` change detection, and browser-only resize handling.
81
+ - **Lightweight**: No external runtime dependencies.
82
+
83
+ ## πŸ“¦ Installation
84
+
85
+ ```bash
86
+ npm install ng-hub-ui-skeleton
87
+ ```
88
+
89
+ ## πŸš€ Usage
90
+
91
+ Import the standalone component (or the optional `HubSkeletonModule` for module-based apps):
92
+
93
+ ```typescript
94
+ import { HubSkeletonComponent } from 'ng-hub-ui-skeleton';
95
+
96
+ @Component({
97
+ selector: 'app-demo',
98
+ standalone: true,
99
+ imports: [HubSkeletonComponent],
100
+ template: `...`
101
+ })
102
+ export class DemoComponent {}
103
+ ```
104
+
105
+ ### Render a bundled preset
106
+
107
+ ```html
108
+ <hub-skeleton preset="card"></hub-skeleton>
109
+ <hub-skeleton preset="list-item"></hub-skeleton>
110
+ <hub-skeleton preset="dashboard-widget"></hub-skeleton>
111
+ ```
112
+
113
+ Bundled preset names: `card`, `list-item`, `table-row`, `detail-view`, `form-section`, `dashboard-widget`, `stat-card`, `chart-panel`, `profile-summary`, `master-detail`, `kanban-card`, `feed-item`, `search-result`, `table-toolbar`, `filter-bar`, `empty-state-skeleton`.
114
+
115
+ ### Render an inline DSL template
116
+
117
+ ```html
118
+ <hub-skeleton
119
+ template="stack(gap:12)>circle(size:48)+stack(gap:8)>line(width:40%)+line(width:72%)"
120
+ ></hub-skeleton>
121
+ ```
122
+
123
+ You can also pass a template definition object instead of a string (see [Responsive templates](#responsive-templates)).
124
+
125
+ ### Parameterized presets
126
+
127
+ Presets expose `{{param}}` placeholders that you can override through the `params` input. Any value passed in `params` is merged on top of the preset defaults.
128
+
129
+ ```html
130
+ <!-- The "card" preset accepts `rows`, `radius`, `titleWidth`, etc. -->
131
+ <hub-skeleton preset="card" [params]="{ rows: 4, radius: 8 }"></hub-skeleton>
132
+
133
+ <!-- The "table-row" preset adapts to the column count -->
134
+ <hub-skeleton preset="table-row" [params]="{ columns: 6 }"></hub-skeleton>
135
+ ```
136
+
137
+ ### Variants
138
+
139
+ Some presets define named variants (for example `card` and `list-item` ship a `compact` variant). Select one with the `variant` input:
140
+
141
+ ```html
142
+ <hub-skeleton preset="card" variant="compact"></hub-skeleton>
143
+ ```
144
+
145
+ Inside the DSL, a variant can be selected per node with the `name@variant` syntax:
146
+
147
+ ```html
148
+ <hub-skeleton template="card@compact"></hub-skeleton>
149
+ ```
150
+
151
+ ### Responsive templates
152
+
153
+ Pass a `HubSkeletonTemplateDefinition` with breakpoint-specific DSL replacements:
154
+
155
+ ```typescript
156
+ import { HubSkeletonTemplateDefinition } from 'ng-hub-ui-skeleton';
157
+
158
+ readonly responsiveTemplate: HubSkeletonTemplateDefinition = {
159
+ dsl: 'grid(columns:1,gap:12)>block(height:120)*2',
160
+ responsive: {
161
+ md: 'grid(columns:2,gap:16)>block(height:160)*4',
162
+ lg: 'grid(columns:4,gap:20)>block(height:200)*4'
163
+ }
164
+ };
165
+ ```
166
+
167
+ ```html
168
+ <hub-skeleton [template]="responsiveTemplate"></hub-skeleton>
169
+ ```
170
+
171
+ Individual modifier values can also be made responsive inline (see [The Template DSL](#️-the-template-dsl)).
172
+
173
+ ### Register custom presets
174
+
175
+ Register your own preset catalogue at the application level. Custom presets are merged on top of the bundled ones (matching names override).
176
+
177
+ ```typescript
178
+ import { ApplicationConfig } from '@angular/core';
179
+ import { provideHubSkeletonPresets } from 'ng-hub-ui-skeleton';
180
+
181
+ export const appConfig: ApplicationConfig = {
182
+ providers: [
183
+ provideHubSkeletonPresets([
184
+ {
185
+ name: 'profile-card',
186
+ description: 'Custom profile card placeholder',
187
+ template:
188
+ 'stack(gap:16)>circle(size:72)+line(width:52%,height:18)+line(width:70%,height:12)+grid(columns:2|md=4,gap:10)>block(height:56)*4',
189
+ defaults: { rows: 2 },
190
+ variants: {
191
+ compact: { defaults: { rows: 1 } }
192
+ }
193
+ }
194
+ ])
195
+ ]
196
+ };
197
+ ```
198
+
199
+ ```html
200
+ <hub-skeleton preset="profile-card"></hub-skeleton>
201
+ ```
202
+
203
+ ## ✍️ The Template DSL
204
+
205
+ The DSL is a compact, Emmet-inspired grammar that compiles into a tree of skeleton nodes.
206
+
207
+ ### Node types
208
+
209
+ | Node | Surface? | Description |
210
+ | -------- | -------- | ------------------------------------------------ |
211
+ | `line` | Yes | A thin text-line placeholder |
212
+ | `block` | Yes | A rectangular block (media, button, image, etc.) |
213
+ | `circle` | Yes | A circular placeholder (avatars, icons) |
214
+ | `stack` | No | Flex container (column by default) |
215
+ | `grid` | No | CSS grid container |
216
+
217
+ Any name that is **not** a built-in node type is resolved as a **preset alias** and expanded recursively.
218
+
219
+ ### Operators
220
+
221
+ | Operator | Meaning | Example |
222
+ | ----------- | ---------------------------------------------------- | -------------------------------- |
223
+ | `>` | Child β€” nest the following siblings inside the node | `stack>line+line` |
224
+ | `+` | Sibling β€” add another node at the same level | `circle+line` |
225
+ | `*N` | Repeat β€” repeat the preceding node `N` times | `line*3` |
226
+ | `(k:v,...)` | Modifiers β€” set properties on a node | `block(height:120,radius:18)` |
227
+ | `@variant` | Variant β€” select a preset variant for an alias node | `card@compact` |
228
+ | `{{param}}` | Parameter β€” interpolated from `params`/preset values | `line(width:{{titleWidth}})` |
229
+
230
+ ### Modifiers
231
+
232
+ Modifiers are key/value pairs inside parentheses, comma-separated. A modifier with no value defaults to `true` (e.g. `grow` is equivalent to `grow:true`).
233
+
234
+ | Modifier | Applies to | Description |
235
+ | ---------- | ---------------- | ---------------------------------------------------------- |
236
+ | `width` | line/block/circle| Node width (percentage or length; raw numbers β†’ `px`) |
237
+ | `height` | line/block/circle| Node height (raw numbers β†’ `px`) |
238
+ | `size` | circle | Diameter (raw numbers β†’ `px`) |
239
+ | `radius` | surface nodes | Border radius (raw numbers β†’ `px`) |
240
+ | `gap` | stack/grid | Gap between children (raw numbers β†’ `px`) |
241
+ | `columns` | grid | Number of grid columns |
242
+ | `direction`| stack | `column` (default) or `row` |
243
+ | `align` | stack/grid | `align-items` value (e.g. `center`, `flex-start`) |
244
+ | `justify` | stack | `justify-content` value (e.g. `space-between`, `flex-end`) |
245
+ | `grow` | any node | When `true`, the node flex-grows to fill space |
246
+
247
+ ### Responsive modifier values
248
+
249
+ A single modifier value can carry breakpoint-specific overrides using the `|` separator and `breakpoint=value` syntax. The bare value (no `=`) is the `base` value, and each breakpoint applies from its width upward.
250
+
251
+ ```
252
+ grid(columns:1|md=2|lg=4)
253
+ block(height:220|lg=280)
254
+ ```
255
+
256
+ Supported breakpoints and their min-widths: `sm` (576px), `md` (768px), `lg` (992px), `xl` (1280px). `base` applies below `sm`.
257
+
258
+ ### Full example
259
+
260
+ ```
261
+ stack(gap:16)>block(height:180,radius:18)+line(height:18,width:56%)+stack(gap:10)>line(width:100%)*2+line(width:76%)
262
+ ```
263
+
264
+ ## πŸ“– API Reference
265
+
266
+ ### `HubSkeletonComponent`
267
+
268
+ Selector: `hub-skeleton`
269
+
270
+ #### Inputs
271
+
272
+ | Input | Type | Default | Description |
273
+ | ------------ | --------------------------------- | ------------------------ | --------------------------------------------------------------------------- |
274
+ | `preset` | `string \| null` | `null` | Built-in or registered preset name to render. |
275
+ | `template` | `HubSkeletonTemplateInput \| null`| `null` | Inline DSL string or template definition object. |
276
+ | `params` | `HubSkeletonParams` | `{}` | Serializable values interpolated into `{{param}}` placeholders. |
277
+ | `variant` | `string \| null` | `null` | Named preset variant to apply. |
278
+ | `animated` | `boolean` | `true` | Toggles the shimmer animation. |
279
+ | `appearance` | `HubSkeletonAppearance` | `'default'` | Visual tone: `'default' \| 'subtle' \| 'contrast'`. |
280
+ | `ariaLabel` | `string` | `'Loading placeholder'` | Accessible label applied to the container. |
281
+
282
+ > Either `preset` or `template` must be provided; otherwise the component throws. An unknown preset name also throws.
283
+
284
+ This component has no outputs.
285
+
286
+ ### `provideHubSkeletonPresets(presets)`
287
+
288
+ Environment provider that appends custom presets to the bundled catalogue for the active injector tree.
289
+
290
+ ```typescript
291
+ function provideHubSkeletonPresets(presets: readonly HubSkeletonPreset[]): EnvironmentProviders;
292
+ ```
293
+
294
+ It is multi-provider backed (token `HUB_SKELETON_PRESETS`), so multiple calls accumulate. Later presets override earlier ones with the same `name`.
295
+
296
+ ### `HubSkeletonPresetRegistryService`
297
+
298
+ Injectable (`providedIn: 'root'`) service that resolves the merged preset catalogue.
299
+
300
+ | Member | Signature | Description |
301
+ | ------------------ | ----------------------------------------------- | -------------------------------------------- |
302
+ | `presets` | `Signal<Map<string, HubSkeletonPreset>>` | All presets merged by name. |
303
+ | `getPreset(name)` | `(name: string) => HubSkeletonPreset \| undefined` | Returns a single preset by name. |
304
+
305
+ ### Exported types
306
+
307
+ ```typescript
308
+ type HubSkeletonBreakpoint = 'base' | 'sm' | 'md' | 'lg' | 'xl';
309
+ type HubSkeletonPrimitive = string | number | boolean;
310
+ type HubSkeletonResponsiveValue<T extends HubSkeletonPrimitive = HubSkeletonPrimitive> =
311
+ | T
312
+ | Partial<Record<HubSkeletonBreakpoint, T>>;
313
+ type HubSkeletonParams = Record<string, HubSkeletonPrimitive | undefined>;
314
+ type HubSkeletonAppearance = 'default' | 'subtle' | 'contrast';
315
+ type HubSkeletonTemplateInput = string | HubSkeletonTemplateDefinition;
316
+
317
+ interface HubSkeletonTemplateDefinition {
318
+ readonly dsl: string;
319
+ readonly responsive?: Partial<Record<Exclude<HubSkeletonBreakpoint, 'base'>, string>>;
320
+ }
321
+
322
+ interface HubSkeletonPreset {
323
+ readonly name: string;
324
+ readonly template: HubSkeletonTemplateInput;
325
+ readonly defaults?: HubSkeletonParams;
326
+ readonly variants?: Record<string, {
327
+ readonly template?: HubSkeletonTemplateInput;
328
+ readonly defaults?: HubSkeletonParams;
329
+ }>;
330
+ readonly description?: string;
331
+ }
332
+ ```
333
+
334
+ Additional DSL helpers are also exported (`parseHubSkeletonDsl`, `interpolateHubSkeletonParams`, `resolveTemplateDsl`, `resolveResponsiveToken`, `resolveBreakpointFromWidth`, `resolveHubSkeletonNodes`) along with the `HUB_SKELETON_DEFAULT_PRESETS` catalogue and the `HubSkeletonModule`.
335
+
336
+ ## 🎨 Styling / CSS Variables
337
+
338
+ The component styles itself with CSS custom properties scoped to the `.hub-skeleton` container. Override them on the host to theme skeletons:
339
+
340
+ | Variable | Default | Description |
341
+ | ------------------------------------- | -------------------------------- | ------------------------------------ |
342
+ | `--hub-skeleton-bg` | `rgba(148, 163, 184, 0.18)` | Base surface color. |
343
+ | `--hub-skeleton-highlight` | `rgba(255, 255, 255, 0.52)` | Shimmer highlight color. |
344
+ | `--hub-skeleton-radius` | `12px` | Default surface border radius. |
345
+ | `--hub-skeleton-gap` | `12px` | Default gap for stack/grid nodes. |
346
+ | `--hub-skeleton-animation-duration` | `1.35s` | Shimmer animation duration. |
347
+
348
+ ```scss
349
+ hub-skeleton {
350
+ --hub-skeleton-bg: rgba(0, 0, 0, 0.08);
351
+ --hub-skeleton-highlight: rgba(255, 255, 255, 0.6);
352
+ --hub-skeleton-radius: 8px;
353
+ --hub-skeleton-animation-duration: 1.6s;
354
+ }
355
+ ```
356
+
357
+ The `appearance` input swaps the base/highlight colors for `subtle` and `contrast` tones. Per-node modifiers (`width`, `height`, `size`, `radius`, `gap`, `columns`, `align`, `justify`) are applied as scoped `--hub-skeleton-node-*` custom properties.
358
+
359
+ ### The `hub-skeleton-theme()` Sass mixin
360
+
361
+ For Sass-based projects, the `hub-skeleton-theme()` mixin overrides the `--hub-skeleton-*` tokens 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. It is token-based and self-contained (no Bootstrap dependency). A skeleton is a neutral placeholder, so there is no semantic color variant: tune the base / highlight surfaces, the corner radius, the gap between nodes and the shimmer speed instead (per-node sizes still come from the template DSL / presets).
362
+
363
+ ```scss
364
+ @use 'ng-hub-ui-skeleton/styles/mixins/skeleton-theme' as *;
365
+
366
+ hub-skeleton.on-dark {
367
+ @include hub-skeleton-theme(
368
+ $bg: rgba(255, 255, 255, 0.1),
369
+ $highlight: rgba(255, 255, 255, 0.22),
370
+ $radius: 8px,
371
+ $animation-duration: 1.8s
372
+ );
373
+ }
374
+ ```
375
+
376
+ Available parameters: `$bg`, `$highlight`, `$radius`, `$gap`, `$animation-duration`.
377
+
378
+ ## πŸ“Š Changelog
379
+
380
+ See [CHANGELOG.md](./CHANGELOG.md) for the full version history.
381
+
382
+ ## 🀝 Contribution
383
+
384
+ Contributions are welcome. Please open an issue to discuss substantial changes before submitting a pull request, and make sure to document every library change in `CHANGELOG.md`.
385
+
386
+ ## β˜• Support
387
+
388
+ - **Issues**: [GitHub Issues](https://github.com/carlos-morcillo/ng-hub-ui/issues)
389
+ - **Author**: [Carlos Morcillo](https://www.carlosmorcillo.com)
390
+
391
+ ## πŸ“„ License
392
+
393
+ MIT Β© [Carlos Morcillo](https://www.carlosmorcillo.com)
394
+
395
+ ---
396
+
397
+ Made with ❀️ by the Hub UI team