wally-ui 1.14.1 → 1.16.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.
Files changed (62) hide show
  1. package/dist/cli.js +0 -0
  2. package/package.json +1 -1
  3. package/playground/showcase/public/sitemap.xml +15 -0
  4. package/playground/showcase/src/app/app.routes.server.ts +8 -0
  5. package/playground/showcase/src/app/components/ai/ai-composer/ai-composer.html +11 -2
  6. package/playground/showcase/src/app/components/ai/ai-composer/ai-composer.ts +13 -3
  7. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.css +0 -0
  8. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.html +41 -0
  9. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.service.spec.ts +16 -0
  10. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.service.ts +175 -0
  11. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.spec.ts +23 -0
  12. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.ts +64 -0
  13. package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.css +0 -0
  14. package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.html +41 -0
  15. package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.spec.ts +228 -0
  16. package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.ts +217 -0
  17. package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.css +0 -0
  18. package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.html +3 -0
  19. package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.spec.ts +56 -0
  20. package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.ts +11 -0
  21. package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.css +0 -0
  22. package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.html +11 -0
  23. package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.spec.ts +57 -0
  24. package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.ts +11 -0
  25. package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.css +0 -0
  26. package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.html +71 -0
  27. package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.spec.ts +468 -0
  28. package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.ts +90 -0
  29. package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.css +0 -0
  30. package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.html +58 -0
  31. package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.spec.ts +173 -0
  32. package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.ts +37 -0
  33. package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.css +0 -0
  34. package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.html +11 -0
  35. package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.spec.ts +166 -0
  36. package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.ts +36 -0
  37. package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.css +0 -0
  38. package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.html +8 -0
  39. package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.spec.ts +137 -0
  40. package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.ts +30 -0
  41. package/playground/showcase/src/app/components/combobox/combobox.css +0 -0
  42. package/playground/showcase/src/app/components/combobox/combobox.html +3 -0
  43. package/playground/showcase/src/app/components/combobox/combobox.spec.ts +391 -0
  44. package/playground/showcase/src/app/components/combobox/combobox.ts +59 -0
  45. package/playground/showcase/src/app/components/combobox/lib/models/combobox.model.ts +13 -0
  46. package/playground/showcase/src/app/components/combobox/lib/service/combobox.service.spec.ts +530 -0
  47. package/playground/showcase/src/app/components/combobox/lib/service/combobox.service.ts +191 -0
  48. package/playground/showcase/src/app/components/combobox/lib/types/combobox-position.type.ts +1 -0
  49. package/playground/showcase/src/app/components/combobox/lib/types/combobox-trigger-mode.type.ts +1 -0
  50. package/playground/showcase/src/app/core/services/seo.service.ts +100 -0
  51. package/playground/showcase/src/app/pages/documentation/components/audio-waveform-docs/audio-waveform-docs.css +1 -0
  52. package/playground/showcase/src/app/pages/documentation/components/audio-waveform-docs/audio-waveform-docs.examples.ts +146 -0
  53. package/playground/showcase/src/app/pages/documentation/components/audio-waveform-docs/audio-waveform-docs.html +576 -0
  54. package/playground/showcase/src/app/pages/documentation/components/audio-waveform-docs/audio-waveform-docs.ts +124 -0
  55. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.css +0 -0
  56. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.html +383 -0
  57. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.spec.ts +23 -0
  58. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.ts +333 -0
  59. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.examples.ts +226 -0
  60. package/playground/showcase/src/app/pages/documentation/components/components.html +27 -0
  61. package/playground/showcase/src/app/pages/documentation/components/components.routes.ts +8 -0
  62. package/playground/showcase/src/app/pages/home/home.html +1 -1
