@dxos/react-ui 0.8.1-staging.391c573 → 0.8.1-staging.9eaf14f
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/lib/browser/index.mjs +425 -612
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +115 -301
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +425 -612
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Avatars/Avatar.d.ts +8 -29
- package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/Avatar.stories.d.ts +5 -11
- package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts +1 -5
- package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/index.d.ts +0 -1
- package/dist/types/src/components/Avatars/index.d.ts.map +1 -1
- package/dist/types/src/components/Icon/Icon.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useIconHref.d.ts +2 -0
- package/dist/types/src/hooks/useIconHref.d.ts.map +1 -0
- package/package.json +14 -12
- package/src/components/Avatars/Avatar.stories.tsx +7 -8
- package/src/components/Avatars/Avatar.tsx +30 -229
- package/src/components/Avatars/AvatarGroup.stories.tsx +12 -19
- package/src/components/Avatars/index.ts +0 -1
- package/src/components/Icon/Icon.tsx +4 -6
- package/src/components/Input/Input.tsx +2 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useIconHref.ts +13 -0
- package/dist/types/src/components/Avatars/AvatarGroup.d.ts +0 -21
- package/dist/types/src/components/Avatars/AvatarGroup.d.ts.map +0 -1
- package/src/components/Avatars/AvatarGroup.tsx +0 -112
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIconHref.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useIconHref.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,WAAW,UAAW,MAAM,uBAIxC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui",
|
|
3
|
-
"version": "0.8.1-staging.
|
|
3
|
+
"version": "0.8.1-staging.9eaf14f",
|
|
4
4
|
"description": "Low-level React components for DXOS, applying a theme to a core group of primitives",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
|
|
28
28
|
"@fluentui/react-tabster": "^9.24.2",
|
|
29
|
+
"@lit/react": "^1.0.5",
|
|
29
30
|
"@radix-ui/primitive": "1.1.1",
|
|
30
31
|
"@radix-ui/react-alert-dialog": "1.1.6",
|
|
31
32
|
"@radix-ui/react-avatar": "1.1.3",
|
|
@@ -61,13 +62,14 @@
|
|
|
61
62
|
"keyborg": "^2.5.0",
|
|
62
63
|
"react-i18next": "^11.18.6",
|
|
63
64
|
"react-remove-scroll": "^2.6.0",
|
|
64
|
-
"@dxos/debug": "0.8.1-staging.
|
|
65
|
-
"@dxos/log": "0.8.1-staging.
|
|
66
|
-
"@dxos/
|
|
67
|
-
"@dxos/react-
|
|
68
|
-
"@dxos/react-
|
|
69
|
-
"@dxos/react-ui-types": "0.8.1-staging.
|
|
70
|
-
"@dxos/
|
|
65
|
+
"@dxos/debug": "0.8.1-staging.9eaf14f",
|
|
66
|
+
"@dxos/log": "0.8.1-staging.9eaf14f",
|
|
67
|
+
"@dxos/lit-ui": "0.8.1-staging.9eaf14f",
|
|
68
|
+
"@dxos/react-input": "0.8.1-staging.9eaf14f",
|
|
69
|
+
"@dxos/react-list": "0.8.1-staging.9eaf14f",
|
|
70
|
+
"@dxos/react-ui-types": "0.8.1-staging.9eaf14f",
|
|
71
|
+
"@dxos/react-hooks": "0.8.1-staging.9eaf14f",
|
|
72
|
+
"@dxos/util": "0.8.1-staging.9eaf14f"
|
|
71
73
|
},
|
|
72
74
|
"devDependencies": {
|
|
73
75
|
"@dnd-kit/core": "^6.0.5",
|
|
@@ -79,15 +81,15 @@
|
|
|
79
81
|
"react": "~18.2.0",
|
|
80
82
|
"react-dom": "~18.2.0",
|
|
81
83
|
"vite": "5.4.7",
|
|
82
|
-
"@dxos/random": "0.8.1-staging.
|
|
83
|
-
"@dxos/
|
|
84
|
-
"@dxos/
|
|
84
|
+
"@dxos/random": "0.8.1-staging.9eaf14f",
|
|
85
|
+
"@dxos/util": "0.8.1-staging.9eaf14f",
|
|
86
|
+
"@dxos/react-ui-theme": "0.8.1-staging.9eaf14f"
|
|
85
87
|
},
|
|
86
88
|
"peerDependencies": {
|
|
87
89
|
"@phosphor-icons/react": "^2.1.5",
|
|
88
90
|
"react": "~18.2.0",
|
|
89
91
|
"react-dom": "~18.2.0",
|
|
90
|
-
"@dxos/react-ui-theme": "0.8.1-staging.
|
|
92
|
+
"@dxos/react-ui-theme": "0.8.1-staging.9eaf14f"
|
|
91
93
|
},
|
|
92
94
|
"publishConfig": {
|
|
93
95
|
"access": "public"
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
|
-
|
|
7
6
|
import React, { type PropsWithChildren } from 'react';
|
|
8
7
|
|
|
8
|
+
import { type HuePalette } from '@dxos/react-ui-theme';
|
|
9
9
|
import { type Size } from '@dxos/react-ui-types';
|
|
10
10
|
import { hexToFallback } from '@dxos/util';
|
|
11
11
|
|
|
12
|
-
import { Avatar, type AvatarVariant, type AvatarStatus, type AvatarAnimation
|
|
12
|
+
import { Avatar, type AvatarVariant, type AvatarStatus, type AvatarAnimation } from './Avatar';
|
|
13
13
|
import { withTheme } from '../../testing';
|
|
14
14
|
|
|
15
15
|
type StorybookAvatarProps = {
|
|
@@ -22,7 +22,7 @@ type StorybookAvatarProps = {
|
|
|
22
22
|
variant?: AvatarVariant;
|
|
23
23
|
animation?: AvatarAnimation;
|
|
24
24
|
size?: Size;
|
|
25
|
-
hue?:
|
|
25
|
+
hue?: HuePalette;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
const StorybookAvatar = (props: PropsWithChildren<StorybookAvatarProps>) => {
|
|
@@ -40,11 +40,10 @@ const StorybookAvatar = (props: PropsWithChildren<StorybookAvatarProps>) => {
|
|
|
40
40
|
const { emoji, hue } = hexToFallback(id);
|
|
41
41
|
return (
|
|
42
42
|
<div className='flex flex-row gap-3 align-middle items-center'>
|
|
43
|
-
<Avatar.Root
|
|
44
|
-
<Avatar.
|
|
45
|
-
{
|
|
46
|
-
|
|
47
|
-
</Avatar.Frame>
|
|
43
|
+
<Avatar.Root>
|
|
44
|
+
<Avatar.Content
|
|
45
|
+
{...{ size, variant, status, animation, imgSrc, hue: props.hue || hue, fallback: fallbackText || emoji }}
|
|
46
|
+
/>
|
|
48
47
|
<div>
|
|
49
48
|
<Avatar.Label classNames='block'>{label}</Avatar.Label>
|
|
50
49
|
<Avatar.Description classNames='block'>
|
|
@@ -2,161 +2,58 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Fallback as AvatarFallbackPrimitive,
|
|
9
|
-
type AvatarImageProps as AvatarImagePrimitiveProps,
|
|
10
|
-
} from '@radix-ui/react-avatar';
|
|
5
|
+
import '@dxos/lit-ui/dx-avatar.pcss';
|
|
6
|
+
|
|
7
|
+
import { createComponent } from '@lit/react';
|
|
11
8
|
import { createContext } from '@radix-ui/react-context';
|
|
12
9
|
import { Primitive } from '@radix-ui/react-primitive';
|
|
13
10
|
import { Slot } from '@radix-ui/react-slot';
|
|
14
|
-
import React, { type ComponentPropsWithRef, forwardRef, type PropsWithChildren } from 'react';
|
|
11
|
+
import React, { type ComponentProps, type ComponentPropsWithRef, forwardRef, type PropsWithChildren } from 'react';
|
|
15
12
|
|
|
13
|
+
import { type AvatarVariant, type AvatarStatus, type AvatarAnimation, DxAvatar as NaturalDxAvatar } from '@dxos/lit-ui';
|
|
16
14
|
import { useId } from '@dxos/react-hooks';
|
|
17
|
-
import {
|
|
15
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
18
16
|
|
|
19
|
-
import { useThemeContext } from '../../hooks';
|
|
17
|
+
import { useIconHref, useThemeContext } from '../../hooks';
|
|
20
18
|
import { type ThemedClassName } from '../../util';
|
|
21
|
-
import { Icon } from '../Icon';
|
|
22
|
-
|
|
23
|
-
type AvatarVariant = 'square' | 'circle';
|
|
24
|
-
type AvatarStatus = 'active' | 'inactive' | 'current' | 'error' | 'warning' | 'internal';
|
|
25
|
-
type AvatarAnimation = 'pulse' | 'none';
|
|
26
19
|
|
|
27
20
|
export type AvatarRootProps = PropsWithChildren<Partial<AvatarContextValue>>;
|
|
28
21
|
|
|
29
22
|
type AvatarContextValue = {
|
|
30
23
|
labelId: string;
|
|
31
24
|
descriptionId: string;
|
|
32
|
-
maskId: string;
|
|
33
|
-
size: Size;
|
|
34
|
-
variant: AvatarVariant;
|
|
35
|
-
status?: AvatarStatus;
|
|
36
|
-
animation?: AvatarAnimation;
|
|
37
|
-
inGroup?: boolean;
|
|
38
|
-
hue?: string;
|
|
39
25
|
};
|
|
40
26
|
|
|
41
27
|
const AVATAR_NAME = 'Avatar';
|
|
42
28
|
const [AvatarProvider, useAvatarContext] = createContext<AvatarContextValue>(AVATAR_NAME);
|
|
43
29
|
|
|
44
|
-
const AvatarRoot = ({
|
|
45
|
-
size = 10,
|
|
46
|
-
variant = 'circle',
|
|
47
|
-
status,
|
|
48
|
-
animation,
|
|
49
|
-
children,
|
|
50
|
-
labelId: propsLabelId,
|
|
51
|
-
descriptionId: propsDescriptionId,
|
|
52
|
-
maskId: propsMaskId,
|
|
53
|
-
inGroup,
|
|
54
|
-
hue,
|
|
55
|
-
}: AvatarRootProps) => {
|
|
30
|
+
const AvatarRoot = ({ children, labelId: propsLabelId, descriptionId: propsDescriptionId }: AvatarRootProps) => {
|
|
56
31
|
const labelId = useId('avatar__label', propsLabelId);
|
|
57
32
|
const descriptionId = useId('avatar__description', propsDescriptionId);
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<AvatarProvider {...{ labelId, descriptionId, maskId, size, variant, status, animation, inGroup, hue }}>
|
|
61
|
-
{children}
|
|
62
|
-
</AvatarProvider>
|
|
63
|
-
);
|
|
33
|
+
return <AvatarProvider {...{ labelId, descriptionId }}>{children}</AvatarProvider>;
|
|
64
34
|
};
|
|
65
35
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
36
|
+
const DxAvatar = createComponent({
|
|
37
|
+
tagName: 'dx-avatar',
|
|
38
|
+
elementClass: NaturalDxAvatar,
|
|
39
|
+
react: React,
|
|
40
|
+
});
|
|
69
41
|
|
|
70
|
-
|
|
71
|
-
({ classNames, children, ...props }, forwardedRef) => {
|
|
72
|
-
const { size, variant, labelId, descriptionId, maskId, inGroup, status, animation, hue } =
|
|
73
|
-
useAvatarContext('AvatarFrame');
|
|
42
|
+
type AvatarContentProps = ThemedClassName<Omit<ComponentProps<typeof DxAvatar>, 'children'>>;
|
|
74
43
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
'aria-labelledby': labelId,
|
|
89
|
-
'aria-describedby': descriptionId,
|
|
90
|
-
})}
|
|
91
|
-
>
|
|
92
|
-
<svg
|
|
93
|
-
viewBox={`0 0 ${sizePx} ${sizePx}`}
|
|
94
|
-
width={sizePx}
|
|
95
|
-
height={sizePx}
|
|
96
|
-
className={tx('avatar.frame', 'avatar__frame', { variant })}
|
|
97
|
-
>
|
|
98
|
-
<defs>
|
|
99
|
-
<mask id={maskId}>
|
|
100
|
-
{variant === 'circle' ? (
|
|
101
|
-
<circle fill='white' cx='50%' cy='50%' r={r} />
|
|
102
|
-
) : (
|
|
103
|
-
<rect
|
|
104
|
-
fill='white'
|
|
105
|
-
width={2 * r}
|
|
106
|
-
height={2 * r}
|
|
107
|
-
x={ringGap + ringWidth}
|
|
108
|
-
y={ringGap + ringWidth}
|
|
109
|
-
rx={rx}
|
|
110
|
-
/>
|
|
111
|
-
)}
|
|
112
|
-
</mask>
|
|
113
|
-
</defs>
|
|
114
|
-
{variant === 'circle' ? (
|
|
115
|
-
<circle cx='50%' cy='50%' r={r} fill={hue ? `var(--dx-${hue}Fill)` : 'var(--surface-bg)'} />
|
|
116
|
-
) : (
|
|
117
|
-
<rect
|
|
118
|
-
fill={hue ? `var(--dx-${hue}Fill)` : 'var(--surface-bg)'}
|
|
119
|
-
x={ringGap + ringWidth}
|
|
120
|
-
y={ringGap + ringWidth}
|
|
121
|
-
width={2 * r}
|
|
122
|
-
height={2 * r}
|
|
123
|
-
rx={rx}
|
|
124
|
-
/>
|
|
125
|
-
)}
|
|
126
|
-
{children}
|
|
127
|
-
{/* {variant === 'circle' ? (
|
|
128
|
-
<circle
|
|
129
|
-
className='avatarFrameStroke fill-transparent stroke-[var(--surface-text)]'
|
|
130
|
-
strokeWidth={strokeWidth}
|
|
131
|
-
fill='none'
|
|
132
|
-
opacity={0.1}
|
|
133
|
-
cx={'50%'}
|
|
134
|
-
cy={'50%'}
|
|
135
|
-
r={r - 0.5 * strokeWidth}
|
|
136
|
-
/>
|
|
137
|
-
) : (
|
|
138
|
-
<rect
|
|
139
|
-
className='avatarFrameStroke fill-transparent stroke-[var(--surface-text)]'
|
|
140
|
-
strokeWidth={strokeWidth}
|
|
141
|
-
opacity={0.1}
|
|
142
|
-
fill='none'
|
|
143
|
-
x={ringGap + ringWidth}
|
|
144
|
-
y={ringGap + ringWidth}
|
|
145
|
-
width={2 * r}
|
|
146
|
-
height={2 * r}
|
|
147
|
-
rx={rx}
|
|
148
|
-
/>
|
|
149
|
-
)} */}
|
|
150
|
-
</svg>
|
|
151
|
-
<span
|
|
152
|
-
role='none'
|
|
153
|
-
className={tx('avatar.ring', 'avatar__ring', { size, variant, status, animation })}
|
|
154
|
-
style={{ borderWidth: ringWidth + 'px' }}
|
|
155
|
-
/>
|
|
156
|
-
</AvatarRootPrimitive>
|
|
157
|
-
);
|
|
158
|
-
},
|
|
159
|
-
);
|
|
44
|
+
const AvatarContent = ({ icon, classNames, ...props }: AvatarContentProps) => {
|
|
45
|
+
const href = useIconHref(icon);
|
|
46
|
+
const { labelId, descriptionId } = useAvatarContext('AvatarContent');
|
|
47
|
+
return (
|
|
48
|
+
<DxAvatar
|
|
49
|
+
{...props}
|
|
50
|
+
icon={href}
|
|
51
|
+
labelId={labelId}
|
|
52
|
+
aria-describedby={descriptionId}
|
|
53
|
+
rootClassName={mx(classNames)}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
160
57
|
|
|
161
58
|
type AvatarLabelProps = ThemedClassName<Omit<ComponentPropsWithRef<typeof Primitive.span>, 'id'>> & {
|
|
162
59
|
asChild?: boolean;
|
|
@@ -200,103 +97,9 @@ const AvatarDescription = forwardRef<HTMLSpanElement, AvatarDescriptionProps>(
|
|
|
200
97
|
},
|
|
201
98
|
);
|
|
202
99
|
|
|
203
|
-
type AvatarMaskedImageProps = ComponentPropsWithRef<'image'>;
|
|
204
|
-
|
|
205
|
-
const AvatarMaskedImage = forwardRef<SVGImageElement, AvatarMaskedImageProps>((props, forwardedRef) => {
|
|
206
|
-
const { maskId } = useAvatarContext('AvatarFallback');
|
|
207
|
-
return (
|
|
208
|
-
<image
|
|
209
|
-
width='100%'
|
|
210
|
-
height='100%'
|
|
211
|
-
{...props}
|
|
212
|
-
mask={`url(#${maskId})`}
|
|
213
|
-
ref={forwardedRef}
|
|
214
|
-
preserveAspectRatio='xMidYMid slice'
|
|
215
|
-
/>
|
|
216
|
-
);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
type AvatarMaskedTextProps = PropsWithChildren<{ large?: boolean }>;
|
|
220
|
-
|
|
221
|
-
const AvatarMaskedText = (props: AvatarMaskedTextProps) => {
|
|
222
|
-
const { maskId, size } = useAvatarContext('AvatarFallback');
|
|
223
|
-
const { large } = props;
|
|
224
|
-
const fontScale = (large ? 4 : 3) * (1 / 1.612);
|
|
225
|
-
const { tx } = useThemeContext();
|
|
226
|
-
return (
|
|
227
|
-
<text
|
|
228
|
-
x='50%'
|
|
229
|
-
y='50%'
|
|
230
|
-
className={tx('avatar.fallbackText', 'avatar__fallback-text')}
|
|
231
|
-
textAnchor='middle'
|
|
232
|
-
alignmentBaseline='central'
|
|
233
|
-
fontSize={size === 'px' ? '200%' : size * fontScale}
|
|
234
|
-
mask={`url(#${maskId})`}
|
|
235
|
-
>
|
|
236
|
-
{props.children}
|
|
237
|
-
</text>
|
|
238
|
-
);
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
type AvatarImageProps = ComponentPropsWithRef<'image'> & Pick<AvatarImagePrimitiveProps, 'onLoadingStatusChange'>;
|
|
242
|
-
|
|
243
|
-
const AvatarImage = forwardRef<SVGImageElement, AvatarImageProps>(
|
|
244
|
-
({ onLoadingStatusChange, ...props }, forwardedRef) => {
|
|
245
|
-
const { size } = useAvatarContext('AvatarImage');
|
|
246
|
-
const pxSize = size === 'px' ? 1 : size * 4;
|
|
247
|
-
if (pxSize <= 20) {
|
|
248
|
-
return null;
|
|
249
|
-
}
|
|
250
|
-
return (
|
|
251
|
-
<AvatarFallbackPrimitive asChild>
|
|
252
|
-
<AvatarMaskedImage {...props} ref={forwardedRef} />
|
|
253
|
-
</AvatarFallbackPrimitive>
|
|
254
|
-
);
|
|
255
|
-
},
|
|
256
|
-
);
|
|
257
|
-
|
|
258
|
-
type AvatarIconProps = {
|
|
259
|
-
icon: string;
|
|
260
|
-
} & Pick<AvatarImagePrimitiveProps, 'onLoadingStatusChange'>;
|
|
261
|
-
|
|
262
|
-
const AvatarIcon = forwardRef<SVGSVGElement, AvatarIconProps>(({ onLoadingStatusChange, ...props }, forwardedRef) => {
|
|
263
|
-
const { size } = useAvatarContext('AvatarIcon');
|
|
264
|
-
const pxSize = size === 'px' ? 1 : size * 4;
|
|
265
|
-
if (pxSize <= 20) {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
return (
|
|
269
|
-
<AvatarFallbackPrimitive asChild>
|
|
270
|
-
<Icon {...props} ref={forwardedRef} />
|
|
271
|
-
</AvatarFallbackPrimitive>
|
|
272
|
-
);
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
type AvatarFallbackProps = ComponentPropsWithRef<'image'> & {
|
|
276
|
-
delayMs?: number;
|
|
277
|
-
text?: string;
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
const AvatarFallback = forwardRef<SVGImageElement, AvatarFallbackProps>(({ delayMs, text, ...props }, forwardedRef) => {
|
|
281
|
-
const isTextOnly = Boolean(text && /[0-9a-zA-Z]+/.test(text));
|
|
282
|
-
const { size } = useAvatarContext('AvatarFallback');
|
|
283
|
-
const numericSize = size === 'px' ? 1 : Number(size);
|
|
284
|
-
return (
|
|
285
|
-
<AvatarFallbackPrimitive delayMs={delayMs} asChild>
|
|
286
|
-
<>
|
|
287
|
-
{numericSize >= 6 && <AvatarMaskedImage {...props} ref={forwardedRef} />}
|
|
288
|
-
{text && <AvatarMaskedText large={!isTextOnly}>{text.toLocaleUpperCase()}</AvatarMaskedText>}
|
|
289
|
-
</>
|
|
290
|
-
</AvatarFallbackPrimitive>
|
|
291
|
-
);
|
|
292
|
-
});
|
|
293
|
-
|
|
294
100
|
export const Avatar = {
|
|
295
101
|
Root: AvatarRoot,
|
|
296
|
-
|
|
297
|
-
Image: AvatarImage,
|
|
298
|
-
Icon: AvatarIcon,
|
|
299
|
-
Fallback: AvatarFallback,
|
|
102
|
+
Content: AvatarContent,
|
|
300
103
|
Label: AvatarLabel,
|
|
301
104
|
Description: AvatarDescription,
|
|
302
105
|
};
|
|
@@ -307,9 +110,7 @@ export type {
|
|
|
307
110
|
AvatarStatus,
|
|
308
111
|
AvatarVariant,
|
|
309
112
|
AvatarAnimation,
|
|
310
|
-
|
|
311
|
-
AvatarImageProps,
|
|
312
|
-
AvatarFallbackProps,
|
|
113
|
+
AvatarContentProps,
|
|
313
114
|
AvatarLabelProps,
|
|
314
115
|
AvatarDescriptionProps,
|
|
315
116
|
};
|
|
@@ -3,49 +3,42 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
|
-
|
|
7
6
|
import React from 'react';
|
|
8
7
|
|
|
8
|
+
import { useId } from '@dxos/react-hooks';
|
|
9
9
|
import { toEmoji } from '@dxos/util';
|
|
10
10
|
|
|
11
11
|
import { Avatar } from './Avatar';
|
|
12
|
-
import { AvatarGroup, AvatarGroupItem } from './AvatarGroup';
|
|
13
12
|
import { withTheme } from '../../testing';
|
|
14
13
|
|
|
15
|
-
const
|
|
16
|
-
'[&_.avatarFrameFill]:fill-lime-500',
|
|
17
|
-
'[&_.avatarFrameFill]:fill-teal-500',
|
|
18
|
-
'[&_.avatarFrameFill]:fill-purple-500',
|
|
19
|
-
'[&_.avatarFrameFill]:fill-pink-500',
|
|
20
|
-
];
|
|
14
|
+
const hues = ['lime', 'teal', 'purple', 'pink'];
|
|
21
15
|
|
|
22
16
|
const StorybookAvatarGroupItem = ({ n }: { n: number }) => {
|
|
23
17
|
const emoji = toEmoji(n);
|
|
24
18
|
return (
|
|
25
|
-
<
|
|
26
|
-
<Avatar.
|
|
27
|
-
|
|
28
|
-
</Avatar.Frame>
|
|
29
|
-
</AvatarGroupItem.Root>
|
|
19
|
+
<Avatar.Root>
|
|
20
|
+
<Avatar.Content fallback={emoji} hue={hues[n]} size={8} variant='circle' />
|
|
21
|
+
</Avatar.Root>
|
|
30
22
|
);
|
|
31
23
|
};
|
|
32
24
|
|
|
33
25
|
const StorybookAvatarGroup = () => {
|
|
26
|
+
const labelId = useId('sb-avatar-group');
|
|
34
27
|
return (
|
|
35
|
-
<
|
|
28
|
+
<div className='dx-avatar-group' aria-labelledby={labelId}>
|
|
36
29
|
{[0, 1, 2, 3].map((n) => (
|
|
37
30
|
<StorybookAvatarGroupItem key={n} n={n} />
|
|
38
31
|
))}
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
</
|
|
42
|
-
</
|
|
32
|
+
<span className='sr-only' id={labelId}>
|
|
33
|
+
23
|
|
34
|
+
</span>
|
|
35
|
+
</div>
|
|
43
36
|
);
|
|
44
37
|
};
|
|
45
38
|
|
|
46
39
|
export default {
|
|
47
40
|
title: 'ui/react-ui-core/AvatarGroup',
|
|
48
|
-
component:
|
|
41
|
+
component: StorybookAvatarGroup,
|
|
49
42
|
render: StorybookAvatarGroup,
|
|
50
43
|
decorators: [withTheme],
|
|
51
44
|
parameters: { chromatic: { disableSnapshot: false } },
|
|
@@ -7,11 +7,9 @@ import React, { type ComponentPropsWithRef, forwardRef, memo } from 'react';
|
|
|
7
7
|
|
|
8
8
|
import { type Size } from '@dxos/react-ui-types';
|
|
9
9
|
|
|
10
|
-
import { useThemeContext } from '../../hooks';
|
|
10
|
+
import { useIconHref, useThemeContext } from '../../hooks';
|
|
11
11
|
import { type ThemedClassName } from '../../util';
|
|
12
12
|
|
|
13
|
-
const ICONS_URL = '/icons.svg';
|
|
14
|
-
|
|
15
13
|
export type IconProps = ThemedClassName<ComponentPropsWithRef<typeof Primitive.svg>> & {
|
|
16
14
|
icon: string;
|
|
17
15
|
size?: Size;
|
|
@@ -19,11 +17,11 @@ export type IconProps = ThemedClassName<ComponentPropsWithRef<typeof Primitive.s
|
|
|
19
17
|
|
|
20
18
|
export const Icon = memo(
|
|
21
19
|
forwardRef<SVGSVGElement, IconProps>(({ icon, classNames, size, ...props }, forwardedRef) => {
|
|
22
|
-
const { tx
|
|
23
|
-
const
|
|
20
|
+
const { tx } = useThemeContext();
|
|
21
|
+
const href = useIconHref(icon);
|
|
24
22
|
return (
|
|
25
23
|
<svg {...props} className={tx('icon.root', 'icon', { size }, classNames)} ref={forwardedRef}>
|
|
26
|
-
<use href={
|
|
24
|
+
<use href={href} />
|
|
27
25
|
</svg>
|
|
28
26
|
);
|
|
29
27
|
}),
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
Validation as ValidationPrimitive,
|
|
29
29
|
type ValidationProps as ValidationPrimitiveProps,
|
|
30
30
|
} from '@dxos/react-input';
|
|
31
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
31
32
|
import { type Density, type Elevation, type ClassNameValue, type Size } from '@dxos/react-ui-types';
|
|
32
33
|
|
|
33
34
|
import { useDensityContext, useElevationContext, useThemeContext } from '../../hooks';
|
|
@@ -307,7 +308,7 @@ const Switch = forwardRef<HTMLInputElement, InputScopedProps<SwitchProps>>(
|
|
|
307
308
|
return (
|
|
308
309
|
<input
|
|
309
310
|
type='checkbox'
|
|
310
|
-
className='dx-checkbox--switch dx-focus-ring'
|
|
311
|
+
className={mx('dx-checkbox--switch dx-focus-ring', classNames)}
|
|
311
312
|
checked={checked}
|
|
312
313
|
onChange={(event) => {
|
|
313
314
|
onCheckedChange(event.target.checked);
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useThemeContext } from './useThemeContext';
|
|
6
|
+
|
|
7
|
+
const ICONS_URL = '/icons.svg';
|
|
8
|
+
|
|
9
|
+
export const useIconHref = (icon?: string) => {
|
|
10
|
+
const { noCache } = useThemeContext();
|
|
11
|
+
const url = noCache ? `${ICONS_URL}?nocache=${new Date().getMinutes()}` : ICONS_URL;
|
|
12
|
+
return icon ? `${url}#${icon}` : undefined;
|
|
13
|
+
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import React, { type ComponentPropsWithRef } from 'react';
|
|
2
|
-
import { type AvatarRootProps } from './Avatar';
|
|
3
|
-
import { type ThemedClassName } from '../../util';
|
|
4
|
-
type AvatarGroupRootProps = Omit<AvatarRootProps, 'status' | 'maskId' | 'inGroup'> & ThemedClassName<ComponentPropsWithRef<'div'>>;
|
|
5
|
-
type AvatarGroupItemRootProps = Omit<AvatarRootProps, 'labelId' | 'descriptionId' | 'inGroup'>;
|
|
6
|
-
type AvatarGroupLabelProps = ThemedClassName<Omit<ComponentPropsWithRef<'span'>, 'id'>> & {
|
|
7
|
-
srOnly?: boolean;
|
|
8
|
-
};
|
|
9
|
-
type AvatarGroupDescriptionProps = ThemedClassName<Omit<ComponentPropsWithRef<'span'>, 'id'>> & {
|
|
10
|
-
srOnly?: boolean;
|
|
11
|
-
};
|
|
12
|
-
export declare const AvatarGroup: {
|
|
13
|
-
Root: React.ForwardRefExoticComponent<Omit<AvatarGroupRootProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
14
|
-
Label: React.ForwardRefExoticComponent<Omit<AvatarGroupLabelProps, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
15
|
-
Description: React.ForwardRefExoticComponent<Omit<AvatarGroupDescriptionProps, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
16
|
-
};
|
|
17
|
-
export declare const AvatarGroupItem: {
|
|
18
|
-
Root: ({ maskId, size, variant, status, children, ...rest }: AvatarGroupItemRootProps) => React.JSX.Element;
|
|
19
|
-
};
|
|
20
|
-
export type { AvatarGroupRootProps, AvatarGroupItemRootProps, AvatarGroupLabelProps, AvatarGroupDescriptionProps };
|
|
21
|
-
//# sourceMappingURL=AvatarGroup.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AvatarGroup.d.ts","sourceRoot":"","sources":["../../../../../src/components/Avatars/AvatarGroup.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,KAAK,qBAAqB,EAAc,MAAM,OAAO,CAAC;AAItE,OAAO,EAAU,KAAK,eAAe,EAAoB,MAAM,UAAU,CAAC;AAE1E,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,KAAK,oBAAoB,GAAG,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC,GAChF,eAAe,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC;AAiChD,KAAK,wBAAwB,GAAG,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,eAAe,GAAG,SAAS,CAAC,CAAC;AA2B/F,KAAK,qBAAqB,GAAG,eAAe,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAkB/G,KAAK,2BAA2B,GAAG,eAAe,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAkBrH,eAAO,MAAM,WAAW;;;;CAA0F,CAAC;AACnH,eAAO,MAAM,eAAe;iEA9DuD,wBAAwB;CA8D/C,CAAC;AAC7D,YAAY,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,CAAC"}
|