@datalayer/core 1.1.50 → 1.1.56

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 (77) hide show
  1. package/README.md +19 -42
  2. package/lib/client/auth/AuthenticationManager.js +6 -4
  3. package/lib/client/auth/strategies.js +2 -0
  4. package/lib/components/animation/AnimatedText.d.ts +98 -0
  5. package/lib/components/animation/AnimatedText.js +220 -0
  6. package/lib/components/animation/index.d.ts +1 -0
  7. package/lib/components/animation/index.js +5 -0
  8. package/lib/components/auth/{LoginToken.d.ts → SigInAPIKey.d.ts} +3 -3
  9. package/lib/components/auth/{LoginToken.js → SigInAPIKey.js} +5 -5
  10. package/lib/components/auth/{Login.d.ts → SignIn.d.ts} +3 -3
  11. package/lib/components/auth/{Login.js → SignIn.js} +12 -12
  12. package/lib/components/auth/{Login.stories.d.ts → SignIn.stories.d.ts} +2 -2
  13. package/lib/components/auth/{Login.stories.js → SignIn.stories.js} +4 -4
  14. package/lib/components/auth/index.d.ts +2 -2
  15. package/lib/components/auth/index.js +2 -2
  16. package/lib/components/avatars/UserAvatar.d.ts +3 -1
  17. package/lib/components/avatars/UserAvatar.js +16 -3
  18. package/lib/components/avatars/UserProfileAvatar.js +2 -6
  19. package/lib/components/collaboration/LiveEditorCollaborators.d.ts +31 -0
  20. package/lib/components/collaboration/LiveEditorCollaborators.js +107 -0
  21. package/lib/components/collaboration/index.d.ts +1 -0
  22. package/lib/components/collaboration/index.js +9 -0
  23. package/lib/components/display/DatalayerBox.d.ts +3 -1
  24. package/lib/components/display/DatalayerBox.js +7 -7
  25. package/lib/components/display/JupyterDialog.d.ts +2 -0
  26. package/lib/components/display/JupyterDialog.js +10 -4
  27. package/lib/components/iam/ExternalTokenSilentLogin.js +2 -2
  28. package/lib/components/index.d.ts +2 -0
  29. package/lib/components/index.js +2 -0
  30. package/lib/components/labels/StatusLabels.d.ts +42 -0
  31. package/lib/components/labels/StatusLabels.js +61 -0
  32. package/lib/components/labels/index.d.ts +1 -0
  33. package/lib/components/labels/index.js +1 -0
  34. package/lib/components/principal/Principal.d.ts +2 -0
  35. package/lib/components/principal/Principal.js +11 -1
  36. package/lib/components/principal/PrincipalAppearance.d.ts +136 -0
  37. package/lib/components/principal/PrincipalAppearance.js +203 -0
  38. package/lib/components/principal/PrincipalAvatar.d.ts +5 -2
  39. package/lib/components/principal/PrincipalAvatar.js +16 -3
  40. package/lib/components/principal/PrincipalBadge.js +7 -0
  41. package/lib/components/principal/PrincipalDetailsOverlay.d.ts +2 -1
  42. package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
  43. package/lib/components/principal/index.d.ts +1 -0
  44. package/lib/components/principal/index.js +1 -0
  45. package/lib/components/progress/ConsumptionBar.d.ts +9 -0
  46. package/lib/components/progress/ConsumptionBar.js +10 -2
  47. package/lib/components/sharing/ShareAccessComponent.js +6 -1
  48. package/lib/config/Configuration.d.ts +17 -8
  49. package/lib/config/Configuration.js +12 -5
  50. package/lib/hooks/useCache.d.ts +2 -0
  51. package/lib/hooks/useCache.js +35 -11
  52. package/lib/hooks/usePrincipalCacheStore.d.ts +2 -0
  53. package/lib/hooks/usePrincipalCacheStore.js +2 -0
  54. package/lib/models/IAM.d.ts +10 -0
  55. package/lib/models/Organization.d.ts +2 -0
  56. package/lib/models/Organization.js +2 -0
  57. package/lib/models/Profile.d.ts +2 -0
  58. package/lib/models/Team.d.ts +2 -0
  59. package/lib/models/Team.js +2 -0
  60. package/lib/models/User.d.ts +4 -0
  61. package/lib/models/User.js +4 -0
  62. package/lib/models/UserDTO.d.ts +6 -0
  63. package/lib/models/UserDTO.js +8 -0
  64. package/lib/state/substates/CoreState.js +3 -2
  65. package/lib/state/substates/IAMState.js +6 -0
  66. package/lib/state/substates/LayoutState.js +62 -7
  67. package/lib/state/substates/OrganizationState.d.ts +6 -0
  68. package/lib/state/substates/OrganizationState.js +5 -0
  69. package/lib/state/substates/ProfileState.d.ts +34 -0
  70. package/lib/state/substates/ProfileState.js +68 -0
  71. package/lib/state/substates/TeamState.d.ts +6 -0
  72. package/lib/state/substates/TeamState.js +3 -0
  73. package/lib/state/substates/index.d.ts +1 -0
  74. package/lib/state/substates/index.js +1 -0
  75. package/lib/views/iam/SignInSimple.d.ts +1 -1
  76. package/lib/views/iam/SignInSimple.js +3 -4
  77. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Authentication components for Datalayer platform
