@kanso-protocol/user-menu 0.1.0 → 0.2.1

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.
@@ -45,7 +45,7 @@ class KpUserMenuComponent {
45
45
  return `kp-user-menu kp-user-menu--${this.size}`;
46
46
  }
47
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: `
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: { properties: { "class": "hostClasses" } }, ngImport: i0, template: `
49
49
  <div class="kp-user-menu__info">
50
50
  <kp-avatar [size]="avatarSize" [initials]="userInitials || null" [showStatus]="true" status="online"/>
51
51
  <div class="kp-user-menu__text">
@@ -63,7 +63,7 @@ class KpUserMenuComponent {
63
63
 
64
64
  <div class="kp-user-menu__divider" aria-hidden="true"></div>
65
65
 
66
- <div class="kp-user-menu__group">
66
+ <div class="kp-user-menu__group" role="menu">
67
67
  <ng-content select="[kpUserMenuItems]"/>
68
68
  </div>
69
69
 
@@ -78,25 +78,25 @@ class KpUserMenuComponent {
78
78
  }
79
79
 
80
80
  @if (showHelpLink) {
81
- <div class="kp-user-menu__group">
81
+ <div class="kp-user-menu__group" role="menu">
82
82
  <ng-content select="[kpUserMenuHelp]"/>
83
83
  </div>
84
84
  <div class="kp-user-menu__divider" aria-hidden="true"></div>
85
85
  }
86
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()">
87
+ <div class="kp-user-menu__group" role="menu">
88
+ <button type="button" role="menuitem" class="kp-user-menu__row kp-user-menu__row--danger" (click)="signOut.emit()">
89
89
  <span class="kp-user-menu__row-icon" aria-hidden="true">
90
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
91
  </span>
92
92
  <span>Sign out</span>
93
93
  </button>
94
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 });
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-accent-danger-fg)}.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-accent-danger-fg)}\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
96
  }
97
97
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpUserMenuComponent, decorators: [{
98
98
  type: Component,
99
- args: [{ selector: 'kp-user-menu', imports: [KpAvatarComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'hostClasses', role: 'menu' }, template: `
99
+ args: [{ selector: 'kp-user-menu', imports: [KpAvatarComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'hostClasses' }, template: `
100
100
  <div class="kp-user-menu__info">
101
101
  <kp-avatar [size]="avatarSize" [initials]="userInitials || null" [showStatus]="true" status="online"/>
102
102
  <div class="kp-user-menu__text">
@@ -114,7 +114,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
114
114
 
115
115
  <div class="kp-user-menu__divider" aria-hidden="true"></div>
116
116
 
117
- <div class="kp-user-menu__group">
117
+ <div class="kp-user-menu__group" role="menu">
118
118
  <ng-content select="[kpUserMenuItems]"/>
119
119
  </div>
120
120
 
@@ -129,21 +129,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
129
129
  }
130
130
 
131
131
  @if (showHelpLink) {
132
- <div class="kp-user-menu__group">
132
+ <div class="kp-user-menu__group" role="menu">
133
133
  <ng-content select="[kpUserMenuHelp]"/>
134
134
  </div>
135
135
  <div class="kp-user-menu__divider" aria-hidden="true"></div>
136
136
  }
137
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()">
138
+ <div class="kp-user-menu__group" role="menu">
139
+ <button type="button" role="menuitem" class="kp-user-menu__row kp-user-menu__row--danger" (click)="signOut.emit()">
140
140
  <span class="kp-user-menu__row-icon" aria-hidden="true">
141
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
142
  </span>
143
143
  <span>Sign out</span>
144
144
  </button>
145
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"] }]
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-accent-danger-fg)}.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-accent-danger-fg)}\n"] }]
147
147
  }], propDecorators: { size: [{
148
148
  type: Input
149
149
  }], userName: [{
@@ -1 +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;;;;"}
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 is a floating panel containing menuitems alongside non-menu chrome\n // (user info card, theme toggle, divider). role=\"menu\" is scoped to each\n // menuitem-bearing group below; the host itself stays a generic container.\n host: { '[class]': 'hostClasses' },\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\" role=\"menu\">\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\" role=\"menu\">\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\" role=\"menu\">\n <button type=\"button\" role=\"menuitem\" 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-accent-danger-fg);\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-accent-danger-fg); }\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;MAyIU,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,OAAA,EAAA,aAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAhIpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,mlFAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EArDS,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;;2FAsIhB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAxI/B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,EAAA,OAAA,EACf,CAAC,iBAAiB,CAAC,mBACX,uBAAuB,CAAC,MAAM,EAAA,IAAA,EAIzC,EAAE,SAAS,EAAE,aAAa,EAAE,EAAA,QAAA,EACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,mlFAAA,CAAA,EAAA;;sBAkFA;;sBAEA;;sBACA;;sBACA;;sBAEA;;sBACA;;sBACA;;sBACA;;sBACA;;sBAEA;;;AC/LH;;AAEG;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanso-protocol/user-menu",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "license": "MIT",
5
5
  "peerDependencies": {
6
6
  "@angular/core": "^18.0.0",