@dxos/react-ui 0.1.22 → 0.1.24-next.6b1f434

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 (199) hide show
  1. package/dist/lib/browser/index.mjs +2434 -77
  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/DeviceList.d.ts +7 -0
  5. package/dist/types/src/components/IdentityList/DeviceList.d.ts.map +1 -0
  6. package/dist/types/src/components/IdentityList/IdentityListItem.d.ts +7 -0
  7. package/dist/types/src/components/IdentityList/IdentityListItem.d.ts.map +1 -0
  8. package/dist/types/src/components/{IdentityListItem → IdentityList}/IdentityListItem.stories.d.ts +2 -1
  9. package/dist/types/src/components/IdentityList/IdentityListItem.stories.d.ts.map +1 -0
  10. package/dist/types/src/components/IdentityList/SpaceMemberList.d.ts +7 -0
  11. package/dist/types/src/components/IdentityList/SpaceMemberList.d.ts.map +1 -0
  12. package/dist/types/src/components/IdentityList/SpaceMemberListContainer.d.ts +9 -0
  13. package/dist/types/src/components/IdentityList/SpaceMemberListContainer.d.ts.map +1 -0
  14. package/dist/types/src/components/IdentityList/index.d.ts +5 -0
  15. package/dist/types/src/components/IdentityList/index.d.ts.map +1 -0
  16. package/dist/types/src/components/InvitationList/InvitationList.d.ts +7 -0
  17. package/dist/types/src/components/InvitationList/InvitationList.d.ts.map +1 -0
  18. package/dist/types/src/components/InvitationList/InvitationList.stories.d.ts +10 -0
  19. package/dist/types/src/components/InvitationList/InvitationList.stories.d.ts.map +1 -0
  20. package/dist/types/src/components/InvitationList/InvitationListContainer.d.ts +7 -0
  21. package/dist/types/src/components/InvitationList/InvitationListContainer.d.ts.map +1 -0
  22. package/dist/types/src/components/InvitationList/InvitationListItem.d.ts +9 -0
  23. package/dist/types/src/components/InvitationList/InvitationListItem.d.ts.map +1 -0
  24. package/dist/types/src/components/InvitationList/InvitationListProps.d.ts +4 -0
  25. package/dist/types/src/components/InvitationList/InvitationListProps.d.ts.map +1 -0
  26. package/dist/types/src/components/InvitationList/InvitationStatusAvatar.d.ts +14 -0
  27. package/dist/types/src/components/InvitationList/InvitationStatusAvatar.d.ts.map +1 -0
  28. package/dist/types/src/components/InvitationList/InvitationStatusAvatar.stories.d.ts +9 -0
  29. package/dist/types/src/components/InvitationList/InvitationStatusAvatar.stories.d.ts.map +1 -0
  30. package/dist/types/src/components/InvitationList/index.d.ts +5 -0
  31. package/dist/types/src/components/InvitationList/index.d.ts.map +1 -0
  32. package/dist/types/src/components/PanelSeparator/PanelSeparator.d.ts +3 -0
  33. package/dist/types/src/components/PanelSeparator/PanelSeparator.d.ts.map +1 -0
  34. package/dist/types/src/components/PanelSeparator/index.d.ts +2 -0
  35. package/dist/types/src/components/PanelSeparator/index.d.ts.map +1 -0
  36. package/dist/types/src/components/SpaceList/SpaceListItem.d.ts +7 -0
  37. package/dist/types/src/components/SpaceList/SpaceListItem.d.ts.map +1 -0
  38. package/dist/types/src/components/SpaceList/index.d.ts +2 -0
  39. package/dist/types/src/components/SpaceList/index.d.ts.map +1 -0
  40. package/dist/types/src/components/index.d.ts +5 -0
  41. package/dist/types/src/components/index.d.ts.map +1 -0
  42. package/dist/types/src/composites/DevicesDialog/DevicesDialog.d.ts +6 -0
  43. package/dist/types/src/composites/DevicesDialog/DevicesDialog.d.ts.map +1 -0
  44. package/dist/types/src/composites/DevicesDialog/index.d.ts +2 -0
  45. package/dist/types/src/composites/DevicesDialog/index.d.ts.map +1 -0
  46. package/dist/types/src/composites/JoinDialog/JoinDialog.d.ts +6 -0
  47. package/dist/types/src/composites/JoinDialog/JoinDialog.d.ts.map +1 -0
  48. package/dist/types/src/composites/JoinDialog/JoinDialog.stories.d.ts +10 -0
  49. package/dist/types/src/composites/JoinDialog/JoinDialog.stories.d.ts.map +1 -0
  50. package/dist/types/src/composites/JoinDialog/index.d.ts +2 -0
  51. package/dist/types/src/composites/JoinDialog/index.d.ts.map +1 -0
  52. package/dist/types/src/composites/Shell/Shell.d.ts +6 -0
  53. package/dist/types/src/composites/Shell/Shell.d.ts.map +1 -0
  54. package/dist/types/src/composites/Shell/index.d.ts +2 -0
  55. package/dist/types/src/composites/Shell/index.d.ts.map +1 -0
  56. package/dist/types/src/composites/SpaceDialog/SpaceDialog.d.ts +6 -0
  57. package/dist/types/src/composites/SpaceDialog/SpaceDialog.d.ts.map +1 -0
  58. package/dist/types/src/composites/SpaceDialog/index.d.ts +2 -0
  59. package/dist/types/src/composites/SpaceDialog/index.d.ts.map +1 -0
  60. package/dist/types/src/composites/index.d.ts +3 -0
  61. package/dist/types/src/composites/index.d.ts.map +1 -1
  62. package/dist/types/src/index.d.ts +1 -0
  63. package/dist/types/src/index.d.ts.map +1 -1
  64. package/dist/types/src/layouts/PanelAlertDialog/PanelAlertDialog.d.ts +14 -0
  65. package/dist/types/src/layouts/PanelAlertDialog/PanelAlertDialog.d.ts.map +1 -0
  66. package/dist/types/src/layouts/PanelAlertDialog/index.d.ts +2 -0
  67. package/dist/types/src/layouts/PanelAlertDialog/index.d.ts.map +1 -0
  68. package/dist/types/src/layouts/PanelDialog/PanelDialog.d.ts +14 -0
  69. package/dist/types/src/layouts/PanelDialog/PanelDialog.d.ts.map +1 -0
  70. package/dist/types/src/layouts/PanelDialog/index.d.ts +2 -0
  71. package/dist/types/src/layouts/PanelDialog/index.d.ts.map +1 -0
  72. package/dist/types/src/layouts/PanelSidebar/PanelSidebar.d.ts +4 -5
  73. package/dist/types/src/layouts/PanelSidebar/PanelSidebar.d.ts.map +1 -1
  74. package/dist/types/src/layouts/index.d.ts +2 -0
  75. package/dist/types/src/layouts/index.d.ts.map +1 -1
  76. package/dist/types/src/panels/DevicesPanel/DevicesPanel.d.ts +10 -0
  77. package/dist/types/src/panels/DevicesPanel/DevicesPanel.d.ts.map +1 -0
  78. package/dist/types/src/panels/DevicesPanel/index.d.ts +2 -0
  79. package/dist/types/src/panels/DevicesPanel/index.d.ts.map +1 -0
  80. package/dist/types/src/panels/JoinPanel/JoinHeading.d.ts +13 -0
  81. package/dist/types/src/panels/JoinPanel/JoinHeading.d.ts.map +1 -0
  82. package/dist/types/src/panels/JoinPanel/JoinPanel.d.ts +3 -0
  83. package/dist/types/src/panels/JoinPanel/JoinPanel.d.ts.map +1 -0
  84. package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts +54 -0
  85. package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts.map +1 -0
  86. package/dist/types/src/panels/JoinPanel/index.d.ts +3 -0
  87. package/dist/types/src/panels/JoinPanel/index.d.ts.map +1 -0
  88. package/dist/types/src/panels/JoinPanel/view-states/AdditionMethodSelector.d.ts +7 -0
  89. package/dist/types/src/panels/JoinPanel/view-states/AdditionMethodSelector.d.ts.map +1 -0
  90. package/dist/types/src/panels/JoinPanel/view-states/IdentityAdded.d.ts +15 -0
  91. package/dist/types/src/panels/JoinPanel/view-states/IdentityAdded.d.ts.map +1 -0
  92. package/dist/types/src/panels/JoinPanel/view-states/IdentityInput.d.ts +6 -0
  93. package/dist/types/src/panels/JoinPanel/view-states/IdentityInput.d.ts.map +1 -0
  94. package/dist/types/src/panels/JoinPanel/view-states/IdentitySelector.d.ts +7 -0
  95. package/dist/types/src/panels/JoinPanel/view-states/IdentitySelector.d.ts.map +1 -0
  96. package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts +10 -0
  97. package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts.map +1 -0
  98. package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts +7 -0
  99. package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts.map +1 -0
  100. package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts +6 -0
  101. package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts.map +1 -0
  102. package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts +6 -0
  103. package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts.map +1 -0
  104. package/dist/types/src/panels/JoinPanel/view-states/ViewState.d.ts +12 -0
  105. package/dist/types/src/panels/JoinPanel/view-states/ViewState.d.ts.map +1 -0
  106. package/dist/types/src/panels/JoinPanel/view-states/index.d.ts +9 -0
  107. package/dist/types/src/panels/JoinPanel/view-states/index.d.ts.map +1 -0
  108. package/dist/types/src/panels/SpacePanel/SpacePanel.d.ts +18 -0
  109. package/dist/types/src/panels/SpacePanel/SpacePanel.d.ts.map +1 -0
  110. package/dist/types/src/panels/SpacePanel/SpacePanel.stories.d.ts +9 -0
  111. package/dist/types/src/panels/SpacePanel/SpacePanel.stories.d.ts.map +1 -0
  112. package/dist/types/src/panels/SpacePanel/index.d.ts +2 -0
  113. package/dist/types/src/panels/SpacePanel/index.d.ts.map +1 -0
  114. package/dist/types/src/panels/index.d.ts +3 -0
  115. package/dist/types/src/panels/index.d.ts.map +1 -1
  116. package/dist/types/src/styles/dialogStyles.d.ts +3 -0
  117. package/dist/types/src/styles/dialogStyles.d.ts.map +1 -0
  118. package/dist/types/src/styles/index.d.ts +2 -0
  119. package/dist/types/src/styles/index.d.ts.map +1 -1
  120. package/dist/types/src/styles/invitationStatusStyles.d.ts +20 -0
  121. package/dist/types/src/styles/invitationStatusStyles.d.ts.map +1 -0
  122. package/dist/types/src/styles/panelStyles.d.ts +2 -1
  123. package/dist/types/src/styles/panelStyles.d.ts.map +1 -1
  124. package/dist/types/src/translations/locales/en-US.d.ts +52 -0
  125. package/dist/types/src/translations/locales/en-US.d.ts.map +1 -1
  126. package/dist/types/src/util/index.d.ts +2 -0
  127. package/dist/types/src/util/index.d.ts.map +1 -0
  128. package/dist/types/src/util/invitationStatusValue.d.ts +8 -0
  129. package/dist/types/src/util/invitationStatusValue.d.ts.map +1 -0
  130. package/package.json +19 -11
  131. package/src/components/IdentityList/DeviceList.tsx +31 -0
  132. package/src/components/{IdentityListItem → IdentityList}/IdentityListItem.stories.tsx +0 -0
  133. package/src/components/{IdentityListItem → IdentityList}/IdentityListItem.tsx +18 -5
  134. package/src/components/IdentityList/SpaceMemberList.tsx +33 -0
  135. package/src/components/IdentityList/SpaceMemberListContainer.tsx +28 -0
  136. package/src/components/IdentityList/index.ts +8 -0
  137. package/src/components/InvitationList/InvitationList.stories.tsx +65 -0
  138. package/src/components/InvitationList/InvitationList.tsx +28 -0
  139. package/src/components/InvitationList/InvitationListContainer.tsx +27 -0
  140. package/src/components/InvitationList/InvitationListItem.tsx +106 -0
  141. package/src/components/InvitationList/InvitationListProps.ts +7 -0
  142. package/src/components/InvitationList/InvitationStatusAvatar.stories.tsx +52 -0
  143. package/src/components/InvitationList/InvitationStatusAvatar.tsx +80 -0
  144. package/src/components/InvitationList/index.ts +8 -0
  145. package/src/components/PanelSeparator/PanelSeparator.tsx +17 -0
  146. package/src/components/PanelSeparator/index.ts +5 -0
  147. package/src/components/SpaceList/SpaceListItem.tsx +32 -0
  148. package/src/components/SpaceList/index.ts +5 -0
  149. package/src/components/index.ts +8 -0
  150. package/src/composites/DevicesDialog/DevicesDialog.tsx +38 -0
  151. package/src/composites/DevicesDialog/index.ts +5 -0
  152. package/src/composites/JoinDialog/JoinDialog.stories.tsx +81 -0
  153. package/src/composites/JoinDialog/JoinDialog.tsx +33 -0
  154. package/src/composites/JoinDialog/index.ts +5 -0
  155. package/src/composites/Shell/Shell.tsx +92 -0
  156. package/src/composites/Shell/index.ts +5 -0
  157. package/src/composites/SpaceDialog/SpaceDialog.tsx +38 -0
  158. package/src/composites/SpaceDialog/index.ts +5 -0
  159. package/src/composites/index.ts +4 -0
  160. package/src/index.ts +1 -0
  161. package/src/layouts/PanelAlertDialog/PanelAlertDialog.tsx +40 -0
  162. package/src/layouts/PanelAlertDialog/index.ts +5 -0
  163. package/src/layouts/PanelDialog/PanelDialog.tsx +39 -0
  164. package/src/layouts/PanelDialog/index.ts +5 -0
  165. package/src/layouts/PanelPopover/PanelPopover.tsx +2 -2
  166. package/src/layouts/PanelSidebar/PanelSidebar.tsx +27 -31
  167. package/src/layouts/index.ts +2 -0
  168. package/src/panels/DevicesPanel/DevicesPanel.tsx +98 -0
  169. package/src/panels/DevicesPanel/index.ts +5 -0
  170. package/src/panels/JoinPanel/JoinHeading.tsx +85 -0
  171. package/src/panels/JoinPanel/JoinPanel.tsx +319 -0
  172. package/src/panels/JoinPanel/JoinPanelProps.ts +90 -0
  173. package/src/panels/JoinPanel/index.ts +6 -0
  174. package/src/panels/JoinPanel/view-states/AdditionMethodSelector.tsx +73 -0
  175. package/src/panels/JoinPanel/view-states/IdentityAdded.tsx +99 -0
  176. package/src/panels/JoinPanel/view-states/IdentityInput.tsx +79 -0
  177. package/src/panels/JoinPanel/view-states/IdentitySelector.tsx +101 -0
  178. package/src/panels/JoinPanel/view-states/InvitationAccepted.tsx +70 -0
  179. package/src/panels/JoinPanel/view-states/InvitationAuthenticator.tsx +142 -0
  180. package/src/panels/JoinPanel/view-states/InvitationInput.tsx +75 -0
  181. package/src/panels/JoinPanel/view-states/InvitationRescuer.tsx +98 -0
  182. package/src/panels/JoinPanel/view-states/ViewState.tsx +204 -0
  183. package/src/panels/JoinPanel/view-states/index.ts +12 -0
  184. package/src/panels/SpacePanel/SpacePanel.stories.tsx +53 -0
  185. package/src/panels/SpacePanel/SpacePanel.tsx +174 -0
  186. package/src/panels/SpacePanel/index.ts +5 -0
  187. package/src/panels/index.ts +3 -0
  188. package/src/styles/dialogStyles.ts +8 -0
  189. package/src/styles/index.ts +2 -0
  190. package/src/styles/invitationStatusStyles.ts +42 -0
  191. package/src/styles/panelStyles.ts +2 -1
  192. package/src/testing/ClientProvider.tsx +1 -1
  193. package/src/translations/locales/en-US.ts +53 -1
  194. package/src/util/index.ts +5 -0
  195. package/src/util/invitationStatusValue.ts +21 -0
  196. package/theme-extensions.js +11 -0
  197. package/dist/types/src/components/IdentityListItem/IdentityListItem.d.ts +0 -6
  198. package/dist/types/src/components/IdentityListItem/IdentityListItem.d.ts.map +0 -1
  199. package/dist/types/src/components/IdentityListItem/IdentityListItem.stories.d.ts.map +0 -1
