@datalayer/core 1.2.18 → 1.2.20

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.
Files changed (228) hide show
  1. package/lib/cli-login.js +5 -51
  2. package/lib/components/anonymous/AnonymousKeyExpired.js +1 -15
  3. package/lib/components/anonymous/AnonymousKeyTimer.js +5 -15
  4. package/lib/components/auth/SignIn.js +2 -2
  5. package/lib/components/avatars/UserAvatar.d.ts +10 -11
  6. package/lib/components/avatars/UserAvatar.js +23 -52
  7. package/lib/components/avatars/UserProfileAvatar.js +1 -1
  8. package/lib/components/avatars/avatarChoice.d.ts +42 -0
  9. package/lib/components/avatars/avatarChoice.js +65 -0
  10. package/lib/components/avatars/index.d.ts +1 -0
  11. package/lib/components/avatars/index.js +1 -0
  12. package/lib/components/billing/BillingEntitySelect.js +6 -48
  13. package/lib/components/checkout/StripeCheckout.js +33 -217
  14. package/lib/components/collaboration/LiveEditorCollaborators.d.ts +3 -4
  15. package/lib/components/collaboration/LiveEditorCollaborators.js +7 -5
  16. package/lib/components/contents/ContentSourceCard.js +2 -11
  17. package/lib/components/contents/HomeFolderObjectsBrowser.d.ts +1 -1
  18. package/lib/components/contents/HomeFolderObjectsBrowser.js +11 -35
  19. package/lib/components/display/CenteredSpinner.js +1 -6
  20. package/lib/components/display/DatalayerBox.js +2 -14
  21. package/lib/components/emoji/faceEmojis.js +48 -0
  22. package/lib/components/emoji/fluent/loaders.js +46 -0
  23. package/lib/components/emoji/fluent/svg/1f30a.d.ts +2 -0
  24. package/lib/components/emoji/fluent/svg/1f30a.js +5 -0
  25. package/lib/components/emoji/fluent/svg/1f310.d.ts +2 -0
  26. package/lib/components/emoji/fluent/svg/1f310.js +5 -0
  27. package/lib/components/emoji/fluent/svg/1f324.d.ts +2 -0
  28. package/lib/components/emoji/fluent/svg/1f324.js +5 -0
  29. package/lib/components/emoji/fluent/svg/1f326.d.ts +2 -0
  30. package/lib/components/emoji/fluent/svg/1f326.js +5 -0
  31. package/lib/components/emoji/fluent/svg/1f327.d.ts +2 -0
  32. package/lib/components/emoji/fluent/svg/1f327.js +5 -0
  33. package/lib/components/emoji/fluent/svg/1f33e.d.ts +2 -0
  34. package/lib/components/emoji/fluent/svg/1f33e.js +5 -0
  35. package/lib/components/emoji/fluent/svg/1f372.d.ts +2 -0
  36. package/lib/components/emoji/fluent/svg/1f372.js +5 -0
  37. package/lib/components/emoji/fluent/svg/1f373.d.ts +2 -0
  38. package/lib/components/emoji/fluent/svg/1f373.js +5 -0
  39. package/lib/components/emoji/fluent/svg/1f39b.d.ts +2 -0
  40. package/lib/components/emoji/fluent/svg/1f39b.js +5 -0
  41. package/lib/components/emoji/fluent/svg/1f3ab.d.ts +2 -0
  42. package/lib/components/emoji/fluent/svg/1f3ab.js +5 -0
  43. package/lib/components/emoji/fluent/svg/1f41b.d.ts +2 -0
  44. package/lib/components/emoji/fluent/svg/1f41b.js +5 -0
  45. package/lib/components/emoji/fluent/svg/1f441.d.ts +2 -0
  46. package/lib/components/emoji/fluent/svg/1f441.js +5 -0
  47. package/lib/components/emoji/fluent/svg/1f465.d.ts +2 -0
  48. package/lib/components/emoji/fluent/svg/1f465.js +5 -0
  49. package/lib/components/emoji/fluent/svg/1f4b9.d.ts +2 -0
  50. package/lib/components/emoji/fluent/svg/1f4b9.js +5 -0
  51. package/lib/components/emoji/fluent/svg/1f4be.d.ts +2 -0
  52. package/lib/components/emoji/fluent/svg/1f4be.js +5 -0
  53. package/lib/components/emoji/fluent/svg/1f4c1.d.ts +2 -0
  54. package/lib/components/emoji/fluent/svg/1f4c1.js +5 -0
  55. package/lib/components/emoji/fluent/svg/1f4c2.d.ts +2 -0
  56. package/lib/components/emoji/fluent/svg/1f4c2.js +5 -0
  57. package/lib/components/emoji/fluent/svg/1f4c4.d.ts +2 -0
  58. package/lib/components/emoji/fluent/svg/1f4c4.js +5 -0
  59. package/lib/components/emoji/fluent/svg/1f4d3.d.ts +2 -0
  60. package/lib/components/emoji/fluent/svg/1f4d3.js +5 -0
  61. package/lib/components/emoji/fluent/svg/1f4d6.d.ts +2 -0
  62. package/lib/components/emoji/fluent/svg/1f4d6.js +5 -0
  63. package/lib/components/emoji/fluent/svg/1f4dc.d.ts +2 -0
  64. package/lib/components/emoji/fluent/svg/1f4dc.js +5 -0
  65. package/lib/components/emoji/fluent/svg/1f4e1.d.ts +2 -0
  66. package/lib/components/emoji/fluent/svg/1f4e1.js +5 -0
  67. package/lib/components/emoji/fluent/svg/1f4e2.d.ts +2 -0
  68. package/lib/components/emoji/fluent/svg/1f4e2.js +5 -0
  69. package/lib/components/emoji/fluent/svg/1f4e7.d.ts +2 -0
  70. package/lib/components/emoji/fluent/svg/1f4e7.js +5 -0
  71. package/lib/components/emoji/fluent/svg/1f500.d.ts +2 -0
  72. package/lib/components/emoji/fluent/svg/1f500.js +5 -0
  73. package/lib/components/emoji/fluent/svg/1f501.d.ts +2 -0
  74. package/lib/components/emoji/fluent/svg/1f501.js +5 -0
  75. package/lib/components/emoji/fluent/svg/1f504.d.ts +2 -0
  76. package/lib/components/emoji/fluent/svg/1f504.js +5 -0
  77. package/lib/components/emoji/fluent/svg/1f52d.d.ts +2 -0
  78. package/lib/components/emoji/fluent/svg/1f52d.js +5 -0
  79. package/lib/components/emoji/fluent/svg/1f552.d.ts +2 -0
  80. package/lib/components/emoji/fluent/svg/1f552.js +5 -0
  81. package/lib/components/emoji/fluent/svg/1f58b.d.ts +2 -0
  82. package/lib/components/emoji/fluent/svg/1f58b.js +5 -0
  83. package/lib/components/emoji/fluent/svg/1f5b2.d.ts +2 -0
  84. package/lib/components/emoji/fluent/svg/1f5b2.js +5 -0
  85. package/lib/components/emoji/fluent/svg/1f5c3.d.ts +2 -0
  86. package/lib/components/emoji/fluent/svg/1f5c3.js +5 -0
  87. package/lib/components/emoji/fluent/svg/1f5d1.d.ts +2 -0
  88. package/lib/components/emoji/fluent/svg/1f5d1.js +5 -0
  89. package/lib/components/emoji/fluent/svg/1f5dc.d.ts +2 -0
  90. package/lib/components/emoji/fluent/svg/1f5dc.js +5 -0
  91. package/lib/components/emoji/fluent/svg/1f604.d.ts +2 -0
  92. package/lib/components/emoji/fluent/svg/1f604.js +5 -0
  93. package/lib/components/emoji/fluent/svg/1f917.d.ts +2 -0
  94. package/lib/components/emoji/fluent/svg/1f917.js +5 -0
  95. package/lib/components/emoji/fluent/svg/1f9d1-200d-2696.d.ts +2 -0
  96. package/lib/components/emoji/fluent/svg/1f9d1-200d-2696.js +5 -0
  97. package/lib/components/emoji/fluent/svg/1fa79.d.ts +2 -0
  98. package/lib/components/emoji/fluent/svg/1fa79.js +5 -0
  99. package/lib/components/emoji/fluent/svg/1fa9d.d.ts +2 -0
  100. package/lib/components/emoji/fluent/svg/1fa9d.js +5 -0
  101. package/lib/components/emoji/fluent/svg/1fa9f.d.ts +2 -0
  102. package/lib/components/emoji/fluent/svg/1fa9f.js +5 -0
  103. package/lib/components/emoji/fluent/svg/23f3.d.ts +2 -0
  104. package/lib/components/emoji/fluent/svg/23f3.js +5 -0
  105. package/lib/components/emoji/fluent/svg/2611.d.ts +2 -0
  106. package/lib/components/emoji/fluent/svg/2611.js +5 -0
  107. package/lib/components/emoji/fluent/svg/2702.d.ts +2 -0
  108. package/lib/components/emoji/fluent/svg/2702.js +5 -0
  109. package/lib/components/emoji/fluent/svg/270f.d.ts +2 -0
  110. package/lib/components/emoji/fluent/svg/270f.js +5 -0
  111. package/lib/components/emoji/fluent/svg/2728.d.ts +2 -0
  112. package/lib/components/emoji/fluent/svg/2728.js +5 -0
  113. package/lib/components/emoji/fluent/svg/2b1c.d.ts +2 -0
  114. package/lib/components/emoji/fluent/svg/2b1c.js +5 -0
  115. package/lib/components/flashes/FlashClosable.js +2 -17
  116. package/lib/components/mcp/ClientBadge.js +1 -1
  117. package/lib/components/mcp/McpErrorBlankslate.js +1 -1
  118. package/lib/components/mcp/ScopeList.js +1 -1
  119. package/lib/components/notebooks/JupyterNotebook.js +1 -2
  120. package/lib/components/principal/Principal.js +2 -10
  121. package/lib/components/principal/PrincipalAppearance.d.ts +24 -1
  122. package/lib/components/principal/PrincipalAppearance.js +107 -80
  123. package/lib/components/principal/PrincipalAvatar.d.ts +5 -7
  124. package/lib/components/principal/PrincipalAvatar.js +12 -38
  125. package/lib/components/principal/PrincipalBadge.js +3 -13
  126. package/lib/components/principal/PrincipalBanner.js +4 -32
  127. package/lib/components/principal/PrincipalDetailsOverlay.d.ts +4 -7
  128. package/lib/components/principal/PrincipalDetailsOverlay.js +8 -24
  129. package/lib/components/principal/PrincipalHoverCard.js +15 -18
  130. package/lib/components/principal/PrincipalSwitcherMenu.js +15 -83
  131. package/lib/components/progress/ConsumptionBar.js +1 -1
  132. package/lib/components/sharing/ShareAccessComponent.js +21 -229
  133. package/lib/components/sharing/SharingEditor.js +1 -1
  134. package/lib/components/spaces/SpaceDetailsOverlay.js +4 -35
  135. package/lib/components/spaces/SpaceDisplay.js +1 -8
  136. package/lib/components/storage/ContentsBrowser.js +3 -26
  137. package/lib/components/storage/ContentsTable.js +4 -23
  138. package/lib/components/students/StudentResultCircle.js +7 -29
  139. package/lib/components/timeline/Timeline.js +4 -36
  140. package/lib/hooks/layouts/LayoutBackdrop.js +2 -1
  141. package/lib/hooks/layouts/LayoutScreencapture.js +1 -1
  142. package/lib/hooks/libraryApp.d.ts +6 -1
  143. package/lib/hooks/libraryApp.js +10 -1
  144. package/lib/hooks/unlinkIAMProvider.d.ts +22 -0
  145. package/lib/hooks/unlinkIAMProvider.js +24 -0
  146. package/lib/hooks/useAuthorization.js +6 -1
  147. package/lib/hooks/useCache.d.ts +8 -1
  148. package/lib/hooks/useCache.js +35 -4
  149. package/lib/hooks/useNavigate.js +8 -2
  150. package/lib/mocks/components/FlashMock.js +3 -8
  151. package/lib/mocks/views/DashboardMock.js +6 -72
  152. package/lib/mocks/views/FormMock.js +3 -2
  153. package/lib/mocks/views/TableMock.js +3 -2
  154. package/lib/mocks/views/WipMock.js +2 -1
  155. package/lib/models/IAMProviderLinked.d.ts +9 -0
  156. package/lib/models/IAMProviderLinked.js +34 -5
  157. package/lib/models/McpTask.d.ts +18 -1
  158. package/lib/models/McpTask.js +15 -0
  159. package/lib/models/Person.d.ts +9 -0
  160. package/lib/models/Person.js +23 -0
  161. package/lib/models/Profile.d.ts +2 -2
  162. package/lib/models/User.js +5 -12
  163. package/lib/models/UserOnboarding.d.ts +9 -0
  164. package/lib/models/UserOnboarding.js +33 -0
  165. package/lib/otel/views/OtelLive.js +4 -62
  166. package/lib/otel/views/OtelLiveSpans.js +4 -29
  167. package/lib/otel/views/OtelLogsList.js +13 -64
  168. package/lib/otel/views/OtelMetricsChart.js +4 -19
  169. package/lib/otel/views/OtelMetricsList.js +8 -77
  170. package/lib/otel/views/OtelSearchBar.js +3 -12
  171. package/lib/otel/views/OtelSpanDetail.js +9 -79
  172. package/lib/otel/views/OtelSpanTree.js +7 -57
  173. package/lib/otel/views/OtelSqlView.js +5 -99
  174. package/lib/otel/views/OtelSystemView.js +4 -34
  175. package/lib/otel/views/OtelTimeline.js +7 -37
  176. package/lib/otel/views/OtelTimelineRangeSlider.js +7 -140
  177. package/lib/otel/views/OtelTracesList.js +12 -76
  178. package/lib/portable/index.d.ts +9 -0
  179. package/lib/portable/index.js +14 -0
  180. package/lib/portable/states.d.ts +39 -0
  181. package/lib/portable/states.js +71 -0
  182. package/lib/state/substates/NavigationState.d.ts +10 -6
  183. package/lib/state/substates/NavigationState.js +18 -8
  184. package/lib/views/api-keys/APIKeyEdit.js +2 -11
  185. package/lib/views/api-keys/APIKeyNew.js +3 -19
  186. package/lib/views/api-keys/APIKeys.js +6 -11
  187. package/lib/views/api-keys/APIKeysStandalone.js +1 -1
  188. package/lib/views/datasources/DatasourceDetail.d.ts +1 -1
  189. package/lib/views/datasources/DatasourceDetail.js +24 -17
  190. package/lib/views/datasources/DatasourceNew.js +2 -6
  191. package/lib/views/datasources/Datasources.js +2 -14
  192. package/lib/views/iam/SignInSimple.js +8 -64
  193. package/lib/views/mcp/AdmittedClients.js +3 -16
  194. package/lib/views/mcp/AlertDestinations.js +3 -11
  195. package/lib/views/mcp/AlertRules.js +4 -9
  196. package/lib/views/mcp/ApprovalQueue.js +5 -22
  197. package/lib/views/mcp/AuditLog.js +7 -44
  198. package/lib/views/mcp/ConnectedAgents.js +1 -6
  199. package/lib/views/mcp/EnterpriseConsole.js +11 -24
  200. package/lib/views/mcp/IdentityProviders.js +7 -31
  201. package/lib/views/mcp/McpDashboard.js +15 -31
  202. package/lib/views/mcp/McpHome.js +8 -55
  203. package/lib/views/mcp/McpObservability.js +14 -86
  204. package/lib/views/mcp/NotebookRuns.js +6 -13
  205. package/lib/views/mcp/OrganizationPolicy.js +3 -9
  206. package/lib/views/mcp/OrganizationUsage.js +5 -12
  207. package/lib/views/mcp/PersonalPolicy.js +3 -3
  208. package/lib/views/mcp/Policies.js +6 -47
  209. package/lib/views/mcp/PolicyForm.js +1 -9
  210. package/lib/views/mcp/PolicyHistory.js +2 -8
  211. package/lib/views/mcp/RunDetail.d.ts +1 -1
  212. package/lib/views/mcp/RunDetail.js +7 -26
  213. package/lib/views/mcp/ScimProvisioning.js +4 -16
  214. package/lib/views/mcp/ServiceAgents.js +4 -17
  215. package/lib/views/mcp/TeamPolicies.js +7 -19
  216. package/lib/views/mcp/ToolAccess.js +16 -23
  217. package/lib/views/mcp/TraceTimeline.js +8 -23
  218. package/lib/views/otel/DashboardView.js +2 -2
  219. package/lib/views/otel/LogsView.js +2 -2
  220. package/lib/views/otel/MetricsView.js +2 -2
  221. package/lib/views/otel/OtelHeader.js +6 -40
  222. package/lib/views/otel/SqlView.js +2 -2
  223. package/lib/views/otel/SystemView.js +2 -2
  224. package/lib/views/otel/TracesView.js +2 -2
  225. package/lib/views/profile/UserBadge.js +6 -98
  226. package/lib/views/secrets/SecretEdit.js +2 -11
  227. package/lib/views/secrets/SecretNew.js +1 -1
  228. package/package.json +1 -1