@@ -0,0 +1,333 @@
1
+ import { Component, OnInit } from '@angular/core';
2
+
3
+ import { AiPromptService } from '../../../../core/services/ai-prompt.service';
4
+ import { SeoService } from '../../../../core/services/seo.service';
5
+ import { getFormattedCode } from '../../../../core/utils/prism';
6
+
7
+ import { ComboboxCodeExamples } from './combobox-docs.examples';
8
+
9
+ import { Breadcrumb, BreadcrumbItem } from '../../../../components/breadcrumb/breadcrumb';
10
+ import { Button } from '../../../../components/button/button';
11
+ import { Combobox } from '../../../../components/combobox/combobox';
12
+ import { ComboboxInput } from '../../../../components/combobox/combobox-input/combobox-input';
13
+ import { ComboboxTrigger } from '../../../../components/combobox/combobox-trigger/combobox-trigger';
14
+ import { ComboboxContent } from '../../../../components/combobox/combobox-content/combobox-content';
15
+
16
+ @Component({
17
+ selector: 'wally-combobox-docs',
18
+ standalone: true,
19
+ imports: [
20
+ Breadcrumb,
21
+ Button,
22
+ Combobox,
23
+ ComboboxInput,
24
+ ComboboxTrigger,
25
+ ComboboxContent
26
+ ],
27
+ templateUrl: './combobox-docs.component.html',
28
+ styleUrl: './combobox-docs.component.css'
29
+ })
30
+ export class ComboboxDocsComponent implements OnInit {
31
+
32
+ breadcrumbItems: BreadcrumbItem[] = [
33
+ { label: 'Home', url: '/' },
34
+ { label: 'Documentation', url: '/documentation' },
35
+ { label: 'Components', url: '/documentation/components' },
36
+ { label: 'Combobox' }
37
+ ];
38
+
39
+ installationCode = getFormattedCode(ComboboxCodeExamples.installation, 'bash');
40
+ importCode = getFormattedCode(ComboboxCodeExamples.import, 'typescript');
41
+ componentImportCode = getFormattedCode(ComboboxCodeExamples.componentImport, 'typescript');
42
+
43
+ basicUsageCode = getFormattedCode(ComboboxCodeExamples.basicUsage, 'html');
44
+ componentSetupCode = getFormattedCode(ComboboxCodeExamples.componentSetup, 'typescript');
45
+ multiSelectCode = getFormattedCode(ComboboxCodeExamples.multiSelect, 'html');
46
+ multiSelectSetupCode = getFormattedCode(ComboboxCodeExamples.multiSelectSetup, 'typescript');
47
+ groupedItemsCode = getFormattedCode(ComboboxCodeExamples.groupedItems, 'html');
48
+ groupedItemsSetupCode = getFormattedCode(ComboboxCodeExamples.groupedItemsSetup, 'typescript');
49
+ customTriggerCode = getFormattedCode(ComboboxCodeExamples.customTrigger, 'html');
50
+ customTriggerSetupCode = getFormattedCode(ComboboxCodeExamples.customTriggerSetup, 'typescript');
51
+ positioningCode = getFormattedCode(ComboboxCodeExamples.positioning, 'html');
52
+ virtualScrollCode = getFormattedCode(ComboboxCodeExamples.virtualScroll, 'typescript');
53
+ keyboardNavigationCode = getFormattedCode(ComboboxCodeExamples.keyboardNavigation, 'text');
54
+ accessingSelectionCode = getFormattedCode(ComboboxCodeExamples.accessingSelection, 'html');
55
+ clearingSelectionCode = getFormattedCode(ComboboxCodeExamples.clearingSelection, 'html');
56
+ realWorldExampleCode = getFormattedCode(ComboboxCodeExamples.realWorldExample, 'html');
57
+ realWorldSetupCode = getFormattedCode(ComboboxCodeExamples.realWorldSetup, 'typescript');
58
+
59
+ fruits = FRUITS;
60
+ countries = ALL_COUNTRIES_DATA;
61
+ programmingLanguages = PROGRAMMING_LANGUAGES;
62
+
63
+ // Seleções
64
+ singleSelection: any[] = [];
65
+ multiSelection: any[] = [];
66
+ groupedSelection: any[] = [];
67
+ customTriggerSelection: any[] = [];
68
+
69
+ constructor(
70
+ private aiPromptService: AiPromptService,
71
+ private seoService: SeoService
72
+ ) { }
73
+
74
+ onSingleSelectionChange(items: any[]): void {
75
+ this.singleSelection = items;
76
+ }
77
+
78
+ onMultiSelectionChange(items: any[]): void {
79
+ this.multiSelection = items;
80
+ }
81
+
82
+ onGroupedSelectionChange(items: any[]): void {
83
+ this.groupedSelection = items;
84
+ }
85
+
86
+ onCustomTriggerSelectionChange(items: any[]): void {
87
+ this.customTriggerSelection = items;
88
+ }
89
+
90
+ ngOnInit(): void {
91
+ this.seoService.updateTags({
92
+ title: 'Combobox Component',
93
+ description: 'A flexible Angular combobox component with search, multi-select support, keyboard navigation, and intelligent viewport-aware positioning. Features input and custom trigger modes, item grouping, and zero external dependencies.',
94
+ url: '/documentation/components/combobox',
95
+ keywords: 'Angular Combobox, TypeScript Combobox, Select Component, Autocomplete, Multi-select, Angular UI Components, Searchable Dropdown'
96
+ });
97
+ }
98
+
99
+ get claudeUrl(): string {
100
+ return this.aiPromptService.generateClaudeUrl();
101
+ }
102
+
103
+ get chatGptUrl(): string {
104
+ return this.aiPromptService.generateChatGptUrl();
105
+ }
106
+ }
107
+
108
+ const ALL_COUNTRIES = [
109
+ 'Afghanistan',
110
+ 'Albania',
111
+ 'Algeria',
112
+ 'Andorra',
113
+ 'Angola',
114
+ 'Antigua and Barbuda',
115
+ 'Argentina',
116
+ 'Armenia',
117
+ 'Australia',
118
+ 'Austria',
119
+ 'Azerbaijan',
120
+ 'Bahamas',
121
+ 'Bahrain',
122
+ 'Bangladesh',
123
+ 'Barbados',
124
+ 'Belarus',
125
+ 'Belgium',
126
+ 'Belize',
127
+ 'Benin',
128
+ 'Bhutan',
129
+ 'Bolivia',
130
+ 'Bosnia and Herzegovina',
131
+ 'Botswana',
132
+ 'Brazil',
133
+ 'Brunei',
134
+ 'Bulgaria',
135
+ 'Burkina Faso',
136
+ 'Burundi',
137
+ 'Cabo Verde',
138
+ 'Cambodia',
139
+ 'Cameroon',
140
+ 'Canada',
141
+ 'Central African Republic',
142
+ 'Chad',
143
+ 'Chile',
144
+ 'China',
145
+ 'Colombia',
146
+ 'Comoros',
147
+ 'Congo (Congo-Brazzaville)',
148
+ 'Costa Rica',
149
+ "Côte d'Ivoire",
150
+ 'Croatia',
151
+ 'Cuba',
152
+ 'Cyprus',
153
+ 'Czechia (Czech Republic)',
154
+ 'Democratic Republic of the Congo',
155
+ 'Denmark',
156
+ 'Djibouti',
157
+ 'Dominica',
158
+ 'Dominican Republic',
159
+ 'Ecuador',
160
+ 'Egypt',
161
+ 'El Salvador',
162
+ 'Equatorial Guinea',
163
+ 'Eritrea',
164
+ 'Estonia',
165
+ 'Eswatini (fmr. ""Swaziland"")',
166
+ 'Ethiopia',
167
+ 'Fiji',
168
+ 'Finland',
169
+ 'France',
170
+ 'Gabon',
171
+ 'Gambia',
172
+ 'Georgia',
173
+ 'Germany',
174
+ 'Ghana',
175
+ 'Greece',
176
+ 'Grenada',
177
+ 'Guatemala',
178
+ 'Guinea',
179
+ 'Guinea-Bissau',
180
+ 'Guyana',
181
+ 'Haiti',
182
+ 'Holy See',
183
+ 'Honduras',
184
+ 'Hungary',
185
+ 'Iceland',
186
+ 'India',
187
+ 'Indonesia',
188
+ 'Iran',
189
+ 'Iraq',
190
+ 'Ireland',
191
+ 'Israel',
192
+ 'Italy',
193
+ 'Jamaica',
194
+ 'Japan',
195
+ 'Jordan',
196
+ 'Kazakhstan',
197
+ 'Kenya',
198
+ 'Kiribati',
199
+ 'Kuwait',
200
+ 'Kyrgyzstan',
201
+ 'Laos',
202
+ 'Latvia',
203
+ 'Lebanon',
204
+ 'Lesotho',
205
+ 'Liberia',
206
+ 'Libya',
207
+ 'Liechtenstein',
208
+ 'Lithuania',
209
+ 'Luxembourg',
210
+ 'Madagascar',
211
+ 'Malawi',
212
+ 'Malaysia',
213
+ 'Maldives',
214
+ 'Mali',
215
+ 'Malta',
216
+ 'Marshall Islands',
217
+ 'Mauritania',
218
+ 'Mauritius',
219
+ 'Mexico',
220
+ 'Micronesia',
221
+ 'Moldova',
222
+ 'Monaco',
223
+ 'Mongolia',
224
+ 'Montenegro',
225
+ 'Morocco',
226
+ 'Mozambique',
227
+ 'Myanmar (formerly Burma)',
228
+ 'Namibia',
229
+ 'Nauru',
230
+ 'Nepal',
231
+ 'Netherlands',
232
+ 'New Zealand',
233
+ 'Nicaragua',
234
+ 'Niger',
235
+ 'Nigeria',
236
+ 'North Korea',
237
+ 'North Macedonia',
238
+ 'Norway',
239
+ 'Oman',
240
+ 'Pakistan',
241
+ 'Palau',
242
+ 'Palestine State',
243
+ 'Panama',
244
+ 'Papua New Guinea',
245
+ 'Paraguay',
246
+ 'Peru',
247
+ 'Philippines',
248
+ 'Poland',
249
+ 'Portugal',
250
+ 'Qatar',
251
+ 'Romania',
252
+ 'Russia',
253
+ 'Rwanda',
254
+ 'Saint Kitts and Nevis',
255
+ 'Saint Lucia',
256
+ 'Saint Vincent and the Grenadines',
257
+ 'Samoa',
258
+ 'San Marino',
259
+ 'Sao Tome and Principe',
260
+ 'Saudi Arabia',
261
+ 'Senegal',
262
+ 'Serbia',
263
+ 'Seychelles',
264
+ 'Sierra Leone',
265
+ 'Singapore',
266
+ 'Slovakia',
267
+ 'Slovenia',
268
+ 'Solomon Islands',
269
+ 'Somalia',
270
+ 'South Africa',
271
+ 'South Korea',
272
+ 'South Sudan',
273
+ 'Spain',
274
+ 'Sri Lanka',
275
+ 'Sudan',
276
+ 'Suriname',
277
+ 'Sweden',
278
+ 'Switzerland',
279
+ 'Syria',
280
+ 'Tajikistan',
281
+ 'Tanzania',
282
+ 'Thailand',
283
+ 'Timor-Leste',
284
+ 'Togo',
285
+ 'Tonga',
286
+ 'Trinidad and Tobago',
287
+ 'Tunisia',
288
+ 'Turkey',
289
+ 'Turkmenistan',
290
+ 'Tuvalu',
291
+ 'Uganda',
292
+ 'Ukraine',
293
+ 'United Arab Emirates',
294
+ 'United Kingdom',
295
+ 'United States of America',
296
+ 'Uruguay',
297
+ 'Uzbekistan',
298
+ 'Vanuatu',
299
+ 'Venezuela',
300
+ 'Vietnam',
301
+ 'Yemen',
302
+ 'Zambia',
303
+ 'Zimbabwe',
304
+ ];
305
+
306
+ const FRUITS = [
307
+ { value: 1, label: 'Apple', description: 'A sweet red fruit' },
308
+ { value: 2, label: 'Banana', description: 'A yellow tropical fruit' },
309
+ { value: 3, label: 'Orange', description: 'A citrus fruit' },
310
+ { value: 4, label: 'Strawberry', description: 'A red berry' },
311
+ { value: 5, label: 'Grapes', description: 'Small round fruits in bunches' },
312
+ { value: 6, label: 'Watermelon', description: 'A large green fruit' },
313
+ { value: 7, label: 'Mango', description: 'A tropical stone fruit' },
314
+ { value: 8, label: 'Pineapple', description: 'A tropical fruit with spiky skin' },
315
+ ];
316
+
317
+ const ALL_COUNTRIES_DATA = ALL_COUNTRIES.map((country, index) => ({
318
+ value: index + 1,
319
+ label: country
320
+ }));
321
+
322
+ const PROGRAMMING_LANGUAGES = [
323
+ { value: 1, label: 'JavaScript', group: 'Frontend', description: 'Dynamic web language' },
324
+ { value: 2, label: 'TypeScript', group: 'Frontend', description: 'Typed JavaScript' },
325
+ { value: 3, label: 'React', group: 'Frontend', description: 'UI library' },
326
+ { value: 4, label: 'Angular', group: 'Frontend', description: 'Full framework' },
327
+ { value: 5, label: 'Vue', group: 'Frontend', description: 'Progressive framework' },
328
+ { value: 6, label: 'Node.js', group: 'Backend', description: 'JavaScript runtime' },
329
+ { value: 7, label: 'Python', group: 'Backend', description: 'Versatile language' },
330
+ { value: 8, label: 'Java', group: 'Backend', description: 'Enterprise language' },
331
+ { value: 9, label: 'Go', group: 'Backend', description: 'Fast compiled language' },
332
+ { value: 10, label: 'Rust', group: 'Backend', description: 'Memory-safe language' },
333
+ ];
@@ -0,0 +1,226 @@
1
+ export const ComboboxCodeExamples = {
2
+ installation: `npx wally-ui add combobox`,
3
+
4
+ import: `import { Combobox } from './components/wally-ui/combobox/combobox';
5
+ import { ComboboxInput } from './components/wally-ui/combobox/combobox-input/combobox-input';
6
+ import { ComboboxTrigger } from './components/wally-ui/combobox/combobox-trigger/combobox-trigger';
7
+ import { ComboboxContent } from './components/wally-ui/combobox/combobox-content/combobox-content';`,
8
+
9
+ componentImport: `@Component({
10
+ selector: 'app-example',
11
+ imports: [
12
+ Combobox,
13
+ ComboboxInput,
14
+ ComboboxTrigger,
15
+ ComboboxContent
16
+ ],
17
+ templateUrl: './example.html'
18
+ })`,
19
+
20
+ basicUsage: `<!-- Single select with input mode -->
21
+ <wally-combobox
22
+ [data]="fruits"
23
+ placeholder="Select a fruit..."
24
+ (selectionChange)="onSelectionChange($event)">
25
+ <wally-combobox-input></wally-combobox-input>
26
+ <wally-combobox-content></wally-combobox-content>
27
+ </wally-combobox>
28
+
29
+ <!-- Display selected item -->
30
+ @if (selectedFruits.length > 0) {
31
+ <p>Selected: {{ selectedFruits[0].label }}</p>
32
+ }`,
33
+
34
+ componentSetup: `import { Component } from '@angular/core';
35
+
36
+ @Component({
37
+ selector: 'app-example',
38
+ templateUrl: './example.html'
39
+ })
40
+ export class ExampleComponent {
41
+ fruits = [
42
+ { value: 1, label: 'Apple', description: 'A sweet red fruit' },
43
+ { value: 2, label: 'Banana', description: 'A yellow tropical fruit' },
44
+ { value: 3, label: 'Orange', description: 'A citrus fruit' }
45
+ ];
46
+
47
+ selectedFruits: any[] = [];
48
+
49
+ onSelectionChange(items: any[]): void {
50
+ this.selectedFruits = items;
51
+ }
52
+ }`,
53
+
54
+ multiSelect: `<wally-combobox
55
+ [data]="countries"
56
+ [multiSelect]="true"
57
+ [closeOnSelect]="false"
58
+ (selectionChange)="onCountriesChange($event)">
59
+ <wally-combobox-input></wally-combobox-input>
60
+ <wally-combobox-content></wally-combobox-content>
61
+ </wally-combobox>
62
+
63
+ @if (selectedCountries.length > 0) {
64
+ <p>{{ selectedCountries.length }} countries selected</p>
65
+ }`,
66
+
67
+ multiSelectSetup: `countries = [
68
+ { value: 1, label: 'United States' },
69
+ { value: 2, label: 'United Kingdom' },
70
+ { value: 3, label: 'Brazil' }
71
+ ];
72
+
73
+ selectedCountries: any[] = [];
74
+
75
+ onCountriesChange(items: any[]): void {
76
+ this.selectedCountries = items;
77
+ }`,
78
+
79
+ groupedItems: `<wally-combobox
80
+ [data]="languages"
81
+ groupBy="group"
82
+ (selectionChange)="onLanguageChange($event)">
83
+ <wally-combobox-input></wally-combobox-input>
84
+ <wally-combobox-content></wally-combobox-content>
85
+ </wally-combobox>`,
86
+
87
+ groupedItemsSetup: `languages = [
88
+ { value: 1, label: 'JavaScript', group: 'Frontend' },
89
+ { value: 2, label: 'TypeScript', group: 'Frontend' },
90
+ { value: 3, label: 'Python', group: 'Backend' },
91
+ { value: 4, label: 'Java', group: 'Backend' }
92
+ ];
93
+
94
+ selectedLanguage: any[] = [];
95
+
96
+ onLanguageChange(items: any[]): void {
97
+ this.selectedLanguage = items;
98
+ }`,
99
+
100
+ customTrigger: `<wally-combobox
101
+ [data]="options"
102
+ triggerMode="custom"
103
+ (selectionChange)="onOptionChange($event)">
104
+ <wally-combobox-trigger>
105
+ <wally-button variant="outline">
106
+ @if (selectedOption.length > 0) {
107
+ {{ selectedOption[0].label }}
108
+ } @else {
109
+ Select an option
110
+ }
111
+ </wally-button>
112
+ </wally-combobox-trigger>
113
+ <wally-combobox-content></wally-combobox-content>
114
+ </wally-combobox>`,
115
+
116
+ customTriggerSetup: `options = [
117
+ { value: 1, label: 'Option 1' },
118
+ { value: 2, label: 'Option 2' },
119
+ { value: 3, label: 'Option 3' }
120
+ ];
121
+
122
+ selectedOption: any[] = [];
123
+
124
+ onOptionChange(items: any[]): void {
125
+ this.selectedOption = items;
126
+ }`,
127
+
128
+ positioning: `<!-- Default: bottom (auto-adjusts based on viewport space) -->
129
+ <wally-combobox [data]="items">
130
+ <wally-combobox-input></wally-combobox-input>
131
+ <wally-combobox-content></wally-combobox-content>
132
+ </wally-combobox>
133
+
134
+ <!-- Force top positioning -->
135
+ <wally-combobox [data]="items">
136
+ <wally-combobox-input></wally-combobox-input>
137
+ <wally-combobox-content [position]="'top'"></wally-combobox-content>
138
+ </wally-combobox>
139
+
140
+ <!-- Position automatically adjusts on window resize -->`,
141
+
142
+ virtualScroll: `<!-- Virtual scrolling is automatically enabled for large datasets -->
143
+ <wally-combobox [data]="largeDataset">
144
+ <wally-combobox-input></wally-combobox-input>
145
+ <wally-combobox-content></wally-combobox-content>
146
+ </wally-combobox>
147
+
148
+ <!-- Note: Virtual scrolling optimizes rendering for 1000+ items -->`,
149
+
150
+ keyboardNavigation: `Keyboard shortcuts:
151
+ - Arrow Down: Navigate to next item
152
+ - Arrow Up: Navigate to previous item
153
+ - Enter: Select focused item
154
+ - Escape: Close dropdown
155
+ - Backspace: Remove last chip (multi-select mode)`,
156
+
157
+ accessingSelection: `<!-- Use selectionChange output to track selected items -->
158
+ <wally-combobox
159
+ [data]="items"
160
+ (selectionChange)="onSelectionChange($event)">
161
+ <wally-combobox-input></wally-combobox-input>
162
+ <wally-combobox-content></wally-combobox-content>
163
+ </wally-combobox>
164
+
165
+ <!-- Display selected items -->
166
+ @if (selectedItems.length > 0) {
167
+ <p>Selected: {{ selectedItems[0].label }}</p>
168
+ }
169
+
170
+ <!-- In component -->
171
+ selectedItems: any[] = [];
172
+
173
+ onSelectionChange(items: any[]): void {
174
+ this.selectedItems = items;
175
+ console.log('Selected values:', items.map(i => i.value));
176
+ }`,
177
+
178
+ clearingSelection: `<!-- The combobox automatically handles clearing via UI -->
179
+ <!-- Multi-select: Individual X buttons on each chip -->
180
+ <!-- Single-select: Clear button (X) when item is selected -->
181
+
182
+ <!-- Built-in clear functionality - no code needed! -->
183
+ <wally-combobox [data]="items">
184
+ <wally-combobox-input></wally-combobox-input>
185
+ <wally-combobox-content></wally-combobox-content>
186
+ </wally-combobox>`,
187
+
188
+ realWorldExample: `<div class="space-y-4">
189
+ <!-- Country selector with multi-select -->
190
+ <wally-combobox
191
+ [data]="countries"
192
+ [multiSelect]="true"
193
+ [closeOnSelect]="false"
194
+ placeholder="Search countries..."
195
+ (selectionChange)="onCountrySelectionChange($event)">
196
+ <wally-combobox-input></wally-combobox-input>
197
+ <wally-combobox-content></wally-combobox-content>
198
+ </wally-combobox>
199
+
200
+ <!-- Display selected countries -->
201
+ @if (selectedCountries.length > 0) {
202
+ <div class="mt-4">
203
+ <h3 class="font-semibold mb-2">Selected Countries:</h3>
204
+ <ul class="list-disc list-inside">
205
+ @for (country of selectedCountries; track country.value) {
206
+ <li>{{ country.label }}</li>
207
+ }
208
+ </ul>
209
+ </div>
210
+ }
211
+ </div>`,
212
+
213
+ realWorldSetup: `countries = [
214
+ { value: 1, label: 'United States', description: 'North America' },
215
+ { value: 2, label: 'United Kingdom', description: 'Europe' },
216
+ { value: 3, label: 'Brazil', description: 'South America' },
217
+ { value: 4, label: 'Japan', description: 'Asia' },
218
+ { value: 5, label: 'Australia', description: 'Oceania' }
219
+ ];
220
+
221
+ selectedCountries: any[] = [];
222
+
223
+ onCountrySelectionChange(items: any[]): void {
224
+ this.selectedCountries = items;
225
+ }`
226
+ };
@@ -40,6 +40,33 @@
40
40
  </h2>
