@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/command/README.md
CHANGED
|
@@ -1,11 +1,441 @@
|
|
|
1
|
-
# Command
|
|
1
|
+
# Command (`@egose/shadcn-theme-ng/command`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A command palette / filterable action list — the Angular port of shadcn/ui `Command` (cmdk). `HlmCommand` (wrapping `BrnCommand` from `@spartan-ng/brain/command`) owns filter/search/disabled state and `valueChange`/`searchChange` outputs; inside it you compose `hlm-command-input` (search field with icon), `hlm-command-list` (scroll region), `hlm-command-group` + `hlm-command-group-label` (sections), `button[hlmCommandItem]` (selectable rows), `hlm-command-separator`, `hlm-command-shortcut` (hint kbd), `hlmCommandEmpty` / `hlmCommandEmptyState` (no-results), and `hlm-command-dialog` (dialog-hosted palette via `@egose/shadcn-theme-ng/dialog`).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Ships as `@egose/shadcn-theme-ng/command` and `@egose/shadcn-theme-ng-tw/command` (the `tw:`-prefixed variant). See the [package README](../../README.md) for install, peer dependencies, and Tailwind setup. Do not publish this project directory independently — it is consumed via the published subpath only.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Installation
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
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
|
+
Peers are listed in the [package README](../../README.md). This subpath declares `@angular/common`, `@angular/core`, and `@spartan-ng/brain` as peers (see `projects/command/package.json`); the dialog variant additionally uses `@egose/shadcn-theme-ng/dialog`.
|
|
18
|
+
|
|
19
|
+
## Imports
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import {
|
|
23
|
+
HlmCommand,
|
|
24
|
+
HlmCommandDialog,
|
|
25
|
+
HlmCommandEmpty,
|
|
26
|
+
HlmCommandEmptyState,
|
|
27
|
+
HlmCommandGroup,
|
|
28
|
+
HlmCommandGroupLabel,
|
|
29
|
+
HlmCommandInput,
|
|
30
|
+
HlmCommandItem,
|
|
31
|
+
HlmCommandList,
|
|
32
|
+
HlmCommandSeparator,
|
|
33
|
+
HlmCommandShortcut,
|
|
34
|
+
HlmCommandImports,
|
|
35
|
+
HlmCommandModule,
|
|
36
|
+
} from '@egose/shadcn-theme-ng/command';
|
|
37
|
+
// tw variant:
|
|
38
|
+
// import { ... } from '@egose/shadcn-theme-ng-tw/command';
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Standalone:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { Component } from '@angular/core';
|
|
45
|
+
import { HlmCommandImports } from '@egose/shadcn-theme-ng/command';
|
|
46
|
+
|
|
47
|
+
@Component({
|
|
48
|
+
selector: 'app-demo',
|
|
49
|
+
standalone: true,
|
|
50
|
+
imports: [...HlmCommandImports],
|
|
51
|
+
template: `...`,
|
|
52
|
+
})
|
|
53
|
+
export class DemoComponent {}
|
|
11
54
|
```
|
|
55
|
+
|
|
56
|
+
NgModule:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { NgModule } from '@angular/core';
|
|
60
|
+
import { HlmCommandModule } from '@egose/shadcn-theme-ng/command';
|
|
61
|
+
|
|
62
|
+
@NgModule({ imports: [HlmCommandModule] })
|
|
63
|
+
export class DemoModule {}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Anatomy / Structure
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<hlm-command [search]="q" (searchChange)="q = $event" (valueChange)="run($event)">
|
|
70
|
+
<hlm-command-input placeholder="Type a command…" />
|
|
71
|
+
<hlm-command-list>
|
|
72
|
+
<div hlmCommandEmpty>No results found.</div>
|
|
73
|
+
<hlm-command-group>
|
|
74
|
+
<span hlmCommandGroupLabel>Suggestions</span>
|
|
75
|
+
<button hlmCommandItem value="calendar">Calendar <span hlmCommandShortcut>⌘C</span></button>
|
|
76
|
+
<button hlmCommandItem value="settings">Settings</button>
|
|
77
|
+
</hlm-command-group>
|
|
78
|
+
<hlm-command-separator></hlm-command-separator>
|
|
79
|
+
<hlm-command-group>
|
|
80
|
+
<span hlmCommandGroupLabel>Actions</span>
|
|
81
|
+
<button hlmCommandItem value="logout">Log out</button>
|
|
82
|
+
</hlm-command-group>
|
|
83
|
+
</hlm-command-list>
|
|
84
|
+
</hlm-command>
|
|
85
|
+
|
|
86
|
+
<!-- Dialog-hosted palette -->
|
|
87
|
+
<hlm-command-dialog
|
|
88
|
+
title="Command Palette"
|
|
89
|
+
description="Search for a command to run..."
|
|
90
|
+
[state]="dialogState"
|
|
91
|
+
(stateChange)="dialogState = $event"
|
|
92
|
+
>
|
|
93
|
+
<hlm-command>…same inner structure…</hlm-command>
|
|
94
|
+
</hlm-command-dialog>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Real selectors:
|
|
98
|
+
|
|
99
|
+
| Class | Selector |
|
|
100
|
+
| ---------------------- | ------------------------------------------------------------------ |
|
|
101
|
+
| `HlmCommand` | `[hlmCommand]`, `hlm-command` |
|
|
102
|
+
| `HlmCommandDialog` | `hlm-command-dialog` (element only) |
|
|
103
|
+
| `HlmCommandInput` | `hlm-command-input` (element only) |
|
|
104
|
+
| `HlmCommandList` | `[hlmCommandList]`, `hlm-command-list` |
|
|
105
|
+
| `HlmCommandGroup` | `[hlmCommandGroup]`, `hlm-command-group` |
|
|
106
|
+
| `HlmCommandGroupLabel` | `[hlmCommandGroupLabel]`, `hlm-command-group-label` |
|
|
107
|
+
| `HlmCommandItem` | `button[hlmCommandItem]`, `button[hlm-command-item]` (button only) |
|
|
108
|
+
| `HlmCommandSeparator` | `[hlmCommandSeparator]`, `hlm-command-separator` |
|
|
109
|
+
| `HlmCommandShortcut` | `[hlmCommandShortcut]`, `hlm-command-shortcut` |
|
|
110
|
+
| `HlmCommandEmpty` | `[hlmCommandEmpty]` (styling only, no brain) |
|
|
111
|
+
| `HlmCommandEmptyState` | `[hlmCommandEmptyState]` (wraps `BrnCommandEmpty`) |
|
|
112
|
+
|
|
113
|
+
## API reference
|
|
114
|
+
|
|
115
|
+
### `HlmCommand` (`[hlmCommand]`, `hlm-command`)
|
|
116
|
+
|
|
117
|
+
| Brain input (`BrnCommand`) | Description |
|
|
118
|
+
| -------------------------- | ------------------------------------------------------------------------------------------- |
|
|
119
|
+
| `id` | Command root id. |
|
|
120
|
+
| `filter` | Custom filter fn `(value, search) => boolean/number`. Omit for default substring filtering. |
|
|
121
|
+
| `search` | Controlled search text. |
|
|
122
|
+
| `disabled` | Disables all items. |
|
|
123
|
+
|
|
124
|
+
| Brain output | Payload | Description |
|
|
125
|
+
| -------------- | ------------------- | --------------------------------------- |
|
|
126
|
+
| `valueChange` | selected item value | Emitted when the active item is chosen. |
|
|
127
|
+
| `searchChange` | `string` | Emitted on search input. |
|
|
128
|
+
|
|
129
|
+
### `HlmCommandInput` (`hlm-command-input`)
|
|
130
|
+
|
|
131
|
+
Search field wrapped in an `hlm-input-group` with a leading search icon.
|
|
132
|
+
|
|
133
|
+
| Input | Type | Default | Description |
|
|
134
|
+
| ------------- | --------------------- | ----------- | ----------------------------------------- |
|
|
135
|
+
| `inputId` | `string \| undefined` | `undefined` | Forwarded to the inner `brnCommandInput`. |
|
|
136
|
+
| `placeholder` | `string` | `''` | Placeholder text. |
|
|
137
|
+
|
|
138
|
+
### `HlmCommandItem` (`button[hlmCommandItem]`)
|
|
139
|
+
|
|
140
|
+
| Brain input (`BrnCommandItem`) | Description |
|
|
141
|
+
| ------------------------------ | --------------------------------------------------------- |
|
|
142
|
+
| `value` | Item value reported via `valueChange` / `selected`. |
|
|
143
|
+
| `disabled` | Disables this row (`data-disabled`, pointer-events none). |
|
|
144
|
+
| `id` | Item id. |
|
|
145
|
+
|
|
146
|
+
| Brain output | Description |
|
|
147
|
+
| ------------ | -------------------------------------------- |
|
|
148
|
+
| `selected` | Emitted when this specific item is selected. |
|
|
149
|
+
|
|
150
|
+
Must be a `<button>` — the selector does not match other elements.
|
|
151
|
+
|
|
152
|
+
### Groups / list / chrome
|
|
153
|
+
|
|
154
|
+
| Directive | Brain inputs | Notes |
|
|
155
|
+
| ---------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
156
|
+
| `HlmCommandList` | `id` (`BrnCommandList`) | Scroll region (`max-h-72`, custom `no-scrollbar`). |
|
|
157
|
+
| `HlmCommandGroup` | `id` (`BrnCommandGroup`) | Section; auto-hides when empty (`data-hidden`). |
|
|
158
|
+
| `HlmCommandGroupLabel` | — | Muted `text-xs` section heading (`role="presentation"`). |
|
|
159
|
+
| `HlmCommandSeparator` | — (`BrnCommandSeparator`) | 1px `bg-border` divider; hides when adjacent groups are empty. |
|
|
160
|
+
| `HlmCommandShortcut` | — | Right-aligned `text-xs tracking-widest` kbd hint; inherits selected-row color. |
|
|
161
|
+
| `HlmCommandEmpty` | — | Static centered `py-6 text-sm` row — show conditionally or always (CSS does not auto-toggle it). |
|
|
162
|
+
| `HlmCommandEmptyState` | — (`BrnCommandEmpty`) | Brain-driven empty marker — auto-shown when the filter removes every item. Prefer this for filtered lists. |
|
|
163
|
+
|
|
164
|
+
### `HlmCommandDialog` (`hlm-command-dialog`)
|
|
165
|
+
|
|
166
|
+
| Input | Type | Default | Description |
|
|
167
|
+
| -------------------- | ---------------- | ---------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
168
|
+
| `title` | `string` | `'Command Palette'` | Sr-only dialog title (accessibility). |
|
|
169
|
+
| `description` | `string` | `'Search for a command to run...'` | Sr-only dialog description. |
|
|
170
|
+
| `state` | `BrnDialogState` | `'closed'` | Controlled dialog state (`'open' \| 'closed'`). Mirrored into an internal `linkedSignal`. |
|
|
171
|
+
| `showCloseButton` | `boolean` | `false` | Show the dialog X button. |
|
|
172
|
+
| `dialogContentClass` | `ClassValue` | `''` | Merged onto the content (`tw:w-96 tw:p-0` base). |
|
|
173
|
+
|
|
174
|
+
| Output | Payload | Description |
|
|
175
|
+
| ------------- | ---------------- | --------------------------------------------------------- |
|
|
176
|
+
| `stateChange` | `BrnDialogState` | Emitted on open/close (also updates the internal signal). |
|
|
177
|
+
|
|
178
|
+
## Examples
|
|
179
|
+
|
|
180
|
+
### 1. Basic inline palette with shortcuts
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { Component, signal } from '@angular/core';
|
|
184
|
+
import { HlmCommandImports } from '@egose/shadcn-theme-ng/command';
|
|
185
|
+
|
|
186
|
+
@Component({
|
|
187
|
+
selector: 'app-basic-command',
|
|
188
|
+
standalone: true,
|
|
189
|
+
imports: [...HlmCommandImports],
|
|
190
|
+
template: `
|
|
191
|
+
<hlm-command class="max-w-md rounded-xl border" (valueChange)="run($event)">
|
|
192
|
+
<hlm-command-input placeholder="Type a command…" />
|
|
193
|
+
<hlm-command-list>
|
|
194
|
+
<div hlmCommandEmpty>No results found.</div>
|
|
195
|
+
<hlm-command-group>
|
|
196
|
+
<span hlmCommandGroupLabel>Suggestions</span>
|
|
197
|
+
<button hlmCommandItem value="calendar">Calendar</button>
|
|
198
|
+
<button hlmCommandItem value="search-emoji">Search emoji</button>
|
|
199
|
+
<button hlmCommandItem value="calculator">Calculator</button>
|
|
200
|
+
</hlm-command-group>
|
|
201
|
+
<hlm-command-separator></hlm-command-separator>
|
|
202
|
+
<hlm-command-group>
|
|
203
|
+
<span hlmCommandGroupLabel>Settings</span>
|
|
204
|
+
<button hlmCommandItem value="profile">Profile <span hlmCommandShortcut>⌘P</span></button>
|
|
205
|
+
<button hlmCommandItem value="billing">Billing <span hlmCommandShortcut>⌘B</span></button>
|
|
206
|
+
</hlm-command-group>
|
|
207
|
+
</hlm-command-list>
|
|
208
|
+
</hlm-command>
|
|
209
|
+
<p class="mt-2 text-sm">Last run: {{ last() }}</p>
|
|
210
|
+
`,
|
|
211
|
+
})
|
|
212
|
+
export class BasicCommandComponent {
|
|
213
|
+
readonly last = signal('none');
|
|
214
|
+
run(value: string) {
|
|
215
|
+
this.last.set(value);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 2. Controlled search + per-item `selected`
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
import { Component, signal } from '@angular/core';
|
|
224
|
+
import { HlmCommandImports } from '@egose/shadcn-theme-ng/command';
|
|
225
|
+
|
|
226
|
+
@Component({
|
|
227
|
+
selector: 'app-controlled-command',
|
|
228
|
+
standalone: true,
|
|
229
|
+
imports: [...HlmCommandImports],
|
|
230
|
+
template: `
|
|
231
|
+
<hlm-command class="max-w-md rounded-xl border" [search]="q()" (searchChange)="q.set($event)">
|
|
232
|
+
<hlm-command-input placeholder="Filter…" />
|
|
233
|
+
<hlm-command-list>
|
|
234
|
+
<span hlmCommandEmptyState>No match for "{{ q() }}"</span>
|
|
235
|
+
<hlm-command-group>
|
|
236
|
+
@for (f of files; track f) {
|
|
237
|
+
<button hlmCommandItem [value]="f" (selected)="open(f)">{{ f }}</button>
|
|
238
|
+
}
|
|
239
|
+
</hlm-command-group>
|
|
240
|
+
</hlm-command-list>
|
|
241
|
+
</hlm-command>
|
|
242
|
+
<button type="button" (click)="q.set('')">Clear search</button>
|
|
243
|
+
`,
|
|
244
|
+
})
|
|
245
|
+
export class ControlledCommandComponent {
|
|
246
|
+
readonly q = signal('');
|
|
247
|
+
readonly files = ['README.md', 'CHANGELOG.md', 'package.json', 'angular.json'];
|
|
248
|
+
open(f: string) {
|
|
249
|
+
console.log('open', f);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### 3. Dialog palette (`hlm-command-dialog`) with keyboard shortcut
|
|
255
|
+
|
|
256
|
+
The standard ⌘K / Ctrl+K palette: a global keydown flips `state` to `'open'`.
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
import { Component, HostListener, signal } from '@angular/core';
|
|
260
|
+
import { HlmCommandImports } from '@egose/shadcn-theme-ng/command';
|
|
261
|
+
import type { BrnDialogState } from '@spartan-ng/brain/dialog';
|
|
262
|
+
|
|
263
|
+
@Component({
|
|
264
|
+
selector: 'app-dialog-command',
|
|
265
|
+
standalone: true,
|
|
266
|
+
imports: [...HlmCommandImports],
|
|
267
|
+
template: `
|
|
268
|
+
<button type="button" (click)="open()">Open palette (⌘K)</button>
|
|
269
|
+
<hlm-command-dialog
|
|
270
|
+
title="Actions"
|
|
271
|
+
description="Search actions…"
|
|
272
|
+
[state]="state()"
|
|
273
|
+
(stateChange)="state.set($event)"
|
|
274
|
+
>
|
|
275
|
+
<hlm-command (valueChange)="run($event)">
|
|
276
|
+
<hlm-command-input placeholder="Search actions…" />
|
|
277
|
+
<hlm-command-list>
|
|
278
|
+
<span hlmCommandEmptyState>Nothing found.</span>
|
|
279
|
+
<hlm-command-group>
|
|
280
|
+
<span hlmCommandGroupLabel>Actions</span>
|
|
281
|
+
<button hlmCommandItem value="new-file">New file <span hlmCommandShortcut>⌘N</span></button>
|
|
282
|
+
<button hlmCommandItem value="save">Save <span hlmCommandShortcut>⌘S</span></button>
|
|
283
|
+
<button hlmCommandItem value="close" (selected)="state.set('closed')">Close palette</button>
|
|
284
|
+
</hlm-command-group>
|
|
285
|
+
</hlm-command-list>
|
|
286
|
+
</hlm-command>
|
|
287
|
+
</hlm-command-dialog>
|
|
288
|
+
`,
|
|
289
|
+
})
|
|
290
|
+
export class DialogCommandComponent {
|
|
291
|
+
readonly state = signal<BrnDialogState>('closed');
|
|
292
|
+
open() {
|
|
293
|
+
this.state.set('open');
|
|
294
|
+
}
|
|
295
|
+
@HostListener('window:keydown', ['$event'])
|
|
296
|
+
onKey(e: KeyboardEvent) {
|
|
297
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
|
|
298
|
+
e.preventDefault();
|
|
299
|
+
this.state.set(this.state() === 'open' ? 'closed' : 'open');
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
run(v: string) {
|
|
303
|
+
console.log('run', v);
|
|
304
|
+
this.state.set('closed');
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### 4. Disabled rows + whole-palette disabled
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
import { Component, signal } from '@angular/core';
|
|
313
|
+
import { HlmCommandImports } from '@egose/shadcn-theme-ng/command';
|
|
314
|
+
|
|
315
|
+
@Component({
|
|
316
|
+
selector: 'app-disabled-command',
|
|
317
|
+
standalone: true,
|
|
318
|
+
imports: [...HlmCommandImports],
|
|
319
|
+
template: `
|
|
320
|
+
<label class="mb-2 flex items-center gap-2 text-sm">
|
|
321
|
+
<input type="checkbox" [checked]="locked()" (change)="locked.set(!locked())" /> Lock palette
|
|
322
|
+
</label>
|
|
323
|
+
<hlm-command class="max-w-md rounded-xl border" [disabled]="locked()">
|
|
324
|
+
<hlm-command-input placeholder="Search…" />
|
|
325
|
+
<hlm-command-list>
|
|
326
|
+
<hlm-command-group>
|
|
327
|
+
<button hlmCommandItem value="edit">Edit</button>
|
|
328
|
+
<button hlmCommandItem value="delete" [disabled]="true">Delete (no permission)</button>
|
|
329
|
+
</hlm-command-group>
|
|
330
|
+
</hlm-command-list>
|
|
331
|
+
</hlm-command>
|
|
332
|
+
`,
|
|
333
|
+
})
|
|
334
|
+
export class DisabledCommandComponent {
|
|
335
|
+
readonly locked = signal(false);
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### 5. Custom filter (fuzzy initials)
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
import { Component } from '@angular/core';
|
|
343
|
+
import { HlmCommandImports } from '@egose/shadcn-theme-ng/command';
|
|
344
|
+
|
|
345
|
+
@Component({
|
|
346
|
+
selector: 'app-filter-command',
|
|
347
|
+
standalone: true,
|
|
348
|
+
imports: [...HlmCommandImports],
|
|
349
|
+
template: `
|
|
350
|
+
<hlm-command class="max-w-md rounded-xl border" [filter]="initialsFilter">
|
|
351
|
+
<hlm-command-input placeholder="Try 'np' for New Project…" />
|
|
352
|
+
<hlm-command-list>
|
|
353
|
+
<span hlmCommandEmptyState>No match.</span>
|
|
354
|
+
<hlm-command-group>
|
|
355
|
+
<button hlmCommandItem value="New Project">New Project</button>
|
|
356
|
+
<button hlmCommandItem value="New Page">New Page</button>
|
|
357
|
+
<button hlmCommandItem value="Open Settings">Open Settings</button>
|
|
358
|
+
</hlm-command-group>
|
|
359
|
+
</hlm-command-list>
|
|
360
|
+
</hlm-command>
|
|
361
|
+
`,
|
|
362
|
+
})
|
|
363
|
+
export class FilterCommandComponent {
|
|
364
|
+
// Match when every search char appears in order in the value's initials+letters:
|
|
365
|
+
readonly initialsFilter = (value: string, search: string) => {
|
|
366
|
+
const v = value.toLowerCase();
|
|
367
|
+
const s = search.toLowerCase().replace(/\s+/g, '');
|
|
368
|
+
let i = 0;
|
|
369
|
+
for (const ch of v) {
|
|
370
|
+
if (ch === s[i]) i++;
|
|
371
|
+
if (i === s.length) return 1;
|
|
372
|
+
}
|
|
373
|
+
return 0;
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### 6. Async results (manual list, no filter)
|
|
379
|
+
|
|
380
|
+
Drive the list yourself (e.g. from `HttpClient`) and disable the built-in filter by matching everything.
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
import { Component, signal } from '@angular/core';
|
|
384
|
+
import { HlmCommandImports } from '@egose/shadcn-theme-ng/command';
|
|
385
|
+
|
|
386
|
+
@Component({
|
|
387
|
+
selector: 'app-async-command',
|
|
388
|
+
standalone: true,
|
|
389
|
+
imports: [...HlmCommandImports],
|
|
390
|
+
template: `
|
|
391
|
+
<hlm-command class="max-w-md rounded-xl border" [filter]="matchAll" [search]="q()" (searchChange)="search($event)">
|
|
392
|
+
<hlm-command-input placeholder="Search users…" />
|
|
393
|
+
<hlm-command-list>
|
|
394
|
+
@if (loading()) {
|
|
395
|
+
<p class="text-muted-foreground px-2 py-6 text-center text-sm">Searching…</p>
|
|
396
|
+
} @else if (results().length === 0) {
|
|
397
|
+
<div hlmCommandEmpty>No users found.</div>
|
|
398
|
+
}
|
|
399
|
+
<hlm-command-group>
|
|
400
|
+
@for (u of results(); track u) {
|
|
401
|
+
<button hlmCommandItem [value]="u">{{ u }}</button>
|
|
402
|
+
}
|
|
403
|
+
</hlm-command-group>
|
|
404
|
+
</hlm-command-list>
|
|
405
|
+
</hlm-command>
|
|
406
|
+
`,
|
|
407
|
+
})
|
|
408
|
+
export class AsyncCommandComponent {
|
|
409
|
+
readonly q = signal('');
|
|
410
|
+
readonly results = signal<string[]>(['Ada', 'Grace', 'Margaret']);
|
|
411
|
+
readonly loading = signal(false);
|
|
412
|
+
readonly matchAll = () => 1;
|
|
413
|
+
|
|
414
|
+
async search(next: string) {
|
|
415
|
+
this.q.set(next);
|
|
416
|
+
this.loading.set(true);
|
|
417
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
418
|
+
const ALL = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton', 'Katherine Johnson'];
|
|
419
|
+
this.results.set(ALL.filter((n) => n.toLowerCase().includes(next.toLowerCase())));
|
|
420
|
+
this.loading.set(false);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
## Accessibility notes
|
|
426
|
+
|
|
427
|
+
- The dialog variant renders sr-only `title`/`description` (`hlm-dialog-header`) so screen readers announce the palette — always set meaningful values instead of the defaults when the palette has a specific purpose.
|
|
428
|
+
- Items are native `<button>`s with `data-selected` / `data-disabled` states; arrow-key navigation and Enter selection come from `BrnCommand` — preserve the `data-[selected]` highlight styles.
|
|
429
|
+
- The input is a labeled search field (placeholder + icon). For icon-only placements, add `inputId` + an external `<label>`.
|
|
430
|
+
- `HlmCommandEmptyState` (brain-driven) is preferable to static `HlmCommandEmpty` for filtered lists so empty announcements track the filter.
|
|
431
|
+
|
|
432
|
+
## Theming / CSS variables
|
|
433
|
+
|
|
434
|
+
No component-specific CSS variables. The root is `bg-popover text-popover-foreground rounded-xl`; selected rows use `data-selected:bg-muted`; the list caps at `max-h-72`. The dialog content is `w-96 p-0` by default — widen via `dialogContentClass`.
|
|
435
|
+
|
|
436
|
+
## Related subpaths
|
|
437
|
+
|
|
438
|
+
- `@egose/shadcn-theme-ng/dialog` — powers `hlm-command-dialog` (state, portal, close button).
|
|
439
|
+
- `@egose/shadcn-theme-ng/input-group` — search-field chrome inside `hlm-command-input`.
|
|
440
|
+
- `@egose/shadcn-theme-ng/popover` — alternative inline host for floating palettes.
|
|
441
|
+
- `@egose/shadcn-theme-ng/combobox` — item-picking alternative when you need a form value instead of an action runner.
|