3
3
  */
4
- export * from './Login';
5
- export * from './LoginToken';
4
+ export * from './SignIn';
5
+ export * from './SigInAPIKey';
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Authentication components for Datalayer platform
7
7
  */
8
- export * from './Login.js';
8
+ export * from './SignIn.js';
9
9
  // LoginCLI is excluded from build - it's meant for CLI apps with full routing.
10
10
  // export * from './LoginCLI.js';
11
- export * from './LoginToken.js';
11
+ export * from './SigInAPIKey.js';
@@ -5,6 +5,7 @@
5
5
  export declare function hasRealAvatar(url?: string): boolean;
6
6
  export type UserAvatarProps = {
7
7
  avatarUrl?: string;
8
+ avatarIcon?: string;
8
9
  /** Avatar edge length in pixels. Defaults to 100. */
9
10
  size?: number;
10
11
  /** Render with rounded square corners instead of a circle. Defaults to true. */
@@ -15,6 +16,7 @@ export type UserAvatarProps = {
15
16
  fallbackBackground?: string;
16
17
  /** Optional icon foreground color override for the default avatar. */
17
18
  fallbackForeground?: string;
19
+ className?: string;
18
20
  };
19
- export declare const UserAvatar: ({ avatarUrl, size, square, iconSize, fallbackBackground, fallbackForeground, }: UserAvatarProps) => JSX.Element;
21
+ export declare const UserAvatar: ({ avatarUrl, avatarIcon, size, square, iconSize, fallbackBackground, fallbackForeground, className, }: UserAvatarProps) => JSX.Element;
20
22
  export default UserAvatar;
@@ -14,6 +14,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
14
14
  import { AlienIcon } from '@datalayer/icons-react';
15
15
  import { Box, useColorPalette } from '@datalayer/primer-addons';
16
16
  import { DLAvatar } from './DLAvatar.js';
17
+ import { getPrincipalAvatarIcon } from '../principal/PrincipalAppearance.js';
17
18
  /**
18
19
  * Returns `true` when the given URL points to a real user avatar (i.e. not a
19
20
  * Gravatar default placeholder).
@@ -27,13 +28,25 @@ export function hasRealAvatar(url) {
27
28
  }
28
29
  return true;
29
30
  }
30
- export const UserAvatar = ({ avatarUrl, size = 100, square = true, iconSize, fallbackBackground, fallbackForeground, }) => {
31
+ export const UserAvatar = ({ avatarUrl, avatarIcon, size = 100, square = true, iconSize, fallbackBackground, fallbackForeground, className, }) => {
31
32
  const palette = useColorPalette();
33
+ const SelectedIcon = getPrincipalAvatarIcon(avatarIcon);
34
+ if (SelectedIcon) {
35
+ return (_jsx(Box, { className: className, sx: {
36
+ width: size,
37
+ height: size,
38
+ borderRadius: square ? 2 : '50%',
39
+ overflow: 'hidden',
40
+ display: 'inline-flex',
41
+ alignItems: 'center',
42
+ justifyContent: 'center',
43
+ }, children: _jsx(SelectedIcon, { size: size, colored: true }) }));
44
+ }
32
45
  if (hasRealAvatar(avatarUrl)) {
33
- return _jsx(DLAvatar, { square: square, src: avatarUrl, size: size });
46
+ return _jsx(DLAvatar, { className: className, square: square, src: avatarUrl, size: size });
34
47
  }
35
48
  const resolvedIconSize = iconSize ?? Math.round(size * 0.48);
36
- return (_jsx(Box, { sx: {
49
+ return (_jsx(Box, { className: className, sx: {
37
50
  width: size,
38
51
  height: size,
39
52
  borderRadius: square ? 2 : '50%',
@@ -6,13 +6,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
6
6
  import { Link } from '@primer/react';
7
7
  import { Box } from '@datalayer/primer-addons';
8
8
  import { AvatarSkeleton } from '../../components/display/index.js';
9
- import { DLAvatar } from './DLAvatar.js';
9
+ import { UserAvatar } from './UserAvatar.js';
10
10
  const Profile = ({ user, size = 100, onClick }) => {
11
- return (_jsx(Box, { style: { width: size }, children: _jsx(DLAvatar
12
- // square
13
- , {
14
- // square
15
- src: user?.avatarUrl, size: size, onClick: onClick }) }));
11
+ return (_jsx(Box, { style: { width: size }, onClick: onClick, children: _jsx(UserAvatar, { avatarUrl: user?.avatarUrl, avatarIcon: user?.avatarIcon, size: size }) }));
16
12
  };
17
13
  export const UserProfileAvatar = ({ onClick, user, size = 100, }) => {
18
14
  return user ? (onClick ? (_jsx(Link, { href: "javascript: return false;", onClick: onClick, children: _jsx(Profile, { user: user, size: size, onClick: onClick }) })) : (_jsx(Profile, { user: user, size: size, onClick: onClick }))) : (_jsx(AvatarSkeleton, { size: size }));
@@ -0,0 +1,31 @@
1
+ export type LiveCollaborator = {
2
+ /** Stable identity — a user uid, or the awareness client id. */
3
+ id: string;
4
+ name: string;
5
+ avatarUrl?: string;
6
+ avatarIcon?: string;
7
+ /** Cursor color of the presence, worn by the initials disc. */
8
+ color?: string;
9
+ };
10
+ /**
11
+ * The slice of a Yjs-style awareness this component reads. Structural, so
12
+ * any provider — Jupyter collaboration, Datalayer spacer — fits without a
13
+ * dependency on its package.
14
+ */
15
+ export type IAwarenessLike = {
16
+ getStates(): Map<number, Record<string, any>>;
17
+ on(event: 'change', handler: () => void): void;
18
+ off(event: 'change', handler: () => void): void;
19
+ };
20
+ export type LiveEditorCollaboratorsProps = {
21
+ /** The presence of the room, followed live when given. */
22
+ awareness?: IAwarenessLike | null;
23
+ /** The collaborators known without a room — owner and granted. */
24
+ collaborators?: LiveCollaborator[];
25
+ /** Diameter of a face, in pixels. */
26
+ size?: number;
27
+ /** How many faces at most; the stack keeps the first ones. */
28
+ max?: number;
29
+ };
30
+ export declare function LiveEditorCollaborators(props: LiveEditorCollaboratorsProps): JSX.Element | null;
31
+ export default LiveEditorCollaborators;
@@ -0,0 +1,107 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2023-2025 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ /*
7
+ * Copyright (c) 2023-2026 Datalayer, Inc.
8
+ * Distributed under the terms of the Modified BSD License.
9
+ */
10
+ /**
11
+ * The faces on a shared document: who is here now, and who belongs here.
12
+ *
13
+ * One avatar stack for every surface that names collaborators — the cards of
14
+ * the home page, the headers of the notebook and document editors, in the
15
+ * web application and in JupyterLab alike. Two sources feed it, both
16
+ * optional and freely combined:
17
+ *
18
+ * - `awareness`: the presence channel of a collaborative editor. The stack
19
+ * follows it live — people appear as they join and leave as they go.
20
+ * - `collaborators`: what is known without a room, the owner and the granted
21
+ * of an item. They fill the stack when there is no presence, and complete
22
+ * it when there is.
23
+ *
24
+ * Every face uses the shared principal avatar rules: a selected icon wins,
25
+ * then a connected-account picture, then the standard personal fallback.
26
+ *
27
+ * @module components/collaboration/LiveEditorCollaborators
28
+ */
29
+ import { useEffect, useMemo, useState } from 'react';
30
+ import { AvatarStack } from '@primer/react';
31
+ import { PrincipalAvatar } from '../principal/PrincipalAvatar.js';
32
+ /** The `user` field of an awareness state, in its several spellings. */
33
+ function collaboratorOfState(clientId, state) {
34
+ const user = state?.user;
35
+ if (!user) {
36
+ return undefined;
37
+ }
38
+ const name = user.display_name || user.displayName || user.name || user.username || '';
39
+ if (!name) {
40
+ return undefined;
41
+ }
42
+ return {
43
+ id: String(user.uid ?? user.id ?? user.username ?? clientId),
44
+ name,
45
+ avatarUrl: user.avatar_url || user.avatarUrl || undefined,
46
+ avatarIcon: user.avatar_icon_s || user.avatarIcon || undefined,
47
+ color: user.color || undefined
48
+ };
49
+ }
50
+ export function LiveEditorCollaborators(props) {
51
+ const { awareness, collaborators = [], max = 5, size = 24 } = props;
52
+ const [present, setPresent] = useState([]);
53
+ useEffect(() => {
54
+ if (!awareness) {
55
+ setPresent([]);
56
+ return;
57
+ }
58
+ const read = () => {
59
+ const seen = new Map();
60
+ awareness.getStates().forEach((state, clientId) => {
61
+ const collaborator = collaboratorOfState(clientId, state);
62
+ // One face per person, however many tabs they have open.
63
+ if (collaborator && !seen.has(collaborator.id)) {
64
+ seen.set(collaborator.id, collaborator);
65
+ }
66
+ });
67
+ setPresent(Array.from(seen.values()));
68
+ };
69
+ read();
70
+ awareness.on('change', read);
71
+ return () => {
72
+ awareness.off('change', read);
73
+ };
74
+ }, [awareness]);
75
+ const faces = useMemo(() => {
76
+ // Who is here leads; who merely belongs completes. Folded by id and
77
+ // then by name: the same person often arrives twice — once under their
78
+ // platform uid, once under the identity the room gave them.
79
+ const merged = new Map();
80
+ const byName = new Map();
81
+ for (const collaborator of [...present, ...collaborators]) {
82
+ const nameKey = collaborator.name.trim().toLowerCase();
83
+ const key = merged.has(collaborator.id)
84
+ ? collaborator.id
85
+ : (byName.get(nameKey) ?? collaborator.id);
86
+ const known = merged.get(key);
87
+ if (!known) {
88
+ merged.set(key, collaborator);
89
+ byName.set(nameKey, key);
90
+ }
91
+ else if ((!known.avatarIcon && collaborator.avatarIcon) ||
92
+ (!known.avatarUrl && collaborator.avatarUrl)) {
93
+ merged.set(key, {
94
+ ...known,
95
+ avatarIcon: known.avatarIcon || collaborator.avatarIcon,
96
+ avatarUrl: known.avatarUrl || collaborator.avatarUrl,
97
+ });
98
+ }
99
+ }
100
+ return Array.from(merged.values()).slice(0, max);
101
+ }, [collaborators, max, present]);
102
+ if (!faces.length) {
103
+ return null;
104
+ }
105
+ return (_jsx(AvatarStack, { size: size, children: faces.map(face => (_jsx(PrincipalAvatar, { kind: "personal", size: size, alt: face.name, avatarUrl: face.avatarUrl, avatarIcon: face.avatarIcon, square: false }, face.id))) }));
106
+ }
107
+ export default LiveEditorCollaborators;
@@ -0,0 +1 @@
1
+ export * from './LiveEditorCollaborators';
@@ -0,0 +1,9 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /*
6
+ * Copyright (c) 2023-2026 Datalayer, Inc.
7
+ * Distributed under the terms of the Modified BSD License.
8
+ */
9
+ export * from './LiveEditorCollaborators.js';
@@ -1,8 +1,10 @@
1
+ import type { PropsWithChildren, ReactNode } from 'react';
1
2
  type DatalayerBoxProps = {
2
3
  id?: string;
3
4
  title: string;
5
+ titleAction?: ReactNode;
4
6
  linkLabel?: string;
5
7
  linkRoute?: string;
6
8
  };
