@omnibase/shadcn 0.5.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.
package/dist/index.cjs CHANGED
@@ -40,6 +40,7 @@ __export(index_exports, {
40
40
  SwitchActiveTenant: () => SwitchActiveTenant,
41
41
  TenantCreator: () => TenantCreator,
42
42
  UserInvite: () => UserInvite,
43
+ UserViewer: () => UserViewer,
43
44
  VerificationForm: () => VerificationForm,
44
45
  filterInputNodes: () => filterInputNodes,
45
46
  findAnchorNode: () => findAnchorNode,
@@ -146,7 +147,7 @@ var alertVariants = (0, import_class_variance_authority.cva)(
146
147
  destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
147
148
  warning: "border-yellow-500/50 text-yellow-700 bg-yellow-50 dark:border-yellow-500 dark:text-yellow-200 dark:bg-yellow-950/20 [&>svg]:text-yellow-600 dark:[&>svg]:text-yellow-200",
148
149
  success: "border-green-500/50 text-green-700 bg-green-50 dark:border-green-500 dark:text-green-200 dark:bg-green-950/20 [&>svg]:text-green-600 dark:[&>svg]:text-green-200",
149
- info: "border-blue-500/50 text-blue-700 bg-blue-50 dark:border-blue-500 dark:text-blue-200 dark:bg-blue-950/20 [&>svg]:text-blue-600 dark:[&>svg]:text-blue-200"
150
+ info: "border-blue-500/50 text-blue-900 bg-blue-50 dark:border-blue-500 dark:text-blue-200 dark:bg-blue-950/20 [&>svg]:text-blue-900 dark:[&>svg]:text-blue-200"
150
151
  }
151
152
  },
152
153
  defaultVariants: {
@@ -2018,6 +2019,256 @@ function RoleCreator({
2018
2019
  ] })
2019
2020
  ] });
2020
2021
  }
