@egose/shadcn-theme-ng 0.1.0 → 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 +1 -1
- package/accordion/README.md +405 -2
- package/alert/README.md +372 -2
- package/alert-dialog/README.md +471 -5
- package/aspect-ratio/README.md +272 -5
- package/autocomplete/README.md +502 -2
- package/avatar/README.md +357 -5
- package/badge/README.md +318 -2
- package/basic-alert/README.md +353 -2
- package/breadcrumb/README.md +406 -5
- package/button/README.md +482 -2
- package/button/fesm2022/button.mjs +85 -107
- package/button/types/button.d.ts +5 -8
- package/button-group/README.md +318 -5
- package/calendar/README.md +357 -2
- package/card/README.md +331 -5
- package/carousel/README.md +333 -5
- package/carousel/fesm2022/carousel.mjs +4 -1
- package/checkbox/README.md +320 -2
- package/collapsible/README.md +332 -5
- package/combobox/README.md +507 -5
- package/combobox/fesm2022/combobox.mjs +4 -1
- package/command/README.md +435 -5
- package/confirmation-dialog/README.md +301 -2
- package/context-menu/README.md +366 -5
- package/date-picker/README.md +465 -2
- package/date-picker/fesm2022/date-picker.mjs +2 -2
- package/dialog/README.md +448 -2
- package/drawer/README.md +395 -5
- package/dropdown-menu/README.md +417 -5
- package/empty/README.md +329 -5
- package/field/README.md +385 -5
- package/form-checkbox/README.md +312 -2
- package/form-date-picker/README.md +322 -2
- package/form-field/README.md +356 -2
- package/form-field-simple/README.md +340 -2
- package/form-searchable-multiselect/README.md +361 -2
- package/form-select/README.md +350 -2
- package/form-text-input/README.md +371 -2
- package/form-textarea/README.md +347 -2
- package/hover-card/README.md +256 -5
- package/icon/README.md +239 -2
- package/input/README.md +269 -2
- package/input-group/README.md +335 -5
- package/input-group/fesm2022/input-group.mjs +3 -3
- package/input-otp/README.md +375 -5
- package/item/README.md +385 -5
- package/item/fesm2022/item.mjs +3 -3
- package/kbd/README.md +291 -5
- package/label/README.md +272 -2
- package/layout-simple/README.md +193 -2
- package/layout-simple/fesm2022/layout-simple.mjs +472 -236
- package/layout-simple/types/layout-simple.d.ts +174 -137
- package/menu/README.md +417 -2
- package/menubar/README.md +343 -5
- package/native-select/README.md +323 -5
- package/navigation-menu/README.md +369 -5
- package/package.json +1 -1
- package/pagination/README.md +388 -5
- package/popover/README.md +331 -2
- package/progress/README.md +311 -5
- package/radio-group/README.md +364 -2
- package/radio-group/fesm2022/radio-group.mjs +5 -1
- package/radio-group/types/radio-group.d.ts +1 -1
- package/resizable/README.md +269 -5
- package/scroll-area/README.md +233 -5
- package/searchable-multiselect/README.md +323 -2
- package/select/README.md +437 -2
- package/separator/README.md +222 -2
- package/sheet/README.md +311 -2
- package/sidebar/README.md +457 -5
- package/skeleton/README.md +217 -5
- package/slider/README.md +273 -5
- package/slider/fesm2022/slider.mjs +3 -3
- package/sonner/README.md +346 -2
- package/spinner/README.md +284 -2
- package/switch/README.md +310 -2
- package/table/README.md +423 -5
- package/tabs/README.md +411 -2
- package/tabs/fesm2022/tabs.mjs +2 -2
- package/textarea/README.md +282 -5
- package/toggle/README.md +270 -5
- package/toggle-group/README.md +340 -5
- package/tooltip/README.md +269 -2
- package/typography/README.md +271 -5
- package/typography/types/typography.d.ts +8 -8
- package/utils/README.md +303 -2
package/dropdown-menu/README.md
CHANGED
|
@@ -1,11 +1,423 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Dropdown Menu (`@egose/shadcn-theme-ng/dropdown-menu`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A dropdown action menu in the shadcn/ui DropdownMenu style: trigger button + floating panel with items, labels, separators, shortcuts, checkbox/radio items, groups, and nested sub-menus. Equivalent to shadcn/ui `DropdownMenu` (Radix).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The Angular implementation is a styling layer over the Angular CDK menu primitives (`CdkMenu`, `CdkMenuTrigger`, `CdkMenuItem`, `CdkMenuItemCheckbox`, `CdkMenuItemRadio`, `CdkMenuGroup`) plus position helpers (`createMenuPosition`, `MENU_SIDE`) and focus handling from `@spartan-ng/brain/core`. An internal `HlmDropdownMenuFocusOnHover` directive moves DOM focus on hover (Radix/shadcn behavior) and is applied automatically to every item type.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
> **Ships as:** `@egose/shadcn-theme-ng/dropdown-menu` and `@egose/shadcn-theme-ng-tw/dropdown-menu`
|
|
8
|
+
> (the `tw:`-prefixed Tailwind variant). Both expose the identical TypeScript surface; only the
|
|
9
|
+
> emitted Tailwind class strings differ. See the [package README](../../README.md) for install
|
|
10
|
+
> steps, peer dependencies, and Tailwind setup. Do not publish this project directory independently.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
8
13
|
|
|
9
14
|
```bash
|
|
10
|
-
|
|
15
|
+
# Plain Tailwind (no prefix)
|
|
16
|
+
npm install @egose/shadcn-theme-ng
|
|
17
|
+
|
|
18
|
+
# tw:-prefixed Tailwind variant
|
|
19
|
+
npm install @egose/shadcn-theme-ng-tw
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Peer dependencies (Angular, `@spartan-ng/brain`, `@ng-icons/*`, `rxjs`, …) are documented in the
|
|
23
|
+
[package README](../../README.md#peer-dependencies). This subpath additionally relies at runtime on
|
|
24
|
+
`@angular/cdk/menu`, `@egose/shadcn-theme-ng/utils`, and `@ng-icons/lucide` (check / chevron icons).
|
|
25
|
+
|
|
26
|
+
## Imports
|
|
27
|
+
|
|
28
|
+
All symbols are exported from the subpath root (`projects/dropdown-menu/src/public-api.ts`):
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import {
|
|
32
|
+
HlmDropdownMenu,
|
|
33
|
+
HlmDropdownMenuTrigger,
|
|
34
|
+
HlmDropdownMenuItem,
|
|
35
|
+
HlmDropdownMenuCheckbox,
|
|
36
|
+
HlmDropdownMenuCheckboxIndicator,
|
|
37
|
+
HlmDropdownMenuRadio,
|
|
38
|
+
HlmDropdownMenuRadioIndicator,
|
|
39
|
+
HlmDropdownMenuLabel,
|
|
40
|
+
HlmDropdownMenuSeparator,
|
|
41
|
+
HlmDropdownMenuShortcut,
|
|
42
|
+
HlmDropdownMenuGroup,
|
|
43
|
+
HlmDropdownMenuSub,
|
|
44
|
+
HlmDropdownMenuSubTrigger,
|
|
45
|
+
HlmDropdownMenuItemSubIndicator,
|
|
46
|
+
provideHlmDropdownMenuConfig,
|
|
47
|
+
injectHlmDropdownMenuConfig,
|
|
48
|
+
HlmDropdownMenuImports,
|
|
49
|
+
HlmDropdownMenuModule,
|
|
50
|
+
} from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
51
|
+
// tw variant: replace with '@egose/shadcn-theme-ng-tw/dropdown-menu'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Standalone component — spread the `*Imports` array:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { Component } from '@angular/core';
|
|
58
|
+
import { HlmDropdownMenuImports } from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
59
|
+
|
|
60
|
+
@Component({
|
|
61
|
+
selector: 'app-demo',
|
|
62
|
+
standalone: true,
|
|
63
|
+
imports: [...HlmDropdownMenuImports],
|
|
64
|
+
template: `...`,
|
|
65
|
+
})
|
|
66
|
+
export class DemoComponent {}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
NgModule-based consumer — import the module:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { NgModule } from '@angular/core';
|
|
73
|
+
import { HlmDropdownMenuModule } from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
74
|
+
|
|
75
|
+
@NgModule({ imports: [HlmDropdownMenuModule] })
|
|
76
|
+
export class DemoModule {}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Anatomy / Structure
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<button hlmBtn variant="outline" [hlmDropdownMenuTrigger]="menu">Open</button>
|
|
83
|
+
|
|
84
|
+
<ng-template #menu>
|
|
85
|
+
<div hlmDropdownMenu>
|
|
86
|
+
<div hlmDropdownMenuLabel>My Account</div>
|
|
87
|
+
<div hlmDropdownMenuSeparator></div>
|
|
88
|
+
<div hlmDropdownMenuGroup>
|
|
89
|
+
<button hlmDropdownMenuItem (triggered)="profile()">
|
|
90
|
+
Profile
|
|
91
|
+
<span hlmDropdownMenuShortcut>⇧⌘P</span>
|
|
92
|
+
</button>
|
|
93
|
+
<button hlmDropdownMenuItem variant="destructive" (triggered)="logout()">Log out</button>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</ng-template>
|
|
11
97
|
```
|
|
98
|
+
|
|
99
|
+
Real selectors (from source):
|
|
100
|
+
|
|
101
|
+
| Class | Selector(s) | Kind |
|
|
102
|
+
| ---------------------------------- | ---------------------------------------------------------- | ----------------------------------- |
|
|
103
|
+
| `HlmDropdownMenu` | `[hlmDropdownMenu], hlm-dropdown-menu` | Directive (hosts `CdkMenu`) |
|
|
104
|
+
| `HlmDropdownMenuTrigger` | `[hlmDropdownMenuTrigger]` | Directive (hosts `CdkMenuTrigger`) |
|
|
105
|
+
| `HlmDropdownMenuItem` | `[hlmDropdownMenuItem], hlm-dropdown-menu-item` | Directive (hosts `CdkMenuItem`) |
|
|
106
|
+
| `HlmDropdownMenuCheckbox` | `[hlmDropdownMenuCheckbox], [hlmDropdownMenuCheckboxItem]` | Directive (hosts checkbox CDK item) |
|
|
107
|
+
| `HlmDropdownMenuCheckboxIndicator` | `hlm-dropdown-menu-checkbox-indicator` | Component (`lucideCheck`) |
|
|
108
|
+
| `HlmDropdownMenuRadio` | `[hlmDropdownMenuRadio]` | Directive (hosts radio CDK item) |
|
|
109
|
+
| `HlmDropdownMenuRadioIndicator` | `hlm-dropdown-menu-radio-indicator` | Component (`lucideCheck`) |
|
|
110
|
+
| `HlmDropdownMenuLabel` | `[hlmDropdownMenuLabel], hlm-dropdown-menu-label` | Directive |
|
|
111
|
+
| `HlmDropdownMenuSeparator` | `[hlmDropdownMenuSeparator], hlm-dropdown-menu-separator` | Directive |
|
|
112
|
+
| `HlmDropdownMenuShortcut` | `[hlmDropdownMenuShortcut], hlm-dropdown-menu-shortcut` | Directive |
|
|
113
|
+
| `HlmDropdownMenuGroup` | `[hlmDropdownMenuGroup], hlm-dropdown-menu-group` | Directive (hosts `CdkMenuGroup`) |
|
|
114
|
+
| `HlmDropdownMenuSub` | `[hlmDropdownMenuSub], hlm-dropdown-menu-sub` | Directive (nested `CdkMenu`) |
|
|
115
|
+
| `HlmDropdownMenuSubTrigger` | `[hlmDropdownMenuSubTrigger]` | Directive (hosts `CdkMenuTrigger`) |
|
|
116
|
+
| `HlmDropdownMenuItemSubIndicator` | `hlm-dropdown-menu-item-sub-indicator` | Component (`lucideChevronRight`) |
|
|
117
|
+
|
|
118
|
+
## API reference
|
|
119
|
+
|
|
120
|
+
### `HlmDropdownMenu` — `[hlmDropdownMenu], hlm-dropdown-menu`
|
|
121
|
+
|
|
122
|
+
Menu panel. Hosts `CdkMenu`. Place inside an `ng-template` referenced by the trigger.
|
|
123
|
+
|
|
124
|
+
| Input | Type | Default | Description |
|
|
125
|
+
| ------------ | -------- | ------- | ------------------------------------------------ |
|
|
126
|
+
| `sideOffset` | `number` | `1` | Gap (`--side-offset`) between trigger and panel. |
|
|
127
|
+
|
|
128
|
+
Host exposes `data-state`, `data-side`, and animation classes derived from the trigger's resolved position.
|
|
129
|
+
|
|
130
|
+
### `HlmDropdownMenuTrigger` — `[hlmDropdownMenuTrigger]`
|
|
131
|
+
|
|
132
|
+
| Input | Type | Default | Description |
|
|
133
|
+
| ------- | ----------- | ------------------- | --------------------- |
|
|
134
|
+
| `align` | `MenuAlign` | config (`'start'`) | Horizontal alignment. |
|
|
135
|
+
| `side` | `MenuSide` | config (`'bottom'`) | Preferred side. |
|
|
136
|
+
|
|
137
|
+
CDK bindings (via `hostDirectives`): `cdkMenuTriggerFor: hlmDropdownMenuTrigger` (the `ng-template`), `cdkMenuTriggerData: hlmDropdownMenuTriggerData`; outputs `cdkMenuOpened: hlmDropdownMenuOpened`, `cdkMenuClosed: hlmDropdownMenuClosed`.
|
|
138
|
+
|
|
139
|
+
### `HlmDropdownMenuItem` — `[hlmDropdownMenuItem], hlm-dropdown-menu-item`
|
|
140
|
+
|
|
141
|
+
| Input | Type | Default | Description |
|
|
142
|
+
| ---------- | ---------------------------- | ----------- | ------------------------------------------------------------ |
|
|
143
|
+
| `disabled` | `boolean` | `false` | Disables the item (forwarded to `cdkMenuItemDisabled`). |
|
|
144
|
+
| `variant` | `'default' \| 'destructive'` | `'default'` | Destructive red styling. |
|
|
145
|
+
| `inset` | `boolean` | `false` | Indents content (`ps-8`), e.g. to align with checkable rows. |
|
|
146
|
+
|
|
147
|
+
Output `triggered` (forwarded from `cdkMenuItemTriggered`) fires on select.
|
|
148
|
+
|
|
149
|
+
### `HlmDropdownMenuCheckbox` — `[hlmDropdownMenuCheckbox], [hlmDropdownMenuCheckboxItem]`
|
|
150
|
+
|
|
151
|
+
Checkable row. Hosts an internal `HlmDropdownMenuCheckboxCdk extends CdkMenuItemCheckbox` (selector `[hlmDropdownMenuCheckboxCdk]`, internal — use the public selector instead).
|
|
152
|
+
|
|
153
|
+
| Input | Type | Default | Description |
|
|
154
|
+
| ---------- | --------- | ------- | ------------------------------------------------------------------------- |
|
|
155
|
+
| `disabled` | `boolean` | — | Forwarded to `cdkMenuItemDisabled`. |
|
|
156
|
+
| `checked` | `boolean` | — | Forwarded to `cdkMenuItemChecked`. Bind with `[checked]` + `(triggered)`. |
|
|
157
|
+
| `keepOpen` | `boolean` | `true` | Keep the menu open after toggling (CDK trigger override). |
|
|
158
|
+
| `inset` | `boolean` | `false` | Indentation. |
|
|
159
|
+
|
|
160
|
+
Pair with `<hlm-dropdown-menu-checkbox-indicator />` (check icon, shown when `data-checked`).
|
|
161
|
+
|
|
162
|
+
### `HlmDropdownMenuRadio` — `[hlmDropdownMenuRadio]`
|
|
163
|
+
|
|
164
|
+
Same contract as checkbox but single-select within its group (hosts `HlmDropdownMenuRadioCdk`, selector `[hlmDropdownMenuRadioCdk]`, internal). Inputs: `disabled`, `checked`, `keepOpen` (default `true`). Pair with `<hlm-dropdown-menu-radio-indicator />`.
|
|
165
|
+
|
|
166
|
+
### Label / separator / shortcut / group
|
|
167
|
+
|
|
168
|
+
| Class | Inputs | Notes |
|
|
169
|
+
| -------------------------- | ------------------------------------ | ----------------------------------------------------------- |
|
|
170
|
+
| `HlmDropdownMenuLabel` | `inset` (`boolean`, default `false`) | Muted section heading. |
|
|
171
|
+
| `HlmDropdownMenuSeparator` | — | Hairline divider. |
|
|
172
|
+
| `HlmDropdownMenuShortcut` | — | Right-aligned kbd hint; place inside an item. |
|
|
173
|
+
| `HlmDropdownMenuGroup` | — | Hosts `CdkMenuGroup` for labelled sections / radio scoping. |
|
|
174
|
+
|
|
175
|
+
### Sub-menus
|
|
176
|
+
|
|
177
|
+
| Class | Inputs | Notes |
|
|
178
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
|
|
179
|
+
| `HlmDropdownMenuSubTrigger` | `align`, `side` (config defaults); CDK `hlmDropdownMenuSubTrigger` (template), `hlmDropdownMenuTriggerData`; outputs `hlmDropdownMenuSubOpened/Closed` | Row that opens a nested menu. Include `<hlm-dropdown-menu-item-sub-indicator />` chevron. |
|
|
180
|
+
| `HlmDropdownMenuSub` | — | Nested panel inside the sub-template. |
|
|
181
|
+
|
|
182
|
+
### Config
|
|
183
|
+
|
|
184
|
+
`HlmDropdownMenuConfig = { align: MenuAlign; side: MenuSide }`, defaults `{ align: 'start', side: 'bottom' }`. Override globally with `provideHlmDropdownMenuConfig({ align, side })`, read with `injectHlmDropdownMenuConfig()`.
|
|
185
|
+
|
|
186
|
+
## Examples
|
|
187
|
+
|
|
188
|
+
### 1. Basic account menu
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { Component } from '@angular/core';
|
|
192
|
+
import { HlmDropdownMenuImports } from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
193
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
194
|
+
|
|
195
|
+
@Component({
|
|
196
|
+
selector: 'app-account-menu',
|
|
197
|
+
standalone: true,
|
|
198
|
+
imports: [...HlmDropdownMenuImports, HlmButton],
|
|
199
|
+
template: `
|
|
200
|
+
<button hlmBtn variant="outline" [hlmDropdownMenuTrigger]="menu">Open</button>
|
|
201
|
+
<ng-template #menu>
|
|
202
|
+
<div hlmDropdownMenu>
|
|
203
|
+
<div hlmDropdownMenuLabel>My Account</div>
|
|
204
|
+
<div hlmDropdownMenuSeparator></div>
|
|
205
|
+
<button hlmDropdownMenuItem (triggered)="go('profile')">Profile</button>
|
|
206
|
+
<button hlmDropdownMenuItem (triggered)="go('billing')">Billing</button>
|
|
207
|
+
<button hlmDropdownMenuItem variant="destructive" (triggered)="go('logout')">Log out</button>
|
|
208
|
+
</div>
|
|
209
|
+
</ng-template>
|
|
210
|
+
`,
|
|
211
|
+
})
|
|
212
|
+
export class AccountMenuComponent {
|
|
213
|
+
go(where: string) {
|
|
214
|
+
console.log(where);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### 2. Shortcuts, inset, and disabled items
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
import { Component } from '@angular/core';
|
|
223
|
+
import { HlmDropdownMenuImports } from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
224
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
225
|
+
|
|
226
|
+
@Component({
|
|
227
|
+
selector: 'app-shortcuts',
|
|
228
|
+
standalone: true,
|
|
229
|
+
imports: [...HlmDropdownMenuImports, HlmButton],
|
|
230
|
+
template: `
|
|
231
|
+
<button hlmBtn variant="outline" [hlmDropdownMenuTrigger]="menu">Edit</button>
|
|
232
|
+
<ng-template #menu>
|
|
233
|
+
<div hlmDropdownMenu>
|
|
234
|
+
<div hlmDropdownMenuLabel inset>Editor</div>
|
|
235
|
+
<button hlmDropdownMenuItem inset (triggered)="noop('undo')">
|
|
236
|
+
Undo <span hlmDropdownMenuShortcut>⌘Z</span>
|
|
237
|
+
</button>
|
|
238
|
+
<button hlmDropdownMenuItem inset (triggered)="noop('redo')">
|
|
239
|
+
Redo <span hlmDropdownMenuShortcut>⇧⌘Z</span>
|
|
240
|
+
</button>
|
|
241
|
+
<div hlmDropdownMenuSeparator></div>
|
|
242
|
+
<button hlmDropdownMenuItem inset disabled>Cut (disabled)</button>
|
|
243
|
+
</div>
|
|
244
|
+
</ng-template>
|
|
245
|
+
`,
|
|
246
|
+
})
|
|
247
|
+
export class ShortcutsComponent {
|
|
248
|
+
noop(what: string) {
|
|
249
|
+
console.log(what);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### 3. Checkbox filters (keep-open toggles)
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
import { Component, signal } from '@angular/core';
|
|
258
|
+
import { HlmDropdownMenuImports } from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
259
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
260
|
+
|
|
261
|
+
@Component({
|
|
262
|
+
selector: 'app-filters',
|
|
263
|
+
standalone: true,
|
|
264
|
+
imports: [...HlmDropdownMenuImports, HlmButton],
|
|
265
|
+
template: `
|
|
266
|
+
<button hlmBtn variant="outline" [hlmDropdownMenuTrigger]="menu">Filter</button>
|
|
267
|
+
<ng-template #menu>
|
|
268
|
+
<div hlmDropdownMenu>
|
|
269
|
+
<div hlmDropdownMenuLabel>Show</div>
|
|
270
|
+
<button hlmDropdownMenuCheckbox [checked]="open()" (triggered)="open.set(!open())">
|
|
271
|
+
Open issues
|
|
272
|
+
<hlm-dropdown-menu-checkbox-indicator />
|
|
273
|
+
</button>
|
|
274
|
+
<button hlmDropdownMenuCheckbox [checked]="closed()" (triggered)="closed.set(!closed())">
|
|
275
|
+
Closed issues
|
|
276
|
+
<hlm-dropdown-menu-checkbox-indicator />
|
|
277
|
+
</button>
|
|
278
|
+
</div>
|
|
279
|
+
</ng-template>
|
|
280
|
+
<p class="tw:text-sm">open={{ open() }} closed={{ closed() }}</p>
|
|
281
|
+
`,
|
|
282
|
+
})
|
|
283
|
+
export class FiltersComponent {
|
|
284
|
+
readonly open = signal(true);
|
|
285
|
+
readonly closed = signal(false);
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 4. Radio sort order
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
import { Component, signal } from '@angular/core';
|
|
293
|
+
import { HlmDropdownMenuImports } from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
294
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
295
|
+
|
|
296
|
+
@Component({
|
|
297
|
+
selector: 'app-sort',
|
|
298
|
+
standalone: true,
|
|
299
|
+
imports: [...HlmDropdownMenuImports, HlmButton],
|
|
300
|
+
template: `
|
|
301
|
+
<button hlmBtn variant="outline" [hlmDropdownMenuTrigger]="menu">Sort: {{ order() }}</button>
|
|
302
|
+
<ng-template #menu>
|
|
303
|
+
<div hlmDropdownMenu>
|
|
304
|
+
<div hlmDropdownMenuGroup>
|
|
305
|
+
<div hlmDropdownMenuLabel>Sort by</div>
|
|
306
|
+
@for (opt of options; track opt) {
|
|
307
|
+
<button hlmDropdownMenuRadio [checked]="order() === opt" (triggered)="order.set(opt)">
|
|
308
|
+
{{ opt }}
|
|
309
|
+
<hlm-dropdown-menu-radio-indicator />
|
|
310
|
+
</button>
|
|
311
|
+
}
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
</ng-template>
|
|
315
|
+
`,
|
|
316
|
+
})
|
|
317
|
+
export class SortComponent {
|
|
318
|
+
readonly options = ['Newest', 'Oldest', 'Most starred'] as const;
|
|
319
|
+
readonly order = signal<(typeof this.options)[number]>('Newest');
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### 5. Nested sub-menu
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
import { Component } from '@angular/core';
|
|
327
|
+
import { HlmDropdownMenuImports } from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
328
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
329
|
+
|
|
330
|
+
@Component({
|
|
331
|
+
selector: 'app-submenu',
|
|
332
|
+
standalone: true,
|
|
333
|
+
imports: [...HlmDropdownMenuImports, HlmButton],
|
|
334
|
+
template: `
|
|
335
|
+
<button hlmBtn variant="outline" [hlmDropdownMenuTrigger]="menu">Share</button>
|
|
336
|
+
<ng-template #menu>
|
|
337
|
+
<div hlmDropdownMenu>
|
|
338
|
+
<button hlmDropdownMenuItem (triggered)="copy()">Copy link</button>
|
|
339
|
+
<button hlmDropdownMenuSubTrigger [hlmDropdownMenuSubTrigger]="invite">
|
|
340
|
+
Invite users
|
|
341
|
+
<hlm-dropdown-menu-item-sub-indicator />
|
|
342
|
+
</button>
|
|
343
|
+
</div>
|
|
344
|
+
</ng-template>
|
|
345
|
+
<ng-template #invite>
|
|
346
|
+
<div hlmDropdownMenuSub>
|
|
347
|
+
<button hlmDropdownMenuItem (triggered)="inviteBy('email')">Email</button>
|
|
348
|
+
<button hlmDropdownMenuItem (triggered)="inviteBy('sms')">SMS</button>
|
|
349
|
+
</div>
|
|
350
|
+
</ng-template>
|
|
351
|
+
`,
|
|
352
|
+
})
|
|
353
|
+
export class SubmenuComponent {
|
|
354
|
+
copy() {
|
|
355
|
+
console.log('copied');
|
|
356
|
+
}
|
|
357
|
+
inviteBy(channel: string) {
|
|
358
|
+
console.log(channel);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 6. Async data menu + global position config
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
import { Component, inject, signal } from '@angular/core';
|
|
367
|
+
import { HlmDropdownMenuImports, provideHlmDropdownMenuConfig } from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
368
|
+
import { HlmButton } from '@egose/shadcn-theme-ng/button';
|
|
369
|
+
|
|
370
|
+
@Component({
|
|
371
|
+
selector: 'app-async-menu',
|
|
372
|
+
standalone: true,
|
|
373
|
+
imports: [...HlmDropdownMenuImports, HlmButton],
|
|
374
|
+
providers: [provideHlmDropdownMenuConfig({ align: 'end', side: 'bottom' })],
|
|
375
|
+
template: `
|
|
376
|
+
<button hlmBtn variant="outline" [hlmDropdownMenuTrigger]="menu" (click)="load()">Projects</button>
|
|
377
|
+
<ng-template #menu>
|
|
378
|
+
<div hlmDropdownMenu>
|
|
379
|
+
<div hlmDropdownMenuLabel>Recent</div>
|
|
380
|
+
@if (loading()) {
|
|
381
|
+
<button hlmDropdownMenuItem disabled>Loading…</button>
|
|
382
|
+
}
|
|
383
|
+
@for (p of projects(); track p) {
|
|
384
|
+
<button hlmDropdownMenuItem (triggered)="open(p)">{{ p }}</button>
|
|
385
|
+
}
|
|
386
|
+
</div>
|
|
387
|
+
</ng-template>
|
|
388
|
+
`,
|
|
389
|
+
})
|
|
390
|
+
export class AsyncMenuComponent {
|
|
391
|
+
readonly projects = signal<string[]>([]);
|
|
392
|
+
readonly loading = signal(false);
|
|
393
|
+
load() {
|
|
394
|
+
if (this.projects().length || this.loading()) return;
|
|
395
|
+
this.loading.set(true);
|
|
396
|
+
setTimeout(() => {
|
|
397
|
+
this.projects.set(['website', 'mobile', 'docs']);
|
|
398
|
+
this.loading.set(false);
|
|
399
|
+
}, 600);
|
|
400
|
+
}
|
|
401
|
+
open(p: string) {
|
|
402
|
+
console.log('open', p);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Accessibility notes
|
|
408
|
+
|
|
409
|
+
- Triggers are native buttons hosting `CdkMenuTrigger`: enter/space/arrows open the menu, escape closes, and focus returns to the trigger.
|
|
410
|
+
- Items are `CdkMenuItem`s with roving focus: arrows move, typeahead jumps, enter/space activates. `disabled` items are skipped.
|
|
411
|
+
- Checkbox/radio rows expose checked state via `data-checked` + icon indicators; screen readers announce them as menu item checkboxes/radios through the CDK roles.
|
|
412
|
+
- Hover moves focus (`HlmDropdownMenuFocusOnHover`) so pointer and keyboard highlight stay in sync — do not add competing `mouseenter` focus handlers.
|
|
413
|
+
|
|
414
|
+
## Theming / CSS variables
|
|
415
|
+
|
|
416
|
+
No component-specific CSS variables. Panel, item, and indicator styling derives from global tokens (`--popover`, `--accent`, `--muted`, `--destructive`, …) with `data-state` / `data-side` / `data-variant` / `data-checked` hooks for custom CSS. Tune placement globally via `provideHlmDropdownMenuConfig`.
|
|
417
|
+
|
|
418
|
+
## Related subpaths
|
|
419
|
+
|
|
420
|
+
- `@egose/shadcn-theme-ng/context-menu` — right-click variant of the same CDK menu system.
|
|
421
|
+
- `@egose/shadcn-theme-ng/menubar` — menubar with the same item/label/separator vocabulary.
|
|
422
|
+
- `@egose/shadcn-theme-ng/popover` — generic floating panel alternative for non-menu content.
|
|
423
|
+
- `@egose/shadcn-theme-ng/button` — `hlmBtn` trigger styling.
|