@@ -226,9 +226,7 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
226
226
  hydratedEntity?.avatarUrl ||
227
227
  cachedPrincipal?.avatarUrl ||
228
228
  undefined,
229
- avatarIcon: principal.avatarIcon ||
230
- hydratedEntity?.avatarIcon ||
231
- undefined,
229
+ avatarIcon: principal.avatarIcon || hydratedEntity?.avatarIcon || undefined,
232
230
  banner: principal.banner || hydratedEntity?.banner || undefined,
233
231
  firstName: principal.firstName ||
234
232
  hydratedEntity?.firstName ||
@@ -290,12 +288,6 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
290
288
  resolvedIsPublic,
291
289
  upsertCachedPrincipal,
292
290
  ]);
293
- return (_jsxs(Box, { sx: {
294
- display: 'inline-flex',
295
- alignItems: 'center',
296
- gap,
297
- minWidth: 0,
298
- ...sx,
299
- }, children: [_jsx(PrincipalAvatar, { kind: resolvedPrincipal.kind, avatarUrl: resolvedPrincipal.avatarUrl, avatarIcon: resolvedPrincipal.avatarIcon, alt: resolvedPrincipal.displayName, size: avatarSize, square: square }), _jsx(PrincipalDetailsOverlay, { kind: resolvedPrincipal.kind, uid: resolvedPrincipal.uid, displayName: resolvedPrincipal.displayName, name: resolvedPrincipal.name, description: resolvedPrincipal.description, handle: resolvedPrincipal.handle, accountHandle: resolvedPrincipal.accountHandle, firstName: resolvedPrincipal.firstName, lastName: resolvedPrincipal.lastName, email: resolvedPrincipal.email, origin: resolvedPrincipal.origin, avatarUrl: resolvedPrincipal.avatarUrl, avatarIcon: resolvedPrincipal.avatarIcon, organizationName: teamOrganizationNameResolved, memberCount: teamMemberCount, isPublic: resolvedIsPublic, isAdmin: isAdmin })] }));
291
+ return (_jsxs(Box, { display: "inline-flex", alignItems: "center", gap: gap, minWidth: 0, sx: sx, children: [_jsx(PrincipalAvatar, { kind: resolvedPrincipal.kind, avatarUrl: resolvedPrincipal.avatarUrl, avatar: resolvedPrincipal.avatarIcon, alt: resolvedPrincipal.displayName, size: avatarSize, square: square }), _jsx(PrincipalDetailsOverlay, { kind: resolvedPrincipal.kind, uid: resolvedPrincipal.uid, displayName: resolvedPrincipal.displayName, name: resolvedPrincipal.name, description: resolvedPrincipal.description, handle: resolvedPrincipal.handle, accountHandle: resolvedPrincipal.accountHandle, firstName: resolvedPrincipal.firstName, lastName: resolvedPrincipal.lastName, email: resolvedPrincipal.email, origin: resolvedPrincipal.origin, avatarUrl: resolvedPrincipal.avatarUrl, avatar: resolvedPrincipal.avatarIcon, organizationName: teamOrganizationNameResolved, memberCount: teamMemberCount, isPublic: resolvedIsPublic, isAdmin: isAdmin })] }));
300
292
  };
