hazo_auth 10.4.13 → 10.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -12,6 +12,8 @@ export * from "./components/layouts/shared/utils/validation.js";
12
12
  export { requestGoogleScopes } from "./lib/auth/request_google_scopes.js";
13
13
  export { PermissionDeniedDialog } from "./components/permission_denied_dialog.client.js";
14
14
  export type { PermissionDeniedDialogProps, PermissionDeniedDetails } from "./components/permission_denied_dialog.client";
15
+ export { UserPickerSelect, UserAvatar, userDisplayName } from "./components/user_picker_select.js";
16
+ export type { UserPickerSelectProps, UserAvatarProps, PickableUser, } from "./components/user_picker_select";
15
17
  export { AuthIssueCard, registerAuthIssueCardRenderer } from './admin-issues/plugin.client.js';
16
18
  export { PermissionDeniedProvider, showPermissionDeniedDialog, handlePermissionDenied, fetchWithPermissionCapture, } from './admin-issues/permission_denied_provider.client.js';
17
19
  export type { PermissionDeniedProviderProps } from './admin-issues/permission_denied_provider.client';
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAYA,cAAc,oBAAoB,CAAC;AAInC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAInI,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIpD,cAAc,uBAAuB,CAAC;AAItC,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AACjH,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC3G,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAC7G,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,qDAAqD,CAAC;AACnH,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,qDAAqD,CAAC;AAGvI,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAIxG,cAAc,8CAA8C,CAAC;AAG7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAGvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,8CAA8C,CAAC;AACtF,YAAY,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AAGzH,OAAO,EAAE,aAAa,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAG5F,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,kDAAkD,CAAC;AAC1D,YAAY,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAYA,cAAc,oBAAoB,CAAC;AAInC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAInI,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIpD,cAAc,uBAAuB,CAAC;AAItC,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AACjH,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC3G,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAC7G,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,qDAAqD,CAAC;AACnH,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,qDAAqD,CAAC;AAGvI,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAIxG,cAAc,8CAA8C,CAAC;AAG7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAGvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,8CAA8C,CAAC;AACtF,YAAY,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AAKzH,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAChG,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,YAAY,GACb,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAAE,aAAa,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAG5F,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,kDAAkD,CAAC;AAC1D,YAAY,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC"}
package/dist/client.js CHANGED
@@ -33,6 +33,10 @@ export * from "./components/layouts/shared/utils/validation.js";
33
33
  export { requestGoogleScopes } from "./lib/auth/request_google_scopes.js";
34
34
  // section: permission_denied_dialog_exports
35
35
  export { PermissionDeniedDialog } from "./components/permission_denied_dialog.client.js";
36
+ // section: user_picker_exports
37
+ // Reusable avatar + username dropdown for choosing a user (issue owner,
38
+ // assignee, mention, etc.). Data-agnostic — caller supplies the candidate list.
39
+ export { UserPickerSelect, UserAvatar, userDisplayName } from "./components/user_picker_select.js";
36
40
  // admin-issues plugin (client card renderer)
37
41
  export { AuthIssueCard, registerAuthIssueCardRenderer } from './admin-issues/plugin.client.js';
38
42
  // permission-denied provider + fetch helper
