@dxos/react-ui 0.1.32-next.86f5578 → 0.1.33
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 +629 -534
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts +9 -0
- package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts.map +1 -0
- package/dist/types/src/components/Clipboard/CopyButton.d.ts +5 -0
- package/dist/types/src/components/Clipboard/CopyButton.d.ts.map +1 -0
- package/dist/types/src/components/Clipboard/index.d.ts +3 -0
- package/dist/types/src/components/Clipboard/index.d.ts.map +1 -0
- package/dist/types/src/components/InvitationEmoji/InvitationEmoji.d.ts +7 -0
- package/dist/types/src/components/InvitationEmoji/InvitationEmoji.d.ts.map +1 -0
- package/dist/types/src/components/InvitationEmoji/index.d.ts +2 -0
- package/dist/types/src/components/InvitationEmoji/index.d.ts.map +1 -0
- package/dist/types/src/components/InvitationList/InvitationList.d.ts.map +1 -1
- package/dist/types/src/components/InvitationList/InvitationListItem.d.ts.map +1 -1
- package/dist/types/src/components/InvitationList/InvitationStatusAvatar.d.ts +2 -1
- package/dist/types/src/components/InvitationList/InvitationStatusAvatar.d.ts.map +1 -1
- package/dist/types/src/components/InvitationList/InvitationStatusAvatar.stories.d.ts +1 -1
- package/dist/types/src/components/index.d.ts +2 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/composites/DevicesDialog/DevicesDialog.d.ts.map +1 -1
- package/dist/types/src/composites/JoinDialog/JoinDialog.d.ts.map +1 -1
- package/dist/types/src/composites/SpaceDialog/SpaceDialog.d.ts.map +1 -1
- package/dist/types/src/panels/IdentityPanel/IdentityPanel.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/JoinHeading.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/JoinPanel.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts.map +1 -1
- package/dist/types/src/translations/locales/en-US.d.ts +1 -0
- package/dist/types/src/translations/locales/en-US.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/components/Clipboard/ClipboardProvider.tsx +26 -0
- package/src/components/Clipboard/CopyButton.tsx +38 -0
- package/src/components/Clipboard/index.ts +6 -0
- package/src/components/InvitationEmoji/InvitationEmoji.tsx +32 -0
- package/src/components/InvitationEmoji/index.ts +5 -0
- package/src/components/InvitationList/InvitationList.tsx +7 -4
- package/src/components/InvitationList/InvitationListItem.tsx +6 -11
- package/src/components/InvitationList/InvitationStatusAvatar.tsx +37 -26
- package/src/components/index.ts +2 -0
- package/src/composites/DevicesDialog/DevicesDialog.tsx +3 -2
- package/src/composites/JoinDialog/JoinDialog.tsx +4 -2
- package/src/composites/SpaceDialog/SpaceDialog.tsx +3 -2
- package/src/panels/IdentityPanel/IdentityPanel.tsx +4 -2
- package/src/panels/JoinPanel/JoinHeading.tsx +3 -12
- package/src/panels/JoinPanel/JoinPanel.tsx +4 -3
- package/src/panels/JoinPanel/view-states/InvitationAuthenticator.tsx +1 -0
- package/src/translations/locales/en-US.ts +1 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { createContext, PropsWithChildren, useCallback, useContext, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
export type ClipboardContextValue = {
|
|
8
|
+
textValue: string;
|
|
9
|
+
setTextValue: (nextValue: string) => Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const ClipboardContext = createContext<ClipboardContextValue>({
|
|
13
|
+
textValue: '',
|
|
14
|
+
setTextValue: async (_) => {}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const useClipboardContext = () => useContext(ClipboardContext);
|
|
18
|
+
|
|
19
|
+
export const ClipboardProvider = ({ children }: PropsWithChildren<{}>) => {
|
|
20
|
+
const [textValue, setInternalTextValue] = useState('');
|
|
21
|
+
const setTextValue = useCallback(async (nextValue: string) => {
|
|
22
|
+
await navigator.clipboard.writeText(nextValue);
|
|
23
|
+
return setInternalTextValue(nextValue);
|
|
24
|
+
}, []);
|
|
25
|
+
return <ClipboardContext.Provider value={{ textValue, setTextValue }}>{children}</ClipboardContext.Provider>;
|
|
26
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Check, Copy } from '@phosphor-icons/react';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { Button, getSize, mx, useTranslation } from '@dxos/react-components';
|
|
9
|
+
|
|
10
|
+
import { useClipboardContext } from './ClipboardProvider';
|
|
11
|
+
|
|
12
|
+
export type CopyButtonProps = {
|
|
13
|
+
value: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const inactiveLabelStyles = 'invisible bs-px -mbe-px';
|
|
17
|
+
|
|
18
|
+
export const CopyButton = ({ value }: CopyButtonProps) => {
|
|
19
|
+
const { t } = useTranslation('os');
|
|
20
|
+
const { textValue, setTextValue } = useClipboardContext();
|
|
21
|
+
const isCopied = textValue === value;
|
|
22
|
+
return (
|
|
23
|
+
<Button
|
|
24
|
+
className='inline-flex flex-col justify-center'
|
|
25
|
+
onClick={() => setTextValue(value)}
|
|
26
|
+
data-testid='copy-invitation'
|
|
27
|
+
>
|
|
28
|
+
<div role='none' className={mx('flex gap-1', isCopied && inactiveLabelStyles)}>
|
|
29
|
+
<span className='pli-1'>{t('copy invitation code label')}</span>
|
|
30
|
+
<Copy className={getSize(4)} weight='bold' />
|
|
31
|
+
</div>
|
|
32
|
+
<div role='none' className={mx('flex gap-1', !isCopied && inactiveLabelStyles)}>
|
|
33
|
+
<span className='pli-1'>{t('copy invitation code success label')}</span>
|
|
34
|
+
<Check className={getSize(4)} weight='bold' />
|
|
35
|
+
</div>
|
|
36
|
+
</Button>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { ComponentPropsWithoutRef } from 'react';
|
|
6
|
+
|
|
7
|
+
import { getSize, mx } from '@dxos/react-components';
|
|
8
|
+
|
|
9
|
+
import { toEmoji } from '../../util';
|
|
10
|
+
|
|
11
|
+
export type InvitationEmojiProps = {
|
|
12
|
+
invitationId?: string;
|
|
13
|
+
size?: 'lg' | 'sm';
|
|
14
|
+
} & ComponentPropsWithoutRef<'div'>;
|
|
15
|
+
|
|
16
|
+
export const InvitationEmoji = ({ invitationId, size = 'lg', ...rootProps }: InvitationEmojiProps) => {
|
|
17
|
+
const invitationEmoji = invitationId && toEmoji(invitationId);
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
role='none'
|
|
21
|
+
{...rootProps}
|
|
22
|
+
className={mx(
|
|
23
|
+
getSize(size === 'sm' ? 8 : 12),
|
|
24
|
+
'inline-flex items-center justify-center leading-none',
|
|
25
|
+
size === 'sm' ? 'text-2xl' : 'text-5xl bg-neutral-300 dark:bg-neutral-700 rounded-full',
|
|
26
|
+
rootProps.className
|
|
27
|
+
)}
|
|
28
|
+
>
|
|
29
|
+
<span role='none'>{invitationEmoji}</span>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -7,6 +7,7 @@ import React from 'react';
|
|
|
7
7
|
import type { CancellableInvitationObservable } from '@dxos/client';
|
|
8
8
|
import { defaultDescription, DensityProvider, mx, useTranslation } from '@dxos/react-components';
|
|
9
9
|
|
|
10
|
+
import { ClipboardProvider } from '../Clipboard';
|
|
10
11
|
import { InvitationListItem, InvitationListItemProps } from './InvitationListItem';
|
|
11
12
|
|
|
12
13
|
export interface InvitationListProps extends Omit<InvitationListItemProps, 'invitation' | 'value'> {
|
|
@@ -18,10 +19,12 @@ export const InvitationList = ({ invitations, ...invitationProps }: InvitationLi
|
|
|
18
19
|
return invitations.length ? (
|
|
19
20
|
<AccordionRoot type='single' collapsible className='flex flex-col gap-1'>
|
|
20
21
|
<DensityProvider density='fine'>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
<ClipboardProvider>
|
|
23
|
+
{invitations.map((invitation, index) => {
|
|
24
|
+
const value = invitation.invitation?.invitationId ?? `inv_${index}`;
|
|
25
|
+
return <InvitationListItem key={value} value={value} invitation={invitation} {...invitationProps} />;
|
|
26
|
+
})}
|
|
27
|
+
</ClipboardProvider>
|
|
25
28
|
</DensityProvider>
|
|
26
29
|
</AccordionRoot>
|
|
27
30
|
) : (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
|
-
import {
|
|
4
|
+
import { ProhibitInset, QrCode, X } from '@phosphor-icons/react';
|
|
5
5
|
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
6
6
|
import { QRCodeSVG } from 'qrcode.react';
|
|
7
7
|
import React, { useCallback } from 'react';
|
|
@@ -11,6 +11,7 @@ import { useInvitationStatus } from '@dxos/react-client';
|
|
|
11
11
|
import { Button, getSize, mx, useId, useTranslation } from '@dxos/react-components';
|
|
12
12
|
|
|
13
13
|
import { invitationStatusValue } from '../../util';
|
|
14
|
+
import { CopyButton } from '../Clipboard';
|
|
14
15
|
import { SharedInvitationListProps } from './InvitationListProps';
|
|
15
16
|
import { InvitationStatusAvatar } from './InvitationStatusAvatar';
|
|
16
17
|
|
|
@@ -39,16 +40,13 @@ export const InvitationListItem = ({
|
|
|
39
40
|
const handleClickRemove = useCallback(() => onClickRemove(invitation), [invitation, onClickRemove]);
|
|
40
41
|
|
|
41
42
|
const invitationUrl = invitationCode && createInvitationUrl(invitationCode);
|
|
42
|
-
const handleClickCopy = useCallback(() => {
|
|
43
|
-
if (invitationUrl) {
|
|
44
|
-
void navigator.clipboard.writeText(invitationUrl);
|
|
45
|
-
}
|
|
46
|
-
}, [invitationUrl]);
|
|
47
43
|
|
|
48
44
|
return (
|
|
49
45
|
<AccordionPrimitive.Item value={value}>
|
|
50
46
|
<AccordionPrimitive.Header className='flex gap-2 items-center'>
|
|
51
|
-
<InvitationStatusAvatar
|
|
47
|
+
<InvitationStatusAvatar
|
|
48
|
+
{...{ status, haltedAt, size: 8, invitationId: invitation?.invitation?.invitationId }}
|
|
49
|
+
/>
|
|
52
50
|
{showShare && invitationUrl ? (
|
|
53
51
|
<>
|
|
54
52
|
<AccordionPrimitive.Trigger asChild>
|
|
@@ -57,10 +55,7 @@ export const InvitationListItem = ({
|
|
|
57
55
|
<QrCode className={getSize(4)} weight='bold' />
|
|
58
56
|
</Button>
|
|
59
57
|
</AccordionPrimitive.Trigger>
|
|
60
|
-
<
|
|
61
|
-
<span className='pli-1'>{t('copy invitation code label')}</span>
|
|
62
|
-
<Copy className={getSize(4)} weight='bold' />
|
|
63
|
-
</Button>
|
|
58
|
+
<CopyButton value={invitationUrl} />
|
|
64
59
|
</>
|
|
65
60
|
) : showAuthCode ? (
|
|
66
61
|
<p className='grow text-xl text-center text-success-500 dark:text-success-300 font-mono'>
|
|
@@ -9,6 +9,7 @@ import { getSize, mx, Size } from '@dxos/react-components';
|
|
|
9
9
|
|
|
10
10
|
import { inactiveStrokeColor, activeStrokeColor, resolvedStrokeColor } from '../../styles';
|
|
11
11
|
import { invitationStatusValue } from '../../util';
|
|
12
|
+
import { InvitationEmoji } from '../InvitationEmoji';
|
|
12
13
|
|
|
13
14
|
export interface InvitationStatusAvatarSlots {
|
|
14
15
|
svg?: ComponentPropsWithoutRef<'svg'>;
|
|
@@ -19,6 +20,7 @@ export interface InvitationStatusAvatarProps {
|
|
|
19
20
|
status: Invitation.State;
|
|
20
21
|
haltedAt?: Invitation.State;
|
|
21
22
|
slots?: InvitationStatusAvatarSlots;
|
|
23
|
+
invitationId?: string;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const svgSize = 32;
|
|
@@ -40,41 +42,50 @@ const circleProps: ComponentPropsWithoutRef<'circle'> = {
|
|
|
40
42
|
strokeDasharray: `${segment - gap} ${2 * segment + gap}`
|
|
41
43
|
};
|
|
42
44
|
|
|
43
|
-
export const InvitationStatusAvatar = ({
|
|
45
|
+
export const InvitationStatusAvatar = ({
|
|
46
|
+
size = 10,
|
|
47
|
+
status,
|
|
48
|
+
haltedAt,
|
|
49
|
+
slots = {},
|
|
50
|
+
invitationId
|
|
51
|
+
}: InvitationStatusAvatarProps) => {
|
|
44
52
|
const resolvedColor = resolvedStrokeColor(status);
|
|
45
53
|
const halted =
|
|
46
54
|
status === Invitation.State.CANCELLED || status === Invitation.State.TIMEOUT || status === Invitation.State.ERROR;
|
|
47
55
|
const cursor = invitationStatusValue.get(halted ? haltedAt! : status)!;
|
|
48
56
|
return (
|
|
49
|
-
<
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
index
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
<div className='inline-block relative'>
|
|
58
|
+
<InvitationEmoji {...{ invitationId }} size='sm' className='absolute inset-0 text-base' />
|
|
59
|
+
<svg {...slots.svg} viewBox={`0 0 ${svgSize} ${svgSize}`} className={mx(getSize(size), slots.svg?.className)}>
|
|
60
|
+
{[...Array(nSegments)].map((_, index) => (
|
|
61
|
+
<circle
|
|
62
|
+
key={index}
|
|
63
|
+
{...circleProps}
|
|
64
|
+
strokeDashoffset={index * segment + baseOffset}
|
|
65
|
+
className={
|
|
66
|
+
index === 0
|
|
67
|
+
? cursor === 1
|
|
68
|
+
? halted
|
|
69
|
+
? resolvedColor
|
|
70
|
+
: activeStrokeColor
|
|
71
|
+
: cursor > 1
|
|
59
72
|
? resolvedColor
|
|
60
|
-
:
|
|
61
|
-
:
|
|
62
|
-
?
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
: inactiveStrokeColor
|
|
74
|
+
: index === 1
|
|
75
|
+
? cursor === 3
|
|
76
|
+
? halted
|
|
77
|
+
? resolvedColor
|
|
78
|
+
: activeStrokeColor
|
|
79
|
+
: cursor > 3
|
|
67
80
|
? resolvedColor
|
|
68
|
-
:
|
|
81
|
+
: inactiveStrokeColor
|
|
69
82
|
: cursor > 3
|
|
70
83
|
? resolvedColor
|
|
71
84
|
: inactiveStrokeColor
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
))}
|
|
78
|
-
</svg>
|
|
85
|
+
}
|
|
86
|
+
/>
|
|
87
|
+
))}
|
|
88
|
+
</svg>
|
|
89
|
+
</div>
|
|
79
90
|
);
|
|
80
91
|
};
|
package/src/components/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Close } from '@radix-ui/react-dialog';
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
|
-
import { ThemeContext, useId } from '@dxos/react-components';
|
|
8
|
+
import { ThemeContext, useId, useThemeContext } from '@dxos/react-components';
|
|
9
9
|
|
|
10
10
|
import { PanelDialog, PanelDialogProps } from '../../layouts';
|
|
11
11
|
import { DevicesPanel, DevicesPanelProps } from '../../panels';
|
|
@@ -16,6 +16,7 @@ export interface DevicesDialogProps
|
|
|
16
16
|
|
|
17
17
|
export const DevicesDialog = ({ slots, ...devicesDialogProps }: DevicesDialogProps) => {
|
|
18
18
|
const titleId = useId('spaceDialog__title');
|
|
19
|
+
const themeContextValue = useThemeContext();
|
|
19
20
|
|
|
20
21
|
return (
|
|
21
22
|
<PanelDialog
|
|
@@ -24,7 +25,7 @@ export const DevicesDialog = ({ slots, ...devicesDialogProps }: DevicesDialogPro
|
|
|
24
25
|
titleId
|
|
25
26
|
}}
|
|
26
27
|
>
|
|
27
|
-
<ThemeContext.Provider value={{ themeVariant: 'os' }}>
|
|
28
|
+
<ThemeContext.Provider value={{ ...themeContextValue, themeVariant: 'os' }}>
|
|
28
29
|
<DevicesPanel
|
|
29
30
|
{...{
|
|
30
31
|
...devicesDialogProps,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Action, Cancel } from '@radix-ui/react-alert-dialog';
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
|
-
import { ThemeContext, useId } from '@dxos/react-components';
|
|
8
|
+
import { ThemeContext, useId, useThemeContext } from '@dxos/react-components';
|
|
9
9
|
|
|
10
10
|
import { PanelAlertDialog, PanelAlertDialogProps } from '../../layouts';
|
|
11
11
|
import { JoinPanel, JoinPanelProps } from '../../panels';
|
|
@@ -16,9 +16,11 @@ export interface JoinDialogProps
|
|
|
16
16
|
|
|
17
17
|
export const JoinDialog = ({ slots, ...joinPanelProps }: JoinDialogProps) => {
|
|
18
18
|
const titleId = useId('joinDialog__title');
|
|
19
|
+
const themeContextValue = useThemeContext();
|
|
20
|
+
|
|
19
21
|
return (
|
|
20
22
|
<PanelAlertDialog {...{ slots, titleId }}>
|
|
21
|
-
<ThemeContext.Provider value={{ themeVariant: 'os' }}>
|
|
23
|
+
<ThemeContext.Provider value={{ ...themeContextValue, themeVariant: 'os' }}>
|
|
22
24
|
<JoinPanel
|
|
23
25
|
{...{
|
|
24
26
|
...joinPanelProps,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Close } from '@radix-ui/react-dialog';
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
|
-
import { ThemeContext, useId } from '@dxos/react-components';
|
|
8
|
+
import { ThemeContext, useId, useThemeContext } from '@dxos/react-components';
|
|
9
9
|
|
|
10
10
|
import { PanelDialog, PanelDialogProps } from '../../layouts';
|
|
11
11
|
import { SpacePanel, SpacePanelProps } from '../../panels';
|
|
@@ -16,6 +16,7 @@ export interface SpaceDialogProps
|
|
|
16
16
|
|
|
17
17
|
export const SpaceDialog = ({ slots, ...spacePanelProps }: SpaceDialogProps) => {
|
|
18
18
|
const titleId = useId('spaceDialog__title');
|
|
19
|
+
const themeContextValue = useThemeContext();
|
|
19
20
|
|
|
20
21
|
return (
|
|
21
22
|
<PanelDialog
|
|
@@ -24,7 +25,7 @@ export const SpaceDialog = ({ slots, ...spacePanelProps }: SpaceDialogProps) =>
|
|
|
24
25
|
titleId
|
|
25
26
|
}}
|
|
26
27
|
>
|
|
27
|
-
<ThemeContext.Provider value={{ themeVariant: 'os' }}>
|
|
28
|
+
<ThemeContext.Provider value={{ ...themeContextValue, themeVariant: 'os' }}>
|
|
28
29
|
<SpacePanel
|
|
29
30
|
{...{
|
|
30
31
|
...spacePanelProps,
|
|
@@ -5,7 +5,7 @@ import React from 'react';
|
|
|
5
5
|
|
|
6
6
|
import type { Identity } from '@dxos/client';
|
|
7
7
|
import { useClient } from '@dxos/react-client';
|
|
8
|
-
import { Avatar, Button, DensityProvider, ThemeContext, useTranslation } from '@dxos/react-components';
|
|
8
|
+
import { Avatar, Button, DensityProvider, ThemeContext, useThemeContext, useTranslation } from '@dxos/react-components';
|
|
9
9
|
|
|
10
10
|
export const IdentityPanel = ({
|
|
11
11
|
identity,
|
|
@@ -16,13 +16,15 @@ export const IdentityPanel = ({
|
|
|
16
16
|
}) => {
|
|
17
17
|
const { t } = useTranslation('os');
|
|
18
18
|
const client = useClient();
|
|
19
|
+
const themeContextValue = useThemeContext();
|
|
20
|
+
|
|
19
21
|
const defaultManageProfile = () => {
|
|
20
22
|
const remoteSource = new URL(client?.config.get('runtime.client.remoteSource') || 'https://halo.dxos.org');
|
|
21
23
|
const tab = window.open(remoteSource.origin, '_blank');
|
|
22
24
|
tab?.focus();
|
|
23
25
|
};
|
|
24
26
|
return (
|
|
25
|
-
<ThemeContext.Provider value={{ themeVariant: 'os' }}>
|
|
27
|
+
<ThemeContext.Provider value={{ ...themeContextValue, themeVariant: 'os' }}>
|
|
26
28
|
<DensityProvider density='fine'>
|
|
27
29
|
<div className='flex flex-col gap-2 justify-center items-center'>
|
|
28
30
|
<Avatar
|
|
@@ -7,8 +7,8 @@ import React, { cloneElement, ForwardedRef, forwardRef } from 'react';
|
|
|
7
7
|
import { useSpace } from '@dxos/react-client';
|
|
8
8
|
import { Button, defaultDescription, getSize, Heading, mx, useId, useTranslation } from '@dxos/react-components';
|
|
9
9
|
|
|
10
|
+
import { InvitationEmoji } from '../../components';
|
|
10
11
|
import { defaultSurface } from '../../styles';
|
|
11
|
-
import { toEmoji } from '../../util';
|
|
12
12
|
import { JoinPanelMode } from './JoinPanelProps';
|
|
13
13
|
import { JoinState } from './joinMachine';
|
|
14
14
|
|
|
@@ -33,8 +33,7 @@ export const JoinHeading = forwardRef(
|
|
|
33
33
|
const name = space?.properties.name;
|
|
34
34
|
const nameId = useId(mode === 'halo-only' ? 'identityDisplayName' : 'spaceDisplayName');
|
|
35
35
|
|
|
36
|
-
const
|
|
37
|
-
const invitationEmoji = invitationKey && toEmoji(invitationKey);
|
|
36
|
+
const invitationId = joinState?.context[mode === 'halo-only' ? 'halo' : 'space'].invitation?.invitationId;
|
|
38
37
|
|
|
39
38
|
const exitButton = (
|
|
40
39
|
<Button
|
|
@@ -65,15 +64,7 @@ export const JoinHeading = forwardRef(
|
|
|
65
64
|
{t(mode === 'halo-only' ? 'selecting identity heading' : 'joining space heading')}
|
|
66
65
|
</Heading>
|
|
67
66
|
<div role='group' className='flex items-center justify-center gap-2'>
|
|
68
|
-
<
|
|
69
|
-
role='none'
|
|
70
|
-
className={mx(
|
|
71
|
-
getSize(12),
|
|
72
|
-
'bg-neutral-300 dark:bg-neutral-700 rounded-full text-center text-4xl leading-[3rem]'
|
|
73
|
-
)}
|
|
74
|
-
>
|
|
75
|
-
{invitationEmoji}
|
|
76
|
-
</span>
|
|
67
|
+
<InvitationEmoji {...{ invitationId }} />
|
|
77
68
|
{name && <p id={nameId}>{name}</p>}
|
|
78
69
|
</div>
|
|
79
70
|
</div>
|
|
@@ -5,7 +5,7 @@ import React, { useEffect } from 'react';
|
|
|
5
5
|
|
|
6
6
|
import { log } from '@dxos/log';
|
|
7
7
|
import { useClient, useIdentity } from '@dxos/react-client';
|
|
8
|
-
import { DensityProvider, useId } from '@dxos/react-components';
|
|
8
|
+
import { DensityProvider, useId, useThemeContext } from '@dxos/react-components';
|
|
9
9
|
|
|
10
10
|
import { JoinHeading } from './JoinHeading';
|
|
11
11
|
import { JoinPanelProps } from './JoinPanelProps';
|
|
@@ -32,6 +32,7 @@ export const JoinPanel = ({
|
|
|
32
32
|
const client = useClient();
|
|
33
33
|
const identity = useIdentity();
|
|
34
34
|
const titleId = useId('joinPanel__title');
|
|
35
|
+
const { hasIosKeyboard } = useThemeContext();
|
|
35
36
|
|
|
36
37
|
const [joinState, joinSend, joinService] = useJoinMachine(client, {
|
|
37
38
|
context: {
|
|
@@ -57,10 +58,10 @@ export const JoinPanel = ({
|
|
|
57
58
|
const innermostState = stateStack[stateStack.length - 1];
|
|
58
59
|
const autoFocusValue = innermostState === 'finishingJoining' ? 'successSpaceInvitation' : innermostState;
|
|
59
60
|
const $nextAutofocus: HTMLElement | null = document.querySelector(`[data-autofocus~="${autoFocusValue}"]`);
|
|
60
|
-
if ($nextAutofocus) {
|
|
61
|
+
if ($nextAutofocus && !(hasIosKeyboard && $nextAutofocus.hasAttribute('data-prevent-ios-autofocus'))) {
|
|
61
62
|
$nextAutofocus.focus();
|
|
62
63
|
}
|
|
63
|
-
}, [joinState.value]);
|
|
64
|
+
}, [joinState.value, hasIosKeyboard]);
|
|
64
65
|
|
|
65
66
|
return (
|
|
66
67
|
<DensityProvider density='fine'>
|
|
@@ -55,6 +55,7 @@ const PureInvitationAuthenticatorContent = ({
|
|
|
55
55
|
autoComplete: 'off',
|
|
56
56
|
pattern: '\\d*',
|
|
57
57
|
'data-autofocus': `connecting${Domain}Invitation inputting${Domain}VerificationCode authenticationFailing${Domain}VerificationCode authenticating${Domain}VerificationCode`,
|
|
58
|
+
'data-prevent-ios-autofocus': true,
|
|
58
59
|
'data-testid': `${invitationType}-auth-code-input`,
|
|
59
60
|
'data-1p-ignore': true
|
|
60
61
|
} as ComponentPropsWithoutRef<'input'>
|
|
@@ -7,6 +7,7 @@ export const os = {
|
|
|
7
7
|
'identity offline description': 'Offline',
|
|
8
8
|
'sidebar label': 'DXOS sidebar',
|
|
9
9
|
'copy invitation code label': 'Copy',
|
|
10
|
+
'copy invitation code success label': 'Copied',
|
|
10
11
|
'open share panel label': 'Share',
|
|
11
12
|
'joining space heading': 'Joining space',
|
|
12
13
|
'join space heading': 'Join a space',
|