2022
+
2023
+ // src/user-viewer/index.tsx
2024
+ var import_react4 = require("react");
2025
+
2026
+ // src/components/ui/table.tsx
2027
+ var React16 = require("react");
2028
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2029
+ function Table({ className, ...props }) {
2030
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2031
+ "div",
2032
+ {
2033
+ "data-slot": "table-container",
2034
+ className: "relative w-full overflow-x-auto",
2035
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2036
+ "table",
2037
+ {
2038
+ "data-slot": "table",
2039
+ className: cn("w-full caption-bottom text-sm", className),
2040
+ ...props
2041
+ }
2042
+ )
2043
+ }
2044
+ );
2045
+ }
2046
+ function TableHeader({ className, ...props }) {
2047
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2048
+ "thead",
2049
+ {
2050
+ "data-slot": "table-header",
2051
+ className: cn("[&_tr]:border-b", className),
2052
+ ...props
2053
+ }
2054
+ );
2055
+ }
2056
+ function TableBody({ className, ...props }) {
2057
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2058
+ "tbody",
2059
+ {
2060
+ "data-slot": "table-body",
2061
+ className: cn("[&_tr:last-child]:border-0", className),
2062
+ ...props
2063
+ }
2064
+ );
2065
+ }
2066
+ function TableRow({ className, ...props }) {
2067
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2068
+ "tr",
2069
+ {
2070
+ "data-slot": "table-row",
2071
+ className: cn(
2072
+ "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
2073
+ className
2074
+ ),
2075
+ ...props
2076
+ }
2077
+ );
2078
+ }
2079
+ function TableHead({ className, ...props }) {
2080
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2081
+ "th",
2082
+ {
2083
+ "data-slot": "table-head",
2084
+ className: cn(
2085
+ "text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
2086
+ className
2087
+ ),
2088
+ ...props
2089
+ }
2090
+ );
2091
+ }
2092
+ function TableCell({ className, ...props }) {
2093
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2094
+ "td",
2095
+ {
2096
+ "data-slot": "table-cell",
2097
+ className: cn(
2098
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
2099
+ className
2100
+ ),
2101
+ ...props
2102
+ }
2103
+ );
2104
+ }
2105
+
2106
+ // src/components/ui/avatar.tsx
2107
+ var React17 = require("react");
2108
+ var AvatarPrimitive = __toESM(require("@radix-ui/react-avatar"), 1);
2109
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2110
+ function Avatar({
2111
+ className,
2112
+ ...props
2113
+ }) {
2114
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2115
+ AvatarPrimitive.Root,
2116
+ {
2117
+ "data-slot": "avatar",
2118
+ className: cn(
2119
+ "relative flex size-8 shrink-0 overflow-hidden rounded-full",
2120
+ className
2121
+ ),
2122
+ ...props
2123
+ }
2124
+ );
2125
+ }
2126
+ function AvatarFallback({
2127
+ className,
2128
+ ...props
2129
+ }) {
2130
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2131
+ AvatarPrimitive.Fallback,
2132
+ {
2133
+ "data-slot": "avatar-fallback",
2134
+ className: cn(
2135
+ "bg-muted flex size-full items-center justify-center rounded-full",
2136
+ className
2137
+ ),
2138
+ ...props
2139
+ }
2140
+ );
2141
+ }
2142
+
2143
+ // src/user-viewer/index.tsx
2144
+ var import_lucide_react4 = require("lucide-react");
2145
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2146
+ function UserViewer({
2147
+ users,
2148
+ availableRoles,
2149
+ canEditUsers,
2150
+ onRoleUpdate,
2151
+ onRemoveUser
2152
+ }) {
2153
+ const [searchQuery, setSearchQuery] = (0, import_react4.useState)("");
2154
+ const [isUpdating, setIsUpdating] = (0, import_react4.useState)({});
2155
+ const getInitials = (firstName, lastName) => {
2156
+ return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
2157
+ };
2158
+ const filteredUsers = (0, import_react4.useMemo)(() => {
2159
+ if (!searchQuery.trim()) return users;
2160
+ const query = searchQuery.toLowerCase();
2161
+ return users.filter(
2162
+ (user) => user.first_name.toLowerCase().includes(query) || user.last_name.toLowerCase().includes(query) || user.email.toLowerCase().includes(query) || user.role.toLowerCase().includes(query)
2163
+ );
2164
+ }, [users, searchQuery]);
2165
+ const handleRoleUpdate = async (userId, newRole) => {
2166
+ if (!onRoleUpdate) return;
2167
+ setIsUpdating((prev) => ({ ...prev, [userId]: true }));
2168
+ try {
2169
+ await onRoleUpdate(userId, newRole);
2170
+ } catch (error) {
2171
+ console.error("Failed to update role:", error);
2172
+ } finally {
2173
+ setIsUpdating((prev) => ({ ...prev, [userId]: false }));
2174
+ }
2175
+ };
2176
+ const handleRemoveUser = async (userId) => {
2177
+ if (!onRemoveUser) return;
2178
+ const confirmed = window.confirm(
2179
+ "Are you sure you want to remove this user from the organization?"
2180
+ );
2181
+ if (!confirmed) return;
2182
+ setIsUpdating((prev) => ({ ...prev, [userId]: true }));
2183
+ try {
2184
+ await onRemoveUser(userId);
2185
+ } catch (error) {
2186
+ console.error("Failed to remove user:", error);
2187
+ } finally {
2188
+ setIsUpdating((prev) => ({ ...prev, [userId]: false }));
2189
+ }
2190
+ };
2191
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Card, { className: "w-full max-w-6xl", children: [
2192
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(CardHeader, { children: [
2193
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(CardTitle, { children: "Team Members" }),
2194
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(CardDescription, { children: canEditUsers ? "View and manage users in your organization" : "View users in your organization" })
2195
+ ] }),
2196
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(CardContent, { children: [
2197
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "mb-6", children: [
2198
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Label, { htmlFor: "search", className: "sr-only", children: "Search users" }),
2199
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "relative", children: [
2200
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react4.Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
2201
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2202
+ Input,
2203
+ {
2204
+ id: "search",
2205
+ type: "text",
2206
+ placeholder: "Search by name, email, or role...",
2207
+ value: searchQuery,
2208
+ onChange: (e) => setSearchQuery(e.target.value),
2209
+ className: "pl-10"
2210
+ }
2211
+ )
2212
+ ] }),
2213
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("p", { className: "text-xs text-muted-foreground mt-2", children: [
2214
+ "Showing ",
2215
+ filteredUsers.length,
2216
+ " of ",
2217
+ users.length,
2218
+ " users"
2219
+ ] })
2220
+ ] }),
2221
+ filteredUsers.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Table, { children: [
2222
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(TableRow, { children: [
2223
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHead, { className: "w-[300px]", children: "User" }),
2224
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHead, { children: "Email" }),
2225
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHead, { className: "w-[180px]", children: "Role" }),
2226
+ canEditUsers && onRemoveUser && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHead, { className: "w-[100px] text-right", children: "Actions" })
2227
+ ] }) }),
2228
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableBody, { children: filteredUsers.map((user) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(TableRow, { children: [
2229
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableCell, { className: "font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-3", children: [
2230
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Avatar, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AvatarFallback, { children: getInitials(user.first_name, user.last_name) }) }),
2231
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
2232
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "font-medium", children: [
2233
+ user.first_name,
2234
+ " ",
2235
+ user.last_name
2236
+ ] }),
2237
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "text-xs text-muted-foreground md:hidden", children: user.email })
2238
+ ] })
2239
+ ] }) }),
2240
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableCell, { className: "hidden md:table-cell", children: user.email }),
2241
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableCell, { children: canEditUsers && onRoleUpdate ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2242
+ Select,
2243
+ {
2244
+ value: user.role,
2245
+ onValueChange: (newRole) => handleRoleUpdate(user.user_id, newRole),
2246
+ disabled: isUpdating[user.user_id],
2247
+ children: [
2248
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SelectTrigger, { className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SelectValue, {}) }),
2249
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SelectContent, { children: availableRoles.map((role) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SelectItem, { value: role, children: role }, role)) })
2250
+ ]
2251
+ }
2252
+ ) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "capitalize text-sm font-medium", children: user.role }) }),
2253
+ canEditUsers && onRemoveUser && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableCell, { className: "text-right", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2254
+ Button,
2255
+ {
2256
+ variant: "ghost",
2257
+ size: "icon",
2258
+ onClick: () => handleRemoveUser(user.user_id),
2259
+ disabled: isUpdating[user.user_id],
2260
+ className: "h-8 w-8",
2261
+ children: [
2262
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react4.UserX, { className: "h-4 w-4" }),
2263
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "sr-only", children: "Remove user" })
2264
+ ]
2265
+ }
2266
+ ) })
2267
+ ] }, user.user_id)) })
2268
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "text-center py-12 border rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-muted-foreground", children: searchQuery ? "No users found matching your search" : "No users in this organization yet" }) })
2269
+ ] })
2270
+ ] });
2271
+ }
2021
2272
  // Annotate the CommonJS export names for ESM import in node:
2022
2273
  0 && (module.exports = {
2023
2274
  LoginForm,
@@ -2029,6 +2280,7 @@ function RoleCreator({
2029
2280
  SwitchActiveTenant,
2030
2281
  TenantCreator,
2031
2282
  UserInvite,
2283
+ UserViewer,
2032
2284
  VerificationForm,
2033
2285
  filterInputNodes,
2034
2286
  findAnchorNode,
package/dist/index.d.cts CHANGED
@@ -157,4 +157,20 @@ interface RoleCreatorProps {
157
157
  }
158
158
  declare function RoleCreator({ definitions, roles, namespaceMap, onRoleCreate, onRoleUpdate, }: RoleCreatorProps): react_jsx_runtime.JSX.Element;
159
159
 
160
- export { type CustomFormProps, type FlowType, LoginForm, type LoginFormProps, type NodesByGroup, PricingTable, type PricingTableProps, RecoveryForm, type RecoveryFormProps, RegistrationForm, type RegistrationFormProps, RoleCreator, SettingsForm, type SettingsFormProps, SwitchActiveTenant, type SwitchActiveTenantProps, TenantCreator, type TenantCreatorConfig, type TenantCreatorFormActions, type TenantCreatorProps, UserInvite, VerificationForm, type VerificationFormProps, filterInputNodes, findAnchorNode, findCsrfToken, findSubmitButton, groupNodesByGroup, isUiNodeInputAttributes, sortNodes };
160
+ interface TenantUser {
161
+ user_id: string;
162
+ first_name: string;
163
+ last_name: string;
164
+ email: string;
165
+ role: string;
166
+ }
167
+ interface UserViewerProps {
168
+ users: TenantUser[];
169
+ availableRoles: string[];
170
+ canEditUsers: boolean;
171
+ onRoleUpdate?: (userId: string, newRole: string) => void | Promise<void>;
172
+ onRemoveUser?: (userId: string) => void | Promise<void>;
173
+ }
174
+ declare function UserViewer({ users, availableRoles, canEditUsers, onRoleUpdate, onRemoveUser, }: UserViewerProps): react_jsx_runtime.JSX.Element;
175
+
176
+ export { type CustomFormProps, type FlowType, LoginForm, type LoginFormProps, type NodesByGroup, PricingTable, type PricingTableProps, RecoveryForm, type RecoveryFormProps, RegistrationForm, type RegistrationFormProps, RoleCreator, SettingsForm, type SettingsFormProps, SwitchActiveTenant, type SwitchActiveTenantProps, TenantCreator, type TenantCreatorConfig, type TenantCreatorFormActions, type TenantCreatorProps, type TenantUser, UserInvite, UserViewer, VerificationForm, type VerificationFormProps, filterInputNodes, findAnchorNode, findCsrfToken, findSubmitButton, groupNodesByGroup, isUiNodeInputAttributes, sortNodes };
package/dist/index.d.ts CHANGED
@@ -157,4 +157,20 @@ interface RoleCreatorProps {
157
157
  }
158
158
  declare function RoleCreator({ definitions, roles, namespaceMap, onRoleCreate, onRoleUpdate, }: RoleCreatorProps): react_jsx_runtime.JSX.Element;
159
159
 
160
- export { type CustomFormProps, type FlowType, LoginForm, type LoginFormProps, type NodesByGroup, PricingTable, type PricingTableProps, RecoveryForm, type RecoveryFormProps, RegistrationForm, type RegistrationFormProps, RoleCreator, SettingsForm, type SettingsFormProps, SwitchActiveTenant, type SwitchActiveTenantProps, TenantCreator, type TenantCreatorConfig, type TenantCreatorFormActions, type TenantCreatorProps, UserInvite, VerificationForm, type VerificationFormProps, filterInputNodes, findAnchorNode, findCsrfToken, findSubmitButton, groupNodesByGroup, isUiNodeInputAttributes, sortNodes };
160
+ interface TenantUser {
161
+ user_id: string;
162
+ first_name: string;
163
+ last_name: string;
164
+ email: string;
165
+ role: string;
166
+ }
167
+ interface UserViewerProps {
168
+ users: TenantUser[];
169
+ availableRoles: string[];
170
+ canEditUsers: boolean;
171
+ onRoleUpdate?: (userId: string, newRole: string) => void | Promise<void>;
172
+ onRemoveUser?: (userId: string) => void | Promise<void>;
173
+ }
174
+ declare function UserViewer({ users, availableRoles, canEditUsers, onRoleUpdate, onRemoveUser, }: UserViewerProps): react_jsx_runtime.JSX.Element;
175
+
176
+ export { type CustomFormProps, type FlowType, LoginForm, type LoginFormProps, type NodesByGroup, PricingTable, type PricingTableProps, RecoveryForm, type RecoveryFormProps, RegistrationForm, type RegistrationFormProps, RoleCreator, SettingsForm, type SettingsFormProps, SwitchActiveTenant, type SwitchActiveTenantProps, TenantCreator, type TenantCreatorConfig, type TenantCreatorFormActions, type TenantCreatorProps, type TenantUser, UserInvite, UserViewer, VerificationForm, type VerificationFormProps, filterInputNodes, findAnchorNode, findCsrfToken, findSubmitButton, groupNodesByGroup, isUiNodeInputAttributes, sortNodes };
package/dist/index.js CHANGED
@@ -95,7 +95,7 @@ var alertVariants = cva(
95
95
  destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
96
96
  warning: "border-yellow-500/50 text-yellow-700 bg-yellow-50 dark:border-yellow-500 dark:text-yellow-200 dark:bg-yellow-950/20 [&>svg]:text-yellow-600 dark:[&>svg]:text-yellow-200",
97
97
  success: "border-green-500/50 text-green-700 bg-green-50 dark:border-green-500 dark:text-green-200 dark:bg-green-950/20 [&>svg]:text-green-600 dark:[&>svg]:text-green-200",
98
- info: "border-blue-500/50 text-blue-700 bg-blue-50 dark:border-blue-500 dark:text-blue-200 dark:bg-blue-950/20 [&>svg]:text-blue-600 dark:[&>svg]:text-blue-200"
98
+ info: "border-blue-500/50 text-blue-900 bg-blue-50 dark:border-blue-500 dark:text-blue-200 dark:bg-blue-950/20 [&>svg]:text-blue-900 dark:[&>svg]:text-blue-200"
99
99
  }
100
100
  },
101
101
  defaultVariants: {
@@ -1967,6 +1967,256 @@ function RoleCreator({
1967
1967
  ] })
1968
1968
  ] });
