@egose/shadcn-theme-ng 0.0.28 → 0.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 +130 -13
- package/accordion/README.md +376 -34
- package/accordion/fesm2022/accordion.mjs +27 -39
- package/alert/README.md +343 -34
- package/alert/fesm2022/alert.mjs +47 -47
- package/alert-dialog/README.md +471 -5
- package/alert-dialog/fesm2022/alert-dialog.mjs +47 -47
- package/aspect-ratio/README.md +272 -5
- package/aspect-ratio/fesm2022/aspect-ratio.mjs +9 -9
- package/autocomplete/README.md +473 -34
- package/autocomplete/fesm2022/autocomplete.mjs +53 -71
- package/avatar/README.md +357 -5
- package/avatar/fesm2022/avatar.mjs +32 -32
- package/badge/README.md +289 -34
- package/badge/fesm2022/badge.mjs +57 -57
- package/basic-alert/README.md +324 -34
- package/basic-alert/fesm2022/basic-alert.mjs +6 -18
- package/breadcrumb/README.md +406 -5
- package/breadcrumb/fesm2022/breadcrumb.mjs +33 -39
- package/button/README.md +453 -34
- package/button/fesm2022/button.mjs +147 -219
- package/button/types/button.d.ts +7 -10
- package/button-group/README.md +318 -5
- package/button-group/fesm2022/button-group.mjs +20 -20
- package/calendar/README.md +328 -34
- package/calendar/fesm2022/calendar.mjs +29 -743
- package/card/README.md +331 -5
- package/card/fesm2022/card.mjs +33 -33
- package/carousel/README.md +333 -5
- package/carousel/fesm2022/carousel.mjs +39 -78
- package/checkbox/README.md +291 -34
- package/checkbox/fesm2022/checkbox.mjs +20 -58
- package/checkbox/types/checkbox.d.ts +5 -4
- package/collapsible/README.md +332 -5
- package/collapsible/fesm2022/collapsible.mjs +15 -15
- package/combobox/README.md +507 -5
- package/combobox/fesm2022/combobox.mjs +91 -224
- package/command/README.md +435 -5
- package/command/fesm2022/command.mjs +49 -109
- package/confirmation-dialog/README.md +272 -34
- package/confirmation-dialog/fesm2022/confirmation-dialog.mjs +15 -40
- package/confirmation-dialog/types/confirmation-dialog.d.ts +8 -4
- package/context-menu/README.md +366 -5
- package/context-menu/fesm2022/context-menu.mjs +9 -9
- package/date-picker/README.md +436 -34
- package/date-picker/fesm2022/date-picker.mjs +64 -267
- package/date-picker/types/date-picker.d.ts +7 -3
- package/dialog/README.md +419 -34
- package/dialog/fesm2022/dialog.mjs +45 -71
- package/drawer/README.md +395 -5
- package/drawer/fesm2022/drawer.mjs +44 -54
- package/dropdown-menu/README.md +417 -5
- package/dropdown-menu/fesm2022/dropdown-menu.mjs +82 -70
- package/dropdown-menu/types/dropdown-menu.d.ts +4 -0
- package/empty/README.md +329 -5
- package/empty/fesm2022/empty.mjs +30 -30
- package/field/README.md +385 -5
- package/field/fesm2022/field.mjs +56 -72
- package/form-checkbox/README.md +283 -34
- package/form-checkbox/fesm2022/form-checkbox.mjs +25 -85
- package/form-checkbox/types/form-checkbox.d.ts +7 -1
- package/form-date-picker/README.md +293 -34
- package/form-date-picker/fesm2022/form-date-picker.mjs +31 -84
- package/form-date-picker/types/form-date-picker.d.ts +7 -1
- package/form-field/README.md +327 -34
- package/form-field/fesm2022/form-field.mjs +33 -19
- package/form-field/types/form-field.d.ts +28 -20
- package/form-field-simple/README.md +311 -34
- package/form-field-simple/fesm2022/form-field-simple.mjs +4 -4
- package/form-searchable-multiselect/README.md +332 -34
- package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +31 -91
- package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +7 -1
- package/form-select/README.md +321 -34
- package/form-select/fesm2022/form-select.mjs +32 -149
- package/form-select/types/form-select.d.ts +7 -1
- package/form-text-input/README.md +342 -34
- package/form-text-input/fesm2022/form-text-input.mjs +35 -149
- package/form-text-input/types/form-text-input.d.ts +9 -12
- package/form-textarea/README.md +318 -34
- package/form-textarea/fesm2022/form-textarea.mjs +34 -109
- package/form-textarea/types/form-textarea.d.ts +8 -1
- package/hover-card/README.md +256 -5
- package/hover-card/fesm2022/hover-card.mjs +19 -19
- package/icon/README.md +210 -34
- package/icon/fesm2022/icon.mjs +8 -8
- package/input/README.md +240 -34
- package/input/fesm2022/input.mjs +17 -12
- package/input/types/input.d.ts +2 -1
- package/input-group/README.md +335 -5
- package/input-group/fesm2022/input-group.mjs +34 -34
- package/input-otp/README.md +375 -5
- package/input-otp/fesm2022/input-otp.mjs +26 -26
- package/item/README.md +385 -5
- package/item/fesm2022/item.mjs +53 -53
- package/kbd/README.md +291 -5
- package/kbd/fesm2022/kbd.mjs +12 -12
- package/label/README.md +243 -34
- package/label/fesm2022/label.mjs +10 -10
- package/label/types/label.d.ts +1 -1
- package/layout-simple/README.md +174 -44
- package/layout-simple/fesm2022/layout-simple.mjs +508 -603
- package/layout-simple/types/layout-simple.d.ts +179 -128
- package/menu/README.md +418 -0
- package/menu/fesm2022/menu.mjs +455 -0
- package/menu/package.json +24 -0
- package/menu/types/menu.d.ts +137 -0
- package/menubar/README.md +343 -5
- package/menubar/fesm2022/menubar.mjs +13 -13
- package/native-select/README.md +323 -5
- package/native-select/fesm2022/native-select.mjs +19 -19
- package/navigation-menu/README.md +369 -5
- package/navigation-menu/fesm2022/navigation-menu.mjs +35 -47
- package/package.json +183 -154
- package/pagination/README.md +388 -5
- package/pagination/fesm2022/pagination.mjs +45 -331
- package/popover/README.md +302 -34
- package/popover/fesm2022/popover.mjs +30 -30
- package/progress/README.md +311 -5
- package/progress/fesm2022/progress.mjs +13 -13
- package/radio-group/README.md +335 -34
- package/radio-group/fesm2022/radio-group.mjs +26 -19
- package/radio-group/types/radio-group.d.ts +1 -1
- package/resizable/README.md +269 -5
- package/resizable/fesm2022/resizable.mjs +18 -26
- package/scroll-area/README.md +233 -5
- package/scroll-area/fesm2022/scroll-area.mjs +9 -9
- package/searchable-multiselect/README.md +294 -34
- package/searchable-multiselect/fesm2022/searchable-multiselect.mjs +28 -117
- package/searchable-multiselect/types/searchable-multiselect.d.ts +8 -2
- package/select/README.md +408 -34
- package/select/fesm2022/select.mjs +71 -111
- package/select/types/select.d.ts +3 -1
- package/separator/README.md +193 -34
- package/separator/fesm2022/separator.mjs +9 -9
- package/separator/types/separator.d.ts +1 -1
- package/sheet/README.md +282 -34
- package/sheet/fesm2022/sheet.mjs +41 -53
- package/sidebar/README.md +457 -5
- package/sidebar/fesm2022/sidebar.mjs +125 -227
- package/skeleton/README.md +217 -5
- package/skeleton/fesm2022/skeleton.mjs +9 -9
- package/slider/README.md +273 -5
- package/slider/fesm2022/slider.mjs +10 -80
- package/sonner/README.md +317 -34
- package/sonner/fesm2022/sonner.mjs +13 -13
- package/spinner/README.md +255 -34
- package/spinner/fesm2022/spinner.mjs +11 -11
- package/switch/README.md +281 -34
- package/switch/fesm2022/switch.mjs +13 -15
- package/table/README.md +423 -5
- package/table/fesm2022/table.mjs +41 -41
- package/tabs/README.md +382 -34
- package/tabs/fesm2022/tabs.mjs +35 -111
- package/textarea/README.md +282 -5
- package/textarea/fesm2022/textarea.mjs +9 -9
- package/toggle/README.md +270 -5
- package/toggle/fesm2022/toggle.mjs +13 -13
- package/toggle-group/README.md +340 -5
- package/toggle-group/fesm2022/toggle-group.mjs +13 -13
- package/toggle-group/types/toggle-group.d.ts +13 -7
- package/tooltip/README.md +240 -34
- package/tooltip/fesm2022/tooltip.mjs +14 -14
- package/typography/README.md +271 -5
- package/typography/fesm2022/typography.mjs +53 -53
- package/typography/types/typography.d.ts +19 -19
- package/utils/README.md +274 -34
- package/utils/fesm2022/utils.mjs +68 -44
- package/accordion/fesm2022/accordion.mjs.map +0 -1
- package/alert/fesm2022/alert.mjs.map +0 -1
- package/alert-dialog/fesm2022/alert-dialog.mjs.map +0 -1
- package/aspect-ratio/fesm2022/aspect-ratio.mjs.map +0 -1
- package/autocomplete/fesm2022/autocomplete.mjs.map +0 -1
- package/avatar/fesm2022/avatar.mjs.map +0 -1
- package/badge/fesm2022/badge.mjs.map +0 -1
- package/basic-alert/fesm2022/basic-alert.mjs.map +0 -1
- package/breadcrumb/fesm2022/breadcrumb.mjs.map +0 -1
- package/button/fesm2022/button.mjs.map +0 -1
- package/button-group/fesm2022/button-group.mjs.map +0 -1
- package/calendar/fesm2022/calendar.mjs.map +0 -1
- package/card/fesm2022/card.mjs.map +0 -1
- package/carousel/fesm2022/carousel.mjs.map +0 -1
- package/checkbox/fesm2022/checkbox.mjs.map +0 -1
- package/collapsible/fesm2022/collapsible.mjs.map +0 -1
- package/combobox/fesm2022/combobox.mjs.map +0 -1
- package/command/fesm2022/command.mjs.map +0 -1
- package/confirmation-dialog/fesm2022/confirmation-dialog.mjs.map +0 -1
- package/context-menu/fesm2022/context-menu.mjs.map +0 -1
- package/date-picker/fesm2022/date-picker.mjs.map +0 -1
- package/dialog/fesm2022/dialog.mjs.map +0 -1
- package/drawer/fesm2022/drawer.mjs.map +0 -1
- package/dropdown-menu/fesm2022/dropdown-menu.mjs.map +0 -1
- package/empty/fesm2022/empty.mjs.map +0 -1
- package/field/fesm2022/field.mjs.map +0 -1
- package/form-checkbox/fesm2022/form-checkbox.mjs.map +0 -1
- package/form-date-picker/fesm2022/form-date-picker.mjs.map +0 -1
- package/form-field/fesm2022/form-field.mjs.map +0 -1
- package/form-field-simple/fesm2022/form-field-simple.mjs.map +0 -1
- package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs.map +0 -1
- package/form-select/fesm2022/form-select.mjs.map +0 -1
- package/form-text-input/fesm2022/form-text-input.mjs.map +0 -1
- package/form-textarea/fesm2022/form-textarea.mjs.map +0 -1
- package/hover-card/fesm2022/hover-card.mjs.map +0 -1
- package/icon/fesm2022/icon.mjs.map +0 -1
- package/input/fesm2022/input.mjs.map +0 -1
- package/input-group/fesm2022/input-group.mjs.map +0 -1
- package/input-otp/fesm2022/input-otp.mjs.map +0 -1
- package/item/fesm2022/item.mjs.map +0 -1
- package/kbd/fesm2022/kbd.mjs.map +0 -1
- package/label/fesm2022/label.mjs.map +0 -1
- package/layout-simple/fesm2022/layout-simple.mjs.map +0 -1
- package/menubar/fesm2022/menubar.mjs.map +0 -1
- package/native-select/fesm2022/native-select.mjs.map +0 -1
- package/navigation-menu/fesm2022/navigation-menu.mjs.map +0 -1
- package/pagination/fesm2022/pagination.mjs.map +0 -1
- package/popover/fesm2022/popover.mjs.map +0 -1
- package/progress/fesm2022/progress.mjs.map +0 -1
- package/radio-group/fesm2022/radio-group.mjs.map +0 -1
- package/resizable/fesm2022/resizable.mjs.map +0 -1
- package/scroll-area/fesm2022/scroll-area.mjs.map +0 -1
- package/searchable-multiselect/fesm2022/searchable-multiselect.mjs.map +0 -1
- package/select/fesm2022/select.mjs.map +0 -1
- package/separator/fesm2022/separator.mjs.map +0 -1
- package/sheet/fesm2022/sheet.mjs.map +0 -1
- package/sidebar/fesm2022/sidebar.mjs.map +0 -1
- package/skeleton/fesm2022/skeleton.mjs.map +0 -1
- package/slider/fesm2022/slider.mjs.map +0 -1
- package/sonner/fesm2022/sonner.mjs.map +0 -1
- package/spinner/fesm2022/spinner.mjs.map +0 -1
- package/switch/fesm2022/switch.mjs.map +0 -1
- package/table/fesm2022/table.mjs.map +0 -1
- package/tabs/fesm2022/tabs.mjs.map +0 -1
- package/textarea/fesm2022/textarea.mjs.map +0 -1
- package/toggle/fesm2022/toggle.mjs.map +0 -1
- package/toggle-group/fesm2022/toggle-group.mjs.map +0 -1
- package/tooltip/fesm2022/tooltip.mjs.map +0 -1
- package/typography/fesm2022/typography.mjs.map +0 -1
- package/utils/fesm2022/utils.mjs.map +0 -1
package/empty/README.md
CHANGED
|
@@ -1,11 +1,335 @@
|
|
|
1
|
-
# Empty
|
|
1
|
+
# Empty (`@egose/shadcn-theme-ng/empty`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An empty-state placeholder in the shadcn/ui Empty style: dashed bordered panel with media (icon/illustration), title, description, and action content. Equivalent to shadcn/ui `Empty`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The Angular implementation is a set of pure styling directives — there is no headless primitive or
|
|
6
|
+
behavioral code. Each directive applies its `data-slot` shadcn classes via `classes()` from
|
|
7
|
+
`@egose/shadcn-theme-ng/utils`; `HlmEmptyMedia` adds a `cva` variant (`default` | `icon`).
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
> **Ships as:** `@egose/shadcn-theme-ng/empty` and `@egose/shadcn-theme-ng-tw/empty`
|
|
10
|
+
> (the `tw:`-prefixed Tailwind variant). Both expose the identical TypeScript surface; only the
|
|
11
|
+
> emitted Tailwind class strings differ. See the [package README](../../README.md) for install
|
|
12
|
+
> steps, peer dependencies, and Tailwind setup. Do not publish this project directory independently.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
8
15
|
|
|
9
16
|
```bash
|
|
10
|
-
|
|
17
|
+
# Plain Tailwind (no prefix)
|
|
18
|
+
npm install @egose/shadcn-theme-ng
|
|
19
|
+
|
|
20
|
+
# tw:-prefixed Tailwind variant
|
|
21
|
+
npm install @egose/shadcn-theme-ng-tw
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Peer dependencies (Angular, `@spartan-ng/brain`, `@ng-icons/*`, `rxjs`, …) are documented in the
|
|
25
|
+
[package README](../../README.md#peer-dependencies). This subpath has no extra runtime component
|
|
26
|
+
dependencies beyond `@egose/shadcn-theme-ng/utils` and `class-variance-authority` (media variant).
|
|
27
|
+
|
|
28
|
+
## Imports
|
|
29
|
+
|
|
30
|
+
All symbols are exported from the subpath root (`projects/empty/src/public-api.ts`):
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import {
|
|
34
|
+
HlmEmpty,
|
|
35
|
+
HlmEmptyHeader,
|
|
36
|
+
HlmEmptyTitle,
|
|
37
|
+
HlmEmptyDescription,
|
|
38
|
+
HlmEmptyContent,
|
|
39
|
+
HlmEmptyMedia,
|
|
40
|
+
HlmEmptyImports,
|
|
41
|
+
HlmEmptyModule,
|
|
42
|
+
} from '@egose/shadcn-theme-ng/empty';
|
|
43
|
+
// tw variant: replace with '@egose/shadcn-theme-ng-tw/empty'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Standalone component — spread the `*Imports` array:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { Component } from '@angular/core';
|
|
50
|
+
import { HlmEmptyImports } from '@egose/shadcn-theme-ng/empty';
|
|
51
|
+
|
|
52
|
+
@Component({
|
|
53
|
+
selector: 'app-demo',
|
|
54
|
+
standalone: true,
|
|
55
|
+
imports: [...HlmEmptyImports],
|
|
56
|
+
template: `...`,
|
|
57
|
+
})
|
|
58
|
+
export class DemoComponent {}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
NgModule-based consumer — import the module:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { NgModule } from '@angular/core';
|
|
65
|
+
import { HlmEmptyModule } from '@egose/shadcn-theme-ng/empty';
|
|
66
|
+
|
|
67
|
+
@NgModule({ imports: [HlmEmptyModule] })
|
|
68
|
+
export class DemoModule {}
|
|
11
69
|
```
|
|
70
|
+
|
|
71
|
+
## Anatomy / Structure
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<div hlmEmpty>
|
|
75
|
+
<div hlmEmptyMedia variant="icon">
|
|
76
|
+
<ng-icon name="lucideInbox" />
|
|
77
|
+
</div>
|
|
78
|
+
<div hlmEmptyHeader>
|
|
79
|
+
<h3 hlmEmptyTitle>No results found</h3>
|
|
80
|
+
<p hlmEmptyDescription>Try adjusting your search or filters.</p>
|
|
81
|
+
</div>
|
|
82
|
+
<div hlmEmptyContent>
|
|
83
|
+
<button hlmBtn variant="outline">Clear filters</button>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Real selectors (from source):
|
|
89
|
+
|
|
90
|
+
| Class | Selector(s) | Kind |
|
|
91
|
+
| --------------------- | -------------------------------------- | -------------------------- |
|
|
92
|
+
| `HlmEmpty` | `[hlmEmpty], hlm-empty` | Directive |
|
|
93
|
+
| `HlmEmptyHeader` | `[hlmEmptyHeader], hlm-empty-header` | Directive |
|
|
94
|
+
| `HlmEmptyTitle` | `[hlmEmptyTitle]` | Directive (attribute only) |
|
|
95
|
+
| `HlmEmptyDescription` | `[hlmEmptyDescription]` | Directive (attribute only) |
|
|
96
|
+
| `HlmEmptyContent` | `[hlmEmptyContent], hlm-empty-content` | Directive |
|
|
97
|
+
| `HlmEmptyMedia` | `[hlmEmptyMedia], hlm-empty-media` | Directive |
|
|
98
|
+
|
|
99
|
+
## API reference
|
|
100
|
+
|
|
101
|
+
All directives are style-only (no inputs except media, no outputs).
|
|
102
|
+
|
|
103
|
+
| Directive | Selector | Description |
|
|
104
|
+
| --------------------- | -------------------------------------- | ------------------------------------------------------------ |
|
|
105
|
+
| `HlmEmpty` | `[hlmEmpty], hlm-empty` | Dashed rounded panel, centered column layout. |
|
|
106
|
+
| `HlmEmptyHeader` | `[hlmEmptyHeader], hlm-empty-header` | Narrow centered stack for title + description. |
|
|
107
|
+
| `HlmEmptyTitle` | `[hlmEmptyTitle]` | Large medium title. Apply to a heading element. |
|
|
108
|
+
| `HlmEmptyDescription` | `[hlmEmptyDescription]` | Muted small description with link styling. Apply to a `<p>`. |
|
|
109
|
+
| `HlmEmptyContent` | `[hlmEmptyContent], hlm-empty-content` | Action area (buttons, inputs) below the header. |
|
|
110
|
+
|
|
111
|
+
### `HlmEmptyMedia` — `[hlmEmptyMedia], hlm-empty-media`
|
|
112
|
+
|
|
113
|
+
| Input | Type | Default | Description |
|
|
114
|
+
| --------- | --------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
115
|
+
| `variant` | `'default' \| 'icon'` | `'default'` (cva default) | `'icon'` renders a muted rounded tile sized for an `ng-icon`; `'default'` is transparent (for illustrations). |
|
|
116
|
+
|
|
117
|
+
Host sets `data-slot="empty-media"` and `data-variant`.
|
|
118
|
+
|
|
119
|
+
## Examples
|
|
120
|
+
|
|
121
|
+
### 1. Basic no-results state
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { Component } from '@angular/core';
|
|
125
|
+
import { HlmEmptyImports } from '@egose/shadcn-theme-ng/empty';
|
|
126
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
127
|
+
|
|
128
|
+
@Component({
|
|
129
|
+
selector: 'app-no-results',
|
|
130
|
+
standalone: true,
|
|
131
|
+
imports: [...HlmEmptyImports, HlmButton],
|
|
132
|
+
template: `
|
|
133
|
+
<div hlmEmpty>
|
|
134
|
+
<div hlmEmptyHeader>
|
|
135
|
+
<h3 hlmEmptyTitle>No results found</h3>
|
|
136
|
+
<p hlmEmptyDescription>Try adjusting your search or filter to find what you're looking for.</p>
|
|
137
|
+
</div>
|
|
138
|
+
<div hlmEmptyContent>
|
|
139
|
+
<button hlmBtn variant="outline" (click)="clear()">Clear filters</button>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
`,
|
|
143
|
+
})
|
|
144
|
+
export class NoResultsComponent {
|
|
145
|
+
clear() {
|
|
146
|
+
console.log('filters cleared');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 2. Icon media variant
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { Component } from '@angular/core';
|
|
155
|
+
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
156
|
+
import { lucideInbox } from '@ng-icons/lucide';
|
|
157
|
+
import { HlmEmptyImports } from '@egose/shadcn-theme-ng/empty';
|
|
158
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
159
|
+
|
|
160
|
+
@Component({
|
|
161
|
+
selector: 'app-inbox-empty',
|
|
162
|
+
standalone: true,
|
|
163
|
+
imports: [...HlmEmptyImports, HlmButton, NgIcon],
|
|
164
|
+
providers: [provideIcons({ lucideInbox })],
|
|
165
|
+
template: `
|
|
166
|
+
<div hlmEmpty>
|
|
167
|
+
<div hlmEmptyMedia variant="icon">
|
|
168
|
+
<ng-icon name="lucideInbox" />
|
|
169
|
+
</div>
|
|
170
|
+
<div hlmEmptyHeader>
|
|
171
|
+
<h3 hlmEmptyTitle>Inbox zero</h3>
|
|
172
|
+
<p hlmEmptyDescription>You're all caught up. New messages will appear here.</p>
|
|
173
|
+
</div>
|
|
174
|
+
<div hlmEmptyContent>
|
|
175
|
+
<button hlmBtn>Compose</button>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
`,
|
|
179
|
+
})
|
|
180
|
+
export class InboxEmptyComponent {}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 3. Illustration media (default variant)
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { Component } from '@angular/core';
|
|
187
|
+
import { HlmEmptyImports } from '@egose/shadcn-theme-ng/empty';
|
|
188
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
189
|
+
|
|
190
|
+
@Component({
|
|
191
|
+
selector: 'app-illustration',
|
|
192
|
+
standalone: true,
|
|
193
|
+
imports: [...HlmEmptyImports, HlmButton],
|
|
194
|
+
template: `
|
|
195
|
+
<div hlmEmpty>
|
|
196
|
+
<div hlmEmptyMedia>
|
|
197
|
+
<img src="/assets/empty-projects.svg" alt="" width="120" height="120" />
|
|
198
|
+
</div>
|
|
199
|
+
<div hlmEmptyHeader>
|
|
200
|
+
<h3 hlmEmptyTitle>No projects yet</h3>
|
|
201
|
+
<p hlmEmptyDescription>
|
|
202
|
+
Get started by creating your first project. Read the <a href="/docs">docs</a> for ideas.
|
|
203
|
+
</p>
|
|
204
|
+
</div>
|
|
205
|
+
<div hlmEmptyContent>
|
|
206
|
+
<button hlmBtn>Create project</button>
|
|
207
|
+
<button hlmBtn variant="ghost">Import</button>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
`,
|
|
211
|
+
})
|
|
212
|
+
export class IllustrationComponent {}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 4. Element spellings
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import { Component } from '@angular/core';
|
|
219
|
+
import { HlmEmptyImports } from '@egose/shadcn-theme-ng/empty';
|
|
220
|
+
|
|
221
|
+
@Component({
|
|
222
|
+
selector: 'app-elements',
|
|
223
|
+
standalone: true,
|
|
224
|
+
imports: [...HlmEmptyImports],
|
|
225
|
+
template: `
|
|
226
|
+
<hlm-empty>
|
|
227
|
+
<hlm-empty-header>
|
|
228
|
+
<h3 hlmEmptyTitle>Nothing here</h3>
|
|
229
|
+
<p hlmEmptyDescription>This space is intentionally left blank.</p>
|
|
230
|
+
</hlm-empty-header>
|
|
231
|
+
<hlm-empty-content>
|
|
232
|
+
<p class="tw:text-sm">Custom element selectors work identically.</p>
|
|
233
|
+
</hlm-empty-content>
|
|
234
|
+
</hlm-empty>
|
|
235
|
+
`,
|
|
236
|
+
})
|
|
237
|
+
export class ElementsComponent {}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 5. Search empty state with input action
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { Component, signal } from '@angular/core';
|
|
244
|
+
import { HlmEmptyImports } from '@egose/shadcn-theme-ng/empty';
|
|
245
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
246
|
+
import { HlmInput } from '@egose/shadcn-theme-ng/input';
|
|
247
|
+
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
248
|
+
import { lucideSearchX } from '@ng-icons/lucide';
|
|
249
|
+
|
|
250
|
+
@Component({
|
|
251
|
+
selector: 'app-search-empty',
|
|
252
|
+
standalone: true,
|
|
253
|
+
imports: [...HlmEmptyImports, HlmButton, HlmInput, NgIcon],
|
|
254
|
+
providers: [provideIcons({ lucideSearchX })],
|
|
255
|
+
template: `
|
|
256
|
+
<div hlmEmpty>
|
|
257
|
+
<div hlmEmptyMedia variant="icon">
|
|
258
|
+
<ng-icon name="lucideSearchX" />
|
|
259
|
+
</div>
|
|
260
|
+
<div hlmEmptyHeader>
|
|
261
|
+
<h3 hlmEmptyTitle>No matches for "{{ query() }}"</h3>
|
|
262
|
+
<p hlmEmptyDescription>Check your spelling or try a different keyword.</p>
|
|
263
|
+
</div>
|
|
264
|
+
<div hlmEmptyContent>
|
|
265
|
+
<input hlmInput [value]="query()" (input)="query.set($any($event.target).value)" placeholder="Search again" />
|
|
266
|
+
<button hlmBtn variant="outline" (click)="query.set('')">Reset search</button>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
`,
|
|
270
|
+
})
|
|
271
|
+
export class SearchEmptyComponent {
|
|
272
|
+
readonly query = signal('qwerty');
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 6. Error / offline state
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
import { Component, signal } from '@angular/core';
|
|
280
|
+
import { HlmEmptyImports } from '@egose/shadcn-theme-ng/empty';
|
|
281
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
282
|
+
import { HlmSpinner } from '@egose/shadcn-theme-ng/spinner';
|
|
283
|
+
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
284
|
+
import { lucideWifiOff } from '@ng-icons/lucide';
|
|
285
|
+
|
|
286
|
+
@Component({
|
|
287
|
+
selector: 'app-offline',
|
|
288
|
+
standalone: true,
|
|
289
|
+
imports: [...HlmEmptyImports, HlmButton, HlmSpinner, NgIcon],
|
|
290
|
+
providers: [provideIcons({ lucideWifiOff })],
|
|
291
|
+
template: `
|
|
292
|
+
<div hlmEmpty>
|
|
293
|
+
<div hlmEmptyMedia variant="icon">
|
|
294
|
+
@if (retrying()) {
|
|
295
|
+
<hlm-spinner />
|
|
296
|
+
} @else {
|
|
297
|
+
<ng-icon name="lucideWifiOff" />
|
|
298
|
+
}
|
|
299
|
+
</div>
|
|
300
|
+
<div hlmEmptyHeader>
|
|
301
|
+
<h3 hlmEmptyTitle>You're offline</h3>
|
|
302
|
+
<p hlmEmptyDescription>We couldn't load your data. Check your connection and retry.</p>
|
|
303
|
+
</div>
|
|
304
|
+
<div hlmEmptyContent>
|
|
305
|
+
<button hlmBtn variant="outline" [disabled]="retrying()" (click)="retry()">Try again</button>
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
`,
|
|
309
|
+
})
|
|
310
|
+
export class OfflineComponent {
|
|
311
|
+
readonly retrying = signal(false);
|
|
312
|
+
retry() {
|
|
313
|
+
this.retrying.set(true);
|
|
314
|
+
setTimeout(() => this.retrying.set(false), 1200);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Accessibility notes
|
|
320
|
+
|
|
321
|
+
- Use a real heading level for `hlmEmptyTitle` (`h2`/`h3` matching the page outline) — the directive adds no role or level itself.
|
|
322
|
+
- Mark decorative media `aria-hidden="true"` (or `alt=""` on images); give meaningful illustrations an `alt` or `role="img"` + `aria-label`.
|
|
323
|
+
- Keep the empty panel out of the tab order except for its interactive content (buttons/inputs); do not add `tabindex` to the container.
|
|
324
|
+
- For async states (loading → empty → results), announce changes with an `aria-live` region around the title or content.
|
|
325
|
+
|
|
326
|
+
## Theming / CSS variables
|
|
327
|
+
|
|
328
|
+
No component-specific CSS variables. Geometry comes from the directives; colors from global tokens (`--muted`, `--muted-foreground`, `--background`). The `icon` media variant sizes `ng-icon` via `[&_ng-icon]` selectors — pass icon size through the icon itself if you need a different size.
|
|
329
|
+
|
|
330
|
+
## Related subpaths
|
|
331
|
+
|
|
332
|
+
- `@egose/shadcn-theme-ng/card` — bordered container alternative when the state needs richer layout.
|
|
333
|
+
- `@egose/shadcn-theme-ng/skeleton` — loading placeholder to show before the empty state resolves.
|
|
334
|
+
- `@egose/shadcn-theme-ng/button` — `hlmBtn` actions inside `hlmEmptyContent`.
|
|
335
|
+
- `@egose/shadcn-theme-ng/spinner` — loading indicator for retrying/error empties.
|
package/empty/fesm2022/empty.mjs
CHANGED
|
@@ -5,12 +5,12 @@ import { cva } from 'class-variance-authority';
|
|
|
5
5
|
|
|
6
6
|
class HlmEmpty {
|
|
7
7
|
constructor() {
|
|
8
|
-
classes(() =>
|
|
8
|
+
classes(() => "gap-4 rounded-lg border-dashed p-12 flex w-full min-w-0 flex-1 flex-col items-center justify-center text-center text-balance");
|
|
9
9
|
}
|
|
10
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
11
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.
|
|
10
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmpty, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
11
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: HlmEmpty, isStandalone: true, selector: "[hlmEmpty],hlm-empty", host: { attributes: { "data-slot": "empty" } }, ngImport: i0 });
|
|
12
12
|
}
|
|
13
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
13
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmpty, decorators: [{
|
|
14
14
|
type: Directive,
|
|
15
15
|
args: [{
|
|
16
16
|
selector: '[hlmEmpty],hlm-empty',
|
|
@@ -20,12 +20,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
20
20
|
|
|
21
21
|
class HlmEmptyContent {
|
|
22
22
|
constructor() {
|
|
23
|
-
classes(() =>
|
|
23
|
+
classes(() => "gap-4 text-sm flex w-full max-w-sm min-w-0 flex-col items-center text-balance");
|
|
24
24
|
}
|
|
25
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
26
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.
|
|
25
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
26
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: HlmEmptyContent, isStandalone: true, selector: "[hlmEmptyContent],hlm-empty-content", host: { attributes: { "data-slot": "empty-content" } }, ngImport: i0 });
|
|
27
27
|
}
|
|
28
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
28
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyContent, decorators: [{
|
|
29
29
|
type: Directive,
|
|
30
30
|
args: [{
|
|
31
31
|
selector: '[hlmEmptyContent],hlm-empty-content',
|
|
@@ -35,12 +35,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
35
35
|
|
|
36
36
|
class HlmEmptyDescription {
|
|
37
37
|
constructor() {
|
|
38
|
-
classes(() =>
|
|
38
|
+
classes(() => "text-sm/relaxed text-muted-foreground [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4");
|
|
39
39
|
}
|
|
40
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
41
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.
|
|
40
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyDescription, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
41
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: HlmEmptyDescription, isStandalone: true, selector: "[hlmEmptyDescription]", host: { attributes: { "data-slot": "empty-description" } }, ngImport: i0 });
|
|
42
42
|
}
|
|
43
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
43
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyDescription, decorators: [{
|
|
44
44
|
type: Directive,
|
|
45
45
|
args: [{
|
|
46
46
|
selector: '[hlmEmptyDescription]',
|
|
@@ -50,12 +50,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
50
50
|
|
|
51
51
|
class HlmEmptyHeader {
|
|
52
52
|
constructor() {
|
|
53
|
-
classes(() =>
|
|
53
|
+
classes(() => "gap-2 flex max-w-sm flex-col items-center");
|
|
54
54
|
}
|
|
55
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
56
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.
|
|
55
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
56
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: HlmEmptyHeader, isStandalone: true, selector: "[hlmEmptyHeader],hlm-empty-header", host: { attributes: { "data-slot": "empty-header" } }, ngImport: i0 });
|
|
57
57
|
}
|
|
58
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
58
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyHeader, decorators: [{
|
|
59
59
|
type: Directive,
|
|
60
60
|
args: [{
|
|
61
61
|
selector: '[hlmEmptyHeader],hlm-empty-header',
|
|
@@ -63,10 +63,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
63
63
|
}]
|
|
64
64
|
}], ctorParameters: () => [] });
|
|
65
65
|
|
|
66
|
-
const emptyMediaVariants = cva(
|
|
66
|
+
const emptyMediaVariants = cva("mb-2 flex shrink-0 items-center justify-center [&_ng-icon]:pointer-events-none [&_ng-icon]:shrink-0", {
|
|
67
67
|
variants: {
|
|
68
68
|
variant: {
|
|
69
|
-
default:
|
|
69
|
+
default: "bg-transparent",
|
|
70
70
|
icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_ng-icon:not([class*='text-'])]:text-[length:--spacing(6)]",
|
|
71
71
|
},
|
|
72
72
|
},
|
|
@@ -80,10 +80,10 @@ class HlmEmptyMedia {
|
|
|
80
80
|
constructor() {
|
|
81
81
|
classes(() => emptyMediaVariants({ variant: this.variant() }));
|
|
82
82
|
}
|
|
83
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
84
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.
|
|
83
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyMedia, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
84
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.3", type: HlmEmptyMedia, isStandalone: true, selector: "[hlmEmptyMedia],hlm-empty-media", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "empty-media" }, properties: { "attr.data-variant": "variant()" } }, ngImport: i0 });
|
|
85
85
|
}
|
|
86
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
86
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyMedia, decorators: [{
|
|
87
87
|
type: Directive,
|
|
88
88
|
args: [{
|
|
89
89
|
selector: '[hlmEmptyMedia],hlm-empty-media',
|
|
@@ -96,12 +96,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
96
96
|
|
|
97
97
|
class HlmEmptyTitle {
|
|
98
98
|
constructor() {
|
|
99
|
-
classes(() =>
|
|
99
|
+
classes(() => "text-lg font-medium tracking-tight");
|
|
100
100
|
}
|
|
101
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
102
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.
|
|
101
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyTitle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
102
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: HlmEmptyTitle, isStandalone: true, selector: "[hlmEmptyTitle]", host: { attributes: { "data-slot": "empty-title" } }, ngImport: i0 });
|
|
103
103
|
}
|
|
104
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
104
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyTitle, decorators: [{
|
|
105
105
|
type: Directive,
|
|
106
106
|
args: [{
|
|
107
107
|
selector: '[hlmEmptyTitle]',
|
|
@@ -121,8 +121,8 @@ const HlmEmptyImports = [
|
|
|
121
121
|
HlmEmptyMedia,
|
|
122
122
|
];
|
|
123
123
|
class HlmEmptyModule {
|
|
124
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
125
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.
|
|
124
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
125
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyModule, imports: [HlmEmpty,
|
|
126
126
|
HlmEmptyContent,
|
|
127
127
|
HlmEmptyDescription,
|
|
128
128
|
HlmEmptyHeader,
|
|
@@ -133,9 +133,9 @@ class HlmEmptyModule {
|
|
|
133
133
|
HlmEmptyHeader,
|
|
134
134
|
HlmEmptyTitle,
|
|
135
135
|
HlmEmptyMedia] });
|
|
136
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.
|
|
136
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyModule });
|
|
137
137
|
}
|
|
138
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
138
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmEmptyModule, decorators: [{
|
|
139
139
|
type: NgModule,
|
|
140
140
|
args: [{
|
|
141
141
|
imports: [...HlmEmptyImports],
|
|
@@ -148,4 +148,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
148
148
|
*/
|
|
149
149
|
|
|
150
150
|
export { HlmEmpty, HlmEmptyContent, HlmEmptyDescription, HlmEmptyHeader, HlmEmptyImports, HlmEmptyMedia, HlmEmptyModule, HlmEmptyTitle };
|
|
151
|
-
|
|
151
|
+
|