@dxos/react-ui 0.1.31 → 0.1.32-next.86f5578

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 (62) hide show
  1. package/dist/lib/browser/index.mjs +1018 -870
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/IdentityList/SpaceMemberListContainer.d.ts.map +1 -1
  5. package/dist/types/src/composites/JoinDialog/JoinDialog.stories.d.ts.map +1 -1
  6. package/dist/types/src/panels/JoinPanel/JoinHeading.d.ts +2 -2
  7. package/dist/types/src/panels/JoinPanel/JoinHeading.d.ts.map +1 -1
  8. package/dist/types/src/panels/JoinPanel/JoinPanel.d.ts +1 -1
  9. package/dist/types/src/panels/JoinPanel/JoinPanel.d.ts.map +1 -1
  10. package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts +1 -1
  11. package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts.map +1 -1
  12. package/dist/types/src/panels/JoinPanel/joinMachine.d.ts +64 -0
  13. package/dist/types/src/panels/JoinPanel/joinMachine.d.ts.map +1 -0
  14. package/dist/types/src/panels/JoinPanel/view-states/AdditionMethodSelector.d.ts +2 -5
  15. package/dist/types/src/panels/JoinPanel/view-states/AdditionMethodSelector.d.ts.map +1 -1
  16. package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts +1 -1
  17. package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts.map +1 -1
  18. package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts +2 -2
  19. package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts.map +1 -1
  20. package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts +2 -2
  21. package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts.map +1 -1
  22. package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts +2 -2
  23. package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts.map +1 -1
  24. package/dist/types/src/panels/JoinPanel/view-states/ViewState.d.ts +4 -6
  25. package/dist/types/src/panels/JoinPanel/view-states/ViewState.d.ts.map +1 -1
  26. package/dist/types/src/panels/JoinPanel/view-states/index.d.ts +0 -1
  27. package/dist/types/src/panels/JoinPanel/view-states/index.d.ts.map +1 -1
  28. package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
  29. package/dist/types/src/translations/locales/en-US.d.ts +3 -1
  30. package/dist/types/src/translations/locales/en-US.d.ts.map +1 -1
  31. package/dist/types/src/util/index.d.ts +1 -0
  32. package/dist/types/src/util/index.d.ts.map +1 -1
  33. package/dist/types/src/util/toEmoji.d.ts +2 -0
  34. package/dist/types/src/util/toEmoji.d.ts.map +1 -0
  35. package/package.json +18 -14
  36. package/src/components/IdentityList/SpaceMemberListContainer.tsx +6 -2
  37. package/src/components/InvitationList/InvitationList.stories.tsx +1 -1
  38. package/src/composites/JoinDialog/JoinDialog.stories.tsx +4 -2
  39. package/src/composites/Shell/Shell.stories.tsx +1 -1
  40. package/src/composites/Shell/Shell.tsx +1 -1
  41. package/src/panels/JoinPanel/JoinHeading.tsx +42 -40
  42. package/src/panels/JoinPanel/JoinPanel.tsx +140 -218
  43. package/src/panels/JoinPanel/JoinPanelProps.ts +1 -1
  44. package/src/panels/JoinPanel/joinMachine.ts +418 -0
  45. package/src/panels/JoinPanel/view-states/AdditionMethodSelector.tsx +9 -21
  46. package/src/panels/JoinPanel/view-states/IdentityAdded.tsx +6 -6
  47. package/src/panels/JoinPanel/view-states/IdentityInput.tsx +4 -4
  48. package/src/panels/JoinPanel/view-states/InvitationAccepted.tsx +22 -18
  49. package/src/panels/JoinPanel/view-states/InvitationAuthenticator.tsx +37 -28
  50. package/src/panels/JoinPanel/view-states/InvitationInput.tsx +21 -21
  51. package/src/panels/JoinPanel/view-states/InvitationRescuer.tsx +58 -41
  52. package/src/panels/JoinPanel/view-states/ViewState.tsx +11 -62
  53. package/src/panels/JoinPanel/view-states/index.ts +0 -1
  54. package/src/playwright/invitations-manager.ts +6 -2
  55. package/src/playwright/invitations.spec.ts +14 -5
  56. package/src/stories/Invitations.stories.tsx +2 -2
  57. package/src/translations/locales/en-US.ts +6 -4
  58. package/src/util/index.ts +1 -0
  59. package/src/util/toEmoji.ts +22 -0
  60. package/dist/types/src/panels/JoinPanel/view-states/IdentitySelector.d.ts +0 -7
  61. package/dist/types/src/panels/JoinPanel/view-states/IdentitySelector.d.ts.map +0 -1
  62. package/src/panels/JoinPanel/view-states/IdentitySelector.tsx +0 -100