@@ -0,0 +1,58 @@
1
+ import * as React from "react";
2
+ export interface PickableUser {
3
+ /** Stable id — the value the picker commits. */
4
+ user_id: string;
5
+ /** Display name; falls back to email, then the id. */
6
+ name?: string | null;
7
+ email?: string | null;
8
+ /** Profile picture URL; absent/failed → tinted initials. */
9
+ profile_picture_url?: string | null;
10
+ }
11
+ export interface UserPickerSelectProps {
12
+ /** Candidate users to choose from. */
13
+ users: PickableUser[];
14
+ /** Selected user_id; null (or "") means unassigned. */
15
+ value: string | null;
16
+ /** Fired with the new user_id, or null when the unassigned row is picked. */
17
+ onChange: (userId: string | null) => void;
18
+ /** Prepend an "Unassigned" row. Default true. */
19
+ includeUnassigned?: boolean;
20
+ /** Label for the unassigned row. Default "Unassigned". */
21
+ unassignedLabel?: string;
22
+ /** Placeholder shown when nothing is selected. Default "Select user". */
23
+ placeholder?: string;
24
+ disabled?: boolean;
25
+ /** Control + avatar sizing. Default "default". */
26
+ size?: "sm" | "default";
27
+ /** Extra classes for the trigger. */
28
+ className?: string;
29
+ /**
30
+ * Classes for the portalled dropdown panel. The list renders in a body-level
31
+ * portal, so it escapes any theme tokens scoped to an ancestor — pass classes
32
+ * here when the surrounding surface pins its own tokens.
33
+ */
34
+ contentClassName?: string;
35
+ /** Inline styles for the portalled dropdown panel (e.g. pinned CSS token vars). */
36
+ contentStyle?: React.CSSProperties;
37
+ "aria-label"?: string;
38
+ }
39
+ /** name → email → id, so a row is never blank. */
40
+ export declare function userDisplayName(u: PickableUser): string;
41
+ export interface UserAvatarProps {
42
+ user?: PickableUser | null;
43
+ size?: "sm" | "default";
44
+ className?: string;
45
+ }
46
+ /**
47
+ * Standalone avatar: the profile picture when present, else tinted initials,
48
+ * else a muted person glyph for the empty/unassigned slot. Exported so callers
49
+ * can reuse the exact same avatar outside the picker (cards, headers, etc.).
50
+ */
51
+ export declare function UserAvatar({ user, size, className }: UserAvatarProps): React.JSX.Element;
52
+ /**
53
+ * A Select whose rows show a profile picture + username. The trigger mirrors the
54
+ * selected row (Radix `SelectValue` copies the item's children), so the chosen
55
+ * user's avatar + name show in the closed control automatically.
56
+ */
57
+ export declare function UserPickerSelect({ users, value, onChange, includeUnassigned, unassignedLabel, placeholder, disabled, size, className, contentClassName, contentStyle, "aria-label": ariaLabel, }: UserPickerSelectProps): React.JSX.Element;
58
+ //# sourceMappingURL=user_picker_select.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user_picker_select.d.ts","sourceRoot":"","sources":["../../src/components/user_picker_select.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAa/B,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,4DAA4D;IAC5D,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,uDAAuD;IACvD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C,iDAAiD;IACjD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kDAAkD;IAClD,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACxB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,YAAY,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAEvD;AA+BD,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,IAAgB,EAAE,SAAS,EAAE,EAAE,eAAe,qBAsBhF;AAGD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,KAAK,EACL,QAAQ,EACR,iBAAwB,EACxB,eAA8B,EAC9B,WAA2B,EAC3B,QAAQ,EACR,IAAgB,EAChB,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,YAAY,EAAE,SAAS,GACxB,EAAE,qBAAqB,qBAqCvB"}
@@ -0,0 +1,76 @@
1
+ // file_description: reusable user-picker dropdown — a Select whose rows render a
2
+ // profile picture (or tinted initials) beside the user's name. Client-safe;
3
+ // built on the shadcn Avatar + Select primitives. Data-agnostic: the caller
4
+ // supplies the candidate users and owns fetching them (e.g. via
5
+ // hazo_get_user_profiles server-side).
6
+ // section: client_directive
7
+ "use client";
8
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
+ import { UserRound } from "lucide-react";
10
+ import { Avatar, AvatarImage, AvatarFallback } from "./ui/avatar.js";
11
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "./ui/select.js";
12
+ import { cn } from "../lib/utils.js";
13
+ // Radix Select forbids an empty-string item value, so the unassigned row uses a
14
+ // sentinel that is mapped back to null across the component boundary.
15
+ const UNASSIGNED = "__hazo_unassigned__";
16
+ // section: helpers
17
+ /** name → email → id, so a row is never blank. */
18
+ export function userDisplayName(u) {
19
+ return (u.name && u.name.trim()) || (u.email && u.email.trim()) || u.user_id;
20
+ }
21
+ /** Up-to-two-letter initials from a label. */
22
+ function initialsOf(label) {
23
+ const s = label.trim();
24
+ if (!s)
25
+ return "?";
26
+ const parts = s.split(/[\s@._-]+/).filter(Boolean);
27
+ if (parts.length === 0)
28
+ return s.slice(0, 2).toUpperCase();
29
+ if (parts.length === 1)
30
+ return parts[0].slice(0, 2).toUpperCase();
31
+ return (parts[0][0] + parts[1][0]).toUpperCase();
32
+ }
33
+ // Deterministic fallback tint from a key, so the same user keeps one colour.
34
+ const TINTS = [
35
+ "bg-indigo-500 text-white",
36
+ "bg-emerald-500 text-white",
37
+ "bg-violet-500 text-white",
38
+ "bg-amber-500 text-white",
39
+ "bg-rose-500 text-white",
40
+ "bg-cyan-500 text-white",
41
+ "bg-sky-500 text-white",
42
+ "bg-fuchsia-500 text-white",
43
+ ];
44
+ function tintOf(key) {
45
+ let hash = 0;
46
+ for (let i = 0; i < key.length; i++)
47
+ hash = (hash * 31 + key.charCodeAt(i)) | 0;
48
+ return TINTS[Math.abs(hash) % TINTS.length];
49
+ }
50
+ /**
51
+ * Standalone avatar: the profile picture when present, else tinted initials,
52
+ * else a muted person glyph for the empty/unassigned slot. Exported so callers
53
+ * can reuse the exact same avatar outside the picker (cards, headers, etc.).
54
+ */
55
+ export function UserAvatar({ user, size = "default", className }) {
56
+ const dim = size === "sm" ? "h-5 w-5" : "h-6 w-6";
57
+ if (!user) {
58
+ return (_jsx(Avatar, { className: cn(dim, "bg-muted text-muted-foreground", className), children: _jsx(AvatarFallback, { className: "bg-transparent", children: _jsx(UserRound, { className: size === "sm" ? "h-3 w-3" : "h-3.5 w-3.5" }) }) }));
59
+ }
60
+ const label = userDisplayName(user);
61
+ return (_jsxs(Avatar, { className: cn(dim, className), children: [user.profile_picture_url ? (_jsx(AvatarImage, { src: user.profile_picture_url, alt: "" })) : null, _jsx(AvatarFallback, { className: cn("text-[9px] font-semibold", tintOf(user.user_id)), children: initialsOf(label) })] }));
62
+ }
63
+ // section: user_picker_select
64
+ /**
65
+ * A Select whose rows show a profile picture + username. The trigger mirrors the
66
+ * selected row (Radix `SelectValue` copies the item's children), so the chosen
67
+ * user's avatar + name show in the closed control automatically.
68
+ */
69
+ export function UserPickerSelect({ users, value, onChange, includeUnassigned = true, unassignedLabel = "Unassigned", placeholder = "Select user", disabled, size = "default", className, contentClassName, contentStyle, "aria-label": ariaLabel, }) {
70
+ const current = value ? value : includeUnassigned ? UNASSIGNED : "";
71
+ const handleChange = (next) => {
72
+ onChange(next === UNASSIGNED ? null : next);
73
+ };
74
+ const triggerSize = size === "sm" ? "h-7 gap-1.5 text-xs" : "h-9 gap-2 text-sm";
75
+ return (_jsxs(Select, { value: current || undefined, onValueChange: handleChange, disabled: disabled, children: [_jsx(SelectTrigger, { "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "Select user", className: cn(triggerSize, "min-w-0 [&>span]:truncate", className), children: _jsx(SelectValue, { placeholder: placeholder }) }), _jsxs(SelectContent, { className: contentClassName, style: contentStyle, children: [includeUnassigned ? (_jsx(SelectItem, { value: UNASSIGNED, children: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(UserAvatar, { user: null, size: size }), _jsx("span", { className: "truncate", children: unassignedLabel })] }) })) : null, users.map((u) => (_jsx(SelectItem, { value: u.user_id, children: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(UserAvatar, { user: u, size: size }), _jsx("span", { className: "truncate", children: userDisplayName(u) })] }) }, u.user_id)))] })] }));
76
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_auth",
3
- "version": "10.4.13",
3
+ "version": "10.5.0",
4
4
  "description": "Zero-config authentication UI components for Next.js with RBAC, OAuth, scope-based multi-tenancy, and invitations",
5
5
  "keywords": [
6
6
  "authentication",