@egose/shadcn-theme-ng-tw 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/button-group/fesm2022/button-group.mjs +1 -1
- 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 +877 -409
- 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/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 +17 -13
- 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 +12 -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/utils/README.md +303 -2
package/menu/README.md
CHANGED
|
@@ -1,3 +1,418 @@
|
|
|
1
|
-
# Menu
|
|
1
|
+
# Menu (`@egose/shadcn-theme-ng/menu`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Headless menu building blocks (CDK `CdkMenu` family) with shadcn styling: container, bar, items, checkbox/radio items, indicators, labels, separators, shortcuts, and sub-menus. This is the styling/behavior layer underneath `dropdown-menu`, `context-menu`, and `menubar` — use it directly when you need a custom menu surface (e.g. an always-visible `hlm-menu-bar` toolbar or a CDK-triggered floating menu) rather than one of the opinionated wrappers.
|
|
4
|
+
|
|
5
|
+
Ships as `@egose/shadcn-theme-ng/menu` and `@egose/shadcn-theme-ng-tw/menu` (tw: variant). See the [package README](../../README.md) for installation, peer dependencies, Tailwind setup, and testing. Do not publish this project directory independently.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Plain Tailwind (no prefix):
|
|
11
|
+
npm install @egose/shadcn-theme-ng
|
|
12
|
+
|
|
13
|
+
# Or the tw:-prefixed variant:
|
|
14
|
+
npm install @egose/shadcn-theme-ng-tw
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Peer dependencies are inherited from the package root (see [package README](../../README.md)). This subpath itself declares `@angular/common`, `@angular/core` as peers plus a `tslib` runtime dependency; at runtime it also uses `@angular/cdk/menu` and `@egose/shadcn-theme-ng/icon` / `.../utils`. No extra install step is needed beyond the package install above.
|
|
18
|
+
|
|
19
|
+
## Imports
|
|
20
|
+
|
|
21
|
+
Real exported symbols (from `src/public-api.ts`):
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import {
|
|
25
|
+
HlmMenu,
|
|
26
|
+
HlmSubMenu,
|
|
27
|
+
HlmMenuBar,
|
|
28
|
+
HlmMenuBarItem,
|
|
29
|
+
HlmMenuGroup,
|
|
30
|
+
HlmMenuItem,
|
|
31
|
+
HlmMenuItemCheck,
|
|
32
|
+
HlmMenuItemCheckbox,
|
|
33
|
+
HlmMenuItemIcon,
|
|
34
|
+
HlmMenuItemRadio,
|
|
35
|
+
HlmMenuItemRadioIndicator,
|
|
36
|
+
HlmMenuItemSubIndicator,
|
|
37
|
+
HlmMenuLabel,
|
|
38
|
+
HlmMenuSeparator,
|
|
39
|
+
HlmMenuShortcut,
|
|
40
|
+
menuVariants, // cva variants for HlmMenu
|
|
41
|
+
HlmMenuItemImports, // items + icons + checks + shortcuts
|
|
42
|
+
HlmMenuStructureImports, // [HlmMenuLabel, HlmMenuSeparator]
|
|
43
|
+
HlmMenuImports, // item + structure + HlmMenu + HlmSubMenu
|
|
44
|
+
HlmMenuBarImports, // HlmMenuImports + HlmMenuBar + HlmMenuBarItem
|
|
45
|
+
HlmMenuItemModule,
|
|
46
|
+
HlmMenuModule,
|
|
47
|
+
HlmMenuBarModule,
|
|
48
|
+
} from '@egose/shadcn-theme-ng/menu';
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Standalone usage (full bar):
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { Component } from '@angular/core';
|
|
55
|
+
import { HlmMenuBarImports } from '@egose/shadcn-theme-ng/menu';
|
|
56
|
+
|
|
57
|
+
@Component({
|
|
58
|
+
selector: 'app-demo',
|
|
59
|
+
standalone: true,
|
|
60
|
+
imports: [...HlmMenuBarImports],
|
|
61
|
+
template: `
|
|
62
|
+
<hlm-menu-bar>
|
|
63
|
+
<button hlmMenuBarItem>File</button>
|
|
64
|
+
</hlm-menu-bar>
|
|
65
|
+
`,
|
|
66
|
+
})
|
|
67
|
+
export class DemoComponent {}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Standalone usage (floating menu only):
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { HlmMenuImports } from '@egose/shadcn-theme-ng/menu';
|
|
74
|
+
|
|
75
|
+
@Component({
|
|
76
|
+
standalone: true,
|
|
77
|
+
imports: [...HlmMenuImports],
|
|
78
|
+
template: `
|
|
79
|
+
<hlm-menu>
|
|
80
|
+
<hlm-menu-label>Actions</hlm-menu-label>
|
|
81
|
+
<button hlmMenuItem>Edit</button>
|
|
82
|
+
</hlm-menu>
|
|
83
|
+
`,
|
|
84
|
+
})
|
|
85
|
+
export class MenuOnlyComponent {}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
NgModule usage:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { NgModule } from '@angular/core';
|
|
92
|
+
import { HlmMenuModule, HlmMenuBarModule, HlmMenuItemModule } from '@egose/shadcn-theme-ng/menu';
|
|
93
|
+
|
|
94
|
+
@NgModule({ imports: [HlmMenuModule, HlmMenuBarModule, HlmMenuItemModule] })
|
|
95
|
+
export class DemoModule {}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
For the `tw:` build, swap the specifier to `@egose/shadcn-theme-ng-tw/menu`. Symbol names are identical.
|
|
99
|
+
|
|
100
|
+
## Anatomy / Structure
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<!-- Static bar -->
|
|
104
|
+
<hlm-menu-bar>
|
|
105
|
+
<button hlmMenuBarItem [cdkMenuTriggerFor]="fileMenu">File</button>
|
|
106
|
+
</hlm-menu-bar>
|
|
107
|
+
|
|
108
|
+
<!-- Floating menu (anchored via CDK trigger) -->
|
|
109
|
+
<ng-template #fileMenu>
|
|
110
|
+
<hlm-menu variant="default">
|
|
111
|
+
<hlm-menu-label>File</hlm-menu-label>
|
|
112
|
+
<button hlmMenuItem>
|
|
113
|
+
<ng-icon hlmMenuIcon name="lucidePencil" />
|
|
114
|
+
Rename
|
|
115
|
+
<hlm-menu-shortcut>⌘R</hlm-menu-shortcut>
|
|
116
|
+
</button>
|
|
117
|
+
<button hlmMenuItem variant="destructive">Delete</button>
|
|
118
|
+
<hlm-menu-separator />
|
|
119
|
+
<hlm-menu-group>
|
|
120
|
+
<button hlmMenuItemCheckbox>
|
|
121
|
+
<hlm-menu-item-check />
|
|
122
|
+
Word wrap
|
|
123
|
+
</button>
|
|
124
|
+
<button hlmMenuItemRadio>
|
|
125
|
+
<hlm-menu-item-radio />
|
|
126
|
+
Option A
|
|
127
|
+
</button>
|
|
128
|
+
</hlm-menu-group>
|
|
129
|
+
<button hlmMenuItem>
|
|
130
|
+
More
|
|
131
|
+
<hlm-menu-item-sub-indicator />
|
|
132
|
+
</button>
|
|
133
|
+
</hlm-menu>
|
|
134
|
+
</ng-template>
|
|
135
|
+
|
|
136
|
+
<hlm-sub-menu><!-- nested submenu surface --></hlm-sub-menu>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
| Class | Selector | Element | Role |
|
|
140
|
+
| --------------------------- | ----------------------------- | ------------------------------ | ---------------------------------------------- |
|
|
141
|
+
| `HlmMenu` | `hlm-menu` | component | Floating menu surface (`CdkMenu`) |
|
|
142
|
+
| `HlmSubMenu` | `hlm-sub-menu` | component | Nested submenu surface (`CdkMenu`) |
|
|
143
|
+
| `HlmMenuBar` | `hlm-menu-bar` | component | Static bar (`CdkMenuBar`) |
|
|
144
|
+
| `HlmMenuBarItem` | `[hlmMenuBarItem]` | any (usually `<button>`) | Bar item (`CdkMenuItem`) |
|
|
145
|
+
| `HlmMenuItem` | `[hlmMenuItem]` | any (usually `<button>`/`<a>`) | Menu row (`CdkMenuItem`) |
|
|
146
|
+
| `HlmMenuGroup` | `hlm-menu-group` | component | Grouping (`CdkMenuGroup`) |
|
|
147
|
+
| `HlmMenuLabel` | `hlm-menu-label` | component | Section heading |
|
|
148
|
+
| `HlmMenuSeparator` | `hlm-menu-separator` | component | Divider |
|
|
149
|
+
| `HlmMenuShortcut` | `hlm-menu-shortcut` | component | Right-aligned hint text |
|
|
150
|
+
| `HlmMenuItemIcon` | `[hlmMenuIcon]` | icon host | Leading-icon sizing (`sm` icon config) |
|
|
151
|
+
| `HlmMenuItemCheckbox` | `[hlmMenuItemCheckbox]` | any | Checkable row (`CdkMenuItemCheckbox`) |
|
|
152
|
+
| `HlmMenuItemRadio` | `[hlmMenuItemRadio]` | any | Radio row (`CdkMenuItemRadio`) |
|
|
153
|
+
| `HlmMenuItemCheck` | `hlm-menu-item-check` | component | Check glyph (shows when parent has `.checked`) |
|
|
154
|
+
| `HlmMenuItemRadioIndicator` | `hlm-menu-item-radio` (!) | component | Dot glyph (shows when parent has `.checked`) |
|
|
155
|
+
| `HlmMenuItemSubIndicator` | `hlm-menu-item-sub-indicator` | component | Chevron-right for submenu parents |
|
|
156
|
+
|
|
157
|
+
> API surprise: the radio indicator's selector is `hlm-menu-item-radio` while its class is `HlmMenuItemRadioIndicator`. The attribute directive `[hlmMenuItemRadio]` (class `HlmMenuItemRadio`) is the _row_; the element `<hlm-menu-item-radio>` is the _dot_. Read selectors carefully when composing radio rows.
|
|
158
|
+
|
|
159
|
+
CDK passthroughs (via `hostDirectives`): `HlmMenuItem` forwards `cdkMenuItemDisabled: disabled` input and `cdkMenuItemTriggered: triggered` output; checkbox/radio variants forward `disabled`/`checked` inputs and `triggered` outputs. `menuVariants` exposes `variant: 'default' | 'menubar'` (`default` adds `my-0.5`, `menubar` adds `my-2`).
|
|
160
|
+
|
|
161
|
+
## API reference
|
|
162
|
+
|
|
163
|
+
| Selector | Inputs | Notes |
|
|
164
|
+
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
165
|
+
| `hlm-menu` (`HlmMenu`) | `variant: 'default' \| 'menubar'` (default `'default'`), `class` | `menuVariants({ variant })` merged with `class` |
|
|
166
|
+
| `hlm-sub-menu` (`HlmSubMenu`) | `class` | Static popover-look surface |
|
|
167
|
+
| `hlm-menu-bar` (`HlmMenuBar`) | `class` | `h-9` bar, `rounded-md border shadow-xs` |
|
|
168
|
+
| `[hlmMenuBarItem]` | `class` | Forwards full `CdkMenuItem` API via host directive |
|
|
169
|
+
| `[hlmMenuItem]` | `variant: 'default' \| 'destructive'` (default `'default'`), `inset: boolean` (default `false`), `class`; CDK `disabled` input + `triggered` output | `data-variant` / `data-inset` reflected; `inset` adds `pl-8` for icon-less alignment |
|
|
170
|
+
| `hlm-menu-label` | `inset: boolean` (default `false`), `class` | `data-inset` reflected; semibold section text |
|
|
171
|
+
| `hlm-menu-separator` | `class` | `h-px bg-border` |
|
|
172
|
+
| `hlm-menu-shortcut` | `class` | `ml-auto text-xs tracking-widest text-muted-foreground` |
|
|
173
|
+
| `[hlmMenuIcon]` | `class` | Provides `sm` icon config; adds `mr-2` |
|
|
174
|
+
| `[hlmMenuItemCheckbox]` / `[hlmMenuItemRadio]` | `class`; CDK `disabled`/`checked` inputs, `triggered` output | Rows reserve `pl-8` for the indicator |
|
|
175
|
+
| `hlm-menu-item-check` | `class` | Check icon; `opacity-0` until ancestor has `.checked` |
|
|
176
|
+
| `hlm-menu-item-radio` (indicator) | `class` | Dot icon; same `.checked` reveal rule |
|
|
177
|
+
| `hlm-menu-item-sub-indicator` | `class` | Chevron-right, `ml-auto size-4` |
|
|
178
|
+
| `hlm-menu-group` | — | `CdkMenuGroup` only |
|
|
179
|
+
|
|
180
|
+
Every `class` input above is `input<ClassValue>('', { alias: 'class' })` merged after the base classes via `hlm()`.
|
|
181
|
+
|
|
182
|
+
## Examples
|
|
183
|
+
|
|
184
|
+
### 1. Static menu bar + floating menu (CDK triggers)
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { Component } from '@angular/core';
|
|
188
|
+
import { CdkMenuTrigger, CdkMenuModule } from '@angular/cdk/menu';
|
|
189
|
+
import { HlmMenuBarImports } from '@egose/shadcn-theme-ng/menu';
|
|
190
|
+
|
|
191
|
+
@Component({
|
|
192
|
+
selector: 'app-menu-bar',
|
|
193
|
+
standalone: true,
|
|
194
|
+
imports: [CdkMenuModule, CdkMenuTrigger, ...HlmMenuBarImports],
|
|
195
|
+
template: `
|
|
196
|
+
<hlm-menu-bar>
|
|
197
|
+
<button hlmMenuBarItem [cdkMenuTriggerFor]="fileTpl">File</button>
|
|
198
|
+
<button hlmMenuBarItem [cdkMenuTriggerFor]="editTpl">Edit</button>
|
|
199
|
+
</hlm-menu-bar>
|
|
200
|
+
|
|
201
|
+
<ng-template #fileTpl>
|
|
202
|
+
<hlm-menu>
|
|
203
|
+
<hlm-menu-label>File</hlm-menu-label>
|
|
204
|
+
<button hlmMenuItem (cdkMenuItemTriggered)="onNew()">New file</button>
|
|
205
|
+
<button hlmMenuItem>Open…</button>
|
|
206
|
+
<hlm-menu-separator />
|
|
207
|
+
<button hlmMenuItem variant="destructive" (cdkMenuItemTriggered)="onDelete()">Delete</button>
|
|
208
|
+
</hlm-menu>
|
|
209
|
+
</ng-template>
|
|
210
|
+
|
|
211
|
+
<ng-template #editTpl>
|
|
212
|
+
<hlm-menu>
|
|
213
|
+
<button hlmMenuItem>Undo</button>
|
|
214
|
+
<button hlmMenuItem>Redo</button>
|
|
215
|
+
</hlm-menu>
|
|
216
|
+
</ng-template>
|
|
217
|
+
`,
|
|
218
|
+
})
|
|
219
|
+
export class MenuBarComponent {
|
|
220
|
+
onNew(): void {
|
|
221
|
+
console.log('new file');
|
|
222
|
+
}
|
|
223
|
+
onDelete(): void {
|
|
224
|
+
console.log('delete');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### 2. Variants, inset, shortcuts, icons
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
import { Component } from '@angular/core';
|
|
233
|
+
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
234
|
+
import { lucidePencil, lucideTrash } from '@ng-icons/lucide';
|
|
235
|
+
import { HlmMenuImports } from '@egose/shadcn-theme-ng/menu';
|
|
236
|
+
|
|
237
|
+
@Component({
|
|
238
|
+
selector: 'app-menu-variants',
|
|
239
|
+
standalone: true,
|
|
240
|
+
imports: [NgIcon, ...HlmMenuImports],
|
|
241
|
+
providers: [provideIcons({ lucidePencil, lucideTrash })],
|
|
242
|
+
template: `
|
|
243
|
+
<hlm-menu>
|
|
244
|
+
<hlm-menu-label>Actions</hlm-menu-label>
|
|
245
|
+
<button hlmMenuItem>
|
|
246
|
+
<ng-icon hlmMenuIcon name="lucidePencil" />
|
|
247
|
+
Rename
|
|
248
|
+
<hlm-menu-shortcut>⌘R</hlm-menu-shortcut>
|
|
249
|
+
</button>
|
|
250
|
+
<button hlmMenuItem inset>Aligned without icon</button>
|
|
251
|
+
<button hlmMenuItem variant="destructive">
|
|
252
|
+
<ng-icon hlmMenuIcon name="lucideTrash" />
|
|
253
|
+
Delete
|
|
254
|
+
<hlm-menu-shortcut>⌫</hlm-menu-shortcut>
|
|
255
|
+
</button>
|
|
256
|
+
</hlm-menu>
|
|
257
|
+
`,
|
|
258
|
+
})
|
|
259
|
+
export class MenuVariantsComponent {}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### 3. Checkbox and radio rows
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
import { Component, signal } from '@angular/core';
|
|
266
|
+
import { HlmMenuImports } from '@egose/shadcn-theme-ng/menu';
|
|
267
|
+
|
|
268
|
+
@Component({
|
|
269
|
+
selector: 'app-menu-checks',
|
|
270
|
+
standalone: true,
|
|
271
|
+
imports: [...HlmMenuImports],
|
|
272
|
+
template: `
|
|
273
|
+
<hlm-menu>
|
|
274
|
+
<hlm-menu-label inset>View</hlm-menu-label>
|
|
275
|
+
<hlm-menu-group>
|
|
276
|
+
<button hlmMenuItemCheckbox [cdkMenuItemChecked]="wordWrap()" (cdkMenuItemTriggered)="toggleWrap()">
|
|
277
|
+
<hlm-menu-item-check />
|
|
278
|
+
Word wrap
|
|
279
|
+
</button>
|
|
280
|
+
<button hlmMenuItemCheckbox [cdkMenuItemChecked]="minimap()" (cdkMenuItemTriggered)="toggleMap()">
|
|
281
|
+
<hlm-menu-item-check />
|
|
282
|
+
Minimap
|
|
283
|
+
</button>
|
|
284
|
+
</hlm-menu-group>
|
|
285
|
+
<hlm-menu-separator />
|
|
286
|
+
<hlm-menu-label inset>Theme</hlm-menu-label>
|
|
287
|
+
<hlm-menu-group>
|
|
288
|
+
<button hlmMenuItemRadio [cdkMenuItemChecked]="theme() === 'light'" (cdkMenuItemTriggered)="theme.set('light')">
|
|
289
|
+
<hlm-menu-item-radio />
|
|
290
|
+
Light
|
|
291
|
+
</button>
|
|
292
|
+
<button hlmMenuItemRadio [cdkMenuItemChecked]="theme() === 'dark'" (cdkMenuItemTriggered)="theme.set('dark')">
|
|
293
|
+
<hlm-menu-item-radio />
|
|
294
|
+
Dark
|
|
295
|
+
</button>
|
|
296
|
+
</hlm-menu-group>
|
|
297
|
+
</hlm-menu>
|
|
298
|
+
`,
|
|
299
|
+
})
|
|
300
|
+
export class MenuChecksComponent {
|
|
301
|
+
readonly wordWrap = signal(true);
|
|
302
|
+
readonly minimap = signal(false);
|
|
303
|
+
readonly theme = signal<'light' | 'dark'>('light');
|
|
304
|
+
|
|
305
|
+
toggleWrap(): void {
|
|
306
|
+
this.wordWrap.update((v) => !v);
|
|
307
|
+
}
|
|
308
|
+
toggleMap(): void {
|
|
309
|
+
this.minimap.update((v) => !v);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
> The check/dot indicators reveal via the CDK-added `.checked` class (`group-[.checked]:opacity-100`). Bind `[cdkMenuItemChecked]` — the `checked` alias exposed through the host directive — and toggle on `(cdkMenuItemTriggered)` (exposed as `triggered`).
|
|
315
|
+
|
|
316
|
+
### 4. Submenu with indicator
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
import { Component } from '@angular/core';
|
|
320
|
+
import { CdkMenuModule } from '@angular/cdk/menu';
|
|
321
|
+
import { HlmMenuImports } from '@egose/shadcn-theme-ng/menu';
|
|
322
|
+
|
|
323
|
+
@Component({
|
|
324
|
+
selector: 'app-menu-sub',
|
|
325
|
+
standalone: true,
|
|
326
|
+
imports: [CdkMenuModule, ...HlmMenuImports],
|
|
327
|
+
template: `
|
|
328
|
+
<hlm-menu>
|
|
329
|
+
<button hlmMenuItem [cdkMenuTriggerFor]="shareTpl">
|
|
330
|
+
Share
|
|
331
|
+
<hlm-menu-item-sub-indicator />
|
|
332
|
+
</button>
|
|
333
|
+
</hlm-menu>
|
|
334
|
+
|
|
335
|
+
<ng-template #shareTpl>
|
|
336
|
+
<hlm-sub-menu>
|
|
337
|
+
<button hlmMenuItem>Email</button>
|
|
338
|
+
<button hlmMenuItem>Copy link</button>
|
|
339
|
+
</hlm-sub-menu>
|
|
340
|
+
</ng-template>
|
|
341
|
+
`,
|
|
342
|
+
})
|
|
343
|
+
export class MenuSubComponent {}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### 5. Menubar-variant floating menu + disabled rows
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
import { Component } from '@angular/core';
|
|
350
|
+
import { HlmMenuImports } from '@egose/shadcn-theme-ng/menu';
|
|
351
|
+
|
|
352
|
+
@Component({
|
|
353
|
+
selector: 'app-menu-menubar-variant',
|
|
354
|
+
standalone: true,
|
|
355
|
+
imports: [...HlmMenuImports],
|
|
356
|
+
template: `
|
|
357
|
+
<hlm-menu variant="menubar">
|
|
358
|
+
<hlm-menu-label>Help</hlm-menu-label>
|
|
359
|
+
<button hlmMenuItem>Documentation</button>
|
|
360
|
+
<button hlmMenuItem [cdkMenuItemDisabled]="true">Release notes (soon)</button>
|
|
361
|
+
</hlm-menu>
|
|
362
|
+
`,
|
|
363
|
+
})
|
|
364
|
+
export class MenuMenubarVariantComponent {}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Note: `variant="menubar"` on `hlm-menu` only adjusts vertical margin (`my-2` vs `my-0.5`); it does not wire menubar behavior — pair it with `hlm-menu-bar` / `HlmMenubar` triggers as in example 1 for the real thing.
|
|
368
|
+
|
|
369
|
+
### 6. Async list + programmatic template menu
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
import { Component, signal } from '@angular/core';
|
|
373
|
+
import { HlmMenuImports } from '@egose/shadcn-theme-ng/menu';
|
|
374
|
+
|
|
375
|
+
@Component({
|
|
376
|
+
selector: 'app-menu-async',
|
|
377
|
+
standalone: true,
|
|
378
|
+
imports: [...HlmMenuImports],
|
|
379
|
+
template: `
|
|
380
|
+
<hlm-menu>
|
|
381
|
+
<hlm-menu-label>Recent files</hlm-menu-label>
|
|
382
|
+
@for (f of files(); track f) {
|
|
383
|
+
<button hlmMenuItem (cdkMenuItemTriggered)="open(f)">
|
|
384
|
+
{{ f }}
|
|
385
|
+
<hlm-menu-shortcut>{{ $index + 1 }}</hlm-menu-shortcut>
|
|
386
|
+
</button>
|
|
387
|
+
} @empty {
|
|
388
|
+
<hlm-menu-label>No recent files</hlm-menu-label>
|
|
389
|
+
}
|
|
390
|
+
</hlm-menu>
|
|
391
|
+
`,
|
|
392
|
+
})
|
|
393
|
+
export class MenuAsyncComponent {
|
|
394
|
+
readonly files = signal<string[]>(['proposal.docx', 'budget.xlsx', 'notes.md']);
|
|
395
|
+
|
|
396
|
+
open(name: string): void {
|
|
397
|
+
console.log('open', name);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Accessibility notes
|
|
403
|
+
|
|
404
|
+
- CDK `CdkMenu`/`CdkMenuBar` own roving-focus, arrow-key navigation, typeahead, and `aria` roles — keep the prescribed nesting (`menu-bar` → trigger → `menu` → items) so keyboard behavior holds.
|
|
405
|
+
- Use `hlm-menu-label` for headings and `hlm-menu-separator` for dividers rather than disabled items; separators are presentational, labels are announced.
|
|
406
|
+
- `variant="destructive"` is color-only — pair destructive actions with explicit text ("Delete") and, for irreversible actions, a confirmation step.
|
|
407
|
+
- Disabled rows (`[cdkMenuItemDisabled]`) are skipped by arrow navigation and announced as disabled.
|
|
408
|
+
|
|
409
|
+
## Theming / CSS variables
|
|
410
|
+
|
|
411
|
+
No theming inputs. Surfaces use `bg-popover text-popover-foreground border shadow-md` and items use `hover:bg-secondary`; all flow from shadcn tokens. Extend per-instance via `class`.
|
|
412
|
+
|
|
413
|
+
## Related subpaths
|
|
414
|
+
|
|
415
|
+
- `@egose/shadcn-theme-ng/dropdown-menu` — opinionated trigger + menu wrapper built on this layer.
|
|
416
|
+
- `@egose/shadcn-theme-ng/context-menu` — right-click variant of the same CDK foundation.
|
|
417
|
+
- `@egose/shadcn-theme-ng/menubar` — desktop app-style menu bar with its own trigger primitive.
|
|
418
|
+
- `@egose/shadcn-theme-ng/icon` — `HlmMenuItemIcon` consumes its `sm` icon config.
|