301
293
  export default Principal;
@@ -1,5 +1,6 @@
1
1
  import type { JSX } from 'react';
2
2
  import { type ComponentType, type SVGProps } from 'react';
3
+ import { type AvatarChoice } from '../avatars/avatarChoice';
3
4
  /**
4
5
  * Who a principal is: a person, an organization, a team — or a service
5
6
  * principal, the one a deployed LOOP application acts in its own name through
@@ -114,7 +115,29 @@ export declare const PRINCIPAL_BANNERS: readonly [{
114
115
  readonly Component: ComponentType<any>;
115
116
  }];
116
117
  export declare function getPrincipalBannerForSeed(seed: string): string;
117
- export declare function getPrincipalAvatarIcon(name?: string): AvatarComponent | undefined;
118
+ /** The names of the avatar set: the icons an avatar may be. */
119
+ export declare const PRINCIPAL_AVATAR_ICON_NAMES: ReadonlySet<string>;
120
+ /** The avatar a kept value names; throws `AvatarRefused` for anything else. */
121
+ export declare function parsePrincipalAvatar(value: string): AvatarChoice;
122
+ /**
123
+ * The avatar a kept value names, or `undefined` when there is none or it is
124
+ * refused — said once on the console, in its sentence: a picture that cannot
125
+ * be drawn is drawn as no choice, never as a broken page.
126
+ */
127
+ export declare function principalAvatarOf(value: string | undefined): AvatarChoice | undefined;
128
+ /**
129
+ * The drawing of a chosen avatar — an emoji or an icon of the set, by its
130
+ * kept value — on nothing: whatever holds it gives it its disc
131
+ * (`UserAvatar`, `PrincipalAvatar`, an application's face). `null` for no
132
+ * choice, or a refused one.
133
+ */
134
+ export declare function ChosenAvatar({ avatar, size, label, }: {
135
+ avatar: string | undefined;
136
+ /** Its edge, in pixels. */
137
+ size: number;
138
+ /** What it is called for a screen reader; empty, it is decoration. */
139
+ label?: string;
140
+ }): JSX.Element | null;
118
141
  export declare function PrincipalBannerImage({ banner, height, }: {
119
142
  banner?: string;
120
143
  height?: number;
@@ -1,7 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Suspense, lazy, useEffect, useState, } from 'react';
3
- import { Box, Button, Text, Tooltip } from '@primer/react';
3
+ import { Box, useColorPalette } from '@datalayer/primer-addons';
4
+ import { Button, SegmentedControl, Text, Tooltip } from '@primer/react';
4
5
  import { Dialog } from '@primer/react/experimental';
6
+ import { AvatarRefused, emojiAvatar, iconAvatar, parseAvatar, } from '../avatars/avatarChoice.js';
7
+ import { FACE_EMOJIS } from '../emoji/faceEmojis.js';
8
+ import { FluentEmoji } from '../emoji/FluentEmoji.js';
5
9
  /**
6
10
  * An avatar icon, fetched the first time it is drawn.
7
11
  *
@@ -576,20 +580,59 @@ export function getPrincipalBannerForSeed(seed) {
576
580
  }
577
581
  return PRINCIPAL_BANNERS[Math.abs(hash) % PRINCIPAL_BANNERS.length].name;
578
582
  }
579
- export function getPrincipalAvatarIcon(name) {
580
- return PRINCIPAL_AVATAR_ICONS.find(option => option.name === name)?.Icon;
583
+ /** The names of the avatar set: the icons an avatar may be. */
584
+ export const PRINCIPAL_AVATAR_ICON_NAMES = new Set(PRINCIPAL_AVATAR_ICONS.map(option => option.name));
585
+ /** The avatar a kept value names; throws `AvatarRefused` for anything else. */
586
+ export function parsePrincipalAvatar(value) {
587
+ return parseAvatar(value, PRINCIPAL_AVATAR_ICON_NAMES);
588
+ }
589
+ /**
590
+ * The avatar a kept value names, or `undefined` when there is none or it is
591
+ * refused — said once on the console, in its sentence: a picture that cannot
592
+ * be drawn is drawn as no choice, never as a broken page.
593
+ */
594
+ export function principalAvatarOf(value) {
595
+ if (!value) {
596
+ return undefined;
597
+ }
598
+ try {
599
+ return parsePrincipalAvatar(value);
600
+ }
601
+ catch (error) {
602
+ if (error instanceof AvatarRefused) {
603
+ console.error(`Avatar refused: ${error.message}`);
604
+ return undefined;
605
+ }
606
+ throw error;
607
+ }
608
+ }
609
+ /**
610
+ * The drawing of a chosen avatar — an emoji or an icon of the set, by its
611
+ * kept value — on nothing: whatever holds it gives it its disc
612
+ * (`UserAvatar`, `PrincipalAvatar`, an application's face). `null` for no
613
+ * choice, or a refused one.
614
+ */
615
+ export function ChosenAvatar({ avatar, size, label = '', }) {
616
+ const choice = principalAvatarOf(avatar);
617
+ if (!choice) {
618
+ return null;
619
+ }
620
+ if (choice.kind === 'emoji') {
621
+ return _jsx(FluentEmoji, { emoji: choice.emoji, size: size, label: label });
622
+ }
623
+ const Icon = PRINCIPAL_AVATAR_ICONS.find(option => option.name === choice.name).Icon;
624
+ // The plain icon, coloured by the theme — never the `colored` variant,
625
+ // whose fixed palette belongs to the emoji it is drawn from.
626
+ return (_jsx(Icon, { size: size, themed: true, colormode: true, "aria-label": label || undefined, "aria-hidden": label ? undefined : true }));
581
627
  }
582
628
  export function PrincipalBannerImage({ banner, height = 180, }) {
583
629
  const Banner = PRINCIPAL_BANNERS.find(option => option.name === banner)?.Component;
584
630
  if (!Banner)
585
631
  return null;
586
- return (_jsx(Box, { sx: {
632
+ return (_jsx(Box, { overflow: "hidden", borderRadius: 2, bg: "canvas.subtle", sx: {
587
633
  position: 'relative',
588
634
  width: '100%',
589
635
  height,
590
- overflow: 'hidden',
591
- borderRadius: 2,
592
- bg: 'canvas.subtle',
593
636
  '& > svg': {
594
637
  position: 'absolute',
595
638
  inset: 0,
@@ -603,8 +646,26 @@ export function PrincipalBannerImage({ banner, height = 180, }) {
603
646
  }
604
647
  export function PrincipalAvatarPicker({ value, onChange, disabled = false, }) {
605
648
  const [open, setOpen] = useState(false);
606
- const selected = PRINCIPAL_AVATAR_ICONS.find(option => option.name === value);
607
- return (_jsxs(_Fragment, { children: [_jsx(Button, { type: "button", disabled: disabled, onClick: () => setOpen(true), children: selected ? `Change Avatar (${selected.label})` : 'Choose Avatar' }), open ? (_jsx(Dialog, { title: "Choose an Avatar", onClose: () => setOpen(false),
649
+ const chosen = principalAvatarOf(value);
650
+ // The colour a chosen avatar is drawn in (`UserAvatar`'s `--datalayer-icon-fg`):
651
+ // the icons are offered as they will look.
652
+ const palette = useColorPalette();
653
+ // The tab the dialog opens on: what is chosen, the icons when nothing is.
654
+ const [tab, setTab] = useState(chosen?.kind === 'emoji' ? 'emoji' : 'icons');
655
+ const choose = (next) => {
656
+ onChange(next);
657
+ setOpen(false);
658
+ };
659
+ const selectedLabel = chosen?.kind === 'emoji'
660
+ ? chosen.emoji
661
+ : chosen
662
+ ? PRINCIPAL_AVATAR_ICONS.find(option => option.name === chosen.name)
663
+ ?.label
664
+ : undefined;
665
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { type: "button", disabled: disabled, onClick: () => {
666
+ setTab(chosen?.kind === 'emoji' ? 'emoji' : 'icons');
667
+ setOpen(true);
668
+ }, leadingVisual: chosen ? () => _jsx(ChosenAvatar, { avatar: value, size: 16 }) : undefined, children: selectedLabel ? `Change Avatar (${selectedLabel})` : 'Choose Avatar' }), open ? (_jsxs(Dialog, { title: "Choose an Avatar", onClose: () => setOpen(false),
608
669
  // The widest the dialog names — 640px — which is what it falls
609
670
  // back to should the width below ever stop applying.
610
671
  width: "xlarge",
@@ -624,62 +685,49 @@ export function PrincipalAvatarPicker({ value, onChange, disabled = false, }) {
624
685
  width: 'min(1080px, calc(100vw - 32px))',
625
686
  maxWidth: 'none',
626
687
  },
627
- }, children: _jsx(Box, { sx: {
628
- display: 'grid',
688
+ }, children: [_jsxs(SegmentedControl, { "aria-label": "Avatar kind", sx: { mb: 3 }, onChange: index => setTab(index === 0 ? 'emoji' : 'icons'), children: [_jsx(SegmentedControl.Button, { selected: tab === 'emoji', children: "Emoji" }), _jsx(SegmentedControl.Button, { selected: tab === 'icons', children: "Icons" })] }), tab === 'emoji' ? (_jsx(Box, { display: "grid", gridTemplateColumns: [
689
+ 'repeat(6, minmax(0, 1fr))',
690
+ 'repeat(12, minmax(0, 1fr))',
691
+ ], gap: 2, children: FACE_EMOJIS.map(emoji => {
692
+ const next = emojiAvatar(emoji);
693
+ const pressed = value === next;
694
+ return (_jsx(Box, { as: "button", type: "button", "aria-label": emoji, "aria-pressed": pressed, onClick: () => choose(next), display: "flex", alignItems: "center", justifyContent: "center", height: 72, width: "100%", p: 0, appearance: "none", cursor: "pointer", border: "1px solid", borderRadius: 2, borderColor: pressed ? 'accent.emphasis' : 'border.default', bg: pressed ? 'accent.subtle' : 'canvas.default', hover: { borderColor: 'accent.emphasis' }, children: _jsx(FluentEmoji, { emoji: emoji, size: 44, label: "" }) }, emoji));
695
+ }) })) : null, tab === 'icons' ? (_jsx(Box, { style: { '--datalayer-icon-fg': palette.primary }, display: "grid",
629
696
  // Twelve to a line, whatever the dialog is wide: the columns
630
697
  // share it evenly and `minmax(0, …)` lets them shrink under
631
698
  // their content, which a long name would otherwise widen.
632
699
  gridTemplateColumns: [
633
700
  'repeat(6, minmax(0, 1fr))',
634
701
  'repeat(12, minmax(0, 1fr))',
635
- ],
636
- gap: 2,
637
- }, children: PRINCIPAL_AVATAR_ICONS.map(({ name, label, description, Icon }) => (
638
- // A button drawn as a card rather than a Primer `Button`: the
639
- // avatar is named under it, as the banners are under theirs.
640
- // The name under a card is clipped when it is long, and a
641
- // picture says only so much: the tooltip gives the whole name
642
- // and what the picture is of.
643
- _jsx(Tooltip, { text: description ? `${label} — ${description}` : label, direction: "n", children: _jsxs(Box, { as: "button", type: "button", "aria-label": description ? `${label} — ${description}` : label, "aria-pressed": value === name, onClick: () => {
644
- onChange(name);
645
- setOpen(false);
646
- }, sx: {
647
- display: 'block',
648
- width: '100%',
649
- p: 0,
650
- overflow: 'hidden',
651
- appearance: 'none',
652
- color: 'fg.default',
653
- cursor: 'pointer',
654
- border: '1px solid',
655
- borderRadius: 2,
656
- borderColor: value === name ? 'accent.emphasis' : 'border.default',
657
- bg: value === name ? 'accent.subtle' : 'canvas.default',
658
- ':hover': { borderColor: 'accent.emphasis' },
659
- }, children: [_jsx(Box, { sx: {
660
- height: 72,
661
- display: 'flex',
662
- alignItems: 'center',
663
- justifyContent: 'center',
664
- }, children: _jsx(Icon, { size: 52, themed: true, colormode: true }) }), _jsx(Text, { sx: {
665
- display: 'block',
666
- px: 2,
667
- py: 1,
668
- fontSize: 0,
669
- textAlign: 'center',
670
- // A name too long for the card is cut rather than
671
- // stretching the grid it sits in.
672
- overflow: 'hidden',
673
- textOverflow: 'ellipsis',
674
- whiteSpace: 'nowrap',
675
- }, children: label })] }) }, name))) }) })) : null] }));
702
+ ], gap: 2, children: PRINCIPAL_AVATAR_ICONS.map(({ name, label, description, Icon }) => (
703
+ // A button drawn as a card rather than a Primer `Button`: the
704
+ // avatar is named under it, as the banners are under theirs.
705
+ // The name under a card is clipped when it is long, and a
706
+ // picture says only so much: the tooltip gives the whole name
707
+ // and what the picture is of.
708
+ _jsx(Tooltip, { text: description ? `${label} — ${description}` : label, direction: "n", children: _jsxs(Box, { as: "button", type: "button", "aria-label": description ? `${label} — ${description}` : label, "aria-pressed": value === iconAvatar(name), onClick: () => choose(iconAvatar(name)), display: "block", width: "100%", p: 0, overflow: "hidden", appearance: "none", color: "fg.default", cursor: "pointer", border: "1px solid", borderRadius: 2, borderColor: value === iconAvatar(name)
709
+ ? 'accent.emphasis'
710
+ : 'border.default', bg: value === iconAvatar(name)
711
+ ? 'accent.subtle'
712
+ : 'canvas.default', hover: { borderColor: 'accent.emphasis' }, children: [_jsx(Box, { height: 72, display: "flex", alignItems: "center", justifyContent: "center", children: _jsx(Icon, { size: 52, themed: true, colormode: true }) }), _jsx(Text, { sx: {
713
+ display: 'block',
714
+ px: 2,
715
+ py: 1,
716
+ fontSize: 0,
717
+ textAlign: 'center',
718
+ // A name too long for the card is cut rather than
719
+ // stretching the grid it sits in.
720
+ overflow: 'hidden',
721
+ textOverflow: 'ellipsis',
722
+ whiteSpace: 'nowrap',
723
+ }, children: label })] }) }, name))) })) : null] })) : null] }));
676
724
  }
677
725
  export function PrincipalBannerPicker({ value, onChange, disabled = false, showPreview = true, }) {
678
726
  const [open, setOpen] = useState(false);
679
727
  const [selectedName, setSelectedName] = useState(value);
680
728
  useEffect(() => setSelectedName(value), [value]);
681
729
  const selected = PRINCIPAL_BANNERS.find(option => option.name === selectedName);
682
- return (_jsxs(_Fragment, { children: [showPreview && selected ? (_jsx(Box, { sx: { mb: 2 }, children: _jsx(PrincipalBannerImage, { banner: selected.name, height: 120 }) })) : null, _jsx(Button, { type: "button", disabled: disabled, onClick: () => setOpen(true), children: selected ? `Change Banner (${selected.label})` : 'Choose Banner' }), open ? (_jsx(Dialog, { title: "Choose a Banner", onClose: () => setOpen(false), width: "xlarge",
730
+ return (_jsxs(_Fragment, { children: [showPreview && selected ? (_jsx(Box, { mb: 2, children: _jsx(PrincipalBannerImage, { banner: selected.name, height: 120 }) })) : null, _jsx(Button, { type: "button", disabled: disabled, onClick: () => setOpen(true), children: selected ? `Change Banner (${selected.label})` : 'Choose Banner' }), open ? (_jsx(Dialog, { title: "Choose a Banner", onClose: () => setOpen(false), width: "xlarge",
683
731
  // Under `&&` for the reason given on the avatar picker: a plain
684
732
  // `sx` ties with the named width and may lose to it.
685
733
  sx: {
@@ -687,38 +735,17 @@ export function PrincipalBannerPicker({ value, onChange, disabled = false, showP
687
735
  width: 'min(960px, calc(100vw - 32px))',
688
736
  maxWidth: 'none',
689
737
  },
690
- }, children: _jsx(Box, { sx: {
691
- display: 'grid',
692
- // Four to a row, so a banner is seen against its neighbours
693
- // rather than one at a time; one column on a narrow overlay,
694
- // where four would be four slivers.
695
- gridTemplateColumns: ['1fr', 'repeat(4, minmax(0, 1fr))'],
696
- gap: 3,
697
- }, children: PRINCIPAL_BANNERS.map(({ name, label, Component }) => (_jsxs(Box, { as: "button", type: "button", "aria-label": label, "aria-pressed": selectedName === name, onClick: () => {
738
+ }, children: _jsx(Box, { display: "grid",
739
+ // Four to a row, so a banner is seen against its neighbours
740
+ // rather than one at a time; one column on a narrow overlay,
741
+ // where four would be four slivers.
742
+ gridTemplateColumns: ['1fr', 'repeat(4, minmax(0, 1fr))'], gap: 3, children: PRINCIPAL_BANNERS.map(({ name, label, Component }) => (_jsxs(Box, { as: "button", type: "button", "aria-label": label, "aria-pressed": selectedName === name, onClick: () => {
698
743
  setSelectedName(name);
699
744
  onChange(name);
700
745
  setOpen(false);
701
- }, sx: {
702
- display: 'block',
703
- width: '100%',
704
- p: 0,
705
- overflow: 'hidden',
706
- appearance: 'none',
707
- color: 'fg.default',
708
- cursor: 'pointer',
709
- border: '1px solid',
710
- borderRadius: 2,
711
- borderColor: selectedName === name
712
- ? 'accent.emphasis'
713
- : 'border.default',
714
- bg: selectedName === name ? 'accent.subtle' : 'canvas.default',
715
- textAlign: 'left',
716
- ':hover': { borderColor: 'accent.emphasis' },
717
- }, children: [_jsx(Box, { sx: {
746
+ }, display: "block", width: "100%", p: 0, overflow: "hidden", appearance: "none", color: "fg.default", cursor: "pointer", border: "1px solid", borderRadius: 2, borderColor: selectedName === name ? 'accent.emphasis' : 'border.default', bg: selectedName === name ? 'accent.subtle' : 'canvas.default', textAlign: "left", hover: { borderColor: 'accent.emphasis' }, children: [_jsx(Box, { aspectRatio: "3 / 1", overflow: "hidden", sx: {
718
747
  position: 'relative',
719
748
  width: '100%',
720
- aspectRatio: '3 / 1',
721
- overflow: 'hidden',
722
749
  '& > svg': {
723
750
  position: 'absolute',
724
751
  inset: 0,
@@ -4,14 +4,12 @@ export type PrincipalAvatarKind = PrincipalType;
4
4
  export type PrincipalAvatarProps = {
5
5
  kind: PrincipalAvatarKind;
6
6
  avatarUrl?: string;
7
- avatarIcon?: string;
8
7
  /**
9
- * A literal emoji this platform draws for a face of its own — an agent —
10
- * rather than a person's chosen picture or icon. Checked before
11
- * `avatarUrl`/`avatarIcon`, and only for `kind: 'personal'`: an agent is a
12
- * personal-shaped seat in every roster it appears in today.
8
+ * The chosen avatar, as it is kept: `emoji:…` or
9
+ * `@datalayer/icons-react:…` (`components/avatars/avatarChoice`). An
10
+ * agent's face is its emoji, as `emoji:…`.
13
11
  */
14
- avatarEmoji?: string;
12
+ avatar?: string;
15
13
  alt?: string;
16
14
  size?: number;
17
15
  square?: boolean;
@@ -24,5 +22,5 @@ export type PrincipalAvatarProps = {
24
22
  ring?: boolean;
25
23
  className?: string;
26
24
  };
27
- export declare function PrincipalAvatar({ kind, avatarUrl, avatarIcon, avatarEmoji, alt, size, square, ring, className, }: PrincipalAvatarProps): JSX.Element;
25
+ export declare function PrincipalAvatar({ kind, avatarUrl, avatar, alt, size, square, ring, className, }: PrincipalAvatarProps): JSX.Element;
28
26
  export default PrincipalAvatar;
@@ -1,18 +1,14 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Box } from '@datalayer/primer-addons';
2
+ import { EntityAvatar } from '@datalayer/primer-addons';
3
3
  import { OrganizationIcon, PeopleIcon } from '@primer/octicons-react';
4
4
  import { UserAvatar } from '../avatars/index.js';
5
- import { getPrincipalAvatarIcon, } from './PrincipalAppearance.js';
5
+ import { ChosenAvatar, principalAvatarOf, } from './PrincipalAppearance.js';
6
6
  function getFallbackIconSize(size) {
7
7
  return Math.max(12, Math.round(size * 0.62));
8
8
  }
9
- export function PrincipalAvatar({ kind, avatarUrl, avatarIcon, avatarEmoji, alt, size = 20, square = false, ring = false, className, }) {
10
- const SelectedIcon = getPrincipalAvatarIcon(avatarIcon);
11
- // Outside the edge rather than a border, so the avatar keeps the size it
12
- // was asked for — see `UserAvatar`, which draws its ring the same way.
13
- const ringSx = ring
14
- ? { boxShadow: '0 0 0 1px var(--borderColor-default, currentColor)' }
15
- : undefined;
9
+ export function PrincipalAvatar({ kind, avatarUrl, avatar, alt, size = 20, square = false, ring = false, className, }) {
10
+ const chosen = principalAvatarOf(avatar);
11
+ const shape = square ? 'rounded' : 'circle';
16
12
  /*
17
13
  * A person is drawn by `UserAvatar`, whatever they wear.
18
14
  *
@@ -25,37 +21,15 @@ export function PrincipalAvatar({ kind, avatarUrl, avatarIcon, avatarEmoji, alt,
25
21
  // A service principal — an application's — is drawn as a person is: its
26
22
  // chosen avatar, or its emoji, on the same disc (LOOP I-07).
27
23
  if (kind === 'personal' || kind === 'service') {
28
- return (_jsx(UserAvatar, { avatarUrl: avatarUrl, avatarIcon: avatarIcon, avatarEmoji: avatarEmoji, size: size, square: square, iconSize: getFallbackIconSize(size), ring: ring, className: className }));
24
+ return (_jsx(UserAvatar, { avatarUrl: avatarUrl, avatar: avatar, size: size, square: square, iconSize: getFallbackIconSize(size), ring: ring, className: className }));
29
25
  }
30
- if (SelectedIcon) {
31
- return (_jsx(Box, { className: className, sx: {
32
- width: size,
33
- height: size,
34
- display: 'inline-flex',
35
- alignItems: 'center',
36
- justifyContent: 'center',
37
- overflow: 'hidden',
38
- borderRadius: square ? 2 : '50%',
39
- // The disc of `UserAvatar`, for the same reason: the shape is what
40
- // says "avatar", and an icon drawn on nothing shows none of it.
41
- bg: 'accent.subtle',
42
- ...ringSx,
43
- }, "aria-label": alt || `${kind} avatar`, children: _jsx(SelectedIcon, { size: getFallbackIconSize(size), themed: true, colormode: true }) }));
26
+ if (chosen) {
27
+ return (
28
+ // The disc of `UserAvatar`, for the same reason: the shape is what says
29
+ // "avatar", and an icon drawn on nothing shows none of it.
30
+ _jsx(EntityAvatar, { className: className, size: size, shape: shape, ring: ring, alt: alt || `${kind} avatar`, children: _jsx(ChosenAvatar, { avatar: avatar, size: getFallbackIconSize(size) }) }));
44
31
  }
45
- const iconSize = getFallbackIconSize(size);
46
- const borderRadius = square ? 2 : '50%';
47
32
  const Icon = kind === 'team' ? PeopleIcon : OrganizationIcon;
48
- return (_jsx(Box, { className: className, sx: {
49
- width: size,
50
- height: size,
51
- display: 'inline-flex',
52
- alignItems: 'center',
53
- justifyContent: 'center',
54
- bg: 'canvas.subtle',
55
- borderRadius,
56
- border: '1px solid',
57
- borderColor: 'border.default',
58
- ...ringSx,
59
- }, "aria-label": alt || (kind === 'team' ? 'Team' : 'Organization'), children: _jsx(Icon, { size: iconSize }) }));
33
+ return (_jsx(EntityAvatar, { className: className, size: size, shape: shape, ring: ring, ground: "canvas", alt: alt || (kind === 'team' ? 'Team' : 'Organization'), children: _jsx(Icon, { size: getFallbackIconSize(size) }) }));
60
34
  }
61
35
  export default PrincipalAvatar;
@@ -4,7 +4,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
6
  import { useMemo } from 'react';
7
- import { Box, Label, Text } from '@primer/react';
7
+ import { Box } from '@datalayer/primer-addons';
8
+ import { Label, Text } from '@primer/react';
8
9
  import { useCache } from '../../hooks/index.js';
9
10
  import { useIAMStore } from '../../state/substates/index.js';
10
11
  import { useSelectedPrincipal } from '../../hooks/useSelectedPrincipal.js';
@@ -220,17 +221,6 @@ export const PrincipalBadge = ({ principal: providedPrincipal, showPrincipalLabe
220
221
  resolvedOrganization?.avatarIcon,
221
222
  resolvedUser?.origin,
222
223
  ]);
223
- return (_jsxs(Box, { sx: {
224
- display: 'inline-flex',
225
- alignItems: 'center',
226
- gap: 2,
227
- px: 2,
228
- py: 1,
229
- border: '1px solid',
230
- borderColor: 'border.default',
231
- borderRadius: 2,
232
- bg: 'canvas.subtle',
233
- ...sx,
234
- }, children: [showPrincipalLabel && (_jsx(Label, { size: "small", variant: "accent", children: principalLabel })), showApplyingToText && (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Applying to" })), _jsx(Principal, { principal: principal, isAdmin: isAdmin }), showOriginLabel && principal.origin && (_jsx(Label, { size: "small", variant: "secondary", children: principal.origin }))] }));
224
+ return (_jsxs(Box, { display: "inline-flex", alignItems: "center", gap: 2, px: 2, py: 1, border: "1px solid", borderColor: "border.default", borderRadius: 2, bg: "canvas.subtle", sx: sx, children: [showPrincipalLabel && (_jsx(Label, { size: "small", variant: "accent", children: principalLabel })), showApplyingToText && (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Applying to" })), _jsx(Principal, { principal: principal, isAdmin: isAdmin }), showOriginLabel && principal.origin && (_jsx(Label, { size: "small", variant: "secondary", children: principal.origin }))] }));
235
225
  };
236
226
  export default PrincipalBadge;
@@ -8,7 +8,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  * (user, organization, or team) with a colored visual so a user
9
9
  * can immediately see which principal a settings page applies to.
10
10
  */
11
- import { Box, Label, Text } from '@primer/react';
11
+ import { Box } from '@datalayer/primer-addons';
12
+ import { Label, Text } from '@primer/react';
12
13
  import { OrganizationIcon, PeopleIcon, PersonIcon, } from '@primer/octicons-react';
13
14
  import { useSelectedPrincipal } from '../../hooks/useSelectedPrincipal.js';
14
15
  import { useIAMStore } from '../../state/substates/index.js';
@@ -39,33 +40,7 @@ export const PrincipalBanner = ({ caption, rightContent, }) => {
39
40
  ? 'attention.muted'
40
41
  : 'accent.muted';
41
42
  const fg = isOrganization ? 'done.fg' : isTeam ? 'attention.fg' : 'accent.fg';
42
- return (_jsxs(Box, { sx: {
43
- display: 'flex',
44
- alignItems: 'center',
45
- gap: 3,
46
- p: 3,
47
- border: '1px solid',
48
- borderColor,
49
- borderRadius: 2,
50
- bg,
51
- }, children: [_jsx(Box, { sx: {
52
- width: 40,
53
- height: 40,
54
- display: 'flex',
55
- alignItems: 'center',
56
- justifyContent: 'center',
57
- borderRadius: '50%',
58
- bg: 'canvas.default',
59
- border: '1px solid',
60
- borderColor,
61
- color: fg,
62
- flex: '0 0 auto',
63
- }, children: _jsx(Icon, { size: 20 }) }), _jsxs(Box, { sx: { minWidth: 0, flex: 1 }, children: [_jsxs(Box, { sx: {
64
- display: 'flex',
65
- alignItems: 'center',
66
- gap: 2,
67
- flexWrap: 'wrap',
68
- }, children: [_jsx(Text, { sx: {
43
+ return (_jsxs(Box, { display: "flex", alignItems: "center", gap: 3, p: 3, border: "1px solid", borderColor: borderColor, borderRadius: 2, bg: bg, children: [_jsx(Box, { width: 40, height: 40, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", bg: "canvas.default", border: "1px solid", borderColor: borderColor, color: fg, flex: "0 0 auto", children: _jsx(Icon, { size: 20 }) }), _jsxs(Box, { minWidth: 0, flex: 1, children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, flexWrap: "wrap", children: [_jsx(Text, { sx: {
69
44
  color: 'fg.muted',
70
45
  fontSize: 0,
71
46
  textTransform: 'uppercase',
@@ -76,9 +51,6 @@ export const PrincipalBanner = ({ caption, rightContent, }) => {
76
51
  ? 'Organization'
77
52
  : isTeam
78
53
  ? 'Team'
79
- : 'User' }), caption && (_jsx(Text, { as: "p", sx: { m: 0, mt: 1, color: 'fg.muted', fontSize: 1 }, children: caption }))] }), rightContent ? (_jsx(Box, { sx: {
80
- flex: ['1 1 100%', '0 0 auto'],
81
- width: ['100%', 'min(640px, 58%)'],
82
- }, children: rightContent })) : null] }));
54
+ : 'User' }), caption && (_jsx(Text, { as: "p", sx: { m: 0, mt: 1, color: 'fg.muted', fontSize: 1 }, children: caption }))] }), rightContent ? (_jsx(Box, { flex: ['1 1 100%', '0 0 auto'], width: ['100%', 'min(640px, 58%)'], children: rightContent })) : null] }));
83
55
  };
84
56
  export default PrincipalBanner;
@@ -14,14 +14,11 @@ export type PrincipalDetailsOverlayProps = {
14
14
  email?: string;
15
15
  origin?: string;
16
16
  avatarUrl?: string;
17
- avatarIcon?: string;
18
17
  /**
19
- * A literal emoji, for a face this platform draws rather than a person's
20
- * own choice of picture or icon — an agent, checked before `avatarUrl`/
21
- * `avatarIcon` since the emoji is its real identity here, not a
22
- * placeholder standing in for one.
18
+ * The chosen avatar, as it is kept: `emoji:…` (an agent's face is its
19
+ * emoji) or `@datalayer/icons-react:…`.
23
20
  */
24
- avatarEmoji?: string;
21
+ avatar?: string;
25
22
  /** Team-specific: parent organization display name. */
26
23
  organizationName?: string;
27
24
  /** Team-specific: number of members. */
@@ -59,7 +56,7 @@ export declare function buildPrincipalProfilePath({ kind, uid, handle, accountHa
59
56
  * anchored on an avatar ({@link PrincipalHoverCard}) both render this, so
60
57
  * the two never drift.
61
58
  */
62
- export declare function PrincipalDetailsCard({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, avatarIcon, avatarEmoji, organizationName, memberCount, isPublic, isAdmin, onNavigate, }: PrincipalDetailsOverlayProps): JSX.Element;
59
+ export declare function PrincipalDetailsCard({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, avatar, organizationName, memberCount, isPublic, isAdmin, onNavigate, }: PrincipalDetailsOverlayProps): JSX.Element;
63
60
  /**
64
61
  * A principal's details, shown from a click on their name.
65
62
  *
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { ActionMenu, Box, Button, Label, Text, ThemeProvider, } from '@primer/react';
2
+ import { Box } from '@datalayer/primer-addons';
3
+ import { ActionMenu, Button, Label, Text, ThemeProvider } from '@primer/react';
3
4
  import { useNavigate } from '../../hooks/index.js';
4
5
  import { PrincipalAvatar } from './PrincipalAvatar.js';
5
6
  import { displayHandleText } from '../display/DisplayHandle.js';
@@ -88,7 +89,7 @@ export function buildPrincipalProfilePath({ kind, uid, handle, accountHandle, is
88
89
  * anchored on an avatar ({@link PrincipalHoverCard}) both render this, so
89
90
  * the two never drift.
90
91
  */
91
- export function PrincipalDetailsCard({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, avatarIcon, avatarEmoji, organizationName, memberCount, isPublic, isAdmin = false, onNavigate, }) {
92
+ export function PrincipalDetailsCard({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, avatar, organizationName, memberCount, isPublic, isAdmin = false, onNavigate, }) {
92
93
  const navigate = useNavigate();
93
94
  // Where a profile or organization link goes: the router of this subtree,
94
95
  // unless the caller knows of one that can actually serve it — see
@@ -139,18 +140,13 @@ export function PrincipalDetailsCard({ kind, uid, displayName, name, description
139
140
  const organizationPath = teamOrganizationHandle
140
141
  ? `/${teamOrganizationHandle.replace(/^@+/, '')}`
141
142
  : '';
142
- return (_jsxs(Box, { sx: { display: 'grid', gap: 3, p: 4, minWidth: 420 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(PrincipalAvatar, { kind: kind, avatarUrl: avatarUrl, avatarIcon: avatarIcon, avatarEmoji: avatarEmoji, alt: normalizedDisplayName, size: 40,
143
+ return (_jsxs(Box, { display: "grid", gap: 3, p: 4, minWidth: 420, children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(PrincipalAvatar, { kind: kind, avatarUrl: avatarUrl, avatar: avatar, alt: normalizedDisplayName, size: 40,
143
144
  // The card sets the avatar on its own ground, the same colour
144
145
  // the avatar itself is on: without an edge of its own it has
145
146
  // no visible shape at all. Round, and ringed.
146
- square: false, ring: true }), _jsxs(Box, { sx: { display: 'grid', gap: 0.5 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: normalizedDisplayName }), kind === 'team' ? (teamHandleOnly ? (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [displayHandleText(teamHandleOnly), teamOrganizationHandle
147
+ square: false, ring: true }), _jsxs(Box, { display: "grid", gap: 0.5, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: normalizedDisplayName }), kind === 'team' ? (teamHandleOnly ? (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [displayHandleText(teamHandleOnly), teamOrganizationHandle
147
148
  ? ` · @${teamOrganizationHandle.replace(/^@+/, '')}`
148
- : ''] })) : null) : resolvedHandle ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: displayHandleText(resolvedHandle) })) : null] })] }), _jsxs(Box, { sx: {
149
- display: 'grid',
150
- gridTemplateColumns: '110px 1fr',
151
- gap: 1,
152
- alignItems: 'baseline',
153
- }, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Kind" }), _jsx(Text, { sx: { fontSize: 1 }, children: kind }), resolvedHandle && kind !== 'team' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Handle" }), _jsx(Text, { sx: { fontSize: 1 }, children: displayHandleText(resolvedHandle) })] })) : null, normalizedUid ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "UID" }), _jsx(Text, { sx: { fontSize: 1 }, children: normalizedUid })] })) : null, kind === 'personal' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "First name" }), _jsx(Text, { sx: { fontSize: 1 }, children: firstName || 'N/A' }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Last name" }), _jsx(Text, { sx: { fontSize: 1 }, children: lastName || 'N/A' }), email ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Email" }), _jsx(Text, { sx: { fontSize: 1 }, children: email })] })) : null, _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Origin" }), _jsx(Label, { size: "small", variant: "secondary", title: normalizedOrigin, sx: {
149
+ : ''] })) : null) : resolvedHandle ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: displayHandleText(resolvedHandle) })) : null] })] }), _jsxs(Box, { display: "grid", gridTemplateColumns: "110px 1fr", gap: 1, alignItems: "baseline", children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Kind" }), _jsx(Text, { sx: { fontSize: 1 }, children: kind }), resolvedHandle && kind !== 'team' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Handle" }), _jsx(Text, { sx: { fontSize: 1 }, children: displayHandleText(resolvedHandle) })] })) : null, normalizedUid ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "UID" }), _jsx(Text, { sx: { fontSize: 1 }, children: normalizedUid })] })) : null, kind === 'personal' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "First name" }), _jsx(Text, { sx: { fontSize: 1 }, children: firstName || 'N/A' }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Last name" }), _jsx(Text, { sx: { fontSize: 1 }, children: lastName || 'N/A' }), email ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Email" }), _jsx(Text, { sx: { fontSize: 1 }, children: email })] })) : null, _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Origin" }), _jsx(Label, { size: "small", variant: "secondary", title: normalizedOrigin, sx: {
154
150
  justifySelf: 'start',
155
151
  width: 'fit-content',
156
152
  maxWidth: '100%',
@@ -166,7 +162,7 @@ export function PrincipalDetailsCard({ kind, uid, displayName, name, description
166
162
  overflow: 'hidden',
167
163
  textOverflow: 'ellipsis',
168
164
  whiteSpace: 'nowrap',
169
- }, children: normalizedOrigin })] }))] }), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end', gap: 2 }, children: [kind === 'team' && organizationPath ? (_jsx(Button, { size: "small", variant: "invisible", onClick: () => go(organizationPath), children: "View Organization" })) : null, _jsx(Button, { size: "small", onClick: () => go(targetPath), disabled: !targetPath, children: "View Profile" })] })] }));
165
+ }, children: normalizedOrigin })] }))] }), _jsxs(Box, { display: "flex", justifyContent: "flex-end", gap: 2, children: [kind === 'team' && organizationPath ? (_jsx(Button, { size: "small", variant: "invisible", onClick: () => go(organizationPath), children: "View Organization" })) : null, _jsx(Button, { size: "small", onClick: () => go(targetPath), disabled: !targetPath, children: "View Profile" })] })] }));
170
166
  }
