@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.
Files changed (35) hide show
  1. package/dist/lib/browser/index.mjs +425 -612
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +115 -301
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +425 -612
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/Avatars/Avatar.d.ts +8 -29
  11. package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
  12. package/dist/types/src/components/Avatars/Avatar.stories.d.ts +5 -11
  13. package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
  14. package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts +1 -5
  15. package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/Avatars/index.d.ts +0 -1
  17. package/dist/types/src/components/Avatars/index.d.ts.map +1 -1
  18. package/dist/types/src/components/Icon/Icon.d.ts.map +1 -1
  19. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  20. package/dist/types/src/hooks/index.d.ts +1 -0
  21. package/dist/types/src/hooks/index.d.ts.map +1 -1
  22. package/dist/types/src/hooks/useIconHref.d.ts +2 -0
  23. package/dist/types/src/hooks/useIconHref.d.ts.map +1 -0
  24. package/package.json +14 -12
  25. package/src/components/Avatars/Avatar.stories.tsx +7 -8
  26. package/src/components/Avatars/Avatar.tsx +30 -229
  27. package/src/components/Avatars/AvatarGroup.stories.tsx +12 -19
  28. package/src/components/Avatars/index.ts +0 -1
  29. package/src/components/Icon/Icon.tsx +4 -6
  30. package/src/components/Input/Input.tsx +2 -1
  31. package/src/hooks/index.ts +1 -0
  32. package/src/hooks/useIconHref.ts +13 -0
  33. package/dist/types/src/components/Avatars/AvatarGroup.d.ts +0 -21
  34. package/dist/types/src/components/Avatars/AvatarGroup.d.ts.map +0 -1
  35. package/src/components/Avatars/AvatarGroup.tsx +0 -112
@@ -0,0 +1,2 @@
1
+ export declare const useIconHref: (icon?: string) => string | undefined;
2
+ //# sourceMappingURL=useIconHref.d.ts.map
@@ -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.391c573",
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.391c573",
65
- "@dxos/log": "0.8.1-staging.391c573",
66
- "@dxos/react-hooks": "0.8.1-staging.391c573",
67
- "@dxos/react-list": "0.8.1-staging.391c573",
68
- "@dxos/react-input": "0.8.1-staging.391c573",
69
- "@dxos/react-ui-types": "0.8.1-staging.391c573",
70
- "@dxos/util": "0.8.1-staging.391c573"
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.391c573",
83
- "@dxos/react-ui-theme": "0.8.1-staging.391c573",
84
- "@dxos/util": "0.8.1-staging.391c573"
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.391c573"
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, type AvatarRootProps } from './Avatar';
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?: AvatarRootProps['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 {...{ size, variant, status, animation, hue: props.hue || hue }}>
44
- <Avatar.Frame>
45
- {!imgSrc && (fallbackText || emoji) && <Avatar.Fallback text={fallbackText || emoji} />}
46
- {imgSrc && <Avatar.Image href={imgSrc} />}
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
- Root as AvatarRootPrimitive,
7
- type AvatarProps as AvatarRootPrimitiveProps,
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 { type Size } from '@dxos/react-ui-types';
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
- const maskId = useId('avatar__mask', propsMaskId);
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
- type AvatarFrameProps = ThemedClassName<AvatarRootPrimitiveProps>;
67
-
68
- const rx = '0.25rem';
36
+ const DxAvatar = createComponent({
37
+ tagName: 'dx-avatar',
38
+ elementClass: NaturalDxAvatar,
39
+ react: React,
40
+ });
69
41
 
70
- const AvatarFrame = forwardRef<HTMLSpanElement, AvatarFrameProps>(
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
- const { tx } = useThemeContext();
76
- const numericSize = size === 'px' ? 1 : Number(size);
77
- const sizePx = numericSize * 4;
78
- const ringWidth = status ? (numericSize > 4 ? 2 : numericSize > 3 ? 1 : 1) : 0;
79
- const ringGap = status ? (numericSize > 12 ? 3 : numericSize > 4 ? 2 : numericSize > 3 ? 1 : 0) : 0;
80
- const r = sizePx / 2 - ringGap - ringWidth;
81
- return (
82
- <AvatarRootPrimitive
83
- role='img'
84
- {...props}
85
- className={tx('avatar.root', 'avatar', { size, variant, inGroup }, classNames)}
86
- ref={forwardedRef}
87
- {...(!inGroup && {
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
- Frame: AvatarFrame,
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
- AvatarFrameProps,
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 items = [
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
- <AvatarGroupItem.Root>
26
- <Avatar.Frame classNames={items[n]}>
27
- <Avatar.Fallback text={emoji} />
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
- <AvatarGroup.Root size={8} variant='circle'>
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
- <AvatarGroup.Label srOnly>
40
- <span>23</span>
41
- </AvatarGroup.Label>
42
- </AvatarGroup.Root>
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: AvatarGroup,
41
+ component: StorybookAvatarGroup,
49
42
  render: StorybookAvatarGroup,
50
43
  decorators: [withTheme],
51
44
  parameters: { chromatic: { disableSnapshot: false } },
@@ -3,4 +3,3 @@
3
3
  //
4
4
 
5
5
  export * from './Avatar';
6
- export * from './AvatarGroup';
@@ -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, noCache } = useThemeContext();
23
- const url = noCache ? `${ICONS_URL}?nocache=${new Date().getMinutes()}` : ICONS_URL;
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={`${url}#${icon}`} />
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);
@@ -4,6 +4,7 @@
4
4
 
5
5
  export * from './useDensityContext';
6
6
  export * from './useElevationContext';
7
+ export * from './useIconHref';
7
8
  export * from './useSafeArea';
8
9
  export * from './useTranslationsContext';
9
10
  export * from './useThemeContext';
@@ -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"}