1969
1969
  }
1970
+
1971
+ // src/user-viewer/index.tsx
1972
+ import { useState as useState7, useMemo as useMemo3 } from "react";
1973
+
1974
+ // src/components/ui/table.tsx
1975
+ import "react";
1976
+ import { jsx as jsx27 } from "react/jsx-runtime";
1977
+ function Table({ className, ...props }) {
1978
+ return /* @__PURE__ */ jsx27(
1979
+ "div",
1980
+ {
1981
+ "data-slot": "table-container",
1982
+ className: "relative w-full overflow-x-auto",
1983
+ children: /* @__PURE__ */ jsx27(
1984
+ "table",
1985
+ {
1986
+ "data-slot": "table",
1987
+ className: cn("w-full caption-bottom text-sm", className),
1988
+ ...props
1989
+ }
1990
+ )
1991
+ }
1992
+ );
1993
+ }
1994
+ function TableHeader({ className, ...props }) {
1995
+ return /* @__PURE__ */ jsx27(
1996
+ "thead",
1997
+ {
1998
+ "data-slot": "table-header",
1999
+ className: cn("[&_tr]:border-b", className),
2000
+ ...props
2001
+ }
2002
+ );
2003
+ }
2004
+ function TableBody({ className, ...props }) {
2005
+ return /* @__PURE__ */ jsx27(
2006
+ "tbody",
2007
+ {
2008
+ "data-slot": "table-body",
2009
+ className: cn("[&_tr:last-child]:border-0", className),
2010
+ ...props
2011
+ }
2012
+ );
2013
+ }
2014
+ function TableRow({ className, ...props }) {
2015
+ return /* @__PURE__ */ jsx27(
2016
+ "tr",
2017
+ {
2018
+ "data-slot": "table-row",
2019
+ className: cn(
2020
+ "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
2021
+ className
2022
+ ),
2023
+ ...props
2024
+ }
2025
+ );
2026
+ }
2027
+ function TableHead({ className, ...props }) {
2028
+ return /* @__PURE__ */ jsx27(
2029
+ "th",
2030
+ {
2031
+ "data-slot": "table-head",
2032
+ className: cn(
2033
+ "text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
2034
+ className
2035
+ ),
2036
+ ...props
2037
+ }
2038
+ );
2039
+ }
2040
+ function TableCell({ className, ...props }) {
2041
+ return /* @__PURE__ */ jsx27(
2042
+ "td",
2043
+ {
2044
+ "data-slot": "table-cell",
2045
+ className: cn(
2046
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
2047
+ className
2048
+ ),
2049
+ ...props
2050
+ }
2051
+ );
2052
+ }
2053
+
2054
+ // src/components/ui/avatar.tsx
2055
+ import "react";
2056
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
2057
+ import { jsx as jsx28 } from "react/jsx-runtime";
2058
+ function Avatar({
2059
+ className,
2060
+ ...props
2061
+ }) {
2062
+ return /* @__PURE__ */ jsx28(
2063
+ AvatarPrimitive.Root,
2064
+ {
2065
+ "data-slot": "avatar",
2066
+ className: cn(
2067
+ "relative flex size-8 shrink-0 overflow-hidden rounded-full",
2068
+ className
2069
+ ),
2070
+ ...props
2071
+ }
2072
+ );
2073
+ }
2074
+ function AvatarFallback({
2075
+ className,
2076
+ ...props
2077
+ }) {
2078
+ return /* @__PURE__ */ jsx28(
2079
+ AvatarPrimitive.Fallback,
2080
+ {
2081
+ "data-slot": "avatar-fallback",
2082
+ className: cn(
2083
+ "bg-muted flex size-full items-center justify-center rounded-full",
2084
+ className
2085
+ ),
2086
+ ...props
2087
+ }
2088
+ );
2089
+ }
2090
+
2091
+ // src/user-viewer/index.tsx
2092
+ import { Search, UserX } from "lucide-react";
2093
+ import { jsx as jsx29, jsxs as jsxs16 } from "react/jsx-runtime";
2094
+ function UserViewer({
2095
+ users,
2096
+ availableRoles,
2097
+ canEditUsers,
2098
+ onRoleUpdate,
2099
+ onRemoveUser
2100
+ }) {
2101
+ const [searchQuery, setSearchQuery] = useState7("");
2102
+ const [isUpdating, setIsUpdating] = useState7({});
2103
+ const getInitials = (firstName, lastName) => {
2104
+ return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
2105
+ };
2106
+ const filteredUsers = useMemo3(() => {
2107
+ if (!searchQuery.trim()) return users;
2108
+ const query = searchQuery.toLowerCase();
2109
+ return users.filter(
2110
+ (user) => user.first_name.toLowerCase().includes(query) || user.last_name.toLowerCase().includes(query) || user.email.toLowerCase().includes(query) || user.role.toLowerCase().includes(query)
2111
+ );
2112
+ }, [users, searchQuery]);
2113
+ const handleRoleUpdate = async (userId, newRole) => {
2114
+ if (!onRoleUpdate) return;
2115
+ setIsUpdating((prev) => ({ ...prev, [userId]: true }));
2116
+ try {
2117
+ await onRoleUpdate(userId, newRole);
2118
+ } catch (error) {
2119
+ console.error("Failed to update role:", error);
2120
+ } finally {
2121
+ setIsUpdating((prev) => ({ ...prev, [userId]: false }));
2122
+ }
2123
+ };
2124
+ const handleRemoveUser = async (userId) => {
2125
+ if (!onRemoveUser) return;
2126
+ const confirmed = window.confirm(
2127
+ "Are you sure you want to remove this user from the organization?"
2128
+ );
2129
+ if (!confirmed) return;
2130
+ setIsUpdating((prev) => ({ ...prev, [userId]: true }));
2131
+ try {
2132
+ await onRemoveUser(userId);
2133
+ } catch (error) {
2134
+ console.error("Failed to remove user:", error);
2135
+ } finally {
2136
+ setIsUpdating((prev) => ({ ...prev, [userId]: false }));
2137
+ }
2138
+ };
2139
+ return /* @__PURE__ */ jsxs16(Card, { className: "w-full max-w-6xl", children: [
2140
+ /* @__PURE__ */ jsxs16(CardHeader, { children: [
2141
+ /* @__PURE__ */ jsx29(CardTitle, { children: "Team Members" }),
2142
+ /* @__PURE__ */ jsx29(CardDescription, { children: canEditUsers ? "View and manage users in your organization" : "View users in your organization" })
2143
+ ] }),
2144
+ /* @__PURE__ */ jsxs16(CardContent, { children: [
2145
+ /* @__PURE__ */ jsxs16("div", { className: "mb-6", children: [
2146
+ /* @__PURE__ */ jsx29(Label, { htmlFor: "search", className: "sr-only", children: "Search users" }),
2147
+ /* @__PURE__ */ jsxs16("div", { className: "relative", children: [
2148
+ /* @__PURE__ */ jsx29(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
2149
+ /* @__PURE__ */ jsx29(
2150
+ Input,
2151
+ {
2152
+ id: "search",
2153
+ type: "text",
2154
+ placeholder: "Search by name, email, or role...",
2155
+ value: searchQuery,
2156
+ onChange: (e) => setSearchQuery(e.target.value),
2157
+ className: "pl-10"
2158
+ }
2159
+ )
2160
+ ] }),
2161
+ /* @__PURE__ */ jsxs16("p", { className: "text-xs text-muted-foreground mt-2", children: [
2162
+ "Showing ",
2163
+ filteredUsers.length,
2164
+ " of ",
2165
+ users.length,
2166
+ " users"
2167
+ ] })
2168
+ ] }),
2169
+ filteredUsers.length > 0 ? /* @__PURE__ */ jsx29("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs16(Table, { children: [
2170
+ /* @__PURE__ */ jsx29(TableHeader, { children: /* @__PURE__ */ jsxs16(TableRow, { children: [
2171
+ /* @__PURE__ */ jsx29(TableHead, { className: "w-[300px]", children: "User" }),
2172
+ /* @__PURE__ */ jsx29(TableHead, { children: "Email" }),
2173
+ /* @__PURE__ */ jsx29(TableHead, { className: "w-[180px]", children: "Role" }),
2174
+ canEditUsers && onRemoveUser && /* @__PURE__ */ jsx29(TableHead, { className: "w-[100px] text-right", children: "Actions" })
2175
+ ] }) }),
2176
+ /* @__PURE__ */ jsx29(TableBody, { children: filteredUsers.map((user) => /* @__PURE__ */ jsxs16(TableRow, { children: [
2177
+ /* @__PURE__ */ jsx29(TableCell, { className: "font-medium", children: /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3", children: [
2178
+ /* @__PURE__ */ jsx29(Avatar, { children: /* @__PURE__ */ jsx29(AvatarFallback, { children: getInitials(user.first_name, user.last_name) }) }),
2179
+ /* @__PURE__ */ jsxs16("div", { children: [
2180
+ /* @__PURE__ */ jsxs16("div", { className: "font-medium", children: [
2181
+ user.first_name,
2182
+ " ",
2183
+ user.last_name
2184
+ ] }),
2185
+ /* @__PURE__ */ jsx29("div", { className: "text-xs text-muted-foreground md:hidden", children: user.email })
2186
+ ] })
2187
+ ] }) }),
2188
+ /* @__PURE__ */ jsx29(TableCell, { className: "hidden md:table-cell", children: user.email }),
2189
+ /* @__PURE__ */ jsx29(TableCell, { children: canEditUsers && onRoleUpdate ? /* @__PURE__ */ jsxs16(
2190
+ Select,
2191
+ {
2192
+ value: user.role,
2193
+ onValueChange: (newRole) => handleRoleUpdate(user.user_id, newRole),
2194
+ disabled: isUpdating[user.user_id],
2195
+ children: [
2196
+ /* @__PURE__ */ jsx29(SelectTrigger, { className: "w-full", children: /* @__PURE__ */ jsx29(SelectValue, {}) }),
2197
+ /* @__PURE__ */ jsx29(SelectContent, { children: availableRoles.map((role) => /* @__PURE__ */ jsx29(SelectItem, { value: role, children: role }, role)) })
2198
+ ]
2199
+ }
2200
+ ) : /* @__PURE__ */ jsx29("span", { className: "capitalize text-sm font-medium", children: user.role }) }),
2201
+ canEditUsers && onRemoveUser && /* @__PURE__ */ jsx29(TableCell, { className: "text-right", children: /* @__PURE__ */ jsxs16(
2202
+ Button,
2203
+ {
2204
+ variant: "ghost",
2205
+ size: "icon",
2206
+ onClick: () => handleRemoveUser(user.user_id),
2207
+ disabled: isUpdating[user.user_id],
2208
+ className: "h-8 w-8",
2209
+ children: [
2210
+ /* @__PURE__ */ jsx29(UserX, { className: "h-4 w-4" }),
2211
+ /* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Remove user" })
2212
+ ]
2213
+ }
2214
+ ) })
2215
+ ] }, user.user_id)) })
2216
+ ] }) }) : /* @__PURE__ */ jsx29("div", { className: "text-center py-12 border rounded-lg", children: /* @__PURE__ */ jsx29("p", { className: "text-muted-foreground", children: searchQuery ? "No users found matching your search" : "No users in this organization yet" }) })
2217
+ ] })
2218
+ ] });
2219
+ }
1970
2220
  export {
1971
2221
  LoginForm,
1972
2222
  PricingTable,
@@ -1977,6 +2227,7 @@ export {
1977
2227
  SwitchActiveTenant,
1978
2228
  TenantCreator,
1979
2229
  UserInvite,
2230
+ UserViewer,
1980
2231
  VerificationForm,
1981
2232
  filterInputNodes,
1982
2233
  findAnchorNode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnibase/shadcn",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "OmniBase ShadCN UI Package",
5
5
  "type": "module",
6
6
  "exports": {
@@ -49,7 +49,7 @@
49
49
  "tailwind-merge": "^2.6.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@omnibase/core-js": "0.7.5",
52
+ "@omnibase/core-js": "0.7.6",
53
53
  "@storybook/addon-docs": "^9.1.15",
54
54
  "@storybook/react-vite": "^9.1.15",
55
55
  "@tailwindcss/vite": "^4.1.16",