41
41
 
42
42
  <div class="space-y-0 border-2 border-neutral-300 dark:border-neutral-700">
43
+ <!-- Audio Waveform Component -->
44
+ <article class="group border-b-2 border-neutral-300 dark:border-neutral-700 last:border-b-0" role="article"
45
+ aria-labelledby="audio-waveform-heading">
46
+ <a href="/documentation/components/audio-waveform"
47
+ class="block px-4 py-4 sm:py-5 bg-white dark:bg-[#0a0a0a] hover:bg-[#0a0a0a] dark:hover:bg-white transition-all duration-150 cursor-pointer"
48
+ aria-label="Navigate to Audio Waveform component documentation with real-time FFT analysis, responsive bar count, and audio recording">
49
+ <div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3">
50
+ <div class="flex-1">
51
+ <div class="flex items-center gap-3 mb-2">
52
+ <h3 id="audio-waveform-heading"
53
+ class="text-base sm:text-lg font-bold text-[#0a0a0a] dark:text-white group-hover:text-white dark:group-hover:text-[#0a0a0a] uppercase tracking-wide transition-colors duration-150">
54
+ <span aria-hidden="true">&gt;_ </span>Audio Waveform
55
+ </h3>
56
+ <span class="text-[10px] font-bold bg-blue-500 text-white px-2 py-1 uppercase tracking-wider"
57
+ aria-label="Status: New Component">
58
+ NEW
59
+ </span>
60
+ </div>
61
+ <p
62
+ class="text-xs sm:text-sm text-neutral-600 dark:text-neutral-400 group-hover:text-neutral-300 dark:group-hover:text-neutral-600 transition-colors duration-150">
63
+ Real-time audio visualizer with Web Audio API, FFT frequency analysis, responsive bar count (mobile/desktop), 60fps animations, and automatic recording to WebM. Audio transcription coming soon.
64
+ </p>
65
+ </div>
66
+ </div>
67
+ </a>
68
+ </article>
69
+
43
70
  <!-- Breadcrumb Component -->