171
167
  /**
172
168
  * A principal's details, shown from a click on their name.
@@ -179,18 +175,6 @@ export function PrincipalDetailsOverlay(props) {
179
175
  normalize(props.handle) ||
180
176
  normalize(props.uid) ||
181
177
  'Principal';
182
- return (_jsx(ThemeProvider, { children: _jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Box, { as: "button", type: "button", sx: {
183
- fontWeight: 'semibold',
184
- color: 'accent.fg',
185
- textDecoration: 'underline',
186
- background: 'transparent',
187
- border: 0,
188
- padding: 0,
189
- margin: 0,
190
- cursor: 'pointer',
191
- ':hover': {
192
- textDecoration: 'underline',
193
- },
194
- }, children: normalizedDisplayName }) }), _jsx(ActionMenu.Overlay, { width: "large", children: _jsx(PrincipalDetailsCard, { ...props }) })] }) }));
178
+ return (_jsx(ThemeProvider, { children: _jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Box, { as: "button", type: "button", fontWeight: "semibold", color: "accent.fg", textDecoration: "underline", background: "transparent", border: 0, padding: 0, margin: 0, cursor: "pointer", hover: { textDecoration: 'underline' }, children: normalizedDisplayName }) }), _jsx(ActionMenu.Overlay, { width: "large", children: _jsx(PrincipalDetailsCard, { ...props }) })] }) }));
195
179
  }
196
180
  export default PrincipalDetailsOverlay;