wally-ui 1.9.0 → 1.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wally-ui",
3
- "version": "1.9.0",
3
+ "version": "1.11.0",
4
4
  "description": "About Where’s Wally? Right here — bringing you ready-to-use Angular components with Wally-UI. Stop searching, start building.",
5
5
  "bin": {
6
6
  "wally": "dist/cli.js"
@@ -1,28 +1,7 @@
1
- <button
2
- [type]="type()"
3
- [disabled]="disabled() || loading()"
4
- [attr.aria-label]="ariaLabel() || null"
5
- [attr.aria-describedby]="ariaDescribedBy() || null"
6
- [attr.aria-pressed]="ariaPressed()"
7
- [attr.aria-busy]="loading()"
1
+ <button [type]="type()" [disabled]="disabled() || loading()" [attr.aria-label]="ariaLabel() || null"
2
+ [attr.aria-describedby]="ariaDescribedBy() || null" [attr.aria-pressed]="ariaPressed()" [attr.aria-busy]="loading()"
8
3
  (click)="handleClick()"
9
- class="
10
- group
11
- relative
12
- w-full
13
- flex items-center justify-center gap-2
14
- text-white text-sm font-medium dark:text-[#0a0a0a]
15
- bg-[#0a0a0a] hover:bg-[#0a0a0a]/85
16
- disabled:bg-[#0a0a0a]/85
17
- dark:bg-white dark:hover:bg-white/85
18
- dark:disabled:bg-white/85
19
- disabled:pointer-events-none
20
- p-2.5
21
- rounded-md
22
- transition duration-300 ease-in-out
23
- antialiased
24
- cursor-pointer
25
- ">
4
+ [class]="'group relative w-full flex items-center justify-center gap-2 text-sm font-medium text-white disabled:pointer-events-none p-2.5 rounded-md transition-all duration-300 ease-in-out antialiased cursor-pointer ' + variantClasses()">
26
5
 
27
6
  @if (showNotification()) {
28
7
  <span class="absolute top-0 right-0 -mt-1 -mr-1 flex size-3">
@@ -34,8 +13,7 @@
34
13
  }
35
14
 
36
15
  @if (loading()) {
37
- <svg class="size-4 animate-spin text-white dark:text-[#0a0a0a]" xmlns="http://www.w3.org/2000/svg" fill="none"
38
- viewBox="0 0 24 24">
16
+ <svg class="size-4 animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
39
17
  <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
40
18
  <path class="opacity-75" fill="currentColor"
41
19
  d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
@@ -1,5 +1,8 @@
1
- import { Component, input, InputSignal, output, OutputEmitterRef } from '@angular/core';
1
+ import { Component, computed, inject, input, InputSignal, output, OutputEmitterRef, Signal } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
+ import { Router } from '@angular/router';
4
+
5
+ type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link';
3
6
 
4
7
  @Component({
5
8
  selector: 'wally-button',
@@ -10,10 +13,14 @@ import { CommonModule } from '@angular/common';
10
13
  templateUrl: './button.html',
11
14
  })
12
15
  export class Button {
16
+ private router = inject(Router);
17
+
13
18
  type: InputSignal<string> = input<string>('button');
14
19
  disabled: InputSignal<boolean> = input<boolean>(false);
15
20
  loading: InputSignal<boolean> = input<boolean>(false);
16
21
  showNotification: InputSignal<boolean> = input<boolean>(false);
22
+ variant: InputSignal<ButtonVariant> = input<ButtonVariant>('primary');
23
+ href: InputSignal<string> = input<string>('');
17
24
 
18
25
  // Accessibility properties
19
26
  ariaLabel: InputSignal<string> = input<string>('');
@@ -22,7 +29,29 @@ export class Button {
22
29
 
23
30
  click: OutputEmitterRef<void> = output<void>();
24
31
 
32
+ // Computed classes based on variant
33
+ variantClasses: Signal<string> = computed(() => {
34
+ const variantMap: Record<ButtonVariant, string> = {
35
+ primary: 'bg-[#0a0a0a] hover:bg-[#0a0a0a]/85 disabled:bg-[#0a0a0a]/85 dark:text-[#0a0a0a] dark:bg-white dark:hover:bg-white/85 dark:disabled:bg-white/85 dark:disabled:text-[#0a0a0a]/60',
36
+ secondary: '!text-[#0a0a0a] bg-neutral-200 hover:bg-neutral-200/60 disabled:bg-neutral-200/80 disabled:!text-neutral-400 dark:!text-white dark:bg-white/20 dark:hover:bg-white/10 dark:disabled:bg-white/5 dark:disabled:text-white/50',
37
+ destructive: 'dark:text-white bg-red-500 hover:bg-red-500/80 disabled:bg-red-500/80 disabled:text-white/80 dark:disabled:text-white/60',
38
+ outline: '!text-[#0a0a0a] bg-transparent border border-neutral-400 hover:bg-neutral-200/60 disabled:!text-neutral-500 dark:!text-white dark:border-neutral-500 dark:bg-neutral-500/10 dark:hover:bg-neutral-500/20 dark:disabled:!text-white/60',
39
+ ghost: '!text-[#0a0a0a] bg-transparent hover:bg-neutral-100 disabled:!text-neutral-400 dark:!text-white dark:hover:bg-white/5 dark:disabled:!text-white/50',
40
+ link: '!text-blue-600 bg-transparent underline-offset-4 hover:underline disabled:!text-blue-400 dark:!text-blue-600 dark:hover:!text-blue-500 dark:disabled:!text-blue-400'
41
+ };
42
+
43
+ return variantMap[this.variant()] || variantMap.primary;
44
+ });
45
+
25
46
  handleClick(): void {
47
+ if (this.variant() === 'link' && this.href()) {
48
+ if (this.href().startsWith('http://') || this.href().startsWith('https://')) {
49
+ window.open(this.href(), '_blank');
50
+ } else {
51
+ this.router.navigate([this.href()]);
52
+ }
53
+ }
54
+
26
55
  this.click.emit();
27
56
  }
28
57
  }
@@ -8,30 +8,171 @@ export const ButtonCodeExamples = {
8
8
  componentImport: `@Component({
9
9
  selector: 'app-example',
10
10
  imports: [Button],
11
- templateUrl: './example.html',
12
- styleUrl: './example.css'
11
+ templateUrl: './example.html'
13
12
  })`,
14
13
 
15
14
  // Basic usage
16
- basicUsage: `<wally-button>Wally Button</wally-button>`,
15
+ basicUsage: `<wally-button>Click me</wally-button>`,
16
+
17
+ // === VARIANTS ===
18
+
19
+ // Primary (Default)
20
+ primaryVariant: `<!-- Default variant -->
21
+ <wally-button>Primary Button</wally-button>
22
+
23
+ <!-- Explicit primary -->
24
+ <wally-button variant="primary">Primary Button</wally-button>`,
25
+
26
+ // Secondary
27
+ secondaryVariant: `<wally-button variant="secondary">Secondary Button</wally-button>`,
28
+
29
+ // Destructive
30
+ destructiveVariant: `<wally-button variant="destructive">Delete Account</wally-button>`,
31
+
32
+ // Outline
33
+ outlineVariant: `<wally-button variant="outline">Outline Button</wally-button>`,
34
+
35
+ // Ghost
36
+ ghostVariant: `<wally-button variant="ghost">Ghost Button</wally-button>`,
37
+
38
+ // Link
39
+ linkVariant: `<!-- Internal navigation -->
40
+ <wally-button variant="link" href="/components">View Components</wally-button>
41
+
42
+ <!-- External link -->
43
+ <wally-button variant="link" href="https://github.com">GitHub</wally-button>`,
44
+
45
+ // === STATES ===
17
46
 
18
- // States
19
47
  disabled: `<wally-button [disabled]="true">Disabled</wally-button>`,
20
- loading: `<wally-button [loading]="true">Loading</wally-button>`,
48
+
49
+ loading: `<wally-button [loading]="true">Loading...</wally-button>`,
50
+
21
51
  notification: `<wally-button [showNotification]="true">Messages</wally-button>`,
22
52
 
23
- // Types
53
+ // === PRODUCTION EXAMPLES ===
54
+
55
+ // CTA Button
56
+ ctaExample: `<!-- Call-to-Action Example -->
57
+ <wally-button>
58
+ Get Started Free
59
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
60
+ stroke-width="2" stroke="currentColor" class="size-5">
61
+ <path stroke-linecap="round" stroke-linejoin="round"
62
+ d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3" />
63
+ </svg>
64
+ </wally-button>`,
65
+
66
+ // Login Form
67
+ loginExample: `<!-- Login Form Example -->
68
+ <form (ngSubmit)="onLogin()">
69
+ <!-- ... form fields ... -->
70
+
71
+ <div class="flex gap-2">
72
+ <wally-button
73
+ type="submit"
74
+ [loading]="isLoggingIn()"
75
+ [disabled]="!loginForm.valid">
76
+ Sign In
77
+ </wally-button>
78
+
79
+ <wally-button
80
+ variant="secondary"
81
+ type="button"
82
+ (click)="goToSignUp()">
83
+ Create Account
84
+ </wally-button>
85
+ </div>
86
+ </form>`,
87
+
88
+ loginExampleTs: `export class LoginComponent {
89
+ isLoggingIn = signal(false);
90
+ loginForm: FormGroup;
91
+
92
+ onLogin() {
93
+ this.isLoggingIn.set(true);
94
+
95
+ this.authService.login(this.loginForm.value)
96
+ .subscribe({
97
+ next: () => this.router.navigate(['/dashboard']),
98
+ error: () => this.isLoggingIn.set(false)
99
+ });
100
+ }
101
+ }`,
102
+
103
+ // Delete Confirmation
104
+ deleteExample: `<!-- Delete Confirmation Modal -->
105
+ <div class="modal">
106
+ <h2>Delete Account?</h2>
107
+ <p>This action cannot be undone.</p>
108
+
109
+ <div class="flex gap-2 justify-end">
110
+ <wally-button
111
+ variant="ghost"
112
+ (click)="closeModal()">
113
+ Cancel
114
+ </wally-button>
115
+
116
+ <wally-button
117
+ variant="destructive"
118
+ [loading]="isDeleting()"
119
+ (click)="confirmDelete()">
120
+ Delete Account
121
+ </wally-button>
122
+ </div>
123
+ </div>`,
124
+
125
+ // Dashboard Actions
126
+ dashboardExample: `<!-- Dashboard Actions -->
127
+ <div class="dashboard-header">
128
+ <wally-button variant="outline" (click)="exportData()">
129
+ Export
130
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
131
+ stroke-width="1.5" stroke="currentColor" class="size-5">
132
+ <path stroke-linecap="round" stroke-linejoin="round"
133
+ d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
134
+ </svg>
135
+ </wally-button>
136
+
137
+ <wally-button (click)="createNew()">
138
+ Create New
139
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
140
+ stroke-width="2" stroke="currentColor" class="size-5">
141
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
142
+ </svg>
143
+ </wally-button>
144
+ </div>`,
145
+
146
+ // Icon Button with Notification
147
+ notificationButton: `<!-- Notification Icon Button -->
148
+ <wally-button
149
+ [showNotification]="hasUnreadMessages()"
150
+ ariaLabel="View messages">
151
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
152
+ stroke-width="1.5" stroke="currentColor" class="size-5">
153
+ <path stroke-linecap="round" stroke-linejoin="round"
154
+ d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75" />
155
+ </svg>
156
+ </wally-button>`,
157
+
158
+ // === BUTTON TYPES ===
159
+
24
160
  submit: `<wally-button type="submit">Submit Form</wally-button>`,
161
+ reset: `<wally-button type="reset" variant="ghost">Reset</wally-button>`,
162
+
163
+ // === EVENTS ===
25
164
 
26
- // Events
27
165
  clickTemplate: `<wally-button (click)="handleClick()">Click Me</wally-button>`,
166
+
28
167
  clickMethod: `handleClick(): void {
29
- this.clickMessage.set('Button clicked!');
168
+ console.log('Button clicked!');
169
+ // Your logic here
30
170
  }`,
31
171
 
32
- // Icons
172
+ // === ICONS ===
173
+
33
174
  iconWithText: `<wally-button>
34
- Save
175
+ Save Changes
35
176
  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
36
177
  stroke-width="1.5" stroke="currentColor" class="size-5">
37
178
  <path stroke-linecap="round" stroke-linejoin="round"
@@ -39,7 +180,7 @@ export const ButtonCodeExamples = {
39
180
  </svg>
40
181
  </wally-button>`,
41
182
 
42
- iconOnly: `<wally-button>
183
+ iconOnly: `<wally-button ariaLabel="Notifications">
43
184
  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
44
185
  stroke-width="1.5" stroke="currentColor" class="size-5">
45
186
  <path stroke-linecap="round" stroke-linejoin="round"
@@ -47,8 +188,19 @@ export const ButtonCodeExamples = {
47
188
  </svg>
48
189
  </wally-button>`,
49
190
 
50
- // Accessibility
51
- ariaLabel: `<wally-button ariaLabel="Save document">
191
+ iconLeft: `<wally-button>
192
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
193
+ stroke-width="2" stroke="currentColor" class="size-5">
194
+ <path stroke-linecap="round" stroke-linejoin="round"
195
+ d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18" />
196
+ </svg>
197
+ Back
198
+ </wally-button>`,
199
+
200
+ // === ACCESSIBILITY ===
201
+
202
+ ariaLabel: `<!-- Essential for icon-only buttons -->
203
+ <wally-button ariaLabel="Save document">
52
204
  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
53
205
  stroke-width="1.5" stroke="currentColor" class="size-5">
54
206
  <path stroke-linecap="round" stroke-linejoin="round"
@@ -56,20 +208,21 @@ export const ButtonCodeExamples = {
56
208
  </svg>
57
209
  </wally-button>`,
58
210
 
59
- ariaPressed: `<wally-button [ariaPressed]="isToggled">
60
- Toggle Setting
211
+ ariaPressed: `<!-- For toggle buttons -->
212
+ <wally-button [ariaPressed]="isMuted()">
213
+ {{ isMuted() ? 'Unmute' : 'Mute' }}
61
214
  </wally-button>`,
62
215
 
63
- ariaBusy: `<wally-button [loading]="true">
64
- Processing...
216
+ ariaBusy: `<!-- Automatically set when loading="true" -->
217
+ <wally-button [loading]="isSaving()">
218
+ Save Changes
65
219
  </wally-button>`,
66
220
 
67
- // Properties
68
- propertyType: `type: string = 'button';`,
69
- propertyDisabled: `disabled: boolean = false;`,
70
- propertyLoading: `loading: boolean = false;`,
71
- propertyShowNotification: `showNotification: boolean = false;`,
72
- propertyAriaLabel: `ariaLabel: string = '';`,
73
- propertyAriaPressed: `ariaPressed: boolean | undefined = undefined;`,
74
- propertyAriaDescribedBy: `ariaDescribedBy: string = '';`,
75
- };
221
+ ariaDescribedBy: `<!-- Connect button to description -->
222
+ <wally-button ariaDescribedBy="save-description">
223
+ Save
224
+ </wally-button>
225
+ <p id="save-description" class="sr-only">
226
+ Saves your changes permanently
227
+ </p>`,
228
+ };