@@ -9,49 +9,54 @@ import { AuthenticatingInvitationObservable } from '@dxos/client';
9
9
  import { useInvitationStatus } from '@dxos/react-client';
10
10
  import { Button, getSize, Input, mx, useTranslation } from '@dxos/react-components';
11
11
 
12
- import { ViewState, ViewStateProps } from './ViewState';
12
+ import { JoinSend, JoinState } from '../joinMachine';
13
+ import { ViewState, ViewStateHeading, ViewStateProps } from './ViewState';
13
14
 
14
15
  const pinLength = 6;
15
16
 
16
17
  export interface InvitationAuthenticatorProps extends ViewStateProps {
17
- invitationType: 'space' | 'halo';
18
+ Domain: 'Space' | 'Halo';
18
19
  failed?: boolean;
19
20
  }
20
21
 
21
22
  const PureInvitationAuthenticatorContent = ({
22
23
  disabled,
23
24
  failed,
24
- dispatch,
25
- invitationType,
25
+ joinSend,
26
+ joinState,
27
+ Domain,
26
28
  onChange,
27
29
  onAuthenticate
28
30
  }: {
29
31
  disabled?: boolean;
30
- dispatch: ViewStateProps['dispatch'];
31
- invitationType: InvitationAuthenticatorProps['invitationType'];
32
+ joinSend: JoinSend;
33
+ joinState?: JoinState;
34
+ Domain: InvitationAuthenticatorProps['Domain'];
32
35
  failed: InvitationAuthenticatorProps['failed'];
33
36
  onChange: ComponentProps<typeof Input>['onChange'];
34
37
  onAuthenticate: ComponentProps<typeof Button>['onClick'];
35
38
  }) => {
36
39
  const { t } = useTranslation('os');
40
+ const invitationType = Domain.toLowerCase() as 'space' | 'halo';
37
41
  return (
38
42
  <>
39
43
  <Input
40
- label={t('auth code input label')}
44
+ label={<ViewStateHeading>{t('auth code input label')}</ViewStateHeading>}
41
45
  size='pin'
42
46
  length={pinLength}
43
47
  onChange={onChange}
44
48
  disabled={disabled}
45
49
  slots={{
46
50
  root: { className: 'm-0' },
47
- label: { className: 'sr-only' },
48
51
  description: { className: 'text-center' },
49
52
  input: {
50
53
  disabled,
51
54
  inputMode: 'numeric',
55
+ autoComplete: 'off',
52
56
  pattern: '\\d*',
53
- 'data-autofocus': `${invitationType} invitation acceptor; invitation authenticator`,
54
- 'data-testid': `${invitationType}-auth-code-input`
57
+ 'data-autofocus': `connecting${Domain}Invitation inputting${Domain}VerificationCode authenticationFailing${Domain}VerificationCode authenticating${Domain}VerificationCode`,
58
+ 'data-testid': `${invitationType}-auth-code-input`,
59
+ 'data-1p-ignore': true
55
60
  } as ComponentPropsWithoutRef<'input'>
56
61
  }}
57
62
  {...(failed && {
@@ -75,7 +80,7 @@ const PureInvitationAuthenticatorContent = ({
75
80
  <Button
76
81
  disabled={disabled}
77
82
  className='flex items-center gap-2 pis-2 pie-4'
78
- onClick={() => dispatch({ type: 'cancel invitation', from: invitationType })}
83
+ onClick={() => joinState?.context[invitationType].invitationObservable?.cancel()}
79
84
  data-testid={`${invitationType}-invitation-authenticator-cancel`}
80
85
  >
81
86
  <CaretLeft weight='bold' className={getSize(4)} />
@@ -87,24 +92,27 @@ const PureInvitationAuthenticatorContent = ({
87
92
  };
88
93
 
89
94
  const InvitationAuthenticatorContent = ({
95
+ joinSend,
96
+ joinState,
90
97
  disabled,
91
98
  invitation,
92
- dispatch,
93
- invitationType,
99
+ Domain,
94
100
  failed
95
101
  }: {
102
+ joinSend: JoinSend;
103
+ joinState?: JoinState;
96
104
  disabled?: boolean;
97
105
  invitation: AuthenticatingInvitationObservable;
98
- dispatch: ViewStateProps['dispatch'];
99
- invitationType: InvitationAuthenticatorProps['invitationType'];
106
+ Domain: InvitationAuthenticatorProps['Domain'];
100
107
  failed: InvitationAuthenticatorProps['failed'];
101
108
  }) => {
109
+ const invitationType = Domain.toLowerCase();
102
110
  const [pinValue, setPinValue] = useState('');
103
111
  const { authenticate } = useInvitationStatus(invitation);
104
112
  const onAuthenticate = useCallback(() => {
105
- dispatch({ type: 'authenticating invitation', from: invitationType });
113
+ joinSend({ type: `authenticate${Domain}VerificationCode` });
106
114
  void authenticate(pinValue);
107
- }, [dispatch, invitationType, authenticate, pinValue]);
115
+ }, [joinSend, authenticate, pinValue]);
108
116
  const onChange = useCallback(
109
117
  ({ target: { value } }: ChangeEvent<HTMLInputElement>) => {
110
118
  setPinValue(value);
@@ -115,26 +123,27 @@ const InvitationAuthenticatorContent = ({
115
123
  [authenticate, pinValue]
116
124
  );
117
125
  return (
118
- <PureInvitationAuthenticatorContent {...{ disabled, failed, dispatch, invitationType, onChange, onAuthenticate }} />
126
+ <PureInvitationAuthenticatorContent
127
+ {...{ disabled, failed, joinSend, joinState, Domain, onChange, onAuthenticate }}
128
+ />
119
129
  );
120
130
  };
121
131
 
122
- export const InvitationAuthenticator = ({
123
- invitationType,
124
- failed,
125
- ...viewStateProps
126
- }: InvitationAuthenticatorProps) => {
127
- const disabled = !viewStateProps.active;
128
- const { activeInvitation, dispatch } = viewStateProps;
132
+ export const InvitationAuthenticator = ({ failed, Domain, ...viewStateProps }: InvitationAuthenticatorProps) => {
133
+ const { joinSend, joinState } = viewStateProps;
134
+ const disabled =
135
+ !viewStateProps.active ||
136
+ ['connecting', 'authenticating'].some((str) => joinState?.configuration[0].id.includes(str));
137
+ const activeInvitation = joinState?.context[Domain.toLowerCase() as 'space' | 'halo'].invitationObservable;
129
138
  return (
130
139
  <ViewState {...viewStateProps}>
131
- {!activeInvitation || activeInvitation === true ? (
140
+ {!activeInvitation ? (
132
141
  <PureInvitationAuthenticatorContent
133
- {...{ disabled, failed, dispatch, invitationType, onChange: () => {}, onAuthenticate: () => {} }}
142
+ {...{ disabled, failed, joinSend, joinState, Domain, onChange: () => {}, onAuthenticate: () => {} }}
134
143
  />
135
144
  ) : (
136
145
  <InvitationAuthenticatorContent
137
- {...{ disabled, failed, invitation: activeInvitation, dispatch, invitationType }}
146
+ {...{ disabled, failed, invitation: activeInvitation, joinSend, joinState, Domain }}
138
147
  />
139
148
  )}
140
149
  </ViewState>
@@ -3,33 +3,33 @@
3
3
  //
4
4
 
5
5
  import { CaretLeft, CaretRight } from '@phosphor-icons/react';
6
- import React, { ComponentPropsWithoutRef, useState } from 'react';
6
+ import React, { ComponentPropsWithoutRef, useEffect, useState } from 'react';
7
7
 
8
- import { InvitationEncoder } from '@dxos/client';
9
- import { useClient } from '@dxos/react-client';
10
8
  import { Button, getSize, Input, mx, useTranslation } from '@dxos/react-components';
11
9
 
12
10
  import { ViewState, ViewStateHeading, ViewStateProps } from './ViewState';
13
11
 
14
12
  export interface InvitationInputProps extends ViewStateProps {
15
- invitationType: 'space' | 'halo';
13
+ Domain: 'Space' | 'Halo';
16
14
  }
17
15
 
18
- export const InvitationInput = ({ invitationType, ...viewStateProps }: InvitationInputProps) => {
19
- const client = useClient();
16
+ export const InvitationInput = ({ Domain, ...viewStateProps }: InvitationInputProps) => {
20
17
  const disabled = !viewStateProps.active;
21
- const { dispatch } = viewStateProps;
18
+ const { joinSend, joinState } = viewStateProps;
22
19
  const { t } = useTranslation('os');
23
20
 
24
- const [inputValue, setInputValue] = useState('');
21
+ const contextUnredeemedCode = joinState?.context[Domain.toLowerCase() as 'space' | 'halo'].unredeemedCode;
22
+
23
+ const [inputValue, setInputValue] = useState(contextUnredeemedCode ?? '');
24
+
25
+ useEffect(() => {
26
+ contextUnredeemedCode && setInputValue(contextUnredeemedCode ?? '');
27
+ }, [contextUnredeemedCode]);
25
28
 
26
29
  const handleNext = () =>
27
- dispatch({
28
- type: 'connecting invitation',
29
- from: invitationType,
30
- invitation: client[invitationType === 'halo' ? 'halo' : 'echo'].acceptInvitation(
31
- InvitationEncoder.decode(inputValue)
32
- )
30
+ joinSend({
31
+ type: `set${Domain}InvitationCode`,
32
+ code: inputValue
33
33
  });
34
34
 
35
35
  return (
@@ -37,13 +37,13 @@ export const InvitationInput = ({ invitationType, ...viewStateProps }: Invitatio
37
37
  <Input
38
38
  disabled={disabled}
39
39
  label={<ViewStateHeading>{t('invitation input label')}</ViewStateHeading>}
40
+ value={inputValue}
40
41
  onChange={({ target: { value } }) => setInputValue(value)}
41
42
  slots={{
42
43
  root: { className: 'm-0' },
43
- label: { className: 'sr-only' },
44
44
  input: {
45
- 'data-autofocus': `${invitationType} invitation acceptor; invitation input`,
46
- 'data-testid': `${invitationType}-invitation-input`,
45
+ 'data-autofocus': `inputting${Domain}InvitationCode`,
46
+ 'data-testid': `${Domain.toLowerCase()}-invitation-input`,
47
47
  onKeyUp: ({ key }) => key === 'Enter' && handleNext()
48
48
  } as ComponentPropsWithoutRef<'input'>
49
49
  }}
@@ -54,17 +54,17 @@ export const InvitationInput = ({ invitationType, ...viewStateProps }: Invitatio
54
54
  disabled={disabled}
55
55
  className='grow flex items-center gap-2 pli-2 order-2'
56
56
  onClick={handleNext}
57
- data-testid={`${invitationType}-invitation-input-continue`}
57
+ data-testid={`${Domain.toLowerCase()}-invitation-input-continue`}
58
58
  >
59
59
  <CaretLeft weight='bold' className={mx(getSize(2), 'invisible')} />
60
60
  <span className='grow'>{t('continue label')}</span>
61
61
  <CaretRight weight='bold' className={getSize(4)} />
62
62
  </Button>
63
63
  <Button
64
- disabled={disabled}
65
- onClick={() => dispatch({ type: 'add identity' })}
64
+ disabled={Domain === 'Space'}
65
+ onClick={() => joinSend({ type: 'deselectAuthMethod' })}
66
66
  className='flex items-center gap-2 pis-2 pie-4'
67
- data-testid={`${invitationType}-invitation-input-back`}
67
+ data-testid={`${Domain.toLowerCase()}-invitation-input-back`}
68
68
  >
69
69
  <CaretLeft weight='bold' className={getSize(4)} />
70
70
  <span>{t('back label')}</span>
@@ -5,34 +5,36 @@
5
5
  import { ArrowsClockwise, CaretLeft, CaretRight } from '@phosphor-icons/react';
6
6
  import React from 'react';
7
7
 
8
- import { AuthenticatingInvitationObservable, Invitation } from '@dxos/client';
9
- import { useInvitationStatus } from '@dxos/react-client';
10
- import { Button, getSize, mx, useTranslation } from '@dxos/react-components';
8
+ import { Invitation } from '@dxos/client';
9
+ import { Button, defaultDescription, getSize, mx, useTranslation } from '@dxos/react-components';
11
10
 
12
- import { ViewState, ViewStateProps } from './ViewState';
11
+ import { JoinSend, JoinState } from '../joinMachine';
12
+ import { ViewState, ViewStateHeading, ViewStateProps } from './ViewState';
13
13
 
14
14
  export interface InvitationConnectorProps extends ViewStateProps {
15
- invitationType: 'space' | 'halo';
15
+ Domain: 'Space' | 'Halo';
16
16
  }
17
17
 
18
18
  const InvitationActions = ({
19
- activeInvitation,
19
+ invitationState,
20
20
  disabled,
21
- dispatch,
22
- invitationType
21
+ joinSend,
22
+ joinState,
23
+ Domain
23
24
  }: {
24
- activeInvitation: AuthenticatingInvitationObservable;
25
+ invitationState?: Invitation.State;
25
26
  disabled?: boolean;
26
- dispatch: ViewStateProps['dispatch'];
27
- invitationType: InvitationConnectorProps['invitationType'];
27
+ joinSend: JoinSend;
28
+ joinState?: JoinState;
29
+ Domain: InvitationConnectorProps['Domain'];
28
30
  }) => {
29
- const { status, cancel } = useInvitationStatus(activeInvitation);
30
31
  const { t } = useTranslation('os');
31
-
32
- switch (status) {
32
+ const invitationType = Domain.toLowerCase() as 'space' | 'halo';
33
+ switch (invitationState) {
33
34
  case Invitation.State.CONNECTING:
34
35
  return (
35
36
  <>
37
+ <ViewStateHeading className={defaultDescription}>{t('connecting status label')}</ViewStateHeading>
36
38
  <div role='none' className='grow' />
37
39
  <div className='flex gap-2'>
38
40
  <Button disabled className='grow flex items-center gap-2 pli-2 order-2' data-testid='next'>
@@ -43,8 +45,7 @@ const InvitationActions = ({
43
45
  <Button
44
46
  disabled={disabled}
45
47
  className='flex items-center gap-2 pis-2 pie-4'
46
- onClick={cancel}
47
- data-autofocus={`${invitationType} invitation acceptor; invitation rescuer`}
48
+ onClick={() => joinState?.context[invitationType].invitationObservable?.cancel()}
48
49
  data-testid='invitation-rescuer-cancel'
49
50
  >
50
51
  <CaretLeft weight='bold' className={getSize(4)} />
@@ -58,40 +59,56 @@ const InvitationActions = ({
58
59
  case Invitation.State.ERROR:
59
60
  default:
60
61
  return (
61
- <Button
62
- disabled={disabled}
63
- className='grow flex items-center gap-2 pli-2'
64
- onClick={() => dispatch({ type: 'reset invitation', from: invitationType })}
65
- data-autofocus={`${invitationType} invitation acceptor; invitation rescuer`}
66
- data-testid='invitation-rescuer-reset'
67
- >
68
- <CaretLeft weight='bold' className={mx(getSize(5), 'invisible')} />
69
- <span className='grow'>{t('reset label')}</span>
70
- <ArrowsClockwise weight='bold' className={getSize(5)} />
71
- </Button>
62
+ <>
63
+ <ViewStateHeading className={defaultDescription}>
64
+ {t(
65
+ invitationState === Invitation.State.TIMEOUT
66
+ ? 'timeout status label'
67
+ : invitationState === Invitation.State.CANCELLED
68
+ ? 'cancelled status label'
69
+ : 'error status label'
70
+ )}
71
+ </ViewStateHeading>
72
+ <div role='none' className='grow' />
73
+ <Button
74
+ disabled={disabled}
75
+ className='flex items-center gap-2 pli-2'
76
+ onClick={() => joinSend({ type: `reset${Domain}Invitation` })}
77
+ data-testid='invitation-rescuer-reset'
78
+ >
79
+ <CaretLeft weight='bold' className={mx(getSize(5), 'invisible')} />
80
+ <span className='grow'>{t('reset label')}</span>
81
+ <ArrowsClockwise className={getSize(4)} />
82
+ </Button>
83
+ </>
72
84
  );
73
85
  }
74
86
  };
75
87
 
76
- export const InvitationRescuer = ({ invitationType, ...viewStateProps }: InvitationConnectorProps) => {
88
+ export const InvitationRescuer = ({ Domain, ...viewStateProps }: InvitationConnectorProps) => {
77
89
  const disabled = !viewStateProps.active;
78
- const { dispatch, activeInvitation } = viewStateProps;
90
+ const { joinSend, joinState } = viewStateProps;
91
+ const invitationState = joinState?.context[Domain.toLowerCase() as 'space' | 'halo'].invitation?.state;
79
92
  const { t } = useTranslation('os');
80
93
  return (
81
94
  <ViewState {...viewStateProps}>
82
- {activeInvitation === true || !activeInvitation ? (
83
- <Button
84
- disabled={disabled}
85
- className='grow flex items-center gap-2 pli-2'
86
- data-autofocus='space invitation acceptor; invitation rescuer'
87
- data-testid='invitation-rescuer-connect'
88
- >
89
- <CaretLeft weight='bold' className={mx(getSize(5), 'invisible')} />
90
- <span className='grow'>{t('connect label')}</span>
91
- <ArrowsClockwise weight='bold' className={getSize(5)} />
92
- </Button>
95
+ {typeof invitationState === 'undefined' ? (
96
+ <>
97
+ <div role='none' className='grow' />
98
+ <Button
99
+ disabled={disabled}
100
+ className='flex items-center gap-2 pli-2'
101
+ data-autofocus={`inputting${Domain}InvitationCode`}
102
+ data-testid='invitation-rescuer-blank-reset'
103
+ onClick={() => joinSend({ type: `reset${Domain}Invitation` })}
104
+ >
105
+ <CaretLeft weight='bold' className={mx(getSize(5), 'invisible')} />
106
+ <span className='grow'>{t('reset label')}</span>
107
+ <ArrowsClockwise className={getSize(5)} />
108
+ </Button>
109
+ </>
93
110
  ) : (
94
- <InvitationActions {...{ activeInvitation, disabled, dispatch, invitationType }} />
111
+ <InvitationActions {...{ invitationState, disabled, joinSend, joinState, Domain }} />
95
112
  )}
96
113
  </ViewState>
97
114
  );
@@ -5,27 +5,26 @@
5
5
  import { CheckCircle, HourglassSimple, X } from '@phosphor-icons/react';
6
6
  import React, { ComponentProps, ComponentPropsWithoutRef, ReactNode, useMemo } from 'react';
7
7
 
8
- import type { AuthenticatingInvitationObservable, Identity } from '@dxos/client';
8
+ import type { AuthenticatingInvitationObservable } from '@dxos/client';
9
9
  import { Invitation } from '@dxos/client';
10
10
  import { useInvitationStatus } from '@dxos/react-client';
11
- import { mx, useTranslation, Trans, Avatar, useId, getSize, strongShimmer } from '@dxos/react-components';
11
+ import { mx, useTranslation, useId, getSize, strongShimmer } from '@dxos/react-components';
12
12
 
13
- import { defaultSurface, subduedSurface, resolvedBgColor, activeBgColor, inactiveBgColor } from '../../../styles';
13
+ import { defaultSurface, resolvedBgColor, activeBgColor, inactiveBgColor } from '../../../styles';
14
14
  import { invitationStatusValue } from '../../../util';
15
- import { JoinDispatch } from '../JoinPanelProps';
15
+ import { JoinSend, JoinState } from '../joinMachine';
16
16
 
17
17
  export interface ViewStateProps extends ComponentProps<'div'> {
18
18
  active: boolean;
19
- dispatch: JoinDispatch;
20
- selectedIdentity?: true | Identity;
21
- activeInvitation?: true | AuthenticatingInvitationObservable;
19
+ joinSend: JoinSend;
20
+ joinState?: JoinState;
22
21
  }
23
22
 
24
23
  const stripe = mx('rounded-full grow', getSize(3));
25
24
 
26
25
  export const ViewStateHeading = ({ children, className, ...props }: ComponentPropsWithoutRef<'h2'>) => {
27
26
  return (
28
- <h2 {...props} className={mx('font-system-medium text-sm md:text-base mbe-1 mli-1 text-center', className)}>
27
+ <h2 {...props} className={mx('font-system-normal text-sm mbe-1 mli-1 text-center', className)}>
29
28
  {children}
30
29
  </h2>
31
30
  );
@@ -74,7 +73,8 @@ const PureViewStateInvitation = ({
74
73
  );
75
74
  };
76
75
 
77
- const ViewStateInvitationStatus = ({ activeInvitation }: { activeInvitation: AuthenticatingInvitationObservable }) => {
76
+ // todo (thure): Restore this?
77
+ const _ViewStateInvitationStatus = ({ activeInvitation }: { activeInvitation: AuthenticatingInvitationObservable }) => {
78
78
  const { t } = useTranslation('os');
79
79
  const { status, haltedAt } = useInvitationStatus(activeInvitation);
80
80
 
@@ -136,19 +136,8 @@ const ViewStateInvitationStatus = ({ activeInvitation }: { activeInvitation: Aut
136
136
  );
137
137
  };
138
138
 
139
- export const ViewState = ({
140
- active,
141
- children,
142
- className,
143
- dispatch,
144
- selectedIdentity,
145
- activeInvitation,
146
- ...props
147
- }: ViewStateProps) => {
139
+ export const ViewState = ({ active, children, className, joinSend, joinState, ...props }: ViewStateProps) => {
148
140
  // note (thure): reserve `order-1` and `order-3` for outgoing steps in different directions
149
- const { t } = useTranslation('os');
150
- const identityLabel = useId('selectedIdentityLabel');
151
-
152
141
  return (
153
142
  <div
154
143
  role='none'
@@ -156,47 +145,7 @@ export const ViewState = ({
156
145
  {...(!active && { 'aria-hidden': true })}
157
146
  className={mx('is-[50%] flex flex-col', active ? 'order-2' : 'order-4', className)}
158
147
  >
159
- {selectedIdentity && (
160
- <div role='none' className={mx(subduedSurface, 'flex-none flex items-center gap-1 pli-2 pbe-1.5')}>
161
- <Trans
162
- {...{
163
- defaults: t('join space as identity heading'),
164
- components: {
165
- icon: (
166
- <Avatar
167
- size={4}
168
- fallbackValue={selectedIdentity === true ? '' : selectedIdentity.identityKey.toHex()}
169
- labelId={identityLabel}
170
- />
171
- ),
172
- label: <span id={identityLabel} />,
173
- part: <span role='none' className='flex items-center gap-1 leading-none' />
174
- },
175
- values: {
176
- labelValue:
177
- selectedIdentity === true
178
- ? ' '
179
- : selectedIdentity.profile?.displayName ?? selectedIdentity.identityKey.truncate()
180
- }
181
- }}
182
- />
183
- </div>
184
- )}
185
- {activeInvitation &&
186
- (activeInvitation === true ? (
187
- <PureViewStateInvitation
188
- {...{
189
- halted: false,
190
- status: Invitation.State.INIT,
191
- label: t('invitation input label'),
192
- cursor: 0,
193
- resolvedColor: inactiveBgColor
194
- }}
195
- />
196
- ) : (
197
- <ViewStateInvitationStatus {...{ activeInvitation }} />
198
- ))}
199
- <div role='region' className={mx(defaultSurface, 'rounded-be-md grow shrink-0 flex flex-col gap-1 p-2')}>
148
+ <div role='region' className={mx(defaultSurface, 'rounded-be-md grow shrink-0 flex flex-col gap-1 p-4 pbs-1')}>
200
149
  {children}
201
150
  </div>
202
151
  </div>
@@ -4,7 +4,6 @@
4
4
 
5
5
  export * from './AdditionMethodSelector';
6
6
  export * from './IdentityAdded';
7
- export * from './IdentitySelector';
8
7
  export * from './IdentityInput';
9
8
  export * from './InvitationAccepted';
10
9
  export * from './InvitationInput';
@@ -141,7 +141,9 @@ export class InvitationsManager {
141
141
  async acceptInvitation(id: number, type: 'device' | 'space', invitation: string) {
142
142
  const peer = this._peer(id);
143
143
  // TODO(wittjosiah): Update ids.
144
- await peer.getByTestId(type === 'device' ? 'join-identity' : 'select-identity').click();
144
+ if (type === 'device') {
145
+ await peer.getByTestId('join-identity').click();
146
+ }
145
147
  await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-invitation-input`).type(invitation);
146
148
  await this.page.keyboard.press('Enter');
147
149
  }
@@ -189,7 +191,9 @@ export class InvitationsManager {
189
191
  async doneInvitation(id: number, type: 'device' | 'space') {
190
192
  const peer = this._peer(id);
191
193
  // TODO(wittjosiah): Update ids.
192
- await peer.getByTestId(type === 'device' ? 'identity-added-done' : 'space-invitation-accepted-done').click();
194
+ await peer
195
+ .getByTestId(type === 'device' ? 'halo-invitation-accepted-done' : 'space-invitation-accepted-done')
196
+ .click();
193
197
  }
194
198
 
195
199
  // TODO(wittjosiah): Peer manager?
@@ -104,9 +104,10 @@ test.describe('Invitations', () => {
104
104
  await manager.acceptInvitation(1, 'device', invitation);
105
105
  await manager.cancelInvitation(1, 'device', 'guest');
106
106
  await manager.resetInvitation(1);
107
+ await manager.invitationInputContinue(1, 'device');
107
108
  const [authenticationCode] = await Promise.all([
108
109
  manager.getAuthenticationCode(),
109
- manager.invitationInputContinue(1, 'device')
110
+ manager.clearAuthenticationCode(1, 'device')
110
111
  ]);
111
112
  await manager.authenticateInvitation(1, 'device', authenticationCode);
112
113
  await manager.doneInvitation(1, 'device');
@@ -126,9 +127,10 @@ test.describe('Invitations', () => {
126
127
  await sleep(100);
127
128
  await manager.setConnectionState(0, ConnectionState.ONLINE);
128
129
  await manager.resetInvitation(1);
130
+ await manager.invitationInputContinue(1, 'device');
129
131
  const [authenticationCode] = await Promise.all([
130
132
  manager.getAuthenticationCode(),
131
- manager.invitationInputContinue(1, 'device')
133
+ manager.clearAuthenticationCode(1, 'device')
132
134
  ]);
133
135
  await manager.authenticateInvitation(1, 'device', authenticationCode);
134
136
  await manager.doneInvitation(1, 'device');
@@ -243,10 +245,13 @@ test.describe('Invitations', () => {
243
245
  expect(await manager.invitationFailed(1)).to.be.true;
244
246
 
245
247
  await manager.resetInvitation(1);
248
+ await manager.invitationInputContinue(1, 'space');
249
+
246
250
  const [authenticationCode] = await Promise.all([
247
251
  manager.getAuthenticationCode(),
248
- manager.invitationInputContinue(1, 'space')
252
+ manager.clearAuthenticationCode(1, 'space')
249
253
  ]);
254
+
250
255
  await manager.authenticateInvitation(1, 'space', authenticationCode);
251
256
  await manager.doneInvitation(1, 'space');
252
257
 
@@ -292,10 +297,13 @@ test.describe('Invitations', () => {
292
297
  await manager.acceptInvitation(1, 'space', invitation);
293
298
  await manager.cancelInvitation(1, 'space', 'guest');
294
299
  await manager.resetInvitation(1);
300
+ await manager.invitationInputContinue(1, 'space');
301
+
295
302
  const [authenticationCode] = await Promise.all([
296
303
  manager.getAuthenticationCode(),
297
- manager.invitationInputContinue(1, 'space')
304
+ manager.clearAuthenticationCode(1, 'space')
298
305
  ]);
306
+
299
307
  await manager.authenticateInvitation(1, 'space', authenticationCode);
300
308
  await manager.doneInvitation(1, 'space');
301
309
 
@@ -317,9 +325,10 @@ test.describe('Invitations', () => {
317
325
  await sleep(100);
318
326
  await manager.setConnectionState(0, ConnectionState.ONLINE);
319
327
  await manager.resetInvitation(1);
328
+ await manager.invitationInputContinue(1, 'space');
320
329
  const [authenticationCode] = await Promise.all([
321
330
  manager.getAuthenticationCode(),
322
- manager.invitationInputContinue(1, 'space')
331
+ manager.clearAuthenticationCode(1, 'space')
323
332
  ]);
324
333
  await manager.authenticateInvitation(1, 'space', authenticationCode);
325
334
  await manager.doneInvitation(1, 'space');
@@ -55,7 +55,7 @@ const Panel = ({ id, panel, setPanel }: { id: number; panel?: PanelType; setPane
55
55
  <ButtonGroup className='mbe-4'>
56
56
  {/* <Tooltip content='Create Space'> */}
57
57
  <Button
58
- onClick={() => client.echo.createSpace({ name: faker.animal.bird() })}
58
+ onClick={() => client.createSpace({ name: faker.animal.bird() })}
59
59
  data-testid='invitations.create-space'
60
60
  >
61
61
  <PlusCircle className={getSize(6)} />
@@ -118,7 +118,7 @@ const render = ({ id }: { id: number }) => {
118
118
  <Tooltip content='Join Existing Identity'> */}
119
119
  <Button
120
120
  onClick={() => setPanel('identity')}
121
- disabled={panel === 'identity'}
121
+ disabled={Boolean(identity) || panel === 'identity'}
122
122
  data-testid='invitations.open-join-identity'
123
123
  >
124
124
  <QrCode weight='fill' className={getSize(6)} />
@@ -8,7 +8,7 @@ export const os = {
8
8
  'sidebar label': 'DXOS sidebar',
9
9
  'copy invitation code label': 'Copy',
10
10
  'open share panel label': 'Share',
11
- 'joining heading': '<small>Joining</small><large>{{name}}</large>',
11
+ 'joining space heading': 'Joining space',
12
12
  'join space heading': 'Join a space',
13
13
  'halo heading': 'Initialize device identity',
14
14
  'exit label': 'Exit',
@@ -27,7 +27,7 @@ export const os = {
27
27
  'join identity label': 'Use an authed device',
28
28
  'join identity description': 'Add this device to an identity you’re already logged into on another device.',
29
29
  'deselect identity label': 'Back to identities',
30
- 'addition method selector title': 'Add an identity to this device',
30
+ 'addition method selector title': 'An identity is required to continue',
31
31
  'new identity input label': 'Add a display name',
32
32
  'recover identity input label': 'Type or paste your seed phrase',
33
33
  'failed to create identity message': 'Failed to create an identity.',
@@ -48,7 +48,7 @@ export const os = {
48
48
  'cancel label': 'Cancel',
49
49
  'done label': 'Done',
50
50
  'reset label': 'Start over',
51
- 'auth code input label': 'Auth code provided by the invitation sender',
51
+ 'auth code input label': 'Enter the verification code',
52
52
  'invitation input label': 'Paste an invitation code or URL',
53
53
  'create device invitation label': 'Invite',
54
54
  'create space invitation label': 'Invite',
@@ -62,5 +62,7 @@ export const os = {
62
62
  'view space invitations label': 'View space invitations',
63
63
  'toggle sidebar label': 'Open/close sidebar',
64
64
  'open sidebar label': 'Open sidebar',
65
- 'close sidebar label': 'Close sidebar'
65
+ 'close sidebar label': 'Close sidebar',
66
+ 'welcome message': 'Welcome',
67
+ 'selecting identity heading': 'Selecting identity'
66
68
  };
package/src/util/index.ts CHANGED
@@ -3,3 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './invitationStatusValue';
6
+ export * from './toEmoji';