7
- export declare const DatalayerBox: (props: React.PropsWithChildren<DatalayerBoxProps>) => import("react/jsx-runtime").JSX.Element;
9
+ export declare const DatalayerBox: (props: PropsWithChildren<DatalayerBoxProps>) => import("react/jsx-runtime").JSX.Element;
8
10
  export default DatalayerBox;
@@ -8,19 +8,19 @@ import { Box } from '@datalayer/primer-addons';
8
8
  import { ArrowRightIcon } from '@primer/octicons-react';
9
9
  import { useNavigate } from '../../hooks/index.js';
10
10
  export const DatalayerBox = (props) => {
11
- const { title, linkLabel, linkRoute, children } = props;
11
+ const { title, titleAction, linkLabel, linkRoute, children } = props;
12
12
  const navigate = useNavigate();
13
13
  return (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
14
14
  display: 'flex',
15
15
  alignItems: 'center',
16
16
  justifyContent: 'space-between',
17
17
  paddingRight: 4,
18
- }, children: [_jsx(Text, { as: "h2", sx: { borderLeft: '6px solid #28b899', paddingLeft: 2 }, children: title }), linkRoute && linkLabel && (_jsxs(Link, { href: "javascript: return false;", onClick: e => navigate(linkRoute), sx: {
19
- display: 'inline-flex',
20
- alignItems: 'center',
21
- gap: 1,
22
- whiteSpace: 'nowrap',
23
- }, children: [linkLabel, _jsx(ArrowRightIcon, {})] }))] }), _jsx(Box, { sx: {
18
+ }, children: [_jsx(Text, { as: "h2", sx: { borderLeft: '6px solid #28b899', paddingLeft: 2 }, children: title }), (titleAction || (linkRoute && linkLabel)) && (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [titleAction, linkRoute && linkLabel && (_jsxs(Link, { href: "javascript: return false;", onClick: e => navigate(linkRoute), sx: {
19
+ display: 'inline-flex',
20
+ alignItems: 'center',
21
+ gap: 1,
22
+ whiteSpace: 'nowrap',
23
+ }, children: [linkLabel, _jsx(ArrowRightIcon, {})] }))] }))] }), _jsx(Box, { sx: {
24
24
  borderColor: 'border.default',
25
25
  borderStyle: 'solid',
26
26
  borderWidth: '1',
@@ -45,6 +45,8 @@ export interface IDialogWrapperOptions<T> {
45
45
  export declare class JupyterDialog<T> extends ReactWidget {
46
46
  protected body: JSXElementConstructor<PropsWithChildren<DialogProps & {
47
47
  setValue: (v: T | Error) => void;
48
+ /** Whether an accepted answer is being acted on. */
49
+ pending?: boolean;
48
50
  }>>;
49
51
  protected checkbox: Partial<Dialog.ICheckbox> | null;
50
52
  protected buttons: Dialog.IButton[];
@@ -56,10 +56,16 @@ export class JupyterDialog extends ReactWidget {
56
56
  this.dialogTitle = options.title;
57
57
  this.onWillAccept = options.onWillAccept;
58
58
  }
59
- _renderBody = (props) => (_jsx(PrimerDialog.Body, { children: createElement(this.body, {
60
- ...props,
61
- setValue: this.setValue,
62
- }) }));
59
+ _renderBody = (props) => {
60
+ const pending = this._pendingButtonIndex !== null;
61
+ return (_jsx(PrimerDialog.Body, { children: _jsx("div", { "aria-busy": pending, ...(pending ? { inert: '' } : {}), style: pending
62
+ ? { pointerEvents: 'none', opacity: 0.6 }
63
+ : undefined, children: createElement(this.body, {
64
+ ...props,
65
+ setValue: this.setValue,
66
+ pending,
67
+ }) }) }));
68
+ };
63
69
  _renderFooter = (props) => (_jsx(DialogFooter, { ...props, checkbox: this.checkbox, setChecked: this.setChecked }));
64
70
  render() {
65
71
  // TODO title color is enforced for JupyterLab.
@@ -18,8 +18,8 @@ const ExternalTokenSilentLoginRoute = (props) => {
18
18
  if (externalToken) {
19
19
  loginAndNavigate(externalToken, logout, checkIAMToken)
20
20
  .catch(error => {
21
- console.debug('Failed to login with the provided token.', error);
22
- enqueueToast('Failed to login with the provided token.', {
21
+ console.debug('Failed to sign in with the provided token.', error);
22
+ enqueueToast('Failed to sign in with the provided token.', {
23
23
  variant: 'error',
24
24
  });
25
25
  })
@@ -1,5 +1,7 @@
1
1
  export * from './auth';
2
+ export * from './animation';
2
3
  export * from './billing';
4
+ export * from './collaboration';
3
5
  export * from './sharing';
4
6
  export * from './sparklines';
5
7
  export * from './time';
@@ -3,7 +3,9 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  export * from './auth/index.js';
6
+ export * from './animation/index.js';
6
7
  export * from './billing/index.js';
8
+ export * from './collaboration/index.js';
7
9
  export * from './sharing/index.js';
8
10
  export * from './sparklines/index.js';
9
11
  export * from './time/index.js';
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The small pills that qualify an entry.
3
+ *
4
+ * A menu entry, a card, a row of a switcher: what qualifies them is always
5
+ * the same mark — one lowercase word in a semantic tone — and it was written
6
+ * out at every place that needed one. These are that mark, named after what
7
+ * they say, so `alpha` looks the same in the user menu, on an integration and
8
+ * wherever it is needed next.
9
+ *
10
+ * @module components/labels/StatusLabels
11
+ */
12
+ import type { ReactNode } from 'react';
13
+ /** The tones a status pill is read in. */
14
+ export type StatusLabelTone = 'accent' | 'attention' | 'success' | 'neutral';
15
+ export type StatusLabelProps = {
16
+ /** Word of the pill; each label has one of its own. */
17
+ children?: ReactNode;
18
+ size?: 'small' | 'large';
19
+ sx?: Record<string, unknown>;
20
+ };
21
+ /**
22
+ * The pill the named labels below are made of.
23
+ *
24
+ * Exported for a qualification that has no label of its own yet; prefer one of
25
+ * the named ones, so the same thing is said the same way everywhere.
26
+ */
27
+ export declare function StatusLabel(props: StatusLabelProps & {
28
+ tone: StatusLabelTone;
29
+ }): JSX.Element;
30
+ /**
31
+ * A feature that is being tried out.
32
+ */
33
+ export declare function AlphaLabel(props?: StatusLabelProps): JSX.Element;
34
+ /**
35
+ * Something reserved to the administrators of the platform.
36
+ */
37
+ export declare function AdminLabel(props?: StatusLabelProps): JSX.Element;
38
+ /**
39
+ * The one that is taken when none is chosen — the default space of an account.
40
+ */
41
+ export declare function DefaultLabel(props?: StatusLabelProps): JSX.Element;
42
+ export default StatusLabel;
@@ -0,0 +1,61 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Label } from '@primer/react';
3
+ const TONES = {
4
+ accent: {
5
+ bg: 'accent.subtle',
6
+ color: 'accent.fg',
7
+ borderColor: 'accent.muted',
8
+ },
9
+ attention: {
10
+ bg: 'attention.subtle',
11
+ color: 'attention.fg',
12
+ borderColor: 'attention.muted',
13
+ },
14
+ success: {
15
+ bg: 'success.subtle',
16
+ color: 'success.fg',
17
+ borderColor: 'success.muted',
18
+ },
19
+ neutral: {
20
+ bg: 'neutral.subtle',
21
+ color: 'fg.muted',
22
+ borderColor: 'border.default',
23
+ },
24
+ };
25
+ /**
26
+ * The pill the named labels below are made of.
27
+ *
28
+ * Exported for a qualification that has no label of its own yet; prefer one of
29
+ * the named ones, so the same thing is said the same way everywhere.
30
+ */
31
+ export function StatusLabel(props) {
32
+ const { children, size = 'small', sx, tone } = props;
33
+ return (_jsx(Label, { variant: "secondary", size: size, sx: {
34
+ textTransform: 'lowercase',
35
+ lineHeight: 1.2,
36
+ ...TONES[tone],
37
+ ...sx,
38
+ }, children: children }));
39
+ }
40
+ /**
41
+ * A feature that is being tried out.
42
+ */
43
+ export function AlphaLabel(props = {}) {
44
+ const { children = 'alpha', ...rest } = props;
45
+ return (_jsx(StatusLabel, { tone: "accent", ...rest, children: children }));
46
+ }
47
+ /**
48
+ * Something reserved to the administrators of the platform.
49
+ */
50
+ export function AdminLabel(props = {}) {
51
+ const { children = 'admin', ...rest } = props;
52
+ return (_jsx(StatusLabel, { tone: "attention", ...rest, children: children }));
53
+ }
54
+ /**
55
+ * The one that is taken when none is chosen — the default space of an account.
56
+ */
57
+ export function DefaultLabel(props = {}) {
58
+ const { children = 'default', ...rest } = props;
59
+ return (_jsx(StatusLabel, { tone: "accent", ...rest, children: children }));
60
+ }
61
+ export default StatusLabel;
@@ -1 +1,2 @@
1
+ export * from './StatusLabels';
1
2
  export * from './VisibilityLabel';
@@ -2,4 +2,5 @@
2
2
  * Copyright (c) 2023-2025 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
+ export * from './StatusLabels.js';
5
6
  export * from './VisibilityLabel.js';
@@ -26,6 +26,8 @@ export type PrincipalDescriptor = {
26
26
  email?: string;
27
27
  origin?: string;
28
28
  avatarUrl?: string;
29
+ avatarIcon?: string;
30
+ banner?: string;
29
31
  };
30
32
  export type PrincipalProps = {
31
33
  principal: PrincipalDescriptor;
@@ -114,6 +114,8 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
114
114
  lastName: profile.last_name,
115
115
  handle: profile.handle,
116
116
  avatarUrl: profile.avatar_url,
117
+ avatarIcon: profile.avatar_icon_s || profile.avatar_icon,
118
+ banner: profile.banner_s || profile.banner,
117
119
  origin: profile.origin,
118
120
  email: profile.email,
119
121
  };
@@ -129,6 +131,8 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
129
131
  description: profile.description || profile.description_t,
130
132
  handle: profile.handle,
131
133
  avatarUrl: profile.avatar_url,
134
+ avatarIcon: profile.avatar_icon_s || profile.avatar_icon,
135
+ banner: profile.banner_s || profile.banner,
132
136
  };
133
137
  }, [hydratedPublicOrgQuery.data]);
134
138
  const hydratedEntity = principal.kind === 'personal'
@@ -222,6 +226,10 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
222
226
  hydratedEntity?.avatarUrl ||
223
227
  cachedPrincipal?.avatarUrl ||
224
228
  undefined,
229
+ avatarIcon: principal.avatarIcon ||
230
+ hydratedEntity?.avatarIcon ||
231
+ undefined,
232
+ banner: principal.banner || hydratedEntity?.banner || undefined,
225
233
  firstName: principal.firstName ||
226
234
  hydratedEntity?.firstName ||
227
235
  cachedPrincipal?.firstName ||
@@ -263,6 +271,8 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
263
271
  email: resolvedPrincipal.email,
264
272
  origin: resolvedPrincipal.origin,
265
273
  avatarUrl: resolvedPrincipal.avatarUrl,
274
+ avatarIcon: resolvedPrincipal.avatarIcon,
275
+ banner: resolvedPrincipal.banner,
266
276
  organizationHandle: teamOrganizationHandleResolved,
267
277
  organizationName: teamOrganizationNameResolved,
268
278
  memberCount: teamMemberCount,
@@ -286,6 +296,6 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
286
296
  gap,
287
297
  minWidth: 0,
288
298
  ...sx,
289
- }, children: [_jsx(PrincipalAvatar, { kind: resolvedPrincipal.kind, avatarUrl: resolvedPrincipal.avatarUrl, 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, organizationName: teamOrganizationNameResolved, memberCount: teamMemberCount, isPublic: resolvedIsPublic, isAdmin: isAdmin })] }));
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 })] }));
290
300
  };
291
301
  export default Principal;