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 +1 -1
- package/playground/showcase/src/app/components/button/button.html +4 -26
- package/playground/showcase/src/app/components/button/button.ts +30 -1
- package/playground/showcase/src/app/pages/documentation/components/button-docs/button-docs.examples.ts +179 -26
- package/playground/showcase/src/app/pages/documentation/components/button-docs/button-docs.html +519 -285
- package/playground/showcase/src/app/pages/documentation/components/button-docs/button-docs.ts +30 -10
- package/playground/showcase/src/app/pages/documentation/documentation.html +83 -79
- package/playground/showcase/src/app/pages/documentation/documentation.ts +5 -1
- package/playground/showcase/src/app/pages/home/home.html +69 -45
- package/playground/showcase/src/app/pages/home/home.ts +2 -1
- package/playground/showcase/src/index.html +68 -10
package/package.json
CHANGED
|
@@ -1,28 +1,7 @@
|
|
|
1
|
-
<button
|
|
2
|
-
[
|
|
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
|
|
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>
|
|
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
|
-
|
|
48
|
+
|
|
49
|
+
loading: `<wally-button [loading]="true">Loading...</wally-button>`,
|
|
50
|
+
|
|
21
51
|
notification: `<wally-button [showNotification]="true">Messages</wally-button>`,
|
|
22
52
|
|
|
23
|
-
//
|
|
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
|
-
|
|
168
|
+
console.log('Button clicked!');
|
|
169
|
+
// Your logic here
|
|
30
170
|
}`,
|
|
31
171
|
|
|
32
|
-
//
|
|
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
|
-
|
|
51
|
-
|
|
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:
|
|
60
|
-
|
|
211
|
+
ariaPressed: `<!-- For toggle buttons -->
|
|
212
|
+
<wally-button [ariaPressed]="isMuted()">
|
|
213
|
+
{{ isMuted() ? 'Unmute' : 'Mute' }}
|
|
61
214
|
</wally-button>`,
|
|
62
215
|
|
|
63
|
-
ariaBusy:
|
|
64
|
-
|
|
216
|
+
ariaBusy: `<!-- Automatically set when loading="true" -->
|
|
217
|
+
<wally-button [loading]="isSaving()">
|
|
218
|
+
Save Changes
|
|
65
219
|
</wally-button>`,
|
|
66
220
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
+
};
|