@@ -0,0 +1,81 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import '@dxosTheme';
6
+
7
+ import { StoryContext, StoryFn } from '@storybook/react';
8
+ import React, { useCallback, useMemo, useState } from 'react';
9
+
10
+ import { Client, Invitation, InvitationEncoder } from '@dxos/client';
11
+ import { TestBuilder } from '@dxos/client/testing';
12
+ import { log } from '@dxos/log';
13
+ import { useAsyncEffect } from '@dxos/react-async';
14
+ import { ClientProvider } from '@dxos/react-client';
15
+ import { Loading } from '@dxos/react-components';
16
+
17
+ import { JoinDialog } from './JoinDialog';
18
+
19
+ export default {
20
+ component: JoinDialog
21
+ };
22
+
23
+ const JoinClientDecorator = (Story: StoryFn, { args }: StoryContext) => {
24
+ const n = 2;
25
+ const testBuilder = new TestBuilder();
26
+ const clients = useMemo(() => {
27
+ return [...Array(n)].map(() => new Client({ services: testBuilder.createClientServicesHost() }));
28
+ }, []);
29
+
30
+ const [invitationCode, setInvitationCode] = useState<string>();
31
+
32
+ const onInvitationEvent = useCallback((invitation: Invitation) => {
33
+ if (!invitationCode) {
34
+ const nextInvitationCode = InvitationEncoder.encode(invitation);
35
+ log.info('[next invitation code]', { nextInvitationCode });
36
+ setInvitationCode(nextInvitationCode);
37
+ }
38
+ }, []);
39
+
40
+ useAsyncEffect(async () => {
41
+ await Promise.all(clients.map((client) => client.initialize()));
42
+ log.info('[initialized]');
43
+
44
+ await clients[0].halo.createProfile({ displayName: 'Os Mutantes' });
45
+
46
+ const space = await clients[0].echo.createSpace();
47
+ log.info('[space created]', space);
48
+ space.properties.name = 'Q3 2022 Planning';
49
+
50
+ const invitation = space.createInvitation({ type: Invitation.Type.INTERACTIVE });
51
+ log.info('[invitation created]', invitation);
52
+
53
+ invitation.subscribe({
54
+ onAuthenticating: onInvitationEvent,
55
+ onCancelled: (...args) => log.warn('[cancelled]', args),
56
+ onConnected: onInvitationEvent,
57
+ onConnecting: onInvitationEvent,
58
+ onError: onInvitationEvent,
59
+ onSuccess: onInvitationEvent,
60
+ onTimeout: (...args) => log.warn('[timeout]', args)
61
+ });
62
+
63
+ return () => {
64
+ void Promise.all(clients.map((client) => client.destroy()));
65
+ };
66
+ }, clients);
67
+
68
+ if (!invitationCode) {
69
+ return <Loading label='Setting things up…' />;
70
+ }
71
+
72
+ return (
73
+ <ClientProvider client={clients[1]} fallback={() => <Loading label='Loading client…' />}>
74
+ <Story args={{ initialInvitationCode: invitationCode, ...args }} />
75
+ </ClientProvider>
76
+ );
77
+ };
78
+
79
+ export const Default = {
80
+ decorators: [JoinClientDecorator]
81
+ };
@@ -0,0 +1,33 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { Action, Cancel } from '@radix-ui/react-alert-dialog';
6
+ import React from 'react';
7
+
8
+ import { ThemeContext, useId } from '@dxos/react-components';
9
+
10
+ import { PanelAlertDialog, PanelAlertDialogProps } from '../../layouts';
11
+ import { JoinPanel, JoinPanelProps } from '../../panels';
12
+
13
+ export interface JoinDialogProps
14
+ extends Omit<PanelAlertDialogProps, 'titleId' | 'children'>,
15
+ Omit<JoinPanelProps, 'exitActionParent' | 'doneActionParent'> {}
16
+
17
+ export const JoinDialog = ({ slots, ...joinPanelProps }: JoinDialogProps) => {
18
+ const titleId = useId('joinDialog__title');
19
+ return (
20
+ <PanelAlertDialog {...{ slots, titleId }}>
21
+ <ThemeContext.Provider value={{ themeVariant: 'os' }}>
22
+ <JoinPanel
23
+ {...{
24
+ ...joinPanelProps,
25
+ titleId,
26
+ exitActionParent: <Cancel asChild />,
27
+ doneActionParent: <Action asChild />
28
+ }}
29
+ />
30
+ </ThemeContext.Provider>
31
+ </PanelAlertDialog>
32
+ );
33
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './JoinDialog';
@@ -0,0 +1,92 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React, { useEffect, useState } from 'react';
6
+
7
+ import { ShellRuntime } from '@dxos/client';
8
+ import { LayoutRequest, ShellDisplay, ShellLayout } from '@dxos/protocols/proto/dxos/iframe';
9
+ import { useClient, useSpace, useSpaces } from '@dxos/react-client';
10
+
11
+ import { DevicesDialog } from '../DevicesDialog';
12
+ import { JoinDialog } from '../JoinDialog';
13
+ import { SpaceDialog } from '../SpaceDialog';
14
+
15
+ export const Shell = ({ runtime, origin }: { runtime: ShellRuntime; origin: string }) => {
16
+ const client = useClient();
17
+ const spaces = useSpaces();
18
+
19
+ const [{ layout, invitationCode, spaceKey }, setLayout] = useState<LayoutRequest>({
20
+ layout: runtime.layout,
21
+ invitationCode: runtime.invitationCode,
22
+ spaceKey: runtime.spaceKey
23
+ });
24
+ const space = useSpace(spaceKey);
25
+
26
+ useEffect(() => {
27
+ return runtime.layoutUpdate.on((request) => setLayout(request));
28
+ }, []);
29
+
30
+ switch (layout) {
31
+ case ShellLayout.AUTH:
32
+ return (
33
+ <JoinDialog
34
+ mode='halo-only'
35
+ initialInvitationCode={invitationCode}
36
+ onDone={async () => {
37
+ // TODO(wittjosiah): Is this app-specific?
38
+ const space = spaces[0] ?? (await client.echo.createSpace());
39
+ await runtime.setAppContext({ display: ShellDisplay.NONE, spaceKey: space.key });
40
+ runtime.setLayout(ShellLayout.DEFAULT);
41
+ }}
42
+ />
43
+ );
44
+
45
+ case ShellLayout.CURRENT_SPACE:
46
+ case ShellLayout.SPACE_LIST:
47
+ return (
48
+ <SpaceDialog
49
+ space={space}
50
+ initialState={layout === ShellLayout.SPACE_LIST ? 'space list' : 'current space'}
51
+ createInvitationUrl={(invitationCode) => `${origin}?spaceInvitationCode=${invitationCode}`}
52
+ onClickJoinSpace={() => runtime.setLayout(ShellLayout.JOIN_SPACE, { spaceKey: space?.key })}
53
+ onClickMember={() => runtime.setLayout(ShellLayout.DEVICES_LIST, { spaceKey: space?.key })}
54
+ onDone={async (space) => {
55
+ // TODO(wittjosiah): If space is newly created the app won't yet know about it.
56
+ // This is a bug that needs to be fixed when upgrading the space service.
57
+ await runtime.setAppContext({ display: ShellDisplay.NONE, spaceKey: space ? space.key : spaceKey });
58
+ runtime.setLayout(ShellLayout.DEFAULT);
59
+ }}
60
+ />
61
+ );
62
+
63
+ case ShellLayout.JOIN_SPACE:
64
+ return (
65
+ <JoinDialog
66
+ initialInvitationCode={invitationCode}
67
+ onDone={async (result) => {
68
+ await runtime.setAppContext({ display: ShellDisplay.NONE, spaceKey: result?.spaceKey ?? undefined });
69
+ runtime.setLayout(ShellLayout.DEFAULT);
70
+ }}
71
+ onExit={async () => {
72
+ await runtime.setAppContext({ display: ShellDisplay.NONE, spaceKey: runtime.spaceKey });
73
+ runtime.setLayout(ShellLayout.DEFAULT);
74
+ }}
75
+ />
76
+ );
77
+
78
+ case ShellLayout.DEVICES_LIST:
79
+ return (
80
+ <DevicesDialog
81
+ createInvitationUrl={(invitationCode) => `${origin}?haloInvitationCode=${invitationCode}`}
82
+ onDone={async () => {
83
+ await runtime.setAppContext({ display: ShellDisplay.NONE, spaceKey: runtime.spaceKey });
84
+ runtime.setLayout(ShellLayout.DEFAULT);
85
+ }}
86
+ />
87
+ );
88
+
89
+ default:
90
+ return null;
91
+ }
92
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './Shell';
@@ -0,0 +1,38 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { Close } from '@radix-ui/react-dialog';
6
+ import React from 'react';
7
+
8
+ import { ThemeContext, useId } from '@dxos/react-components';
9
+
10
+ import { PanelDialog, PanelDialogProps } from '../../layouts';
11
+ import { SpacePanel, SpacePanelProps } from '../../panels';
12
+
13
+ export interface SpaceDialogProps
14
+ extends Omit<PanelDialogProps, 'titleId' | 'children'>,
15
+ Omit<SpacePanelProps, 'doneActionParent'> {}
16
+
17
+ export const SpaceDialog = ({ slots, ...spacePanelProps }: SpaceDialogProps) => {
18
+ const titleId = useId('spaceDialog__title');
19
+
20
+ return (
21
+ <PanelDialog
22
+ {...{
23
+ slots: { ...slots, root: { onOpenChange: (open) => open || spacePanelProps.onDone?.(null), ...slots?.root } },
24
+ titleId
25
+ }}
26
+ >
27
+ <ThemeContext.Provider value={{ themeVariant: 'os' }}>
28
+ <SpacePanel
29
+ {...{
30
+ ...spacePanelProps,
31
+ titleId,
32
+ doneActionParent: <Close asChild />
33
+ }}
34
+ />
35
+ </ThemeContext.Provider>
36
+ </PanelDialog>
37
+ );
38
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './SpaceDialog';
@@ -1,4 +1,8 @@
1
1
  //
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
+
4
5
  export * from './IdentityPopover';
6
+ export * from './JoinDialog';
7
+ export * from './Shell';
8
+ export * from './SpaceDialog';
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
+ export * from './components';
5
6
  export * from './composites';
6
7
  export * from './layouts';
7
8
  export * from './panels';
@@ -0,0 +1,40 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import * as AlertDialog from '@radix-ui/react-alert-dialog';
6
+ import React, { ComponentPropsWithoutRef, PropsWithChildren } from 'react';
7
+
8
+ import { mx } from '@dxos/react-components';
9
+
10
+ import { defaultDialogContent, defaultOverlay } from '../../styles';
11
+
12
+ export interface PanelAlertDialogSlots {
13
+ root: ComponentPropsWithoutRef<typeof AlertDialog.Root>;
14
+ overlay: ComponentPropsWithoutRef<typeof AlertDialog.Overlay>;
15
+ content: ComponentPropsWithoutRef<typeof AlertDialog.Content>;
16
+ trigger: ComponentPropsWithoutRef<typeof AlertDialog.Trigger>;
17
+ }
18
+
19
+ export type PanelAlertDialogProps = PropsWithChildren<{
20
+ titleId: string;
21
+ slots?: Partial<PanelAlertDialogSlots>;
22
+ }>;
23
+
24
+ export const PanelAlertDialog = ({ titleId, slots = {}, children }: PanelAlertDialogProps) => {
25
+ return (
26
+ <AlertDialog.Root defaultOpen {...slots.root}>
27
+ {slots.trigger && <AlertDialog.Trigger {...slots.trigger} />}
28
+ <AlertDialog.Overlay {...slots.overlay} className={mx(defaultOverlay, 'z-40', slots.overlay?.className)}>
29
+ <AlertDialog.Content
30
+ onEscapeKeyDown={(event) => event.preventDefault()}
31
+ {...slots.content}
32
+ aria-labelledby={titleId}
33
+ className={mx(defaultDialogContent, slots.content?.className)}
34
+ >
35
+ {children}
36
+ </AlertDialog.Content>
37
+ </AlertDialog.Overlay>
38
+ </AlertDialog.Root>
39
+ );
40
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './PanelAlertDialog';
@@ -0,0 +1,39 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import * as Dialog from '@radix-ui/react-dialog';
6
+ import React, { ComponentPropsWithoutRef, PropsWithChildren } from 'react';
7
+
8
+ import { mx } from '@dxos/react-components';
9
+
10
+ import { defaultDialogContent, defaultOverlay } from '../../styles';
11
+
12
+ export interface PanelDialogSlots {
13
+ root: ComponentPropsWithoutRef<typeof Dialog.Root>;
14
+ overlay: ComponentPropsWithoutRef<typeof Dialog.Overlay>;
15
+ content: ComponentPropsWithoutRef<typeof Dialog.Content>;
16
+ trigger: ComponentPropsWithoutRef<typeof Dialog.Trigger>;
17
+ }
18
+
19
+ export type PanelDialogProps = PropsWithChildren<{
20
+ titleId: string;
21
+ slots?: Partial<PanelDialogSlots>;
22
+ }>;
23
+
24
+ export const PanelDialog = ({ titleId, slots = {}, children }: PanelDialogProps) => {
25
+ return (
26
+ <Dialog.Root defaultOpen {...slots.root}>
27
+ {slots.trigger && <Dialog.Trigger {...slots.trigger} />}
28
+ <Dialog.Overlay {...slots.overlay} className={mx(defaultOverlay, 'z-40', slots.overlay?.className)}>
29
+ <Dialog.Content
30
+ {...slots.content}
31
+ aria-labelledby={titleId}
32
+ className={mx(defaultDialogContent, slots.content?.className)}
33
+ >
34
+ {children}
35
+ </Dialog.Content>
36
+ </Dialog.Overlay>
37
+ </Dialog.Root>
38
+ );
39
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './PanelDialog';
@@ -6,7 +6,7 @@ import React, { ComponentProps } from 'react';
6
6
 
7
7
  import { mx, Popover } from '@dxos/react-components';
8
8
 
9
- import { defaultPanel, defaultArrow } from '../../styles';
9
+ import { defaultSurface, defaultArrow } from '../../styles';
10
10
 
11
11
  /**
12
12
  * This component essentially sets default styles for popovers which have panels as their content
@@ -24,7 +24,7 @@ export const PanelPopover = ({ slots, children, ...popoverProps }: ComponentProp
24
24
  collisionPadding: 8,
25
25
  sideOffset: 4,
26
26
  ...slots?.content,
27
- className: mx(defaultPanel, slots?.content?.className)
27
+ className: mx(defaultSurface, slots?.content?.className)
28
28
  },
29
29
  trigger: {
30
30
  ...slots?.trigger,
@@ -7,7 +7,6 @@ import React, {
7
7
  ComponentProps,
8
8
  createContext,
9
9
  Dispatch,
10
- Fragment,
11
10
  PropsWithChildren,
12
11
  SetStateAction,
13
12
  useCallback,
@@ -19,8 +18,6 @@ import { defaultOverlay, mx, useMediaQuery, useTranslation } from '@dxos/react-c
19
18
 
20
19
  export type PanelSidebarState = 'show' | 'hide';
21
20
 
22
- export const sidebarWidth = 272;
23
-
24
21
  export interface PanelSidebarContextValue {
25
22
  setDisplayState: Dispatch<SetStateAction<PanelSidebarState>>;
26
23
  displayState: PanelSidebarState;
@@ -39,9 +36,8 @@ export const useTogglePanelSidebar = () => {
39
36
  };
40
37
 
41
38
  export interface PanelSidebarProviderSlots {
42
- content?: ComponentProps<typeof Fragment>;
43
- fixedBlockStart?: ComponentProps<'div'>;
44
- fixedBlockEnd?: ComponentProps<'div'>;
39
+ content?: ComponentProps<typeof DialogPrimitive.Content>;
40
+ main?: ComponentProps<'div'>;
45
41
  }
46
42
 
47
43
  export interface PanelSidebarProviderProps {
@@ -51,20 +47,22 @@ export interface PanelSidebarProviderProps {
51
47
 
52
48
  export const PanelSidebarProvider = ({ children, slots }: PropsWithChildren<PanelSidebarProviderProps>) => {
53
49
  const { t } = useTranslation('os');
54
- const [displayState, setInternalDisplayState] = useState<PanelSidebarState>('hide');
55
- const [transitionShow, setTransitionShow] = useState(false);
50
+ const [isLg] = useMediaQuery('lg', { ssr: false });
51
+ const [displayState, setInternalDisplayState] = useState<PanelSidebarState>(isLg ? 'show' : 'hide');
56
52
  const isOpen = displayState === 'show';
57
-
58
- const [isLg] = useMediaQuery('lg');
53
+ const [transitionShow, setTransitionShow] = useState(isOpen);
54
+ const [domShow, setDomShow] = useState(isOpen);
59
55
 
60
56
  const internalHide = () => {
61
57
  setTransitionShow(false);
58
+ setInternalDisplayState('hide');
62
59
  setTimeout(() => {
63
- setInternalDisplayState('hide');
60
+ setDomShow(false);
64
61
  }, 200);
65
62
  };
66
63
 
67
64
  const internalShow = () => {
65
+ setDomShow(true);
68
66
  setInternalDisplayState('show');
69
67
  setTimeout(() => {
70
68
  setTransitionShow(true);
@@ -77,30 +75,24 @@ export const PanelSidebarProvider = ({ children, slots }: PropsWithChildren<Pane
77
75
 
78
76
  return (
79
77
  <PanelSidebarContext.Provider value={{ setDisplayState, displayState }}>
80
- <DialogPrimitive.Root open={isOpen} modal={!isLg}>
78
+ <DialogPrimitive.Root open={domShow} modal={!isLg}>
79
+ {/* Sidebar. */}
81
80
  <DialogPrimitive.Content
81
+ onOpenAutoFocus={(event) => isLg && event.preventDefault()}
82
+ onCloseAutoFocus={(event) => isLg && event.preventDefault()}
83
+ {...slots?.content}
82
84
  className={mx(
83
- 'fixed block-start-0 block-end-0 is-[272px] z-50 transition-[inset-inline-start,inset-inline-end] duration-200 ease-in-out',
84
- 'bg-neutral-50 dark:bg-neutral-950',
85
- transitionShow ? 'inline-start-0' : `inline-start-[-${sidebarWidth}px]`
85
+ 'fixed block-start-0 block-end-0 is-sidebar z-30 overscroll-contain overflow-x-hidden overflow-y-auto',
86
+ 'transition-[inset-inline-start,inset-inline-end] duration-200 ease-in-out',
87
+ transitionShow ? 'inline-start-0' : '-inline-start-sidebar',
88
+ slots?.content?.className
86
89
  )}
87
90
  >
88
91
  <DialogPrimitive.Title className='sr-only'>{t('sidebar label')}</DialogPrimitive.Title>
89
- <Fragment {...slots?.content} />
92
+ {slots?.content?.children}
90
93
  </DialogPrimitive.Content>
91
- {slots?.fixedBlockStart && (
92
- <div
93
- role='none'
94
- {...slots?.fixedBlockStart}
95
- className={mx(
96
- 'fixed inline-end-0 block-start-0 z-[49] transition-[inset-inline-start,inset-inline-end] duration-200 ease-in-out',
97
- transitionShow ? 'inline-start-[272px]' : 'inline-start-0',
98
- slots?.fixedBlockStart?.className
99
- )}
100
- >
101
- {slots?.fixedBlockStart?.children}
102
- </div>
103
- )}
94
+
95
+ {/* TODO(burdon): Simple comment required. */}
104
96
  {!isLg && (
105
97
  <DialogPrimitive.Overlay
106
98
  className={mx(
@@ -111,11 +103,15 @@ export const PanelSidebarProvider = ({ children, slots }: PropsWithChildren<Pane
111
103
  onClick={internalHide}
112
104
  />
113
105
  )}
106
+
107
+ {/* Main content. */}
114
108
  <div
115
109
  role='none'
110
+ {...slots?.main}
116
111
  className={mx(
117
- 'bs-full transition-[padding-inline-start] duration-200 ease-in-out',
118
- isLg && isOpen ? 'pis-[272px]' : 'pis-0'
112
+ 'transition-[padding-inline-start] duration-200 ease-in-out',
113
+ isLg && isOpen ? 'pis-sidebar' : 'pis-0',
114
+ slots?.main?.className
119
115
  )}
120
116
  >
121
117
  {children}
@@ -4,3 +4,5 @@
4
4
 
5
5
  export * from './PanelPopover';
6
6
  export * from './PanelSidebar';
7
+ export * from './PanelAlertDialog';
8
+ export * from './PanelDialog';
@@ -0,0 +1,98 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { UserPlus, X } from 'phosphor-react';
6
+ import React, { cloneElement, useReducer } from 'react';
7
+
8
+ import { useClient, useDevices, useHaloInvitations, useIdentity } from '@dxos/react-client';
9
+ import { Button, getSize, mx, Tooltip, useTranslation } from '@dxos/react-components';
10
+
11
+ import { DeviceList, InvitationList, PanelSeparator } from '../../components';
12
+ import { defaultSurface, subduedSurface } from '../../styles';
13
+
14
+ export type DevicesPanelProps = {
15
+ titleId?: string;
16
+ createInvitationUrl: (invitationCode: string) => string;
17
+ doneActionParent?: Parameters<typeof cloneElement>[0];
18
+ onDone?: () => void;
19
+ };
20
+
21
+ export type DevicesView = 'device list';
22
+
23
+ const DeviceListView = ({ createInvitationUrl, titleId, onDone, doneActionParent }: DevicesPanelProps) => {
24
+ const { t } = useTranslation('os');
25
+ const client = useClient();
26
+ const identity = useIdentity();
27
+ const devices = useDevices();
28
+ const invitations = useHaloInvitations();
29
+ const displayName = identity?.displayName;
30
+
31
+ if (!identity) {
32
+ return null;
33
+ }
34
+
35
+ const doneButton = (
36
+ <Button compact variant='ghost' onClick={() => onDone?.()} data-testid='show-all-spaces'>
37
+ <X className={getSize(4)} weight='bold' />
38
+ </Button>
39
+ );
40
+
41
+ return (
42
+ <div role='none' className='flex flex-col'>
43
+ <div role='none' className={mx(subduedSurface, 'rounded-bs-md flex items-center p-2 gap-2')}>
44
+ {/* TODO(wittjosiah): Label this as the identity panel. */}
45
+ <h2 id={titleId} className={mx('grow font-system-medium', !displayName && 'font-mono')}>
46
+ {displayName ?? identity.identityKey.truncate()}
47
+ </h2>
48
+ <Tooltip content={t('close label')} zIndex='z-50'>
49
+ {doneActionParent ? cloneElement(doneActionParent, {}, doneButton) : doneButton}
50
+ </Tooltip>
51
+ </div>
52
+ <div role='region' className={mx(defaultSurface, 'rounded-be-md p-2')}>
53
+ <InvitationList
54
+ invitations={invitations}
55
+ onClickRemove={({ invitation }) => invitation && client.halo.removeInvitation(invitation.invitationId!)}
56
+ createInvitationUrl={createInvitationUrl}
57
+ />
58
+ <Button
59
+ className='is-full flex gap-2 mbs-2'
60
+ compact
61
+ onClick={() => client.halo.createInvitation()}
62
+ data-testid='create-space-invitation'
63
+ >
64
+ <span>{t('create space invitation label')}</span>
65
+ <UserPlus className={getSize(4)} weight='bold' />
66
+ </Button>
67
+ <PanelSeparator />
68
+ <DeviceList devices={devices} />
69
+ </div>
70
+ </div>
71
+ );
72
+ };
73
+
74
+ type DevicesPanelState = {
75
+ activeView: DevicesView;
76
+ };
77
+
78
+ type DevicesPanelAction = {
79
+ type: null;
80
+ };
81
+
82
+ // TODO(wittjosiah): Rename identity panel and include other views?
83
+ export const DevicesPanel = (props: DevicesPanelProps) => {
84
+ const reducer = (state: DevicesPanelState, action: DevicesPanelAction) => {
85
+ const nextState = { ...state };
86
+ switch (action.type) {
87
+ case null:
88
+ }
89
+ return nextState;
90
+ };
91
+
92
+ const [panelState] = useReducer(reducer, {
93
+ activeView: 'device list'
94
+ });
95
+
96
+ // TODO(wittjosiah): Use ViewState or similar.
97
+ return <>{panelState.activeView === 'device list' ? <DeviceListView {...props} /> : null}</>;
98
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './DevicesPanel';