@kanso-protocol/user-menu 0.2.1 → 0.5.3

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.
@@ -1,6 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { EventEmitter, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
  import { KpAvatarComponent } from '@kanso-protocol/avatar';
4
+ import { KpMenuItemComponent } from '@kanso-protocol/menu';
4
5
 
5
6
  /**
6
7
  * Kanso Protocol — UserMenu
@@ -85,18 +86,15 @@ class KpUserMenuComponent {
85
86
  }
86
87
 
87
88
  <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
- <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>
89
+ <kp-menu-item label="Sign out" [danger]="true" (click)="signOut.emit()">
90
+ <svg kpMenuItemIcon 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
+ </kp-menu-item>
94
92
  </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-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 });
93
+ `, 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-surface-base);border:1px solid var(--kp-color-border-default);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-text-strong)}.kp-user-menu__plan{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:var(--kp-color-primary-default-bg-rest);color:var(--kp-color-foreground-on-saturated);font-size:11px;font-weight:600;line-height:1}.kp-user-menu__email{font-size:12px;color:var(--kp-color-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kp-user-menu__divider{height:1px;background:var(--kp-color-surface-strong)}.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-text-default)}.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-text-default);cursor:pointer;transition:background var(--kp-motion-duration-fast) ease}.kp-user-menu__row:hover{background:var(--kp-color-surface-subtle)}.kp-user-menu__row-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--kp-color-text-muted)}.kp-user-menu__row-icon svg{width:100%;height:100%}.kp-user-menu__row--danger,.kp-user-menu__row--danger .kp-user-menu__row-icon{color:var(--kp-color-menu-item-fg-danger-rest)}.kp-user-menu__row--danger:hover{background:var(--kp-color-danger-subtle-bg-rest);color:var(--kp-color-menu-item-fg-danger-hover)}\n"], dependencies: [{ kind: "component", type: KpAvatarComponent, selector: "kp-avatar", inputs: ["size", "shape", "appearance", "initials", "src", "alt", "showStatus", "status", "showRing", "ariaLabelOverride"] }, { kind: "component", type: KpMenuItemComponent, selector: "kp-menu-item", inputs: ["size", "label", "description", "shortcut", "hasChevron", "selected", "danger", "disabled", "forceState"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
96
94
  }
97
95
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpUserMenuComponent, decorators: [{
98
96
  type: Component,
99
- args: [{ selector: 'kp-user-menu', imports: [KpAvatarComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'hostClasses' }, template: `
97
+ args: [{ selector: 'kp-user-menu', imports: [KpAvatarComponent, KpMenuItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'hostClasses' }, template: `
100
98
  <div class="kp-user-menu__info">
101
99
  <kp-avatar [size]="avatarSize" [initials]="userInitials || null" [showStatus]="true" status="online"/>
102
100
  <div class="kp-user-menu__text">
@@ -136,14 +134,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
136
134
  }
137
135
 
138
136
  <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
- <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>
137
+ <kp-menu-item label="Sign out" [danger]="true" (click)="signOut.emit()">
138
+ <svg kpMenuItemIcon 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>
139
+ </kp-menu-item>
145
140
  </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-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"] }]
141
+ `, 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-surface-base);border:1px solid var(--kp-color-border-default);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-text-strong)}.kp-user-menu__plan{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:var(--kp-color-primary-default-bg-rest);color:var(--kp-color-foreground-on-saturated);font-size:11px;font-weight:600;line-height:1}.kp-user-menu__email{font-size:12px;color:var(--kp-color-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kp-user-menu__divider{height:1px;background:var(--kp-color-surface-strong)}.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-text-default)}.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-text-default);cursor:pointer;transition:background var(--kp-motion-duration-fast) ease}.kp-user-menu__row:hover{background:var(--kp-color-surface-subtle)}.kp-user-menu__row-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--kp-color-text-muted)}.kp-user-menu__row-icon svg{width:100%;height:100%}.kp-user-menu__row--danger,.kp-user-menu__row--danger .kp-user-menu__row-icon{color:var(--kp-color-menu-item-fg-danger-rest)}.kp-user-menu__row--danger:hover{background:var(--kp-color-danger-subtle-bg-rest);color:var(--kp-color-menu-item-fg-danger-hover)}\n"] }]
147
142
  }], propDecorators: { size: [{
148
143
  type: Input
149
144
  }], 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 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;;;;"}
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';\nimport { KpMenuItemComponent } from '@kanso-protocol/menu';\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, KpMenuItemComponent],\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 <kp-menu-item label=\"Sign out\" [danger]=\"true\" (click)=\"signOut.emit()\">\n <svg kpMenuItemIcon 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 </kp-menu-item>\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-surface-base);\n border: 1px solid var(--kp-color-border-default);\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-text-strong); }\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-primary-default-bg-rest);\n color: var(--kp-color-foreground-on-saturated);\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-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n\n .kp-user-menu__divider { height: 1px; background: var(--kp-color-surface-strong); }\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-text-default); }\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-text-default);\n cursor: pointer;\n transition: background var(--kp-motion-duration-fast) ease;\n }\n /* Match DropdownMenu menu-item hover exactly: bg → surface-subtle,\n fg unchanged. The user-menu-row was previously using\n surface-muted (one step darker) which read differently from\n regular menu items. Architectural follow-up: replace\n .kp-user-menu__row with <kp-menu-item>. */\n .kp-user-menu__row:hover { background: var(--kp-color-surface-subtle); }\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-text-muted);\n }\n .kp-user-menu__row-icon svg { width: 100%; height: 100%; }\n\n .kp-user-menu__row--danger {\n color: var(--kp-color-menu-item-fg-danger-rest);\n }\n .kp-user-menu__row--danger .kp-user-menu__row-icon { color: var(--kp-color-menu-item-fg-danger-rest); }\n .kp-user-menu__row--danger:hover { background: var(--kp-color-danger-subtle-bg-rest); color: var(--kp-color-menu-item-fg-danger-hover); }\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":";;;;;AAkBA;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;MA2IU,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,EAlIpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CT,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,mzEAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAlDS,iBAAiB,kLAAE,mBAAmB,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,OAAA,EAAA,aAAA,EAAA,UAAA,EAAA,YAAA,EAAA,UAAA,EAAA,QAAA,EAAA,UAAA,EAAA,YAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAwIrC,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBA1I/B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,WACf,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,EAAA,eAAA,EAChC,uBAAuB,CAAC,MAAM,QAIzC,EAAE,SAAS,EAAE,aAAa,EAAE,EAAA,QAAA,EACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,mzEAAA,CAAA,EAAA;;sBAuFA;;sBAEA;;sBACA;;sBACA;;sBAEA;;sBACA;;sBACA;;sBACA;;sBACA;;sBAEA;;;AClMH;;AAEG;;;;"}
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@kanso-protocol/user-menu",
3
- "version": "0.2.1",
3
+ "version": "0.5.3",
4
4
  "license": "MIT",
5
5
  "peerDependencies": {
6
6
  "@angular/core": "^18.0.0",
7
7
  "@angular/common": "^18.0.0",
8
- "@kanso-protocol/core": "^0.0.1",
9
- "@kanso-protocol/avatar": ">=0.1.0"
8
+ "@kanso-protocol/core": ">=0.5.3",
9
+ "@kanso-protocol/avatar": ">=0.5.3",
10
+ "@kanso-protocol/menu": ">=0.5.3"
10
11
  },
11
12
  "description": "Kanso Protocol — user-menu (pattern).",
12
13
  "author": "GregNBlack",