@kanso-protocol/user-menu 0.1.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.
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { EventEmitter, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { KpAvatarComponent } from '@kanso-protocol/avatar';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Kanso Protocol — UserMenu
|
|
7
|
+
*
|
|
8
|
+
* Preset dropdown shown from the user Avatar in Header. User block
|
|
9
|
+
* at top, main menu, optional theme toggle + help links, Sign out.
|
|
10
|
+
*
|
|
11
|
+
* Slots:
|
|
12
|
+
* - `[kpUserMenuItems]` — main menu items (Profile / Settings / Billing / Team)
|
|
13
|
+
* - `[kpUserMenuHelp]` — help links
|
|
14
|
+
* - `[kpUserMenuTheme]` — theme toggle row (e.g. a SegmentedControl)
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <kp-user-menu
|
|
18
|
+
* userName="Greg Black"
|
|
19
|
+
* userInitials="GB"
|
|
20
|
+
* userEmail="greg@example.com"
|
|
21
|
+
* [showPlanBadge]="true"
|
|
22
|
+
* planName="Pro"
|
|
23
|
+
* >
|
|
24
|
+
* <div kpUserMenuItems>
|
|
25
|
+
* <kp-menu-item icon="user" label="Profile" (click$)="goto('profile')"/>
|
|
26
|
+
* ...
|
|
27
|
+
* </div>
|
|
28
|
+
* </kp-user-menu>
|
|
29
|
+
*/
|
|
30
|
+
class KpUserMenuComponent {
|
|
31
|
+
size = 'md';
|
|
32
|
+
userName = 'Greg Black';
|
|
33
|
+
userEmail = 'greg@example.com';
|
|
34
|
+
userInitials = 'GB';
|
|
35
|
+
showEmail = true;
|
|
36
|
+
showPlanBadge = false;
|
|
37
|
+
planName = 'Pro';
|
|
38
|
+
showThemeToggle = false;
|
|
39
|
+
showHelpLink = true;
|
|
40
|
+
signOut = new EventEmitter();
|
|
41
|
+
get avatarSize() {
|
|
42
|
+
return this.size === 'md' ? 'lg' : 'md';
|
|
43
|
+
}
|
|
44
|
+
get hostClasses() {
|
|
45
|
+
return `kp-user-menu kp-user-menu--${this.size}`;
|
|
46
|
+
}
|
|
47
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpUserMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
48
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: KpUserMenuComponent, isStandalone: true, selector: "kp-user-menu", inputs: { size: "size", userName: "userName", userEmail: "userEmail", userInitials: "userInitials", showEmail: "showEmail", showPlanBadge: "showPlanBadge", planName: "planName", showThemeToggle: "showThemeToggle", showHelpLink: "showHelpLink" }, outputs: { signOut: "signOut" }, host: { attributes: { "role": "menu" }, properties: { "class": "hostClasses" } }, ngImport: i0, template: `
|
|
49
|
+
<div class="kp-user-menu__info">
|
|
50
|
+
<kp-avatar [size]="avatarSize" [initials]="userInitials || null" [showStatus]="true" status="online"/>
|
|
51
|
+
<div class="kp-user-menu__text">
|
|
52
|
+
<span class="kp-user-menu__name-row">
|
|
53
|
+
<span class="kp-user-menu__name">{{ userName }}</span>
|
|
54
|
+
@if (showPlanBadge) {
|
|
55
|
+
<span class="kp-user-menu__plan">{{ planName }}</span>
|
|
56
|
+
}
|
|
57
|
+
</span>
|
|
58
|
+
@if (showEmail && userEmail) {
|
|
59
|
+
<span class="kp-user-menu__email">{{ userEmail }}</span>
|
|
60
|
+
}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div class="kp-user-menu__divider" aria-hidden="true"></div>
|
|
65
|
+
|
|
66
|
+
<div class="kp-user-menu__group">
|
|
67
|
+
<ng-content select="[kpUserMenuItems]"/>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="kp-user-menu__divider" aria-hidden="true"></div>
|
|
71
|
+
|
|
72
|
+
@if (showThemeToggle) {
|
|
73
|
+
<div class="kp-user-menu__theme">
|
|
74
|
+
<span class="kp-user-menu__theme-label">Theme</span>
|
|
75
|
+
<ng-content select="[kpUserMenuTheme]"/>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="kp-user-menu__divider" aria-hidden="true"></div>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@if (showHelpLink) {
|
|
81
|
+
<div class="kp-user-menu__group">
|
|
82
|
+
<ng-content select="[kpUserMenuHelp]"/>
|
|
83
|
+
</div>
|
|
84
|
+
<div class="kp-user-menu__divider" aria-hidden="true"></div>
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
<div class="kp-user-menu__group">
|
|
88
|
+
<button type="button" class="kp-user-menu__row kp-user-menu__row--danger" (click)="signOut.emit()">
|
|
89
|
+
<span class="kp-user-menu__row-icon" aria-hidden="true">
|
|
90
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M9 12h12l-3-3m0 6 3-3M15 17v1a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/></svg>
|
|
91
|
+
</span>
|
|
92
|
+
<span>Sign out</span>
|
|
93
|
+
</button>
|
|
94
|
+
</div>
|
|
95
|
+
`, isInline: true, styles: [":host{box-sizing:border-box;display:flex;flex-direction:column;width:var(--kp-user-menu-w, 280px);padding:4px 0;border-radius:12px;background:var(--kp-color-white, var(--kp-color-white));border:1px solid var(--kp-color-gray-200, var(--kp-color-gray-200));box-shadow:var(--kp-elevation-overlay);font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}:host(.kp-user-menu--sm){--kp-user-menu-w: 240px;--kp-user-menu-pad: 8px}:host(.kp-user-menu--md){--kp-user-menu-w: 280px;--kp-user-menu-pad: 12px}.kp-user-menu__info{display:flex;align-items:center;gap:12px;padding:var(--kp-user-menu-pad, 12px) calc(var(--kp-user-menu-pad, 12px) + 4px)}.kp-user-menu__text{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 auto}.kp-user-menu__name-row{display:inline-flex;align-items:center;gap:6px}.kp-user-menu__name{font-size:14px;font-weight:500;color:var(--kp-color-gray-900, var(--kp-color-gray-900))}.kp-user-menu__plan{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:var(--kp-color-blue-600, var(--kp-color-blue-600));color:var(--kp-color-white);font-size:11px;font-weight:600;line-height:1}.kp-user-menu__email{font-size:12px;color:var(--kp-color-gray-500, var(--kp-color-gray-500));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kp-user-menu__divider{height:1px;background:var(--kp-color-gray-200, var(--kp-color-gray-200))}.kp-user-menu__group{padding:4px;display:flex;flex-direction:column;gap:0}.kp-user-menu__theme{display:flex;align-items:center;gap:8px;padding:var(--kp-user-menu-pad, 12px) calc(var(--kp-user-menu-pad, 12px) + 4px)}.kp-user-menu__theme-label{flex:1 1 auto;font-size:14px;color:var(--kp-color-gray-700, var(--kp-color-gray-700))}.kp-user-menu__row{all:unset;display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;font-size:13px;color:var(--kp-color-gray-700, var(--kp-color-gray-700));cursor:pointer;transition:background var(--kp-motion-duration-fast) ease}.kp-user-menu__row:hover{background:var(--kp-color-gray-100, var(--kp-color-gray-100));color:var(--kp-color-gray-900, var(--kp-color-gray-900))}.kp-user-menu__row-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--kp-color-gray-500, var(--kp-color-gray-500))}.kp-user-menu__row-icon svg{width:100%;height:100%}.kp-user-menu__row--danger{color:var(--kp-color-red-600, var(--kp-color-red-600))}.kp-user-menu__row--danger .kp-user-menu__row-icon{color:var(--kp-color-red-500, var(--kp-color-red-500))}.kp-user-menu__row--danger:hover{background:var(--kp-color-red-50, var(--kp-color-red-50));color:var(--kp-color-red-700, var(--kp-color-red-700))}\n"], dependencies: [{ kind: "component", type: KpAvatarComponent, selector: "kp-avatar", inputs: ["size", "shape", "appearance", "initials", "src", "alt", "showStatus", "status", "showRing", "ariaLabelOverride"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
96
|
+
}
|
|
97
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpUserMenuComponent, decorators: [{
|
|
98
|
+
type: Component,
|
|
99
|
+
args: [{ selector: 'kp-user-menu', imports: [KpAvatarComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'hostClasses', role: 'menu' }, template: `
|
|
100
|
+
<div class="kp-user-menu__info">
|
|
101
|
+
<kp-avatar [size]="avatarSize" [initials]="userInitials || null" [showStatus]="true" status="online"/>
|
|
102
|
+
<div class="kp-user-menu__text">
|
|
103
|
+
<span class="kp-user-menu__name-row">
|
|
104
|
+
<span class="kp-user-menu__name">{{ userName }}</span>
|
|
105
|
+
@if (showPlanBadge) {
|
|
106
|
+
<span class="kp-user-menu__plan">{{ planName }}</span>
|
|
107
|
+
}
|
|
108
|
+
</span>
|
|
109
|
+
@if (showEmail && userEmail) {
|
|
110
|
+
<span class="kp-user-menu__email">{{ userEmail }}</span>
|
|
111
|
+
}
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div class="kp-user-menu__divider" aria-hidden="true"></div>
|
|
116
|
+
|
|
117
|
+
<div class="kp-user-menu__group">
|
|
118
|
+
<ng-content select="[kpUserMenuItems]"/>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div class="kp-user-menu__divider" aria-hidden="true"></div>
|
|
122
|
+
|
|
123
|
+
@if (showThemeToggle) {
|
|
124
|
+
<div class="kp-user-menu__theme">
|
|
125
|
+
<span class="kp-user-menu__theme-label">Theme</span>
|
|
126
|
+
<ng-content select="[kpUserMenuTheme]"/>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="kp-user-menu__divider" aria-hidden="true"></div>
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@if (showHelpLink) {
|
|
132
|
+
<div class="kp-user-menu__group">
|
|
133
|
+
<ng-content select="[kpUserMenuHelp]"/>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="kp-user-menu__divider" aria-hidden="true"></div>
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
<div class="kp-user-menu__group">
|
|
139
|
+
<button type="button" class="kp-user-menu__row kp-user-menu__row--danger" (click)="signOut.emit()">
|
|
140
|
+
<span class="kp-user-menu__row-icon" aria-hidden="true">
|
|
141
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M9 12h12l-3-3m0 6 3-3M15 17v1a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/></svg>
|
|
142
|
+
</span>
|
|
143
|
+
<span>Sign out</span>
|
|
144
|
+
</button>
|
|
145
|
+
</div>
|
|
146
|
+
`, styles: [":host{box-sizing:border-box;display:flex;flex-direction:column;width:var(--kp-user-menu-w, 280px);padding:4px 0;border-radius:12px;background:var(--kp-color-white, var(--kp-color-white));border:1px solid var(--kp-color-gray-200, var(--kp-color-gray-200));box-shadow:var(--kp-elevation-overlay);font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}:host(.kp-user-menu--sm){--kp-user-menu-w: 240px;--kp-user-menu-pad: 8px}:host(.kp-user-menu--md){--kp-user-menu-w: 280px;--kp-user-menu-pad: 12px}.kp-user-menu__info{display:flex;align-items:center;gap:12px;padding:var(--kp-user-menu-pad, 12px) calc(var(--kp-user-menu-pad, 12px) + 4px)}.kp-user-menu__text{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 auto}.kp-user-menu__name-row{display:inline-flex;align-items:center;gap:6px}.kp-user-menu__name{font-size:14px;font-weight:500;color:var(--kp-color-gray-900, var(--kp-color-gray-900))}.kp-user-menu__plan{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:var(--kp-color-blue-600, var(--kp-color-blue-600));color:var(--kp-color-white);font-size:11px;font-weight:600;line-height:1}.kp-user-menu__email{font-size:12px;color:var(--kp-color-gray-500, var(--kp-color-gray-500));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kp-user-menu__divider{height:1px;background:var(--kp-color-gray-200, var(--kp-color-gray-200))}.kp-user-menu__group{padding:4px;display:flex;flex-direction:column;gap:0}.kp-user-menu__theme{display:flex;align-items:center;gap:8px;padding:var(--kp-user-menu-pad, 12px) calc(var(--kp-user-menu-pad, 12px) + 4px)}.kp-user-menu__theme-label{flex:1 1 auto;font-size:14px;color:var(--kp-color-gray-700, var(--kp-color-gray-700))}.kp-user-menu__row{all:unset;display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;font-size:13px;color:var(--kp-color-gray-700, var(--kp-color-gray-700));cursor:pointer;transition:background var(--kp-motion-duration-fast) ease}.kp-user-menu__row:hover{background:var(--kp-color-gray-100, var(--kp-color-gray-100));color:var(--kp-color-gray-900, var(--kp-color-gray-900))}.kp-user-menu__row-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--kp-color-gray-500, var(--kp-color-gray-500))}.kp-user-menu__row-icon svg{width:100%;height:100%}.kp-user-menu__row--danger{color:var(--kp-color-red-600, var(--kp-color-red-600))}.kp-user-menu__row--danger .kp-user-menu__row-icon{color:var(--kp-color-red-500, var(--kp-color-red-500))}.kp-user-menu__row--danger:hover{background:var(--kp-color-red-50, var(--kp-color-red-50));color:var(--kp-color-red-700, var(--kp-color-red-700))}\n"] }]
|
|
147
|
+
}], propDecorators: { size: [{
|
|
148
|
+
type: Input
|
|
149
|
+
}], userName: [{
|
|
150
|
+
type: Input
|
|
151
|
+
}], userEmail: [{
|
|
152
|
+
type: Input
|
|
153
|
+
}], userInitials: [{
|
|
154
|
+
type: Input
|
|
155
|
+
}], showEmail: [{
|
|
156
|
+
type: Input
|
|
157
|
+
}], showPlanBadge: [{
|
|
158
|
+
type: Input
|
|
159
|
+
}], planName: [{
|
|
160
|
+
type: Input
|
|
161
|
+
}], showThemeToggle: [{
|
|
162
|
+
type: Input
|
|
163
|
+
}], showHelpLink: [{
|
|
164
|
+
type: Input
|
|
165
|
+
}], signOut: [{
|
|
166
|
+
type: Output
|
|
167
|
+
}] } });
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Generated bundle index. Do not edit.
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
export { KpUserMenuComponent };
|
|
174
|
+
//# sourceMappingURL=kanso-protocol-user-menu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kanso-protocol-user-menu.mjs","sources":["../../../../../packages/patterns/user-menu/src/user-menu.component.ts","../../../../../packages/patterns/user-menu/src/kanso-protocol-user-menu.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n Output,\n} from '@angular/core';\nimport { KpAvatarComponent } from '@kanso-protocol/avatar';\n\nexport type KpUserMenuSize = 'sm' | 'md';\n\nexport interface KpUserMenuItem {\n id: string;\n label: string;\n danger?: boolean;\n}\n\n/**\n * Kanso Protocol — UserMenu\n *\n * Preset dropdown shown from the user Avatar in Header. User block\n * at top, main menu, optional theme toggle + help links, Sign out.\n *\n * Slots:\n * - `[kpUserMenuItems]` — main menu items (Profile / Settings / Billing / Team)\n * - `[kpUserMenuHelp]` — help links\n * - `[kpUserMenuTheme]` — theme toggle row (e.g. a SegmentedControl)\n *\n * @example\n * <kp-user-menu\n * userName=\"Greg Black\"\n * userInitials=\"GB\"\n * userEmail=\"greg@example.com\"\n * [showPlanBadge]=\"true\"\n * planName=\"Pro\"\n * >\n * <div kpUserMenuItems>\n * <kp-menu-item icon=\"user\" label=\"Profile\" (click$)=\"goto('profile')\"/>\n * ...\n * </div>\n * </kp-user-menu>\n */\n@Component({\n selector: 'kp-user-menu',\n imports: [KpAvatarComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { '[class]': 'hostClasses', role: 'menu' },\n template: `\n <div class=\"kp-user-menu__info\">\n <kp-avatar [size]=\"avatarSize\" [initials]=\"userInitials || null\" [showStatus]=\"true\" status=\"online\"/>\n <div class=\"kp-user-menu__text\">\n <span class=\"kp-user-menu__name-row\">\n <span class=\"kp-user-menu__name\">{{ userName }}</span>\n @if (showPlanBadge) {\n <span class=\"kp-user-menu__plan\">{{ planName }}</span>\n }\n </span>\n @if (showEmail && userEmail) {\n <span class=\"kp-user-menu__email\">{{ userEmail }}</span>\n }\n </div>\n </div>\n\n <div class=\"kp-user-menu__divider\" aria-hidden=\"true\"></div>\n\n <div class=\"kp-user-menu__group\">\n <ng-content select=\"[kpUserMenuItems]\"/>\n </div>\n\n <div class=\"kp-user-menu__divider\" aria-hidden=\"true\"></div>\n\n @if (showThemeToggle) {\n <div class=\"kp-user-menu__theme\">\n <span class=\"kp-user-menu__theme-label\">Theme</span>\n <ng-content select=\"[kpUserMenuTheme]\"/>\n </div>\n <div class=\"kp-user-menu__divider\" aria-hidden=\"true\"></div>\n }\n\n @if (showHelpLink) {\n <div class=\"kp-user-menu__group\">\n <ng-content select=\"[kpUserMenuHelp]\"/>\n </div>\n <div class=\"kp-user-menu__divider\" aria-hidden=\"true\"></div>\n }\n\n <div class=\"kp-user-menu__group\">\n <button type=\"button\" class=\"kp-user-menu__row kp-user-menu__row--danger\" (click)=\"signOut.emit()\">\n <span class=\"kp-user-menu__row-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 12h12l-3-3m0 6 3-3M15 17v1a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1\"/></svg>\n </span>\n <span>Sign out</span>\n </button>\n </div>\n `,\n styles: [`\n :host {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n width: var(--kp-user-menu-w, 280px);\n padding: 4px 0;\n border-radius: 12px;\n background: var(--kp-color-white, var(--kp-color-white));\n border: 1px solid var(--kp-color-gray-200, var(--kp-color-gray-200));\n box-shadow: var(--kp-elevation-overlay);\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n }\n :host(.kp-user-menu--sm) { --kp-user-menu-w: 240px; --kp-user-menu-pad: 8px; }\n :host(.kp-user-menu--md) { --kp-user-menu-w: 280px; --kp-user-menu-pad: 12px; }\n\n .kp-user-menu__info {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: var(--kp-user-menu-pad, 12px) calc(var(--kp-user-menu-pad, 12px) + 4px);\n }\n .kp-user-menu__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }\n .kp-user-menu__name-row { display: inline-flex; align-items: center; gap: 6px; }\n .kp-user-menu__name { font-size: 14px; font-weight: 500; color: var(--kp-color-gray-900, var(--kp-color-gray-900)); }\n .kp-user-menu__plan {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: 999px;\n background: var(--kp-color-blue-600, var(--kp-color-blue-600));\n color: var(--kp-color-white);\n font-size: 11px;\n font-weight: 600;\n line-height: 1;\n }\n .kp-user-menu__email { font-size: 12px; color: var(--kp-color-gray-500, var(--kp-color-gray-500)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n\n .kp-user-menu__divider { height: 1px; background: var(--kp-color-gray-200, var(--kp-color-gray-200)); }\n\n .kp-user-menu__group { padding: 4px; display: flex; flex-direction: column; gap: 0; }\n\n .kp-user-menu__theme {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: var(--kp-user-menu-pad, 12px) calc(var(--kp-user-menu-pad, 12px) + 4px);\n }\n .kp-user-menu__theme-label { flex: 1 1 auto; font-size: 14px; color: var(--kp-color-gray-700, var(--kp-color-gray-700)); }\n\n .kp-user-menu__row {\n all: unset;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n font-size: 13px;\n color: var(--kp-color-gray-700, var(--kp-color-gray-700));\n cursor: pointer;\n transition: background var(--kp-motion-duration-fast) ease;\n }\n .kp-user-menu__row:hover { background: var(--kp-color-gray-100, var(--kp-color-gray-100)); color: var(--kp-color-gray-900, var(--kp-color-gray-900)); }\n .kp-user-menu__row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: var(--kp-color-gray-500, var(--kp-color-gray-500));\n }\n .kp-user-menu__row-icon svg { width: 100%; height: 100%; }\n\n .kp-user-menu__row--danger {\n color: var(--kp-color-red-600, var(--kp-color-red-600));\n }\n .kp-user-menu__row--danger .kp-user-menu__row-icon { color: var(--kp-color-red-500, var(--kp-color-red-500)); }\n .kp-user-menu__row--danger:hover { background: var(--kp-color-red-50, var(--kp-color-red-50)); color: var(--kp-color-red-700, var(--kp-color-red-700)); }\n `],\n})\nexport class KpUserMenuComponent {\n @Input() size: KpUserMenuSize = 'md';\n\n @Input() userName: string | null = 'Greg Black';\n @Input() userEmail: string | null = 'greg@example.com';\n @Input() userInitials: string | null = 'GB';\n\n @Input() showEmail = true;\n @Input() showPlanBadge = false;\n @Input() planName = 'Pro';\n @Input() showThemeToggle = false;\n @Input() showHelpLink = true;\n\n @Output() signOut = new EventEmitter<void>();\n\n get avatarSize(): 'md' | 'lg' {\n return this.size === 'md' ? 'lg' : 'md';\n }\n\n get hostClasses(): string {\n return `kp-user-menu kp-user-menu--${this.size}`;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAiBA;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;MAsIU,mBAAmB,CAAA;IACrB,IAAI,GAAmB,IAAI;IAE3B,QAAQ,GAAkB,YAAY;IACtC,SAAS,GAAkB,kBAAkB;IAC7C,YAAY,GAAkB,IAAI;IAElC,SAAS,GAAG,IAAI;IAChB,aAAa,GAAG,KAAK;IACrB,QAAQ,GAAG,KAAK;IAChB,eAAe,GAAG,KAAK;IACvB,YAAY,GAAG,IAAI;AAElB,IAAA,OAAO,GAAG,IAAI,YAAY,EAAQ;AAE5C,IAAA,IAAI,UAAU,GAAA;AACZ,QAAA,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;IACzC;AAEA,IAAA,IAAI,WAAW,GAAA;AACb,QAAA,OAAO,CAAA,2BAAA,EAA8B,IAAI,CAAC,IAAI,EAAE;IAClD;uGArBW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,mBAAmB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,QAAA,EAAA,UAAA,EAAA,SAAA,EAAA,WAAA,EAAA,YAAA,EAAA,cAAA,EAAA,SAAA,EAAA,WAAA,EAAA,aAAA,EAAA,eAAA,EAAA,QAAA,EAAA,UAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,MAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,aAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAhIpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,mnFAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAlDS,iBAAiB,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,OAAA,EAAA,YAAA,EAAA,UAAA,EAAA,KAAA,EAAA,KAAA,EAAA,YAAA,EAAA,QAAA,EAAA,UAAA,EAAA,mBAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAmIhB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBArI/B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,WACf,CAAC,iBAAiB,CAAC,EAAA,eAAA,EACX,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAA,QAAA,EACtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,mnFAAA,CAAA,EAAA;;sBAkFA;;sBAEA;;sBACA;;sBACA;;sBAEA;;sBACA;;sBACA;;sBACA;;sBACA;;sBAEA;;;AC5LH;;AAEG;;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kanso-protocol/user-menu",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"peerDependencies": {
|
|
6
|
+
"@angular/core": "^18.0.0",
|
|
7
|
+
"@angular/common": "^18.0.0",
|
|
8
|
+
"@kanso-protocol/core": "^0.0.1",
|
|
9
|
+
"@kanso-protocol/avatar": ">=0.1.0"
|
|
10
|
+
},
|
|
11
|
+
"description": "Kanso Protocol — user-menu (pattern).",
|
|
12
|
+
"author": "GregNBlack",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/GregNBlack/kanso-protocol.git",
|
|
16
|
+
"directory": "packages/patterns/user-menu"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://gregnblack.github.io/kanso-protocol/?path=/docs/patterns-usermenu--docs",
|
|
19
|
+
"bugs": "https://github.com/GregNBlack/kanso-protocol/issues",
|
|
20
|
+
"keywords": [
|
|
21
|
+
"design-system",
|
|
22
|
+
"angular",
|
|
23
|
+
"kanso",
|
|
24
|
+
"user-menu"
|
|
25
|
+
],
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"module": "fesm2022/kanso-protocol-user-menu.mjs",
|
|
28
|
+
"typings": "types/kanso-protocol-user-menu.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
"./package.json": {
|
|
31
|
+
"default": "./package.json"
|
|
32
|
+
},
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./types/kanso-protocol-user-menu.d.ts",
|
|
35
|
+
"default": "./fesm2022/kanso-protocol-user-menu.mjs"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"type": "module",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"tslib": "^2.3.0"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { EventEmitter } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
type KpUserMenuSize = 'sm' | 'md';
|
|
5
|
+
interface KpUserMenuItem {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
danger?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Kanso Protocol — UserMenu
|
|
12
|
+
*
|
|
13
|
+
* Preset dropdown shown from the user Avatar in Header. User block
|
|
14
|
+
* at top, main menu, optional theme toggle + help links, Sign out.
|
|
15
|
+
*
|
|
16
|
+
* Slots:
|
|
17
|
+
* - `[kpUserMenuItems]` — main menu items (Profile / Settings / Billing / Team)
|
|
18
|
+
* - `[kpUserMenuHelp]` — help links
|
|
19
|
+
* - `[kpUserMenuTheme]` — theme toggle row (e.g. a SegmentedControl)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* <kp-user-menu
|
|
23
|
+
* userName="Greg Black"
|
|
24
|
+
* userInitials="GB"
|
|
25
|
+
* userEmail="greg@example.com"
|
|
26
|
+
* [showPlanBadge]="true"
|
|
27
|
+
* planName="Pro"
|
|
28
|
+
* >
|
|
29
|
+
* <div kpUserMenuItems>
|
|
30
|
+
* <kp-menu-item icon="user" label="Profile" (click$)="goto('profile')"/>
|
|
31
|
+
* ...
|
|
32
|
+
* </div>
|
|
33
|
+
* </kp-user-menu>
|
|
34
|
+
*/
|
|
35
|
+
declare class KpUserMenuComponent {
|
|
36
|
+
size: KpUserMenuSize;
|
|
37
|
+
userName: string | null;
|
|
38
|
+
userEmail: string | null;
|
|
39
|
+
userInitials: string | null;
|
|
40
|
+
showEmail: boolean;
|
|
41
|
+
showPlanBadge: boolean;
|
|
42
|
+
planName: string;
|
|
43
|
+
showThemeToggle: boolean;
|
|
44
|
+
showHelpLink: boolean;
|
|
45
|
+
signOut: EventEmitter<void>;
|
|
46
|
+
get avatarSize(): 'md' | 'lg';
|
|
47
|
+
get hostClasses(): string;
|
|
48
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<KpUserMenuComponent, never>;
|
|
49
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<KpUserMenuComponent, "kp-user-menu", never, { "size": { "alias": "size"; "required": false; }; "userName": { "alias": "userName"; "required": false; }; "userEmail": { "alias": "userEmail"; "required": false; }; "userInitials": { "alias": "userInitials"; "required": false; }; "showEmail": { "alias": "showEmail"; "required": false; }; "showPlanBadge": { "alias": "showPlanBadge"; "required": false; }; "planName": { "alias": "planName"; "required": false; }; "showThemeToggle": { "alias": "showThemeToggle"; "required": false; }; "showHelpLink": { "alias": "showHelpLink"; "required": false; }; }, { "signOut": "signOut"; }, never, ["[kpUserMenuItems]", "[kpUserMenuTheme]", "[kpUserMenuHelp]"], true, never>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { KpUserMenuComponent };
|
|
53
|
+
export type { KpUserMenuItem, KpUserMenuSize };
|