44
71
  <article class="group border-b-2 border-neutral-300 dark:border-neutral-700 last:border-b-0" role="article"
45
72
  aria-labelledby="breadcrumb-heading">
@@ -32,5 +32,13 @@ export const componentsRoutes: Routes = [
32
32
  {
33
33
  path: 'selection-popover',
34
34
  loadComponent: () => import('./selection-popover-docs/selection-popover-docs').then(m => m.SelectionPopoverDocs)
35
+ },
36
+ {
37
+ path: 'audio-waveform',
38
+ loadComponent: () => import('./audio-waveform-docs/audio-waveform-docs').then(m => m.AudioWaveformDocs)
39
+ },
40
+ {
41
+ path: 'combobox',
42
+ loadComponent: () => import('./combobox-docs/combobox-docs.component').then(m => m.ComboboxDocsComponent)
35
43
  }
36
44
  ];
@@ -119,7 +119,7 @@
119
119
  </h4>
120
120
  <p
121
121
  class="text-xs sm:text-sm text-neutral-600 dark:text-neutral-400 group-hover:text-neutral-300 dark:group-hover:text-neutral-600 transition-colors duration-150">
122
- Browse 4+ production-ready Angular components: Button, Input, Carousel, Breadcrumb
122
+ Browse 7+ production-ready Angular components: Button, Input, Carousel, Breadcrumb
123
123
  with TypeScript examples
124
124
  </p>
125
125
  </div>