@dxos/shell 0.6.14-main.f49f251 → 0.6.14-staging.0f558a0

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 (90) hide show
  1. package/dist/bundle/shell.mjs +5152 -5049
  2. package/dist/bundle/shell.mjs.map +1 -1
  3. package/dist/bundle/shell.umd.js +57 -57
  4. package/dist/bundle/shell.umd.js.map +1 -1
  5. package/dist/bundle/style.css +1 -1
  6. package/dist/lib/browser/meta.json +1 -1
  7. package/dist/lib/browser/react.mjs +50 -53
  8. package/dist/lib/browser/react.mjs.map +3 -3
  9. package/dist/lib/browser/testing/index.mjs +3 -39
  10. package/dist/lib/browser/testing/index.mjs.map +4 -4
  11. package/dist/lib/node/chunk-Q7SFCCGT.cjs +33 -0
  12. package/dist/lib/node/chunk-Q7SFCCGT.cjs.map +7 -0
  13. package/dist/lib/node/meta.json +1 -0
  14. package/dist/lib/node/react.cjs +4760 -0
  15. package/dist/lib/node/react.cjs.map +7 -0
  16. package/dist/lib/node/react.css +7 -0
  17. package/dist/lib/node/react.css.map +7 -0
  18. package/dist/lib/node/testing/index.cjs +183 -0
  19. package/dist/lib/node/testing/index.cjs.map +7 -0
  20. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  21. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  22. package/dist/lib/node-esm/meta.json +1 -0
  23. package/dist/lib/node-esm/react.css +7 -0
  24. package/dist/lib/node-esm/react.css.map +7 -0
  25. package/dist/lib/node-esm/react.mjs +4806 -0
  26. package/dist/lib/node-esm/react.mjs.map +7 -0
  27. package/dist/lib/node-esm/testing/index.mjs +163 -0
  28. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  29. package/dist/types/src/components/DeviceList/DeviceListItem.d.ts.map +1 -1
  30. package/dist/types/src/components/DeviceList/DeviceListItem.js +4 -10
  31. package/dist/types/src/components/DeviceList/DeviceListItem.js.map +1 -1
  32. package/dist/types/src/components/IdentityList/SpaceMemberList.stories.js +2 -2
  33. package/dist/types/src/components/IdentityList/SpaceMemberList.stories.js.map +1 -1
  34. package/dist/types/src/components/InvitationList/InvitationList.stories.js +10 -10
  35. package/dist/types/src/components/InvitationList/InvitationList.stories.js.map +1 -1
  36. package/dist/types/src/components/Panel/Action.d.ts +2 -0
  37. package/dist/types/src/components/Panel/Action.d.ts.map +1 -1
  38. package/dist/types/src/components/Panel/Action.js +16 -14
  39. package/dist/types/src/components/Panel/Action.js.map +1 -1
  40. package/dist/types/src/panels/IdentityPanel/IdentityPanel.d.ts.map +1 -1
  41. package/dist/types/src/panels/IdentityPanel/IdentityPanel.js +13 -6
  42. package/dist/types/src/panels/IdentityPanel/IdentityPanel.js.map +1 -1
  43. package/dist/types/src/panels/IdentityPanel/IdentityPanelProps.d.ts +1 -0
  44. package/dist/types/src/panels/IdentityPanel/IdentityPanelProps.d.ts.map +1 -1
  45. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.d.ts.map +1 -1
  46. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.js +3 -3
  47. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.js.map +1 -1
  48. package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.d.ts.map +1 -1
  49. package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.js +5 -0
  50. package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.js.map +1 -1
  51. package/dist/types/src/panels/SpacePanel/SpacePanel.d.ts.map +1 -1
  52. package/dist/types/src/panels/SpacePanel/SpacePanel.js +2 -2
  53. package/dist/types/src/panels/SpacePanel/SpacePanel.js.map +1 -1
  54. package/dist/types/src/panels/SpacePanel/SpacePanel.stories.js +15 -15
  55. package/dist/types/src/panels/SpacePanel/SpacePanel.stories.js.map +1 -1
  56. package/dist/types/src/panels/SpacePanel/SpacePanelProps.d.ts +1 -0
  57. package/dist/types/src/panels/SpacePanel/SpacePanelProps.d.ts.map +1 -1
  58. package/dist/types/src/panels/SpacePanel/steps/SpaceManager.d.ts.map +1 -1
  59. package/dist/types/src/panels/SpacePanel/steps/SpaceManager.js +5 -3
  60. package/dist/types/src/panels/SpacePanel/steps/SpaceManager.js.map +1 -1
  61. package/dist/types/src/playwright/invitations-manager.d.ts +1 -2
  62. package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
  63. package/dist/types/src/playwright/invitations-manager.js +11 -4
  64. package/dist/types/src/playwright/invitations-manager.js.map +1 -1
  65. package/dist/types/src/playwright/invitations.spec.js +13 -9
  66. package/dist/types/src/playwright/invitations.spec.js.map +1 -1
  67. package/dist/types/src/testing/index.d.ts +0 -1
  68. package/dist/types/src/testing/index.d.ts.map +1 -1
  69. package/dist/types/src/testing/index.js +1 -1
  70. package/dist/types/src/testing/index.js.map +1 -1
  71. package/dist/types/src/testing/shell-manager.d.ts.map +1 -1
  72. package/dist/types/src/testing/shell-manager.js +2 -0
  73. package/dist/types/src/testing/shell-manager.js.map +1 -1
  74. package/package.json +38 -27
  75. package/src/components/DeviceList/DeviceListItem.tsx +38 -42
  76. package/src/components/IdentityList/SpaceMemberList.stories.tsx +1 -1
  77. package/src/components/InvitationList/InvitationList.stories.tsx +1 -1
  78. package/src/components/Panel/Action.tsx +40 -31
  79. package/src/panels/IdentityPanel/IdentityPanel.tsx +13 -3
  80. package/src/panels/IdentityPanel/IdentityPanelProps.ts +1 -0
  81. package/src/panels/IdentityPanel/steps/IdentityActionChooser.tsx +5 -3
  82. package/src/panels/IdentityPanel/useEdgeAgentsHandlers.ts +7 -0
  83. package/src/panels/SpacePanel/SpacePanel.stories.tsx +1 -1
  84. package/src/panels/SpacePanel/SpacePanel.tsx +2 -1
  85. package/src/panels/SpacePanel/SpacePanelProps.ts +1 -0
  86. package/src/panels/SpacePanel/steps/SpaceManager.tsx +5 -3
  87. package/src/playwright/invitations-manager.ts +10 -4
  88. package/src/playwright/invitations.spec.ts +14 -9
  89. package/src/testing/index.ts +2 -1
  90. package/src/testing/shell-manager.ts +2 -0
@@ -0,0 +1,4806 @@
1
+ import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
+ import {
3
+ __export
4
+ } from "./chunk-HSLMI22Q.mjs";
5
+
6
+ // packages/sdk/shell/src/components/AgentConfig.tsx
7
+ import { ArrowsClockwise, Database, Plus, Power } from "@phosphor-icons/react";
8
+ import React from "react";
9
+ import { Avatar, Button, Link, Tooltip, Trans, useTranslation } from "@dxos/react-ui";
10
+ import { descriptionText, getSize, mx, valenceColorText } from "@dxos/react-ui-theme";
11
+ var AgentConfig = ({ agentStatus, validationMessage, onAgentDestroy, onAgentCreate, onAgentRefresh }) => {
12
+ const { t } = useTranslation("os");
13
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h2", {
14
+ className: mx(descriptionText, "text-center mbs-4")
15
+ }, t("agent heading")), validationMessage && /* @__PURE__ */ React.createElement("p", {
16
+ role: "alert",
17
+ className: mx(valenceColorText("error"), "mlb-2")
18
+ }, validationMessage), agentStatus === "created" || agentStatus === "creating" || agentStatus === "getting" || agentStatus === "destroying" ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
19
+ role: "group",
20
+ className: "mlb-2 flex gap-2 items-center",
21
+ "aria-describedby": "devices-panel.create-agent.description"
22
+ }, /* @__PURE__ */ React.createElement(Avatar.Root, {
23
+ status: agentStatus === "created" ? "warning" : "inactive",
24
+ variant: "square"
25
+ }, /* @__PURE__ */ React.createElement(Avatar.Frame, {
26
+ classNames: "place-self-center"
27
+ }, /* @__PURE__ */ React.createElement(Database, {
28
+ weight: "duotone",
29
+ width: 24,
30
+ height: 24,
31
+ x: 8,
32
+ y: 8,
33
+ ...agentStatus !== "created" && {
34
+ className: "opacity-50"
35
+ }
36
+ })), /* @__PURE__ */ React.createElement(Avatar.Label, {
37
+ classNames: "flex-1 text-sm truncate"
38
+ }, t(agentStatus === "created" ? "agent requested label" : agentStatus === "creating" ? "creating agent label" : agentStatus === "destroying" ? "destroying agent label" : "getting agent label"))), agentStatus === "created" && /* @__PURE__ */ React.createElement(Tooltip.Root, null, /* @__PURE__ */ React.createElement(Tooltip.Trigger, {
39
+ asChild: true
40
+ }, /* @__PURE__ */ React.createElement(Button, {
41
+ variant: "ghost",
42
+ classNames: "pli-0 is-[--rail-action] bs-[--rail-action]",
43
+ "data-testid": "agent.destroy",
44
+ onClick: onAgentDestroy
45
+ }, /* @__PURE__ */ React.createElement("span", {
46
+ className: "sr-only"
47
+ }, t("destroy agent label")), /* @__PURE__ */ React.createElement(Power, {
48
+ className: getSize(5)
49
+ }))), /* @__PURE__ */ React.createElement(Tooltip.Portal, null, /* @__PURE__ */ React.createElement(Tooltip.Content, {
50
+ side: "bottom",
51
+ classNames: "z-50"
52
+ }, t("destroy agent label"))))), agentStatus === "created" && /* @__PURE__ */ React.createElement("p", {
53
+ id: "devices-panel.create-agent.description",
54
+ className: mx(descriptionText, "mlb-2")
55
+ }, t("agent requested description"))) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Button, {
56
+ variant: "ghost",
57
+ classNames: "mlb-2 is-full justify-start gap-2 !pis-0 !pie-3",
58
+ "data-testid": agentStatus === "creatable" ? "devices-panel.create-agent" : "devices-panel.agent-error",
59
+ onClick: agentStatus === "creatable" ? onAgentCreate : onAgentRefresh,
60
+ "aria-describedby": "devices-panel.create-agent.description"
61
+ }, /* @__PURE__ */ React.createElement("div", {
62
+ role: "img",
63
+ className: mx(getSize(8), "m-1 rounded-sm bg-input grid place-items-center")
64
+ }, agentStatus === "creatable" ? /* @__PURE__ */ React.createElement(Plus, {
65
+ weight: "light",
66
+ className: getSize(6)
67
+ }) : /* @__PURE__ */ React.createElement(ArrowsClockwise, {
68
+ weight: "light",
69
+ className: getSize(6)
70
+ })), /* @__PURE__ */ React.createElement("span", {
71
+ className: "grow font-medium text-start"
72
+ }, t(agentStatus === "creatable" ? "create agent label" : ""))), agentStatus === "creatable" && /* @__PURE__ */ React.createElement("div", {
73
+ role: "none",
74
+ className: "space-y-2",
75
+ id: "devices-panel.create-agent.description"
76
+ }, /* @__PURE__ */ React.createElement("p", {
77
+ className: descriptionText
78
+ }, /* @__PURE__ */ React.createElement(Trans, {
79
+ t,
80
+ i18nKey: "create agent clickwrap",
81
+ components: {
82
+ tosLink: /* @__PURE__ */ React.createElement(Link, {
83
+ target: "_blank",
84
+ rel: "noreferrer"
85
+ })
86
+ }
87
+ })), /* @__PURE__ */ React.createElement("p", {
88
+ className: descriptionText
89
+ }, t("create agent description")))));
90
+ };
91
+
92
+ // packages/sdk/shell/src/components/Clipboard/CopyButton.tsx
93
+ import { Check, Copy } from "@phosphor-icons/react";
94
+ import React3, { useState as useState2 } from "react";
95
+ import { Button as Button2, Tooltip as Tooltip2, useTranslation as useTranslation2 } from "@dxos/react-ui";
96
+ import { getSize as getSize2, mx as mx2 } from "@dxos/react-ui-theme";
97
+
98
+ // packages/sdk/shell/src/components/Clipboard/ClipboardProvider.tsx
99
+ import React2, { createContext, useCallback, useContext, useState } from "react";
100
+ var ClipboardContext = /* @__PURE__ */ createContext({
101
+ textValue: "",
102
+ setTextValue: async (_) => {
103
+ }
104
+ });
105
+ var useClipboardContext = () => useContext(ClipboardContext);
106
+ var ClipboardProvider = ({ children }) => {
107
+ const [textValue, setInternalTextValue] = useState("");
108
+ const setTextValue = useCallback(async (nextValue) => {
109
+ await navigator.clipboard.writeText(nextValue);
110
+ return setInternalTextValue(nextValue);
111
+ }, []);
112
+ return /* @__PURE__ */ React2.createElement(ClipboardContext.Provider, {
113
+ value: {
114
+ textValue,
115
+ setTextValue
116
+ }
117
+ }, children);
118
+ };
119
+
120
+ // packages/sdk/shell/src/components/Clipboard/CopyButton.tsx
121
+ var inactiveLabelStyles = "invisible bs-px -mbe-px overflow-hidden";
122
+ var CopyButton = ({ value, classNames, iconProps: iconProps2, ...props }) => {
123
+ const { t } = useTranslation2("os");
124
+ const { textValue, setTextValue } = useClipboardContext();
125
+ const isCopied = textValue === value;
126
+ return /* @__PURE__ */ React3.createElement(Button2, {
127
+ ...props,
128
+ classNames: [
129
+ "inline-flex flex-col justify-center",
130
+ classNames
131
+ ],
132
+ onClick: () => setTextValue(value),
133
+ "data-testid": "copy-invitation"
134
+ }, /* @__PURE__ */ React3.createElement("div", {
135
+ role: "none",
136
+ className: mx2("flex gap-1 items-center", isCopied && inactiveLabelStyles)
137
+ }, /* @__PURE__ */ React3.createElement("span", {
138
+ className: "pli-1"
139
+ }, t("copy invitation code label")), /* @__PURE__ */ React3.createElement(Copy, {
140
+ className: getSize2(5),
141
+ ...iconProps2
142
+ })), /* @__PURE__ */ React3.createElement("div", {
143
+ role: "none",
144
+ className: mx2("flex gap-1 items-center", !isCopied && inactiveLabelStyles)
145
+ }, /* @__PURE__ */ React3.createElement("span", {
146
+ className: "pli-1"
147
+ }, t("copy success label")), /* @__PURE__ */ React3.createElement(Check, {
148
+ className: getSize2(5),
149
+ ...iconProps2
150
+ })));
151
+ };
152
+ var CopyButtonIconOnly = ({ value, classNames, iconProps: iconProps2, variant, ...props }) => {
153
+ const { t } = useTranslation2("os");
154
+ const { textValue, setTextValue } = useClipboardContext();
155
+ const isCopied = textValue === value;
156
+ const label = isCopied ? t("copy success label") : t("copy invitation code label");
157
+ const [open, setOpen] = useState2(false);
158
+ return /* @__PURE__ */ React3.createElement(Tooltip2.Root, {
159
+ delayDuration: 1500,
160
+ open,
161
+ onOpenChange: setOpen
162
+ }, /* @__PURE__ */ React3.createElement(Tooltip2.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip2.Content, {
163
+ side: "bottom",
164
+ sideOffset: 12,
165
+ classNames: "z-30"
166
+ }, /* @__PURE__ */ React3.createElement("span", null, label), /* @__PURE__ */ React3.createElement(Tooltip2.Arrow, null))), /* @__PURE__ */ React3.createElement(Tooltip2.Trigger, {
167
+ "aria-label": label,
168
+ ...props,
169
+ onClick: () => setTextValue(value).then(() => setOpen(true)),
170
+ "data-testid": "copy-invitation",
171
+ asChild: true
172
+ }, /* @__PURE__ */ React3.createElement(Button2, {
173
+ variant,
174
+ classNames: [
175
+ "inline-flex flex-col justify-center",
176
+ classNames
177
+ ]
178
+ }, /* @__PURE__ */ React3.createElement(Copy, {
179
+ className: getSize2(5),
180
+ ...iconProps2
181
+ }))));
182
+ };
183
+
184
+ // packages/sdk/shell/src/components/CompoundButton/CompoundButton.tsx
185
+ import React4 from "react";
186
+ import { useId, useThemeContext, useElevationContext } from "@dxos/react-ui";
187
+ import { descriptionText as descriptionText2, descriptionTextPrimary, mx as mx3 } from "@dxos/react-ui-theme";
188
+ var CompoundButton = ({ children, description, before, after, variant = "default", elevation: propsElevation, slots = {}, ...buttonProps }) => {
189
+ const labelId = useId("compoundButton-label");
190
+ const descriptionId = useId("compoundButton-description");
191
+ const { tx } = useThemeContext();
192
+ const elevation = useElevationContext(propsElevation);
193
+ const styleProps = {
194
+ ...buttonProps,
195
+ variant,
196
+ elevation,
197
+ textWrap: true
198
+ };
199
+ const buttonClassName = tx("button.root", "button button--compound", styleProps, "flex items-center gap-4 plb-2.5", slots.root?.className);
200
+ return /* @__PURE__ */ React4.createElement("button", {
201
+ ...buttonProps,
202
+ ...slots.root,
203
+ className: buttonClassName,
204
+ "aria-labelledby": labelId,
205
+ ...description && {
206
+ "aria-describedby": descriptionId
207
+ }
208
+ }, before && /* @__PURE__ */ React4.createElement("div", {
209
+ role: "none",
210
+ className: "grow-0"
211
+ }, before), /* @__PURE__ */ React4.createElement("div", {
212
+ role: "none",
213
+ ...slots.middle,
214
+ className: mx3("grow whitespace-normal flex flex-col gap-1 text-left", slots.middle?.className)
215
+ }, /* @__PURE__ */ React4.createElement("p", {
216
+ ...slots.label,
217
+ id: labelId,
218
+ className: mx3(slots.label?.className)
219
+ }, children), description && /* @__PURE__ */ React4.createElement("p", {
220
+ id: descriptionId,
221
+ ...slots.description,
222
+ className: mx3("text-xs mbe-1 font-normal", variant === "primary" ? descriptionTextPrimary : descriptionText2, slots.description?.className)
223
+ }, description)), after && /* @__PURE__ */ React4.createElement("div", {
224
+ role: "none",
225
+ className: "grow-0"
226
+ }, after));
227
+ };
228
+
229
+ // packages/sdk/shell/src/components/EmojiPicker.tsx
230
+ import emojiData from "@emoji-mart/data";
231
+ import EmojiMart from "@emoji-mart/react";
232
+ import { ArrowCounterClockwise, CaretDown, UserCircle } from "@phosphor-icons/react";
233
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
234
+ import React5, { useRef, useState as useState3 } from "react";
235
+ import { Button as Button3, Popover, Toolbar, Tooltip as Tooltip3, useMediaQuery, useThemeContext as useThemeContext2, useTranslation as useTranslation3 } from "@dxos/react-ui";
236
+ import { getSize as getSize3 } from "@dxos/react-ui-theme";
237
+ var EmojiPickerToolbarButton = ({ disabled, defaultEmoji, emoji, onChangeEmoji, classNames }) => {
238
+ const { t } = useTranslation3("os");
239
+ const { themeMode } = useThemeContext2();
240
+ const [_emojiValue, setEmojiValue] = useControllableState({
241
+ prop: emoji,
242
+ onChange: onChangeEmoji,
243
+ defaultProp: defaultEmoji
244
+ });
245
+ const [emojiPickerOpen, setEmojiPickerOpen] = useState3(false);
246
+ const suppressNextTooltip = useRef(false);
247
+ const [triggerTooltipOpen, setTriggerTooltipOpen] = useState3(false);
248
+ return /* @__PURE__ */ React5.createElement(Tooltip3.Root, {
249
+ open: triggerTooltipOpen,
250
+ onOpenChange: (nextOpen) => {
251
+ if (suppressNextTooltip.current) {
252
+ setTriggerTooltipOpen(false);
253
+ suppressNextTooltip.current = false;
254
+ } else {
255
+ setTriggerTooltipOpen(nextOpen);
256
+ }
257
+ }
258
+ }, /* @__PURE__ */ React5.createElement(Popover.Root, {
259
+ open: emojiPickerOpen,
260
+ onOpenChange: (nextOpen) => {
261
+ setEmojiPickerOpen(nextOpen);
262
+ suppressNextTooltip.current = true;
263
+ }
264
+ }, /* @__PURE__ */ React5.createElement(Tooltip3.Trigger, {
265
+ asChild: true
266
+ }, /* @__PURE__ */ React5.createElement(Popover.Trigger, {
267
+ asChild: true
268
+ }, /* @__PURE__ */ React5.createElement(Toolbar.Button, {
269
+ classNames: [
270
+ "gap-2 text-2xl plb-1",
271
+ classNames
272
+ ],
273
+ disabled
274
+ }, /* @__PURE__ */ React5.createElement("span", {
275
+ className: "sr-only"
276
+ }, t("select emoji label")), /* @__PURE__ */ React5.createElement(UserCircle, {
277
+ className: getSize3(5)
278
+ })))), /* @__PURE__ */ React5.createElement(Tooltip3.Portal, null, /* @__PURE__ */ React5.createElement(Tooltip3.Content, {
279
+ side: "bottom",
280
+ classNames: "z-50"
281
+ }, t("select emoji label"), /* @__PURE__ */ React5.createElement(Tooltip3.Arrow, null))), /* @__PURE__ */ React5.createElement(Popover.Content, {
282
+ side: "bottom",
283
+ onKeyDownCapture: (event) => {
284
+ if (event.key === "Escape") {
285
+ event.stopPropagation();
286
+ setEmojiPickerOpen(false);
287
+ suppressNextTooltip.current = true;
288
+ }
289
+ }
290
+ }, /* @__PURE__ */ React5.createElement(EmojiMart, {
291
+ data: emojiData,
292
+ onEmojiSelect: ({ native }) => {
293
+ if (native) {
294
+ setEmojiValue(native);
295
+ setEmojiPickerOpen(false);
296
+ }
297
+ },
298
+ autoFocus: true,
299
+ maxFrequentRows: 0,
300
+ noCountryFlags: true,
301
+ theme: themeMode
302
+ }), /* @__PURE__ */ React5.createElement(Popover.Arrow, null))));
303
+ };
304
+ var EmojiPickerBlock = ({ disabled, defaultEmoji, emoji, onChangeEmoji, onClickClear }) => {
305
+ const { t } = useTranslation3("os");
306
+ const [isMd] = useMediaQuery("md", {
307
+ ssr: false
308
+ });
309
+ const [emojiValue, setEmojiValue] = useControllableState({
310
+ prop: emoji,
311
+ onChange: onChangeEmoji,
312
+ defaultProp: defaultEmoji
313
+ });
314
+ const [emojiPickerOpen, setEmojiPickerOpen] = useState3(false);
315
+ return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Popover.Root, {
316
+ open: emojiPickerOpen,
317
+ onOpenChange: setEmojiPickerOpen
318
+ }, /* @__PURE__ */ React5.createElement(Popover.Trigger, {
319
+ asChild: true
320
+ }, /* @__PURE__ */ React5.createElement(Button3, {
321
+ variant: "ghost",
322
+ classNames: "gap-2 text-2xl plb-1",
323
+ disabled
324
+ }, /* @__PURE__ */ React5.createElement("span", {
325
+ className: "sr-only"
326
+ }, t("select emoji label")), /* @__PURE__ */ React5.createElement("span", {
327
+ className: "grow pis-14"
328
+ }, emojiValue), /* @__PURE__ */ React5.createElement(CaretDown, {
329
+ className: getSize3(4)
330
+ }))), /* @__PURE__ */ React5.createElement(Popover.Content, {
331
+ side: "right",
332
+ sideOffset: isMd ? 0 : -310,
333
+ onKeyDownCapture: (event) => {
334
+ if (event.key === "Escape") {
335
+ event.stopPropagation();
336
+ setEmojiPickerOpen(false);
337
+ }
338
+ }
339
+ }, /* @__PURE__ */ React5.createElement(EmojiMart, {
340
+ data: emojiData,
341
+ onEmojiSelect: ({ native }) => {
342
+ if (native) {
343
+ setEmojiValue(native);
344
+ setEmojiPickerOpen(false);
345
+ }
346
+ },
347
+ autoFocus: true,
348
+ maxFrequentRows: 0,
349
+ noCountryFlags: true
350
+ }), /* @__PURE__ */ React5.createElement(Popover.Arrow, null))), /* @__PURE__ */ React5.createElement(Tooltip3.Root, null, /* @__PURE__ */ React5.createElement(Tooltip3.Trigger, {
351
+ asChild: true
352
+ }, /* @__PURE__ */ React5.createElement(Button3, {
353
+ variant: "ghost",
354
+ onClick: onClickClear,
355
+ disabled
356
+ }, /* @__PURE__ */ React5.createElement("span", {
357
+ className: "sr-only"
358
+ }, t("clear label")), /* @__PURE__ */ React5.createElement(ArrowCounterClockwise, null))), /* @__PURE__ */ React5.createElement(Tooltip3.Portal, null, /* @__PURE__ */ React5.createElement(Tooltip3.Content, {
359
+ style: {
360
+ zIndex: 70
361
+ },
362
+ side: "right"
363
+ }, t("clear label"), /* @__PURE__ */ React5.createElement(Tooltip3.Arrow, null)))));
364
+ };
365
+
366
+ // packages/sdk/shell/src/components/HuePicker.tsx
367
+ import { ArrowCounterClockwise as ArrowCounterClockwise2, CaretDown as CaretDown2, Check as Check2, Palette } from "@phosphor-icons/react";
368
+ import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
369
+ import React6, { useRef as useRef2, useState as useState4 } from "react";
370
+ import { Button as Button4, DropdownMenu, Toolbar as Toolbar2, Tooltip as Tooltip4, useThemeContext as useThemeContext3, useTranslation as useTranslation4 } from "@dxos/react-ui";
371
+ import { getSize as getSize4, hueTokenThemes, mx as mx4 } from "@dxos/react-ui-theme";
372
+ var HuePreview = ({ hue }) => {
373
+ const { tx } = useThemeContext3();
374
+ const size = 20;
375
+ return /* @__PURE__ */ React6.createElement("svg", {
376
+ width: size,
377
+ height: size,
378
+ viewBox: `0 0 ${size} ${size}`
379
+ }, /* @__PURE__ */ React6.createElement("rect", {
380
+ x: 0,
381
+ y: 0,
382
+ width: size,
383
+ height: size,
384
+ className: tx("hue.fill", "select--hue__preview", {
385
+ hue
386
+ })
387
+ }));
388
+ };
389
+ var hueTokens = Object.keys(hueTokenThemes).slice(0, 16);
390
+ var HuePickerToolbarButton = ({ disabled, hue, onChangeHue, classNames, defaultHue }) => {
391
+ const { t } = useTranslation4("os");
392
+ const [hueValue, setHueValue] = useControllableState2({
393
+ prop: hue,
394
+ onChange: onChangeHue,
395
+ defaultProp: defaultHue
396
+ });
397
+ const [huePickerOpen, setHuePickerOpen] = useState4(false);
398
+ const suppressNextTooltip = useRef2(false);
399
+ const [triggerTooltipOpen, setTriggerTooltipOpen] = useState4(false);
400
+ return /* @__PURE__ */ React6.createElement(Tooltip4.Root, {
401
+ open: triggerTooltipOpen,
402
+ onOpenChange: (nextOpen) => {
403
+ if (suppressNextTooltip.current) {
404
+ setTriggerTooltipOpen(false);
405
+ suppressNextTooltip.current = false;
406
+ } else {
407
+ setTriggerTooltipOpen(nextOpen);
408
+ }
409
+ }
410
+ }, /* @__PURE__ */ React6.createElement(DropdownMenu.Root, {
411
+ modal: false,
412
+ open: huePickerOpen,
413
+ onOpenChange: (nextOpen) => {
414
+ setHuePickerOpen(nextOpen);
415
+ suppressNextTooltip.current = true;
416
+ }
417
+ }, /* @__PURE__ */ React6.createElement(Tooltip4.Trigger, {
418
+ asChild: true
419
+ }, /* @__PURE__ */ React6.createElement(DropdownMenu.Trigger, {
420
+ asChild: true
421
+ }, /* @__PURE__ */ React6.createElement(Toolbar2.Button, {
422
+ classNames: mx4("gap-2 plb-1", classNames),
423
+ disabled
424
+ }, /* @__PURE__ */ React6.createElement("span", {
425
+ className: "sr-only"
426
+ }, t("select hue label")), /* @__PURE__ */ React6.createElement(Palette, {
427
+ className: getSize4(5)
428
+ })))), /* @__PURE__ */ React6.createElement(Tooltip4.Portal, null, /* @__PURE__ */ React6.createElement(Tooltip4.Content, {
429
+ side: "bottom",
430
+ classNames: "z-50"
431
+ }, t("select hue label"), /* @__PURE__ */ React6.createElement(Tooltip4.Arrow, null))), /* @__PURE__ */ React6.createElement(DropdownMenu.Content, {
432
+ side: "bottom",
433
+ classNames: "!w-40"
434
+ }, /* @__PURE__ */ React6.createElement(DropdownMenu.Viewport, {
435
+ classNames: "grid grid-cols-4"
436
+ }, hueTokens.map((hue2) => {
437
+ return /* @__PURE__ */ React6.createElement(DropdownMenu.CheckboxItem, {
438
+ key: hue2,
439
+ checked: hue2 === hueValue,
440
+ onCheckedChange: () => setHueValue(hue2),
441
+ classNames: "px-0 py-2 items-center justify-center"
442
+ }, /* @__PURE__ */ React6.createElement(HuePreview, {
443
+ hue: hue2
444
+ }));
445
+ })))));
446
+ };
447
+ var HuePickerBlock = ({ disabled, hue, onChangeHue, defaultHue, onClickClear }) => {
448
+ const { t } = useTranslation4("os");
449
+ const [hueValue, setHueValue] = useControllableState2({
450
+ prop: hue,
451
+ onChange: onChangeHue,
452
+ defaultProp: defaultHue
453
+ });
454
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(DropdownMenu.Root, {
455
+ modal: false
456
+ }, /* @__PURE__ */ React6.createElement(DropdownMenu.Trigger, {
457
+ asChild: true
458
+ }, /* @__PURE__ */ React6.createElement(Button4, {
459
+ variant: "ghost",
460
+ classNames: "gap-2 plb-1",
461
+ disabled
462
+ }, /* @__PURE__ */ React6.createElement("span", {
463
+ className: "sr-only"
464
+ }, t("select hue label")), /* @__PURE__ */ React6.createElement("div", {
465
+ role: "none",
466
+ className: "pis-14 grow flex items-center justify-center gap-2"
467
+ }, /* @__PURE__ */ React6.createElement(HuePreview, {
468
+ hue: hueValue
469
+ }), /* @__PURE__ */ React6.createElement("span", null, t(`${hueValue} label`))), /* @__PURE__ */ React6.createElement(CaretDown2, {
470
+ className: getSize4(4)
471
+ }))), /* @__PURE__ */ React6.createElement(DropdownMenu.Content, {
472
+ side: "right"
473
+ }, /* @__PURE__ */ React6.createElement(DropdownMenu.Viewport, null, Object.keys(hueTokenThemes).map((hue2) => {
474
+ return /* @__PURE__ */ React6.createElement(DropdownMenu.CheckboxItem, {
475
+ key: hue2,
476
+ checked: hue2 === hueValue,
477
+ onCheckedChange: () => setHueValue(hue2)
478
+ }, /* @__PURE__ */ React6.createElement(HuePreview, {
479
+ hue: hue2
480
+ }), /* @__PURE__ */ React6.createElement("span", {
481
+ className: "grow"
482
+ }, t(`${hue2} label`)), /* @__PURE__ */ React6.createElement(DropdownMenu.ItemIndicator, null, /* @__PURE__ */ React6.createElement(Check2, null)));
483
+ })), /* @__PURE__ */ React6.createElement(DropdownMenu.Arrow, null))), /* @__PURE__ */ React6.createElement(Tooltip4.Root, null, /* @__PURE__ */ React6.createElement(Tooltip4.Trigger, {
484
+ asChild: true
485
+ }, /* @__PURE__ */ React6.createElement(Button4, {
486
+ variant: "ghost",
487
+ onClick: onClickClear,
488
+ disabled
489
+ }, /* @__PURE__ */ React6.createElement("span", {
490
+ className: "sr-only"
491
+ }, t("clear label")), /* @__PURE__ */ React6.createElement(ArrowCounterClockwise2, null))), /* @__PURE__ */ React6.createElement(Tooltip4.Portal, null, /* @__PURE__ */ React6.createElement(Tooltip4.Content, {
492
+ style: {
493
+ zIndex: 70
494
+ },
495
+ side: "right"
496
+ }, t("clear label"), /* @__PURE__ */ React6.createElement(Tooltip4.Arrow, null)))));
497
+ };
498
+
499
+ // packages/sdk/shell/src/components/IdentityList/IdentityListItem.tsx
500
+ import React7, { forwardRef } from "react";
501
+ import { generateName } from "@dxos/display-name";
502
+ import { SpaceMember } from "@dxos/react-client/echo";
503
+ import { ListItem, Avatar as Avatar2, useId as useId2 } from "@dxos/react-ui";
504
+ import { mx as mx5 } from "@dxos/react-ui-theme";
505
+ import { keyToFallback } from "@dxos/util";
506
+ var IdentityListItem = /* @__PURE__ */ forwardRef(({ identity, presence, onClick, classNames, ...props }, forwardedRef) => {
507
+ const fallbackValue = keyToFallback(identity.identityKey);
508
+ const labelId = useId2("identityListItem__label");
509
+ const displayName = identity.profile?.displayName ?? generateName(identity.identityKey.toHex());
510
+ return /* @__PURE__ */ React7.createElement(ListItem.Root, {
511
+ ...props,
512
+ classNames: mx5("flex gap-2 pis-3 pie-1 items-center", onClick && "cursor-pointer", classNames),
513
+ onClick: () => onClick?.(),
514
+ "data-testid": "identity-list-item",
515
+ labelId,
516
+ ref: forwardedRef
517
+ }, /* @__PURE__ */ React7.createElement(Avatar2.Root, {
518
+ status: presence === SpaceMember.PresenceState.ONLINE ? "active" : "inactive",
519
+ labelId,
520
+ hue: identity.profile?.data?.hue || fallbackValue.hue
521
+ }, /* @__PURE__ */ React7.createElement(Avatar2.Frame, {
522
+ classNames: "place-self-center"
523
+ }, /* @__PURE__ */ React7.createElement(Avatar2.Fallback, {
524
+ text: identity.profile?.data?.emoji || fallbackValue.emoji
525
+ })), /* @__PURE__ */ React7.createElement(Avatar2.Label, {
526
+ classNames: "text-sm truncate pli-2"
527
+ }, displayName)));
528
+ });
529
+
530
+ // packages/sdk/shell/src/components/IdentityList/SpaceMemberList.tsx
531
+ import React8, { useMemo } from "react";
532
+ import { useClient } from "@dxos/react-client";
533
+ import { useMembers } from "@dxos/react-client/echo";
534
+ import { useTranslation as useTranslation5, List } from "@dxos/react-ui";
535
+ import { descriptionText as descriptionText3, mx as mx6 } from "@dxos/react-ui-theme";
536
+ var SpaceMemberList = ({ spaceKey, includeSelf, onSelect }) => {
537
+ const client = useClient();
538
+ const allUnsortedMembers = useMembers(spaceKey);
539
+ const members = useMemo(() => includeSelf ? allUnsortedMembers.sort((member) => member.identity.identityKey.equals(client.halo.identity.get().identityKey) ? -1 : 1) : allUnsortedMembers.filter((member) => !member.identity.identityKey.equals(client.halo.identity.get().identityKey)), [
540
+ allUnsortedMembers
541
+ ]);
542
+ return /* @__PURE__ */ React8.createElement(SpaceMemberListImpl, {
543
+ members,
544
+ onSelect
545
+ });
546
+ };
547
+ var SpaceMemberListImpl = ({ members, onSelect }) => {
548
+ const { t } = useTranslation5("os");
549
+ const visibleMembers = members.filter((member) => member.identity);
550
+ return visibleMembers.length > 0 ? /* @__PURE__ */ React8.createElement(List, {
551
+ classNames: "flex flex-col gap-2",
552
+ "data-testid": "space-members-list"
553
+ }, visibleMembers.map((member) => {
554
+ return /* @__PURE__ */ React8.createElement(IdentityListItem, {
555
+ key: member.identity.identityKey.toHex(),
556
+ identity: member.identity,
557
+ presence: member.presence,
558
+ onClick: onSelect && (() => onSelect(member))
559
+ });
560
+ })) : /* @__PURE__ */ React8.createElement("div", {
561
+ role: "none",
562
+ className: "grow flex items-center p-2"
563
+ }, /* @__PURE__ */ React8.createElement("p", {
564
+ className: mx6(descriptionText3, "text-center is-full mlb-2")
565
+ }, t("empty space members message")));
566
+ };
567
+
568
+ // packages/sdk/shell/src/components/DeviceList/DeviceList.tsx
569
+ import { CaretRight, Plus as Plus2 } from "@phosphor-icons/react";
570
+ import React10 from "react";
571
+ import { Button as Button6, List as List2, useTranslation as useTranslation7 } from "@dxos/react-ui";
572
+ import { descriptionText as descriptionText4, getSize as getSize6, mx as mx7 } from "@dxos/react-ui-theme";
573
+
574
+ // packages/sdk/shell/src/components/DeviceList/DeviceListItem.tsx
575
+ import { Compass, Desktop, DeviceMobile, Devices, DotsThree, ShareFat, Power as Power2, Robot, Database as Database2, FirstAidKit } from "@phosphor-icons/react";
576
+ import React9, { forwardRef as forwardRef2 } from "react";
577
+ import { generateName as generateName2 } from "@dxos/display-name";
578
+ import { Device, DeviceType, DeviceKind } from "@dxos/react-client/halo";
579
+ import { ConnectionState } from "@dxos/react-client/mesh";
580
+ import { ListItem as ListItem2, Avatar as Avatar3, useId as useId3, Tag, useTranslation as useTranslation6, DropdownMenu as DropdownMenu2, Button as Button5 } from "@dxos/react-ui";
581
+ import { getSize as getSize5 } from "@dxos/react-ui-theme";
582
+ import { keyToFallback as keyToFallback2 } from "@dxos/util";
583
+ var iconProps = {
584
+ weight: "duotone",
585
+ width: 24,
586
+ height: 24,
587
+ x: 8,
588
+ y: 8
589
+ };
590
+ var DeviceListItem = /* @__PURE__ */ forwardRef2(({ device, onClickAdd, onClickEdit, onClickReset, onClickRecover, onClickJoinExisting, classNames, connectionState, onAgentDestroy: _, ...props }, forwardedRef) => {
591
+ const { t } = useTranslation6("os");
592
+ const fallbackValue = keyToFallback2(device.deviceKey);
593
+ const labelId = useId3("identityListItem__label");
594
+ const displayName = device.profile ? t("device name placeholder", {
595
+ os: device.profile.os,
596
+ platform: device.profile.platform
597
+ }) : generateName2(device.deviceKey.toHex());
598
+ const isCurrent = device.kind === DeviceKind.CURRENT;
599
+ return /* @__PURE__ */ React9.createElement(ListItem2.Root, {
600
+ ...props,
601
+ classNames: [
602
+ "flex gap-2 items-center mlb-2",
603
+ classNames
604
+ ],
605
+ "data-testid": `device-list-item${isCurrent ? "-current" : ""}`,
606
+ labelId,
607
+ ref: forwardedRef
608
+ }, /* @__PURE__ */ React9.createElement(Avatar3.Root, {
609
+ status: isCurrent && connectionState === ConnectionState.OFFLINE ? "error" : device.presence === Device.PresenceState.ONLINE ? "active" : "inactive",
610
+ labelId,
611
+ hue: fallbackValue.hue,
612
+ variant: "square"
613
+ }, /* @__PURE__ */ React9.createElement(Avatar3.Frame, {
614
+ classNames: "place-self-center"
615
+ }, device.profile?.type ? device.profile.type === DeviceType.AGENT_MANAGED ? /* @__PURE__ */ React9.createElement(Database2, iconProps) : device.profile.type === DeviceType.BROWSER ? /* @__PURE__ */ React9.createElement(Compass, iconProps) : device.profile.type === DeviceType.NATIVE ? /* @__PURE__ */ React9.createElement(Desktop, iconProps) : [
616
+ DeviceType.AGENT,
617
+ DeviceType.AGENT_MANAGED
618
+ ].includes(device.profile.type) ? /* @__PURE__ */ React9.createElement(Robot, iconProps) : device.profile.type === DeviceType.MOBILE ? /* @__PURE__ */ React9.createElement(DeviceMobile, iconProps) : /* @__PURE__ */ React9.createElement(Devices, iconProps) : /* @__PURE__ */ React9.createElement(Avatar3.Fallback, {
619
+ text: fallbackValue.emoji
620
+ })), /* @__PURE__ */ React9.createElement(Avatar3.Label, {
621
+ classNames: "flex-1 text-sm truncate"
622
+ }, displayName), isCurrent && /* @__PURE__ */ React9.createElement(Tag, {
623
+ color: "primary"
624
+ }, t("current device tag label")), device.kind === DeviceKind.CURRENT && /* @__PURE__ */ React9.createElement(DropdownMenu2.Root, null, /* @__PURE__ */ React9.createElement(DropdownMenu2.Trigger, {
625
+ asChild: true
626
+ }, /* @__PURE__ */ React9.createElement(Button5, {
627
+ variant: "ghost",
628
+ classNames: "pli-0 is-[--rail-action] bs-[--rail-action]",
629
+ "data-testid": `device-list-item${isCurrent ? "-current" : ""}.options`
630
+ }, /* @__PURE__ */ React9.createElement("span", {
631
+ className: "sr-only"
632
+ }, t("more options label")), /* @__PURE__ */ React9.createElement(DotsThree, {
633
+ className: getSize5(5)
634
+ }))), /* @__PURE__ */ React9.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React9.createElement(DropdownMenu2.Viewport, null, /* @__PURE__ */ React9.createElement(DropdownMenu2.Item, {
635
+ "data-testid": "device-list-item-current.join-existing",
636
+ onClick: onClickJoinExisting
637
+ }, /* @__PURE__ */ React9.createElement(ShareFat, {
638
+ className: getSize5(5)
639
+ }), t("choose join new identity label")), onClickRecover && /* @__PURE__ */ React9.createElement(DropdownMenu2.Item, {
640
+ "data-testid": "device-list-item-current.recover",
641
+ onClick: onClickRecover
642
+ }, /* @__PURE__ */ React9.createElement(FirstAidKit, {
643
+ className: getSize5(5)
644
+ }), t("choose recover identity label")), /* @__PURE__ */ React9.createElement(DropdownMenu2.Item, {
645
+ "data-testid": "device-list-item-current.reset",
646
+ onClick: onClickReset
647
+ }, /* @__PURE__ */ React9.createElement(Power2, {
648
+ className: getSize5(5)
649
+ }), t("reset device label")))))));
650
+ });
651
+
652
+ // packages/sdk/shell/src/components/DeviceList/DeviceList.tsx
653
+ var DeviceList = ({ devices, connectionState, onClickAdd, onClickEdit, onClickReset, onClickRecover, onClickJoinExisting, onAgentDestroy }) => {
654
+ const { t } = useTranslation7("os");
655
+ return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement("h2", {
656
+ className: mx7(descriptionText4, "text-center mbs-4")
657
+ }, t("devices heading")), devices.length > 0 && /* @__PURE__ */ React10.createElement(List2, null, devices.map((device) => {
658
+ return /* @__PURE__ */ React10.createElement(DeviceListItem, {
659
+ key: device.deviceKey.toHex(),
660
+ device,
661
+ onClickEdit: () => onClickEdit?.(device),
662
+ onClickReset,
663
+ onClickRecover,
664
+ onClickJoinExisting,
665
+ connectionState,
666
+ onAgentDestroy
667
+ });
668
+ })), /* @__PURE__ */ React10.createElement(Button6, {
669
+ variant: "ghost",
670
+ classNames: "justify-start gap-2 !pis-0 !pie-3 is-full",
671
+ "data-testid": "devices-panel.create-invitation",
672
+ onClick: onClickAdd
673
+ }, /* @__PURE__ */ React10.createElement("div", {
674
+ role: "img",
675
+ className: mx7(getSize6(8), "m-1 rounded-sm bg-input grid place-items-center")
676
+ }, /* @__PURE__ */ React10.createElement(Plus2, {
677
+ weight: "light",
678
+ className: getSize6(6)
679
+ })), /* @__PURE__ */ React10.createElement("span", {
680
+ className: "grow font-medium text-start"
681
+ }, t("choose add device label")), /* @__PURE__ */ React10.createElement(CaretRight, {
682
+ weight: "bold",
683
+ className: getSize6(4)
684
+ })));
685
+ };
686
+
687
+ // packages/sdk/shell/src/components/InvitationList/InvitationListItem.tsx
688
+ import { X } from "@phosphor-icons/react";
689
+ import { formatDistanceToNow } from "date-fns";
690
+ import React12, { useCallback as useCallback2 } from "react";
691
+ import { Invitation, useInvitationStatus } from "@dxos/react-client/invitations";
692
+ import { Button as Button7, ListItem as ListItem3, useTranslation as useTranslation8, Avatar as Avatar4, useThemeContext as useThemeContext4, Tooltip as Tooltip5 } from "@dxos/react-ui";
693
+ import { focusRing, getSize as getSize7, mx as mx9 } from "@dxos/react-ui-theme";
694
+ import { hexToEmoji } from "@dxos/util";
695
+
696
+ // packages/sdk/shell/src/components/AuthCode.tsx
697
+ import React11, { useRef as useRef3 } from "react";
698
+ import { mx as mx8 } from "@dxos/react-ui-theme";
699
+ var AuthCode = (props) => {
700
+ const { code, large, classNames } = props;
701
+ const l = code?.length ?? 0;
702
+ const left = code?.slice(0, l / 2);
703
+ const right = code?.slice(l / 2);
704
+ const codeRef = useRef3(null);
705
+ const handleClick = () => {
706
+ if (codeRef.current) {
707
+ const selection = window.getSelection();
708
+ selection?.removeAllRanges();
709
+ const range = document.createRange();
710
+ range.selectNodeContents(codeRef.current);
711
+ selection?.addRange(range);
712
+ }
713
+ void navigator.clipboard.writeText(code ?? "");
714
+ };
715
+ return /* @__PURE__ */ React11.createElement("span", {
716
+ className: mx8(large ? "text-6xl" : "text-2xl", "font-mono pli-2.5 rounded cursor-pointer", classNames),
717
+ onClick: handleClick,
718
+ ref: codeRef
719
+ }, /* @__PURE__ */ React11.createElement("span", {
720
+ className: "mie-[0.4em]"
721
+ }, left), /* @__PURE__ */ React11.createElement("span", null, right));
722
+ };
723
+
724
+ // packages/sdk/shell/src/components/InvitationList/InvitationListItem.tsx
725
+ var InvitationListItem = (props) => {
726
+ const { invitation } = props;
727
+ const invitationStatus = useInvitationStatus(invitation);
728
+ return /* @__PURE__ */ React12.createElement(InvitationListItemImpl, {
729
+ ...props,
730
+ invitationStatus
731
+ });
732
+ };
733
+ var avatarProps = {
734
+ size: 10,
735
+ variant: "circle"
736
+ };
737
+ var AvatarStackEffect = ({ animation, status, reverseEffects }) => {
738
+ const { tx } = useThemeContext4();
739
+ return /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement("span", {
740
+ role: "none",
741
+ className: mx9("absolute inline-end-auto opacity-20", reverseEffects ? "inline-start-3" : "inline-start-1", getSize7(avatarProps.size))
742
+ }, /* @__PURE__ */ React12.createElement("span", {
743
+ role: "none",
744
+ className: tx("avatar.ring", "avatar__ring", {
745
+ ...avatarProps,
746
+ status,
747
+ animation
748
+ }),
749
+ style: {
750
+ animationDelay: "400ms"
751
+ }
752
+ })), /* @__PURE__ */ React12.createElement("span", {
753
+ role: "none",
754
+ className: mx9("absolute inline-end-auto opacity-50", reverseEffects ? "inline-start-2" : "inline-start-2", getSize7(avatarProps.size))
755
+ }, /* @__PURE__ */ React12.createElement("span", {
756
+ role: "none",
757
+ className: tx("avatar.ring", "avatar__ring", {
758
+ ...avatarProps,
759
+ status,
760
+ animation
761
+ }),
762
+ style: {
763
+ animationDelay: "200ms"
764
+ }
765
+ })));
766
+ };
767
+ var InvitationListItemImpl = ({ invitation, invitationStatus: propsInvitationStatus, send, onClickRemove, createInvitationUrl, reverseEffects, ...props }) => {
768
+ const { t } = useTranslation8("os");
769
+ const { cancel, status: invitationStatus, invitationCode, authCode, multiUse, shareable } = propsInvitationStatus;
770
+ const isCancellable = !([
771
+ Invitation.State.ERROR,
772
+ Invitation.State.TIMEOUT,
773
+ Invitation.State.CANCELLED
774
+ ].indexOf(invitationStatus) >= 0);
775
+ const showShare = shareable && (multiUse || [
776
+ Invitation.State.INIT,
777
+ Invitation.State.CONNECTING,
778
+ Invitation.State.CONNECTED
779
+ ].indexOf(invitationStatus) >= 0);
780
+ const showAuthCode = invitationStatus === Invitation.State.READY_FOR_AUTHENTICATION;
781
+ const handleClickRemove = useCallback2(() => onClickRemove?.(invitation), [
782
+ invitation,
783
+ onClickRemove
784
+ ]);
785
+ const invitationUrl = invitationCode && createInvitationUrl(invitationCode);
786
+ const invitationId = invitation?.get().invitationId;
787
+ const invitationHasLifetime = invitation?.get().lifetime;
788
+ const invitationTimeLeft = invitation?.expiry ? formatDistanceToNow(invitation?.expiry, {
789
+ addSuffix: true
790
+ }) : void 0;
791
+ const avatarAnimation = [
792
+ Invitation.State.INIT,
793
+ Invitation.State.CONNECTING,
794
+ Invitation.State.CONNECTED,
795
+ Invitation.State.READY_FOR_AUTHENTICATION,
796
+ Invitation.State.AUTHENTICATING
797
+ ].includes(invitationStatus) ? "pulse" : "none";
798
+ const avatarError = [
799
+ Invitation.State.ERROR,
800
+ Invitation.State.TIMEOUT,
801
+ Invitation.State.CANCELLED
802
+ ].includes(invitationStatus);
803
+ const avatarGreen = [
804
+ Invitation.State.CONNECTED,
805
+ Invitation.State.READY_FOR_AUTHENTICATION,
806
+ Invitation.State.AUTHENTICATING,
807
+ Invitation.State.SUCCESS
808
+ ].includes(invitationStatus);
809
+ const avatarStatus = avatarError ? "error" : avatarGreen ? "active" : "inactive";
810
+ return /* @__PURE__ */ React12.createElement(ListItem3.Root, {
811
+ id: invitationCode,
812
+ ...props,
813
+ classNames: [
814
+ "flex gap-2 pis-3 pie-1 items-center relative",
815
+ props.classNames
816
+ ]
817
+ }, /* @__PURE__ */ React12.createElement(ListItem3.Heading, {
818
+ classNames: "sr-only"
819
+ }, t(multiUse ? "invite many list item label" : "invite one list item label")), multiUse && /* @__PURE__ */ React12.createElement(AvatarStackEffect, {
820
+ status: avatarStatus,
821
+ animation: avatarAnimation,
822
+ reverseEffects
823
+ }), /* @__PURE__ */ React12.createElement(Tooltip5.Root, null, /* @__PURE__ */ React12.createElement(Avatar4.Root, {
824
+ ...avatarProps,
825
+ animation: avatarAnimation,
826
+ status: avatarStatus
827
+ }, /* @__PURE__ */ React12.createElement(Tooltip5.Trigger, {
828
+ asChild: true
829
+ }, /* @__PURE__ */ React12.createElement(Avatar4.Frame, {
830
+ tabIndex: 0,
831
+ classNames: [
832
+ focusRing,
833
+ "relative rounded-full place-self-center"
834
+ ]
835
+ }, /* @__PURE__ */ React12.createElement(Avatar4.Fallback, {
836
+ text: hexToEmoji(invitationId)
837
+ })))), /* @__PURE__ */ React12.createElement(Tooltip5.Portal, null, /* @__PURE__ */ React12.createElement(Tooltip5.Content, {
838
+ side: "left",
839
+ classNames: "z-[70]"
840
+ }, t(multiUse ? "invite many qr label" : "invite one qr label"), /* @__PURE__ */ React12.createElement(Tooltip5.Arrow, null)))), showShare && invitationUrl ? /* @__PURE__ */ React12.createElement(Tooltip5.Root, null, /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Tooltip5.Trigger, {
841
+ asChild: true
842
+ }, /* @__PURE__ */ React12.createElement(Button7, {
843
+ variant: "ghost",
844
+ classNames: "grow justify-start font-medium",
845
+ onClick: () => send({
846
+ type: "selectInvitation",
847
+ invitation
848
+ }),
849
+ "data-testid": "show-qrcode"
850
+ }, /* @__PURE__ */ React12.createElement("span", null, t("open share panel label")))), /* @__PURE__ */ React12.createElement(CopyButtonIconOnly, {
851
+ variant: "ghost",
852
+ value: invitationUrl
853
+ })), /* @__PURE__ */ React12.createElement(Tooltip5.Portal, null, /* @__PURE__ */ React12.createElement(Tooltip5.Content, {
854
+ side: "left",
855
+ classNames: "z-[70]"
856
+ }, invitationHasLifetime && /* @__PURE__ */ React12.createElement("span", null, "Expires ", invitationTimeLeft)))) : showAuthCode ? /* @__PURE__ */ React12.createElement(AuthCode, {
857
+ code: authCode,
858
+ classNames: "grow"
859
+ }) : invitationStatus === Invitation.State.CONNECTING ? /* @__PURE__ */ React12.createElement("span", {
860
+ className: "pli-2 grow text-neutral-500"
861
+ }, "Connecting...") : invitationStatus === Invitation.State.AUTHENTICATING ? /* @__PURE__ */ React12.createElement("span", {
862
+ className: "pli-2 grow text-neutral-500"
863
+ }, "Authenticating...") : invitationStatus === Invitation.State.ERROR || invitationStatus === Invitation.State.TIMEOUT ? /* @__PURE__ */ React12.createElement("span", {
864
+ className: "pli-2 grow text-neutral-500"
865
+ }, "Failed") : invitationStatus === Invitation.State.CANCELLED ? /* @__PURE__ */ React12.createElement("span", {
866
+ className: "pli-2 grow text-neutral-500"
867
+ }, "Cancelled") : invitationStatus === Invitation.State.SUCCESS ? /* @__PURE__ */ React12.createElement("span", {
868
+ className: "pli-2 grow truncate"
869
+ }, "User joined") : !shareable ? /* @__PURE__ */ React12.createElement("span", {
870
+ className: "pli-2 grow text-neutral-500"
871
+ }, "Pending Invitation") : /* @__PURE__ */ React12.createElement("span", {
872
+ className: "grow"
873
+ }, " "), isCancellable ? /* @__PURE__ */ React12.createElement(Button7, {
874
+ variant: "ghost",
875
+ classNames: "flex gap-1 pli-0",
876
+ onClick: cancel,
877
+ "data-testid": "cancel-invitation"
878
+ }, /* @__PURE__ */ React12.createElement("span", {
879
+ className: "sr-only"
880
+ }, t("cancel invitation label")), /* @__PURE__ */ React12.createElement(X, {
881
+ className: getSize7(4)
882
+ })) : /* @__PURE__ */ React12.createElement(Button7, {
883
+ variant: "ghost",
884
+ classNames: "flex gap-1 pli-0",
885
+ onClick: handleClickRemove,
886
+ "data-testid": "remove-invitation"
887
+ }, /* @__PURE__ */ React12.createElement("span", {
888
+ className: "sr-only"
889
+ }, t("remove invitation label")), /* @__PURE__ */ React12.createElement(X, {
890
+ className: getSize7(4)
891
+ })));
892
+ };
893
+
894
+ // packages/sdk/shell/src/components/InvitationList/InvitationListContainer.tsx
895
+ import React14, { useCallback as useCallback3 } from "react";
896
+ import { useSpace, useSpaceInvitations } from "@dxos/react-client/echo";
897
+
898
+ // packages/sdk/shell/src/components/InvitationList/InvitationList.tsx
899
+ import React13 from "react";
900
+ import { List as List3 } from "@dxos/react-ui";
901
+ import { mx as mx10 } from "@dxos/react-ui-theme";
902
+ var InvitationList = ({ invitations, send, ...invitationProps }) => {
903
+ const { className, InvitationListItem: Item = InvitationListItem } = invitationProps;
904
+ return /* @__PURE__ */ React13.createElement(List3, {
905
+ classNames: mx10("flex flex-col gap-2", className)
906
+ }, invitations.map((invitation) => {
907
+ const value = invitation.get().invitationId;
908
+ return /* @__PURE__ */ React13.createElement(Item, {
909
+ key: value,
910
+ send,
911
+ invitation,
912
+ ...invitationProps
913
+ });
914
+ }));
915
+ };
916
+
917
+ // packages/sdk/shell/src/components/InvitationList/InvitationListContainer.tsx
918
+ var InvitationListContainer = ({ spaceKey, createInvitationUrl, send }) => {
919
+ const space = useSpace(spaceKey);
920
+ const invitations = useSpaceInvitations(spaceKey);
921
+ const handleClickRemove = useCallback3((invitation) => {
922
+ void invitation.cancel();
923
+ }, [
924
+ space
925
+ ]);
926
+ return /* @__PURE__ */ React14.createElement(InvitationList, {
927
+ invitations,
928
+ onClickRemove: handleClickRemove,
929
+ createInvitationUrl,
930
+ send
931
+ });
932
+ };
933
+
934
+ // packages/sdk/shell/src/components/Panel/Action.tsx
935
+ import { CaretDown as CaretDown3, Check as Check3, Placeholder } from "@phosphor-icons/react";
936
+ import { useControllableState as useControllableState3 } from "@radix-ui/react-use-controllable-state";
937
+ import React15, { forwardRef as forwardRef3 } from "react";
938
+ import { Button as Button8, DropdownMenu as DropdownMenu3, useTranslation as useTranslation9 } from "@dxos/react-ui";
939
+ import { descriptionText as descriptionText5, getSize as getSize8, mx as mx11 } from "@dxos/react-ui-theme";
940
+ var defaultActions = {
941
+ noopAction: {
942
+ label: "No-op",
943
+ description: "",
944
+ icon: Placeholder,
945
+ onClick: () => {
946
+ }
947
+ }
948
+ };
949
+ var BifurcatedAction = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
950
+ const { classNames, variant, isFull = true, actions = defaultActions, activeAction: propsActiveAction, onChangeActiveAction, defaultActiveAction, "data-testid": testId, ...rest } = props;
951
+ const dropdownTestId = testId && `${testId}.more`;
952
+ const [activeActionKey2 = Object.keys(actions)[0], setActiveAction] = useControllableState3({
953
+ prop: propsActiveAction,
954
+ onChange: onChangeActiveAction,
955
+ defaultProp: defaultActiveAction
956
+ });
957
+ const activeAction = actions[activeActionKey2] ?? {};
958
+ const { t } = useTranslation9("os");
959
+ return /* @__PURE__ */ React15.createElement("div", {
960
+ role: "none",
961
+ className: mx11("mbs-2 flex gap-px items-center", isFull && "is-full")
962
+ }, /* @__PURE__ */ React15.createElement(Button8, {
963
+ ...rest,
964
+ classNames: [
965
+ "bs-11 flex-1 min-is-0 flex gap-2 rounded-ie-none",
966
+ classNames
967
+ ],
968
+ ref: forwardedRef,
969
+ variant,
970
+ "data-testid": testId,
971
+ onClick: activeAction.onClick
972
+ }, activeAction.icon && /* @__PURE__ */ React15.createElement(activeAction.icon, {
973
+ className: getSize8(5)
974
+ }), /* @__PURE__ */ React15.createElement("span", null, activeAction.label)), /* @__PURE__ */ React15.createElement(DropdownMenu3.Root, null, /* @__PURE__ */ React15.createElement(DropdownMenu3.Trigger, {
975
+ asChild: true
976
+ }, /* @__PURE__ */ React15.createElement(Button8, {
977
+ classNames: [
978
+ "bs-11 flex-none rounded-is-none",
979
+ classNames
980
+ ],
981
+ "data-testid": dropdownTestId
982
+ }, /* @__PURE__ */ React15.createElement("span", {
983
+ className: "sr-only"
984
+ }, t("invite options label")), /* @__PURE__ */ React15.createElement(CaretDown3, {
985
+ className: getSize8(4)
986
+ }))), /* @__PURE__ */ React15.createElement(DropdownMenu3.Portal, null, /* @__PURE__ */ React15.createElement(DropdownMenu3.Content, null, /* @__PURE__ */ React15.createElement(DropdownMenu3.Viewport, null, Object.entries(actions).map(([id, action]) => {
987
+ return /* @__PURE__ */ React15.createElement(DropdownMenu3.CheckboxItem, {
988
+ key: id,
989
+ "aria-labelledby": `${id}__label`,
990
+ "aria-describedby": `${id}__description`,
991
+ checked: activeActionKey2 === id,
992
+ onCheckedChange: (checked) => checked && setActiveAction(id),
993
+ classNames: "gap-2",
994
+ "data-testid": action.testId
995
+ }, action.icon && /* @__PURE__ */ React15.createElement(action.icon, {
996
+ className: getSize8(5)
997
+ }), /* @__PURE__ */ React15.createElement("div", {
998
+ role: "none",
999
+ className: "flex-1 min-is-0 space-b-1"
1000
+ }, /* @__PURE__ */ React15.createElement("p", {
1001
+ id: `${id}__label`
1002
+ }, action.label), action.description && /* @__PURE__ */ React15.createElement("p", {
1003
+ id: `${id}__description`,
1004
+ className: descriptionText5
1005
+ }, action.description)), /* @__PURE__ */ React15.createElement(DropdownMenu3.ItemIndicator, {
1006
+ asChild: true
1007
+ }, /* @__PURE__ */ React15.createElement(Check3, {
1008
+ weight: "bold",
1009
+ className: getSize8(4)
1010
+ })));
1011
+ })), /* @__PURE__ */ React15.createElement(DropdownMenu3.Arrow, null)))));
1012
+ });
1013
+ var Action = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
1014
+ const { children, classNames, variant, isFull = true, ...rest } = props;
1015
+ return /* @__PURE__ */ React15.createElement(Button8, {
1016
+ ...rest,
1017
+ classNames: [
1018
+ isFull && "is-full",
1019
+ "bs-11 flex gap-2 mbs-2",
1020
+ classNames
1021
+ ],
1022
+ ref: forwardedRef,
1023
+ variant
1024
+ }, children);
1025
+ });
1026
+
1027
+ // packages/sdk/shell/src/components/Panel/Actions.tsx
1028
+ import React16, { forwardRef as forwardRef4 } from "react";
1029
+ import { mx as mx12 } from "@dxos/react-ui-theme";
1030
+ var Actions = /* @__PURE__ */ forwardRef4(({ classNames, children, ...props }, forwardedRef) => {
1031
+ return /* @__PURE__ */ React16.createElement("div", {
1032
+ ...props,
1033
+ className: mx12("flex flex-col gap-2 mbs-2", Array.isArray(children) && children.length > 1 ? "justify-between" : "justify-center", classNames),
1034
+ ref: forwardedRef
1035
+ }, children);
1036
+ });
1037
+
1038
+ // packages/sdk/shell/src/components/Panel/CloseButton.tsx
1039
+ import { X as X2 } from "@phosphor-icons/react";
1040
+ import React17 from "react";
1041
+ import { Button as Button9, useTranslation as useTranslation10 } from "@dxos/react-ui";
1042
+ import { getSize as getSize9, mx as mx13 } from "@dxos/react-ui-theme";
1043
+ var CloseButton = ({ onDone, ...props }) => {
1044
+ const { t } = useTranslation10("os");
1045
+ return /* @__PURE__ */ React17.createElement(Button9, {
1046
+ variant: "ghost",
1047
+ classNames: mx13("plb-0 pli-2 absolute block-start-0 inline-end-0 z-[1]"),
1048
+ onClick: () => onDone?.(),
1049
+ ...props
1050
+ }, /* @__PURE__ */ React17.createElement(X2, {
1051
+ weight: "bold",
1052
+ className: getSize9(4)
1053
+ }), /* @__PURE__ */ React17.createElement("span", {
1054
+ className: "sr-only"
1055
+ }, t("exit label")));
1056
+ };
1057
+
1058
+ // packages/sdk/shell/src/components/Panel/Emoji.tsx
1059
+ import React18 from "react";
1060
+ import { mx as mx14, getSize as getSize10 } from "@dxos/react-ui-theme";
1061
+ var Emoji = ({ text, className }) => {
1062
+ const size = 14;
1063
+ return /* @__PURE__ */ React18.createElement("div", {
1064
+ role: "none",
1065
+ className: mx14(getSize10(size), "rounded relative pointer-events-none", className)
1066
+ }, /* @__PURE__ */ React18.createElement("svg", {
1067
+ viewBox: `0 0 ${size * 4} ${size * 4}`,
1068
+ width: size * 4,
1069
+ height: size * 4
1070
+ }, /* @__PURE__ */ React18.createElement("text", {
1071
+ x: "50%",
1072
+ y: "50%",
1073
+ textAnchor: "middle",
1074
+ dominantBaseline: "middle",
1075
+ baselineShift: "-0.25rem",
1076
+ fontSize: "2.25rem"
1077
+ }, text)));
1078
+ };
1079
+ var Centered = (props) => {
1080
+ const { children } = props;
1081
+ return /* @__PURE__ */ React18.createElement("div", {
1082
+ role: "none",
1083
+ className: "absolute inset-0 flex items-center justify-center"
1084
+ }, children);
1085
+ };
1086
+
1087
+ // packages/sdk/shell/src/components/Panel/Heading.tsx
1088
+ import React19, { forwardRef as forwardRef5 } from "react";
1089
+ import { descriptionText as descriptionText6, mx as mx15 } from "@dxos/react-ui-theme";
1090
+ var Heading = /* @__PURE__ */ forwardRef5(({ titleId, title, titleSrOnly, children, corner }, forwardedRef) => {
1091
+ return /* @__PURE__ */ React19.createElement("div", {
1092
+ role: "none",
1093
+ className: "pbe-2 relative",
1094
+ ref: forwardedRef
1095
+ }, corner, /* @__PURE__ */ React19.createElement("h1", {
1096
+ ...!titleSrOnly && {
1097
+ id: titleId
1098
+ },
1099
+ className: mx15(descriptionText6, "text-center mlb-2", titleSrOnly && "invisible")
1100
+ }, title), titleSrOnly && /* @__PURE__ */ React19.createElement("span", {
1101
+ id: titleId
1102
+ }, title), children);
1103
+ });
1104
+
1105
+ // packages/sdk/shell/src/components/Panel/Label.tsx
1106
+ import React20 from "react";
1107
+ import { descriptionText as descriptionText7, mx as mx16 } from "@dxos/react-ui-theme";
1108
+ var Label = (props) => {
1109
+ const { children } = props;
1110
+ return /* @__PURE__ */ React20.createElement("span", {
1111
+ className: mx16(descriptionText7, "text-center mli-6 whitespace-normal")
1112
+ }, children);
1113
+ };
1114
+
1115
+ // packages/sdk/shell/src/components/Panel/Input.tsx
1116
+ import React21 from "react";
1117
+ import { Input as UiInput } from "@dxos/react-ui";
1118
+ var Input = ({ validationMessage, label, ...props }) => {
1119
+ return /* @__PURE__ */ React21.createElement(UiInput.Root, null, /* @__PURE__ */ React21.createElement(UiInput.Label, null, label), /* @__PURE__ */ React21.createElement(UiInput.TextInput, {
1120
+ ...props,
1121
+ classNames: "plb-3 mbs-2 text-center"
1122
+ }), /* @__PURE__ */ React21.createElement(UiInput.DescriptionAndValidation, null, validationMessage && /* @__PURE__ */ React21.createElement(UiInput.Validation, null, validationMessage)));
1123
+ };
1124
+
1125
+ // packages/sdk/shell/src/components/Panel/StepHeading.tsx
1126
+ import React22, { forwardRef as forwardRef6 } from "react";
1127
+ import { mx as mx17 } from "@dxos/react-ui-theme";
1128
+ var StepHeading = /* @__PURE__ */ forwardRef6(({ children, className, ...props }, forwardedRef) => {
1129
+ return /* @__PURE__ */ React22.createElement("h2", {
1130
+ ...props,
1131
+ className: mx17("font-normal text-sm mbe-4 mli-1 text-center", className),
1132
+ ref: forwardedRef
1133
+ }, children);
1134
+ });
1135
+
1136
+ // packages/sdk/shell/src/components/Viewport/Viewport.tsx
1137
+ import { useFocusFinders } from "@fluentui/react-tabster";
1138
+ import { createContextScope } from "@radix-ui/react-context";
1139
+ import { useControllableState as useControllableState4 } from "@radix-ui/react-use-controllable-state";
1140
+ import React23, { forwardRef as forwardRef7, useEffect } from "react";
1141
+ import { useForwardedRef } from "@dxos/react-ui";
1142
+ import { mx as mx18 } from "@dxos/react-ui-theme";
1143
+ var VIEWPORT_NAME = "Viewport";
1144
+ var VIEWS_NAME = "ViewportViews";
1145
+ var VIEW_NAME = "ViewportView";
1146
+ var [createViewportContext, createViewportScope] = createContextScope(VIEWPORT_NAME, []);
1147
+ var [ViewportProvider, useViewportContext] = createViewportContext(VIEWPORT_NAME);
1148
+ var ViewportRoot = ({ __viewportScope, classNames, children, defaultActiveView, activeView: propsActiveView, focusManaged = false, onActiveViewChange, ...props }) => {
1149
+ const [activeView = "never", setActiveView] = useControllableState4({
1150
+ prop: propsActiveView,
1151
+ defaultProp: defaultActiveView,
1152
+ onChange: onActiveViewChange
1153
+ });
1154
+ return /* @__PURE__ */ React23.createElement(ViewportProvider, {
1155
+ focusManaged,
1156
+ activeView,
1157
+ setActiveView,
1158
+ scope: __viewportScope
1159
+ }, /* @__PURE__ */ React23.createElement("div", {
1160
+ role: "region",
1161
+ "aria-live": "polite",
1162
+ ...props,
1163
+ className: mx18("is-full overflow-hidden", classNames)
1164
+ }, children));
1165
+ };
1166
+ ViewportRoot.displayName = VIEWPORT_NAME;
1167
+ var ViewportViews = ({ classNames, children, ...props }) => {
1168
+ const size = {
1169
+ inlineSize: `${Math.ceil(children.length) * 100}%`
1170
+ };
1171
+ return /* @__PURE__ */ React23.createElement("div", {
1172
+ role: "none",
1173
+ style: size,
1174
+ ...props,
1175
+ className: mx18("flex", classNames)
1176
+ }, children);
1177
+ };
1178
+ ViewportViews.displayName = VIEWS_NAME;
1179
+ var ViewportView = /* @__PURE__ */ forwardRef7(({ __viewportScope, classNames, children, id, ...props }, forwardedRef) => {
1180
+ const { activeView, focusManaged } = useViewportContext(VIEW_NAME, __viewportScope);
1181
+ const isActive = id === activeView;
1182
+ const ref = useForwardedRef(forwardedRef);
1183
+ const { findFirstFocusable } = useFocusFinders();
1184
+ useEffect(() => {
1185
+ if (!focusManaged && isActive && document.body.hasAttribute("data-is-keyboard") && ref.current) {
1186
+ findFirstFocusable(ref.current)?.focus();
1187
+ }
1188
+ }, [
1189
+ focusManaged,
1190
+ ref.current,
1191
+ isActive
1192
+ ]);
1193
+ return /* @__PURE__ */ React23.createElement("section", {
1194
+ ...props,
1195
+ ...!isActive && {
1196
+ "aria-hidden": true
1197
+ },
1198
+ className: mx18("min-is-0 flex-1 flex flex-col", isActive ? "order-2" : "order-4 invisible", classNames),
1199
+ ref
1200
+ }, children);
1201
+ });
1202
+ ViewportView.displayName = VIEW_NAME;
1203
+ var Viewport = {
1204
+ Root: ViewportRoot,
1205
+ Views: ViewportViews,
1206
+ View: ViewportView
1207
+ };
1208
+
1209
+ // packages/sdk/shell/src/components/SpaceListItem.tsx
1210
+ import React24, { forwardRef as forwardRef8 } from "react";
1211
+ import { Avatar as Avatar5, useId as useId4 } from "@dxos/react-ui";
1212
+ import { mx as mx19 } from "@dxos/react-ui-theme";
1213
+ import { humanize, keyToEmoji } from "@dxos/util";
1214
+ var SpaceListItem = /* @__PURE__ */ forwardRef8(({ space, onClick }, ref) => {
1215
+ const fallbackValue = keyToEmoji(space.key);
1216
+ const labelId = useId4("identityListItem__label");
1217
+ const displayName = space.properties.name ?? humanize(space.key.toHex());
1218
+ return /* @__PURE__ */ React24.createElement("li", {
1219
+ className: mx19("flex gap-2 items-center mbe-2", onClick && "cursor-pointer"),
1220
+ onClick: () => onClick?.(),
1221
+ ref,
1222
+ "data-testid": "space-list-item"
1223
+ }, /* @__PURE__ */ React24.createElement(Avatar5.Root, {
1224
+ labelId
1225
+ }, /* @__PURE__ */ React24.createElement(Avatar5.Frame, null, /* @__PURE__ */ React24.createElement(Avatar5.Fallback, {
1226
+ text: fallbackValue
1227
+ })), /* @__PURE__ */ React24.createElement(Avatar5.Label, {
1228
+ classNames: "text-sm truncate"
1229
+ }, displayName)));
1230
+ });
1231
+
1232
+ // packages/sdk/shell/src/composites/IdentityDialog/IdentityDialog.tsx
1233
+ import React42 from "react";
1234
+ import { Dialog, useId as useId10 } from "@dxos/react-ui";
1235
+
1236
+ // packages/sdk/shell/src/panels/IdentityPanel/IdentityPanel.tsx
1237
+ import { FirstAidKit as FirstAidKit2, Key, Plugs, PlugsConnected } from "@phosphor-icons/react";
1238
+ import React29, { useEffect as useEffect4, useMemo as useMemo3, useState as useState9 } from "react";
1239
+ import { generateName as generateName3 } from "@dxos/display-name";
1240
+ import { invariant as invariant3 } from "@dxos/invariant";
1241
+ import { log as log6 } from "@dxos/log";
1242
+ import { useClient as useClient6 } from "@dxos/react-client";
1243
+ import { useIdentity, useDevices, useHaloInvitations as useHaloInvitations2 } from "@dxos/react-client/halo";
1244
+ import { useInvitationStatus as useInvitationStatus2 } from "@dxos/react-client/invitations";
1245
+ import { useNetworkStatus, ConnectionState as ConnectionState2 } from "@dxos/react-client/mesh";
1246
+ import { Avatar as Avatar6, Input as Input2, Toolbar as Toolbar3, Tooltip as Tooltip6, useId as useId6, useTranslation as useTranslation14 } from "@dxos/react-ui";
1247
+ import { getSize as getSize13 } from "@dxos/react-ui-theme";
1248
+ import { hexToEmoji as hexToEmoji4, hexToHue as hexToHue2, keyToFallback as keyToFallback3 } from "@dxos/util";
1249
+
1250
+ // packages/sdk/shell/src/panels/IdentityPanel/identityMachine.ts
1251
+ import { useMachine } from "@xstate/react";
1252
+ import { assign, createMachine } from "xstate";
1253
+ import { log } from "@dxos/log";
1254
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/IdentityPanel/identityMachine.ts";
1255
+ var identityMachine = createMachine({
1256
+ id: "identity",
1257
+ predictableActionArguments: true,
1258
+ context: {
1259
+ identity: null,
1260
+ identitySubscribable: null
1261
+ },
1262
+ initial: "choosingAction",
1263
+ invoke: {
1264
+ src: (context) => context.identitySubscribable
1265
+ },
1266
+ states: {
1267
+ unknown: {
1268
+ always: [
1269
+ {
1270
+ cond: "initiallyManagingDeviceInvitation",
1271
+ target: "managingDeviceInvitation",
1272
+ actions: "log"
1273
+ },
1274
+ {
1275
+ target: "choosingAction",
1276
+ actions: "log"
1277
+ }
1278
+ ]
1279
+ },
1280
+ choosingAction: {},
1281
+ managingDeviceInvitation: {},
1282
+ confirmingResetStorage: {},
1283
+ confirmingRecover: {},
1284
+ confirmingJoinNewIdentity: {}
1285
+ },
1286
+ on: {
1287
+ unchooseAction: {
1288
+ target: ".choosingAction",
1289
+ actions: [
1290
+ "unsetInvitation",
1291
+ "log"
1292
+ ]
1293
+ },
1294
+ deselectInvitation: {
1295
+ target: ".choosingAction",
1296
+ actions: [
1297
+ "unsetInvitation",
1298
+ "log"
1299
+ ]
1300
+ },
1301
+ selectInvitation: {
1302
+ target: ".managingDeviceInvitation",
1303
+ actions: [
1304
+ "setInvitation",
1305
+ "log"
1306
+ ]
1307
+ },
1308
+ chooseJoinNewIdentity: {
1309
+ target: ".confirmingJoinNewIdentity",
1310
+ actions: "log"
1311
+ },
1312
+ chooseRecoverIdentity: {
1313
+ target: ".confirmingRecover",
1314
+ actions: "log"
1315
+ },
1316
+ chooseResetStorage: {
1317
+ target: ".confirmingResetStorage",
1318
+ actions: "log"
1319
+ }
1320
+ }
1321
+ }, {
1322
+ guards: {
1323
+ initiallyManagingDeviceInvitation: ({ initialDisposition }, _event) => initialDisposition === "manage-device-invitation"
1324
+ },
1325
+ actions: {
1326
+ setIdentity: assign({
1327
+ identity: (context, event) => event?.identity ?? null
1328
+ }),
1329
+ setInvitation: assign({
1330
+ invitation: (context, event) => event?.invitation ?? null
1331
+ }),
1332
+ unsetInvitation: assign({
1333
+ invitation: () => void 0
1334
+ }),
1335
+ log: (context, event) => {
1336
+ log("[transition]", {
1337
+ event,
1338
+ context
1339
+ }, {
1340
+ F: __dxlog_file,
1341
+ L: 98,
1342
+ S: void 0,
1343
+ C: (f, a) => f(...a)
1344
+ });
1345
+ }
1346
+ }
1347
+ });
1348
+ var useIdentityMachine = (client, options) => {
1349
+ return useMachine(identityMachine, {
1350
+ ...options,
1351
+ context: {
1352
+ ...options?.context,
1353
+ identity: client.halo.identity.get(),
1354
+ identitySubscribable: client.halo.identity.map((identity) => ({
1355
+ type: "setIdentity",
1356
+ identity
1357
+ }))
1358
+ }
1359
+ });
1360
+ };
1361
+
1362
+ // packages/sdk/shell/src/panels/IdentityPanel/steps/IdentityActionChooser.tsx
1363
+ import React25 from "react";
1364
+ import { log as log2 } from "@dxos/log";
1365
+ import { useClient as useClient2 } from "@dxos/react-client";
1366
+ import { useHaloInvitations, DeviceType as DeviceType2 } from "@dxos/react-client/halo";
1367
+ import { Invitation as Invitation2, InvitationEncoder } from "@dxos/react-client/invitations";
1368
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/IdentityPanel/steps/IdentityActionChooser.tsx";
1369
+ var IdentityActionChooser = (props) => {
1370
+ const { send } = props;
1371
+ const client = useClient2();
1372
+ const invitations = useHaloInvitations();
1373
+ const createInvitation = () => {
1374
+ invitations.forEach((invitation2) => invitation2.cancel());
1375
+ const invitation = client.halo.share();
1376
+ if (client.config.values.runtime?.app?.env?.DX_ENVIRONMENT !== "production") {
1377
+ const subscription = invitation.subscribe((invitation2) => {
1378
+ const invitationCode = InvitationEncoder.encode(invitation2);
1379
+ if (invitation2.state === Invitation2.State.CONNECTING) {
1380
+ log2.info(JSON.stringify({
1381
+ invitationCode,
1382
+ authCode: invitation2.authCode
1383
+ }), void 0, {
1384
+ F: __dxlog_file2,
1385
+ L: 29,
1386
+ S: void 0,
1387
+ C: (f, a) => f(...a)
1388
+ });
1389
+ subscription.unsubscribe();
1390
+ }
1391
+ });
1392
+ }
1393
+ send?.({
1394
+ type: "selectInvitation",
1395
+ invitation
1396
+ });
1397
+ };
1398
+ const isProduction = client.config.values.runtime?.app?.env?.DX_ENVIRONMENT === "production";
1399
+ return /* @__PURE__ */ React25.createElement(IdentityActionChooserImpl, {
1400
+ ...props,
1401
+ onClickAdd: createInvitation,
1402
+ onClickJoinExisting: () => send?.({
1403
+ type: "chooseJoinNewIdentity"
1404
+ }),
1405
+ onClickRecover: isProduction ? void 0 : () => send?.({
1406
+ type: "chooseRecoverIdentity"
1407
+ }),
1408
+ onClickReset: () => send?.({
1409
+ type: "chooseResetStorage"
1410
+ })
1411
+ });
1412
+ };
1413
+ var IdentityActionChooserImpl = ({ devices, connectionState, agentHostingEnabled, onClickAdd, onClickJoinExisting, onClickRecover, onClickReset, ...agentProps }) => {
1414
+ const edgeDeviceAvailable = devices.find((device) => device.profile?.type === DeviceType2.AGENT_MANAGED && device.profile?.os?.toUpperCase() === "EDGE");
1415
+ return /* @__PURE__ */ React25.createElement("div", {
1416
+ role: "none",
1417
+ className: "bs-40 grow overflow-y-auto overflow-x-hidden"
1418
+ }, /* @__PURE__ */ React25.createElement(DeviceList, {
1419
+ devices,
1420
+ connectionState,
1421
+ onClickAdd,
1422
+ onClickJoinExisting,
1423
+ onClickRecover: agentProps.agentStatus === "created" ? onClickRecover : void 0,
1424
+ onClickReset,
1425
+ onAgentDestroy: agentProps.onAgentDestroy
1426
+ }), !edgeDeviceAvailable && agentHostingEnabled && /* @__PURE__ */ React25.createElement(AgentConfig, agentProps));
1427
+ };
1428
+
1429
+ // packages/sdk/shell/src/panels/IdentityPanel/steps/ProfileForm.tsx
1430
+ import React26, { useState as useState5 } from "react";
1431
+ import { log as log3 } from "@dxos/log";
1432
+ import { useTranslation as useTranslation11 } from "@dxos/react-ui";
1433
+ import { hexToEmoji as hexToEmoji2, hexToHue } from "@dxos/util";
1434
+
1435
+ // packages/sdk/shell/src/panels/IdentityPanel/useAgentHandlers.ts
1436
+ import { useClient as useClient5 } from "@dxos/react-client";
1437
+
1438
+ // packages/sdk/shell/src/panels/IdentityPanel/useEdgeAgentsHandlers.ts
1439
+ import { useEffect as useEffect2, useState as useState6 } from "react";
1440
+ import { invariant } from "@dxos/invariant";
1441
+ import { QueryAgentStatusResponse } from "@dxos/protocols/proto/dxos/client/services";
1442
+ import { EdgeReplicationSetting } from "@dxos/protocols/proto/dxos/echo/metadata";
1443
+ import { useClient as useClient3 } from "@dxos/react-client";
1444
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/IdentityPanel/useEdgeAgentsHandlers.ts";
1445
+ var useEdgeAgentHandlers = ({ identity }) => {
1446
+ const [validationMessage, setValidationMessage] = useState6("");
1447
+ const [lastReceivedStatus, setLastReceivedStatus] = useState6(QueryAgentStatusResponse.AgentStatus.UNKNOWN);
1448
+ const [agentStatus, setAgentStatus] = useState6("getting");
1449
+ const client = useClient3();
1450
+ const agentHostingEnabled = Boolean(client.config.values.runtime?.client?.edgeFeatures?.agents);
1451
+ const handleStatus = (status) => {
1452
+ switch (status) {
1453
+ case QueryAgentStatusResponse.AgentStatus.ACTIVE:
1454
+ case QueryAgentStatusResponse.AgentStatus.INACTIVE:
1455
+ setAgentStatus("created");
1456
+ break;
1457
+ case QueryAgentStatusResponse.AgentStatus.NOT_FOUND:
1458
+ setAgentStatus("creatable");
1459
+ break;
1460
+ case QueryAgentStatusResponse.AgentStatus.UNKNOWN:
1461
+ setAgentStatus("getting");
1462
+ break;
1463
+ }
1464
+ };
1465
+ useEffect2(() => {
1466
+ const stream = client.services.services.EdgeAgentService?.queryAgentStatus();
1467
+ stream?.subscribe(({ status }) => {
1468
+ setLastReceivedStatus(status);
1469
+ handleStatus(status);
1470
+ });
1471
+ return () => {
1472
+ void stream?.close().catch(() => {
1473
+ });
1474
+ };
1475
+ }, []);
1476
+ const onAgentCreate = async () => {
1477
+ invariant(identity, "Identity not found", {
1478
+ F: __dxlog_file3,
1479
+ L: 58,
1480
+ S: void 0,
1481
+ A: [
1482
+ "identity",
1483
+ "'Identity not found'"
1484
+ ]
1485
+ });
1486
+ const service = client.services.services.EdgeAgentService;
1487
+ if (!service) {
1488
+ setAgentStatus("error");
1489
+ setValidationMessage("Agent service not initialized.");
1490
+ return;
1491
+ }
1492
+ if (!agentHostingEnabled) {
1493
+ setAgentStatus("error");
1494
+ setValidationMessage("Edge agents are disabled in config.");
1495
+ return;
1496
+ }
1497
+ setAgentStatus("creating");
1498
+ setValidationMessage("");
1499
+ try {
1500
+ await service.createAgent();
1501
+ await Promise.all(client.spaces.get().map((space) => space?.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED)));
1502
+ setAgentStatus("created");
1503
+ } catch (err) {
1504
+ setAgentStatus("error");
1505
+ setValidationMessage(`Error creating an agent: ${err.message}`);
1506
+ }
1507
+ };
1508
+ const onAgentDestroy = async () => {
1509
+ setValidationMessage("Agents are non-destructible.");
1510
+ };
1511
+ const onAgentRefresh = async () => {
1512
+ setValidationMessage("");
1513
+ handleStatus(lastReceivedStatus);
1514
+ };
1515
+ return {
1516
+ onAgentCreate,
1517
+ onAgentDestroy,
1518
+ onAgentRefresh,
1519
+ validationMessage,
1520
+ agentStatus,
1521
+ agentHostingEnabled
1522
+ };
1523
+ };
1524
+
1525
+ // packages/sdk/shell/src/panels/IdentityPanel/useKubeAgentHandlers.ts
1526
+ import { useCallback as useCallback4, useEffect as useEffect3, useState as useState7 } from "react";
1527
+ import { invariant as invariant2 } from "@dxos/invariant";
1528
+ import { log as log4 } from "@dxos/log";
1529
+ import { useClient as useClient4, useAgentHostingClient } from "@dxos/react-client";
1530
+ import { Invitation as Invitation3, InvitationEncoder as InvitationEncoder2 } from "@dxos/react-client/invitations";
1531
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/IdentityPanel/useKubeAgentHandlers.ts";
1532
+ var useKubeAgentHandlers = ({ invitations, identity }) => {
1533
+ const [validationMessage, setValidationMessage] = useState7("");
1534
+ const [agentStatus, setAgentStatus] = useState7("getting");
1535
+ const agentHostingProviderClient = useAgentHostingClient();
1536
+ const client = useClient4();
1537
+ const updateAgentStatus = async () => {
1538
+ if (agentHostingProviderClient) {
1539
+ setAgentStatus("getting");
1540
+ try {
1541
+ const agentId = await agentHostingProviderClient?.getAgent(identity?.identityKey.truncate() ?? "never");
1542
+ if (agentId) {
1543
+ setAgentStatus("created");
1544
+ } else {
1545
+ setAgentStatus("creatable");
1546
+ }
1547
+ } catch (err) {
1548
+ setAgentStatus("error");
1549
+ setValidationMessage(`Couldn\u2019t check agent status: ${err.message}`);
1550
+ }
1551
+ } else {
1552
+ setAgentStatus("error");
1553
+ setValidationMessage("No agent provider configured.");
1554
+ }
1555
+ };
1556
+ const createAgent = async (invitationCode) => {
1557
+ invariant2(identity, "Identity not found", {
1558
+ F: __dxlog_file4,
1559
+ L: 50,
1560
+ S: void 0,
1561
+ A: [
1562
+ "identity",
1563
+ "'Identity not found'"
1564
+ ]
1565
+ });
1566
+ if (agentHostingProviderClient) {
1567
+ setAgentStatus("creating");
1568
+ setValidationMessage("");
1569
+ try {
1570
+ const agentId = await agentHostingProviderClient?.createAgent(invitationCode, identity.identityKey.truncate());
1571
+ if (agentId) {
1572
+ setAgentStatus("created");
1573
+ } else {
1574
+ setAgentStatus("creatable");
1575
+ setValidationMessage("Error creating agent.");
1576
+ }
1577
+ } catch (err) {
1578
+ setValidationMessage(`Error creating agent: ${err.message}`);
1579
+ return updateAgentStatus();
1580
+ }
1581
+ } else {
1582
+ setAgentStatus("error");
1583
+ setValidationMessage("No agent provider configured.");
1584
+ }
1585
+ };
1586
+ const destroyAgent = async () => {
1587
+ invariant2(identity, "Identity not found", {
1588
+ F: __dxlog_file4,
1589
+ L: 73,
1590
+ S: void 0,
1591
+ A: [
1592
+ "identity",
1593
+ "'Identity not found'"
1594
+ ]
1595
+ });
1596
+ if (agentHostingProviderClient) {
1597
+ setAgentStatus("destroying");
1598
+ setValidationMessage("");
1599
+ try {
1600
+ await agentHostingProviderClient?.destroyAgent(identity.identityKey.truncate());
1601
+ setAgentStatus("creatable");
1602
+ } catch (err) {
1603
+ setValidationMessage(`Error destroying agent: ${err.message}`);
1604
+ return updateAgentStatus();
1605
+ }
1606
+ } else {
1607
+ setAgentStatus("error");
1608
+ setValidationMessage("No agent provider configured.");
1609
+ }
1610
+ };
1611
+ useEffect3(() => {
1612
+ void updateAgentStatus();
1613
+ }, []);
1614
+ const handleAgentCreate = useCallback4(async (invitation) => {
1615
+ const invitationCode = InvitationEncoder2.encode(invitation);
1616
+ if (invitation.state === Invitation3.State.CONNECTING) {
1617
+ log4.info(JSON.stringify({
1618
+ invitationCode,
1619
+ authCode: invitation.authCode
1620
+ }), void 0, {
1621
+ F: __dxlog_file4,
1622
+ L: 97,
1623
+ S: void 0,
1624
+ C: (f, a) => f(...a)
1625
+ });
1626
+ return createAgent(invitationCode);
1627
+ }
1628
+ }, []);
1629
+ const onAgentCreate = async () => {
1630
+ invitations.forEach((invitation2) => invitation2.cancel());
1631
+ const invitation = client.halo.share({
1632
+ type: Invitation3.Type.INTERACTIVE,
1633
+ authMethod: Invitation3.AuthMethod.NONE,
1634
+ multiUse: true
1635
+ });
1636
+ invitation.subscribe(handleAgentCreate);
1637
+ };
1638
+ const onAgentRefresh = async () => {
1639
+ setValidationMessage("");
1640
+ await updateAgentStatus();
1641
+ };
1642
+ return {
1643
+ onAgentCreate,
1644
+ onAgentDestroy: destroyAgent,
1645
+ onAgentRefresh,
1646
+ validationMessage,
1647
+ agentStatus,
1648
+ agentHostingEnabled: !!agentHostingProviderClient
1649
+ };
1650
+ };
1651
+
1652
+ // packages/sdk/shell/src/panels/IdentityPanel/useAgentHandlers.ts
1653
+ var useAgentHandlers = (params) => {
1654
+ const client = useClient5();
1655
+ if (client.config.values?.runtime?.client?.edgeFeatures?.agents) {
1656
+ return useEdgeAgentHandlers(params);
1657
+ } else {
1658
+ return useKubeAgentHandlers(params);
1659
+ }
1660
+ };
1661
+
1662
+ // packages/sdk/shell/src/steps/InvitationManager.tsx
1663
+ import { Check as Check4, X as X3 } from "@phosphor-icons/react";
1664
+ import React27, { useMemo as useMemo2 } from "react";
1665
+ import { QR } from "react-qr-rounded";
1666
+ import { useId as useId5, useTranslation as useTranslation12 } from "@dxos/react-ui";
1667
+ import { descriptionText as descriptionText8, getSize as getSize11, mx as mx20 } from "@dxos/react-ui-theme";
1668
+ import { hexToEmoji as hexToEmoji3 } from "@dxos/util";
1669
+
1670
+ // packages/sdk/shell/src/util/invitationStatusValue.ts
1671
+ import { Invitation as Invitation4 } from "@dxos/react-client/invitations";
1672
+ var invitationStatusValue = /* @__PURE__ */ new Map([
1673
+ [
1674
+ Invitation4.State.ERROR,
1675
+ -3
1676
+ ],
1677
+ [
1678
+ Invitation4.State.TIMEOUT,
1679
+ -2
1680
+ ],
1681
+ [
1682
+ Invitation4.State.CANCELLED,
1683
+ -1
1684
+ ],
1685
+ [
1686
+ Invitation4.State.INIT,
1687
+ 0
1688
+ ],
1689
+ [
1690
+ Invitation4.State.CONNECTING,
1691
+ 1
1692
+ ],
1693
+ [
1694
+ Invitation4.State.CONNECTED,
1695
+ 2
1696
+ ],
1697
+ [
1698
+ Invitation4.State.READY_FOR_AUTHENTICATION,
1699
+ 3
1700
+ ],
1701
+ [
1702
+ Invitation4.State.AUTHENTICATING,
1703
+ 4
1704
+ ],
1705
+ [
1706
+ Invitation4.State.SUCCESS,
1707
+ 5
1708
+ ]
1709
+ ]);
1710
+
1711
+ // packages/sdk/shell/src/steps/InvitationManager.tsx
1712
+ var InvitationManagerView = ({ children, ...props }) => {
1713
+ return /* @__PURE__ */ React27.createElement(Viewport.View, {
1714
+ ...props,
1715
+ classNames: "grow flex flex-col justify-around items-center"
1716
+ }, children);
1717
+ };
1718
+ var InvitationManager = ({ invitationUrl, active, send, status, multiUse, authCode, id = "0" }) => {
1719
+ const { t } = useTranslation12("os");
1720
+ const qrLabel = useId5("invitation-manager__qr-code");
1721
+ const statusValue = multiUse ? 0 : invitationStatusValue.get(status) ?? 0;
1722
+ const showAuthCode = statusValue === 3;
1723
+ const emoji = hexToEmoji3(id);
1724
+ const activeView = useMemo2(() => {
1725
+ if (multiUse) {
1726
+ return "showing qr";
1727
+ }
1728
+ switch (true) {
1729
+ case statusValue === 5:
1730
+ case statusValue < 0:
1731
+ return "showing final";
1732
+ case statusValue === 3:
1733
+ return "showing auth code";
1734
+ default:
1735
+ return "showing qr";
1736
+ }
1737
+ }, [
1738
+ statusValue
1739
+ ]);
1740
+ return /* @__PURE__ */ React27.createElement(React27.Fragment, null, /* @__PURE__ */ React27.createElement(Viewport.Root, {
1741
+ activeView,
1742
+ classNames: "grow plb-1"
1743
+ }, /* @__PURE__ */ React27.createElement(Viewport.Views, null, /* @__PURE__ */ React27.createElement(InvitationManagerView, {
1744
+ id: "showing qr",
1745
+ emoji
1746
+ }, /* @__PURE__ */ React27.createElement("p", {
1747
+ className: "text-sm mlb-1 font-normal text-center"
1748
+ }, t(multiUse ? "invite many qr label" : "invite one qr label")), /* @__PURE__ */ React27.createElement("div", {
1749
+ role: "none",
1750
+ className: mx20(descriptionText8, "is-full max-is-[14rem] relative")
1751
+ }, /* @__PURE__ */ React27.createElement(QR, {
1752
+ rounding: 100,
1753
+ backgroundColor: "transparent",
1754
+ color: "currentColor",
1755
+ className: mx20("is-full bs-full p-2", showAuthCode && "invisible"),
1756
+ "aria-labelledby": qrLabel,
1757
+ errorCorrectionLevel: "Q",
1758
+ cutout: true
1759
+ }, invitationUrl ?? "never"), /* @__PURE__ */ React27.createElement(Centered, null, /* @__PURE__ */ React27.createElement(Emoji, {
1760
+ text: emoji
1761
+ }))), /* @__PURE__ */ React27.createElement("span", {
1762
+ id: qrLabel,
1763
+ className: "sr-only"
1764
+ }, t("qr label")), /* @__PURE__ */ React27.createElement(CopyButton, {
1765
+ variant: "ghost",
1766
+ value: invitationUrl ?? "never"
1767
+ })), /* @__PURE__ */ React27.createElement(InvitationManagerView, {
1768
+ id: "showing auth code"
1769
+ }, /* @__PURE__ */ React27.createElement(Label, null, t("auth code message")), /* @__PURE__ */ React27.createElement(AuthCode, {
1770
+ code: authCode,
1771
+ large: true,
1772
+ classNames: "text-black dark:text-white"
1773
+ }), /* @__PURE__ */ React27.createElement(Label, null, t("auth other device emoji message")), emoji && /* @__PURE__ */ React27.createElement(Emoji, {
1774
+ text: emoji
1775
+ })), /* @__PURE__ */ React27.createElement(InvitationManagerView, {
1776
+ id: "showing final"
1777
+ }, statusValue > 0 ? /* @__PURE__ */ React27.createElement(Check4, {
1778
+ className: mx20("m-1.5", getSize11(6))
1779
+ }) : /* @__PURE__ */ React27.createElement(X3, {
1780
+ className: mx20("m-1.5", getSize11(6))
1781
+ })))), /* @__PURE__ */ React27.createElement(Actions, {
1782
+ classNames: "mbs-4"
1783
+ }, /* @__PURE__ */ React27.createElement(Action, {
1784
+ disabled: !active,
1785
+ onClick: () => send?.({
1786
+ type: "deselectInvitation"
1787
+ })
1788
+ }, t("back label"))));
1789
+ };
1790
+
1791
+ // packages/sdk/shell/src/steps/ConfirmReset.tsx
1792
+ import { Warning } from "@phosphor-icons/react";
1793
+ import React28, { useState as useState8 } from "react";
1794
+ import { log as log5 } from "@dxos/log";
1795
+ import { Message, useTranslation as useTranslation13 } from "@dxos/react-ui";
1796
+ import { getSize as getSize12, mx as mx21 } from "@dxos/react-ui-theme";
1797
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/steps/ConfirmReset.tsx";
1798
+ var ConfirmReset = ({ active, onCancel, onConfirm, mode }) => {
1799
+ const { t } = useTranslation13("os");
1800
+ const [validationMessage, setValidationMessage] = useState8("");
1801
+ const [pending, setPending] = useState8(false);
1802
+ const processReset = async () => {
1803
+ setPending(true);
1804
+ return onConfirm?.().then(() => setPending(false), (error) => {
1805
+ log5.catch(error, void 0, {
1806
+ F: __dxlog_file5,
1807
+ L: 38,
1808
+ S: void 0,
1809
+ C: (f, a) => f(...a)
1810
+ });
1811
+ setValidationMessage(t("failed to reset identity message"));
1812
+ setPending(false);
1813
+ });
1814
+ };
1815
+ return /* @__PURE__ */ React28.createElement(ConfirmResetImpl, {
1816
+ disabled: !active,
1817
+ pending,
1818
+ validationMessage,
1819
+ onConfirm: processReset,
1820
+ onCancel,
1821
+ mode
1822
+ });
1823
+ };
1824
+ var ConfirmResetImpl = ({ disabled, pending, validationMessage, onConfirm, onCancel, mode }) => {
1825
+ const { t } = useTranslation13("os");
1826
+ const confirmationValue = t("confirmation value");
1827
+ const [inputValue, setInputValue] = useState8("");
1828
+ const testIdAffix = mode === "join new identity" ? "join-new-identity" : mode === "recover" ? "recover" : "reset-storage";
1829
+ return /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement("div", {
1830
+ role: "none",
1831
+ className: "grow flex flex-col gap-2 justify-center"
1832
+ }, /* @__PURE__ */ React28.createElement(Message.Root, {
1833
+ valence: "error"
1834
+ }, /* @__PURE__ */ React28.createElement(Message.Title, null, /* @__PURE__ */ React28.createElement(Warning, {
1835
+ className: mx21(getSize12(6), "inline mie-2")
1836
+ }), t("sign out chooser title")), /* @__PURE__ */ React28.createElement(Message.Body, null, t("sign out chooser message"))), /* @__PURE__ */ React28.createElement(Input, {
1837
+ validationMessage,
1838
+ label: /* @__PURE__ */ React28.createElement(StepHeading, {
1839
+ className: "text-start mlb-2"
1840
+ }, t(mode === "join new identity" ? "join new identity input label" : mode === "recover" ? "recover reset input label" : "reset storage input label", {
1841
+ confirmationValue
1842
+ })),
1843
+ disabled,
1844
+ "data-testid": `${testIdAffix}.reset-identity-input`,
1845
+ placeholder: t("confirmation placeholder", {
1846
+ confirmationValue
1847
+ }),
1848
+ onChange: ({ target: { value } }) => setInputValue(value)
1849
+ })), /* @__PURE__ */ React28.createElement(Actions, null, onCancel && /* @__PURE__ */ React28.createElement(Action, {
1850
+ disabled,
1851
+ onClick: onCancel,
1852
+ "data-testid": `${testIdAffix}.reset-identity-cancel`
1853
+ }, t("cancel label")), onConfirm && /* @__PURE__ */ React28.createElement(Action, {
1854
+ variant: "destructive",
1855
+ disabled: disabled || pending || inputValue !== confirmationValue,
1856
+ onClick: onConfirm,
1857
+ "data-testid": `${testIdAffix}.reset-identity-confirm`
1858
+ }, pending ? t("reset in progress label") : t("reset device label"))));
1859
+ };
1860
+
1861
+ // packages/sdk/shell/src/panels/IdentityPanel/IdentityPanel.tsx
1862
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/IdentityPanel/IdentityPanel.tsx";
1863
+ var viewStyles = "pbs-1 pbe-3 pli-3";
1864
+ var getHueValue = (identity) => identity?.profile?.data?.hue || hexToHue2(identity?.identityKey.toHex() ?? "0");
1865
+ var getEmojiValue = (identity) => identity?.profile?.data?.emoji || hexToEmoji4(identity?.identityKey.toHex() ?? "0");
1866
+ var IdentityHeading = ({ titleId, title, identity, hideRecover, onDone, onUpdateProfile, connectionState, onChangeConnectionState }) => {
1867
+ const client = useClient6();
1868
+ const fallbackValue = keyToFallback3(identity.identityKey);
1869
+ const { t } = useTranslation14("os");
1870
+ const [displayName, setDisplayName] = useState9(identity.profile?.displayName ?? "");
1871
+ const [emoji, setEmojiDirectly] = useState9(getEmojiValue(identity));
1872
+ const [hue, setHueDirectly] = useState9(getHueValue(identity));
1873
+ const { textValue, setTextValue } = useClipboardContext();
1874
+ const identityHex = identity.identityKey.toHex();
1875
+ const publicKeyCopied = textValue === identityHex;
1876
+ const setEmoji = (nextEmoji) => {
1877
+ setEmojiDirectly(nextEmoji);
1878
+ void onUpdateProfile?.({
1879
+ ...identity.profile,
1880
+ data: {
1881
+ ...identity.profile?.data,
1882
+ emoji: nextEmoji
1883
+ }
1884
+ });
1885
+ };
1886
+ const setHue = (nextHue) => {
1887
+ setHueDirectly(nextHue);
1888
+ void onUpdateProfile?.({
1889
+ ...identity.profile,
1890
+ data: {
1891
+ ...identity.profile?.data,
1892
+ hue: nextHue
1893
+ }
1894
+ });
1895
+ };
1896
+ const handleRecoveryCode = async () => {
1897
+ invariant3(client.services.services.IdentityService, "IdentityService not available", {
1898
+ F: __dxlog_file6,
1899
+ L: 77,
1900
+ S: void 0,
1901
+ A: [
1902
+ "client.services.services.IdentityService",
1903
+ "'IdentityService not available'"
1904
+ ]
1905
+ });
1906
+ const { seedphrase } = await client.services.services.IdentityService.createRecoveryPhrase();
1907
+ void setTextValue(seedphrase);
1908
+ };
1909
+ const isConnected = connectionState === ConnectionState2.ONLINE;
1910
+ return /* @__PURE__ */ React29.createElement(Heading, {
1911
+ titleId,
1912
+ title,
1913
+ corner: /* @__PURE__ */ React29.createElement(CloseButton, {
1914
+ onDone
1915
+ })
1916
+ }, /* @__PURE__ */ React29.createElement(Avatar6.Root, {
1917
+ size: 16,
1918
+ variant: "circle",
1919
+ status: isConnected ? "active" : "error",
1920
+ hue: hue || fallbackValue.hue
1921
+ }, /* @__PURE__ */ React29.createElement(Toolbar3.Root, {
1922
+ classNames: "flex justify-center"
1923
+ }, /* @__PURE__ */ React29.createElement(Avatar6.Frame, {
1924
+ classNames: "relative z-[2] -mli-4 chromatic-ignore"
1925
+ }, /* @__PURE__ */ React29.createElement(Avatar6.Fallback, {
1926
+ text: emoji || fallbackValue.emoji
1927
+ }))), /* @__PURE__ */ React29.createElement(Avatar6.Label, {
1928
+ classNames: "sr-only",
1929
+ "data-testid": "identityHeading.displayName"
1930
+ }, identity.profile?.displayName ?? generateName3(identity.identityKey.toHex())), /* @__PURE__ */ React29.createElement(Input2.Root, null, /* @__PURE__ */ React29.createElement(Input2.Label, {
1931
+ srOnly: true
1932
+ }, t("display name input label")), /* @__PURE__ */ React29.createElement(Input2.TextInput, {
1933
+ variant: "subdued",
1934
+ "data-testid": "display-name-input",
1935
+ placeholder: t("display name input placeholder"),
1936
+ classNames: "mbs-2 text-center font-light text-xl",
1937
+ value: displayName,
1938
+ onChange: ({ target: { value } }) => setDisplayName(value),
1939
+ onBlur: ({ target: { value } }) => onUpdateProfile?.({
1940
+ ...identity.profile,
1941
+ displayName: value
1942
+ })
1943
+ })), /* @__PURE__ */ React29.createElement(Toolbar3.Root, {
1944
+ classNames: "flex justify-center items-center gap-1 pt-3"
1945
+ }, /* @__PURE__ */ React29.createElement(EmojiPickerToolbarButton, {
1946
+ emoji,
1947
+ onChangeEmoji: setEmoji,
1948
+ classNames: "bs-[--rail-action]"
1949
+ }), /* @__PURE__ */ React29.createElement(HuePickerToolbarButton, {
1950
+ hue,
1951
+ onChangeHue: setHue,
1952
+ classNames: "bs-[--rail-action]"
1953
+ }), /* @__PURE__ */ React29.createElement(Tooltip6.Root, null, /* @__PURE__ */ React29.createElement(Tooltip6.Trigger, {
1954
+ asChild: true
1955
+ }, /* @__PURE__ */ React29.createElement(Toolbar3.Button, {
1956
+ classNames: "bs-[--rail-action]",
1957
+ "data-testid": "update-profile-form-copy-key",
1958
+ onClick: () => setTextValue(identityHex)
1959
+ }, /* @__PURE__ */ React29.createElement("span", {
1960
+ className: "sr-only"
1961
+ }, t(publicKeyCopied ? "copy success label" : "copy self public key label")), /* @__PURE__ */ React29.createElement(Key, {
1962
+ className: getSize13(5)
1963
+ }))), /* @__PURE__ */ React29.createElement(Tooltip6.Portal, null, /* @__PURE__ */ React29.createElement(Tooltip6.Content, {
1964
+ side: "bottom",
1965
+ classNames: "z-50"
1966
+ }, t(publicKeyCopied ? "copy success label" : "copy self public key label"), /* @__PURE__ */ React29.createElement(Tooltip6.Arrow, null)))), !hideRecover && /* @__PURE__ */ React29.createElement(Tooltip6.Root, null, /* @__PURE__ */ React29.createElement(Tooltip6.Trigger, {
1967
+ asChild: true
1968
+ }, /* @__PURE__ */ React29.createElement(Toolbar3.Button, {
1969
+ classNames: "bs-[--rail-action]",
1970
+ onClick: handleRecoveryCode
1971
+ }, /* @__PURE__ */ React29.createElement(FirstAidKit2, {
1972
+ className: getSize13(5)
1973
+ }))), /* @__PURE__ */ React29.createElement(Tooltip6.Portal, null, /* @__PURE__ */ React29.createElement(Tooltip6.Content, {
1974
+ side: "bottom",
1975
+ classNames: "z-50"
1976
+ }, t("create recovery code label"), /* @__PURE__ */ React29.createElement(Tooltip6.Arrow, null)))), /* @__PURE__ */ React29.createElement(Tooltip6.Root, null, /* @__PURE__ */ React29.createElement(Tooltip6.Trigger, {
1977
+ asChild: true
1978
+ }, /* @__PURE__ */ React29.createElement(Toolbar3.Button, {
1979
+ classNames: [
1980
+ "bs-[--rail-action]",
1981
+ !isConnected && "text-error-500"
1982
+ ],
1983
+ onClick: () => onChangeConnectionState?.(isConnected ? ConnectionState2.OFFLINE : ConnectionState2.ONLINE)
1984
+ }, /* @__PURE__ */ React29.createElement("span", {
1985
+ className: "sr-only"
1986
+ }, t(isConnected ? "disconnect label" : "connect label")), isConnected ? /* @__PURE__ */ React29.createElement(PlugsConnected, {
1987
+ className: getSize13(5)
1988
+ }) : /* @__PURE__ */ React29.createElement(Plugs, {
1989
+ className: getSize13(5)
1990
+ }))), /* @__PURE__ */ React29.createElement(Tooltip6.Portal, null, /* @__PURE__ */ React29.createElement(Tooltip6.Content, {
1991
+ side: "bottom",
1992
+ classNames: "z-50"
1993
+ }, t(isConnected ? "disconnect label" : "connect label"), /* @__PURE__ */ React29.createElement(Tooltip6.Arrow, null)))))));
1994
+ };
1995
+ var IdentityPanelImpl = (props) => {
1996
+ const { identity, titleId, activeView, onUpdateProfile, onResetStorage, onRecover, onJoinNewIdentity, IdentityActionChooser: IdentityActionChooserComponent = IdentityActionChooser, InvitationManager: InvitationManagerComponent = InvitationManager, connectionState, onChangeConnectionState, onDone, ...rest } = props;
1997
+ const { t } = useTranslation14("os");
1998
+ const title = useMemo3(() => {
1999
+ switch (activeView) {
2000
+ case "device invitation manager":
2001
+ return t("choose add device label");
2002
+ default:
2003
+ return t("identity heading");
2004
+ }
2005
+ }, [
2006
+ activeView,
2007
+ t
2008
+ ]);
2009
+ const onCancelReset = () => rest.send?.("unchooseAction");
2010
+ const hideRecover = rest.agentStatus !== "created";
2011
+ return /* @__PURE__ */ React29.createElement(React29.Fragment, null, /* @__PURE__ */ React29.createElement(IdentityHeading, {
2012
+ identity,
2013
+ titleId,
2014
+ title,
2015
+ hideRecover,
2016
+ onDone,
2017
+ onUpdateProfile,
2018
+ connectionState,
2019
+ onChangeConnectionState
2020
+ }), /* @__PURE__ */ React29.createElement(Viewport.Root, {
2021
+ activeView
2022
+ }, /* @__PURE__ */ React29.createElement(Viewport.Views, null, /* @__PURE__ */ React29.createElement(Viewport.View, {
2023
+ id: "identity action chooser",
2024
+ classNames: viewStyles
2025
+ }, /* @__PURE__ */ React29.createElement(IdentityActionChooserComponent, {
2026
+ active: activeView === "identity action chooser",
2027
+ ...rest,
2028
+ connectionState
2029
+ })), /* @__PURE__ */ React29.createElement(Viewport.View, {
2030
+ id: "device invitation manager",
2031
+ classNames: viewStyles
2032
+ }, /* @__PURE__ */ React29.createElement(InvitationManagerComponent, {
2033
+ active: activeView === "device invitation manager",
2034
+ ...rest,
2035
+ invitationUrl: rest.createInvitationUrl(rest.invitationCode)
2036
+ })), /* @__PURE__ */ React29.createElement(Viewport.View, {
2037
+ classNames: viewStyles,
2038
+ id: "confirm join new identity"
2039
+ }, /* @__PURE__ */ React29.createElement(ConfirmReset, {
2040
+ active: activeView === "confirm join new identity",
2041
+ ...rest,
2042
+ mode: "join new identity",
2043
+ onConfirm: onJoinNewIdentity,
2044
+ onCancel: onCancelReset
2045
+ })), /* @__PURE__ */ React29.createElement(Viewport.View, {
2046
+ classNames: viewStyles,
2047
+ id: "confirm recover"
2048
+ }, /* @__PURE__ */ React29.createElement(ConfirmReset, {
2049
+ active: activeView === "confirm recover",
2050
+ ...rest,
2051
+ mode: "recover",
2052
+ onConfirm: onRecover,
2053
+ onCancel: onCancelReset
2054
+ })), /* @__PURE__ */ React29.createElement(Viewport.View, {
2055
+ classNames: viewStyles,
2056
+ id: "confirm reset storage"
2057
+ }, /* @__PURE__ */ React29.createElement(ConfirmReset, {
2058
+ active: activeView === "confirm reset storage",
2059
+ ...rest,
2060
+ mode: "reset storage",
2061
+ onConfirm: onResetStorage,
2062
+ onCancel: onCancelReset
2063
+ })))));
2064
+ };
2065
+ var IdentityPanelWithInvitationImpl = ({ invitation, ...props }) => {
2066
+ const invitationStatus = useInvitationStatus2(invitation);
2067
+ return /* @__PURE__ */ React29.createElement(IdentityPanelImpl, {
2068
+ ...props,
2069
+ ...invitationStatus
2070
+ });
2071
+ };
2072
+ var IdentityPanel = ({ titleId: propsTitleId, createInvitationUrl = (code) => code, initialDisposition = "default", ...props }) => {
2073
+ const titleId = useId6("identityPanel__heading", propsTitleId);
2074
+ const client = useClient6();
2075
+ const devices = useDevices();
2076
+ const identity = useIdentity();
2077
+ const invitations = useHaloInvitations2();
2078
+ const agentProps = useAgentHandlers({
2079
+ identity,
2080
+ invitations
2081
+ });
2082
+ if (!identity) {
2083
+ log6.error("IdentityPanel rendered with no active identity.", void 0, {
2084
+ F: __dxlog_file6,
2085
+ L: 288,
2086
+ S: void 0,
2087
+ C: (f, a) => f(...a)
2088
+ });
2089
+ return null;
2090
+ }
2091
+ const [identityState, identitySend, identityService] = useIdentityMachine(client, {
2092
+ context: {
2093
+ initialDisposition
2094
+ }
2095
+ });
2096
+ const { swarm: connectionState } = useNetworkStatus();
2097
+ const handleChangeConnectionState = async (nextState) => client?.mesh.updateConfig(nextState);
2098
+ useEffect4(() => {
2099
+ const subscription = identityService.subscribe((state) => {
2100
+ log6("[state]", state, {
2101
+ F: __dxlog_file6,
2102
+ L: 301,
2103
+ S: void 0,
2104
+ C: (f, a) => f(...a)
2105
+ });
2106
+ });
2107
+ return subscription.unsubscribe;
2108
+ }, [
2109
+ identityService
2110
+ ]);
2111
+ const activeView = useMemo3(() => {
2112
+ switch (true) {
2113
+ case identityState.matches("choosingAction"):
2114
+ return "identity action chooser";
2115
+ case identityState.matches("managingDeviceInvitation"):
2116
+ return "device invitation manager";
2117
+ case identityState.matches("confirmingResetStorage"):
2118
+ return "confirm reset storage";
2119
+ case identityState.matches("confirmingRecover"):
2120
+ return "confirm recover";
2121
+ case identityState.matches("confirmingJoinNewIdentity"):
2122
+ return "confirm join new identity";
2123
+ default:
2124
+ return "identity action chooser";
2125
+ }
2126
+ }, [
2127
+ identityState
2128
+ ]);
2129
+ const onUpdateProfile = async (profile) => {
2130
+ identitySend({
2131
+ type: "updateProfile"
2132
+ });
2133
+ await client.halo.updateProfile(profile);
2134
+ };
2135
+ const implProps = {
2136
+ ...props,
2137
+ identity,
2138
+ devices,
2139
+ activeView,
2140
+ send: identitySend,
2141
+ titleId,
2142
+ createInvitationUrl,
2143
+ onUpdateProfile,
2144
+ connectionState,
2145
+ onChangeConnectionState: handleChangeConnectionState,
2146
+ ...agentProps
2147
+ };
2148
+ return identityState.context.invitation ? /* @__PURE__ */ React29.createElement(IdentityPanelWithInvitationImpl, {
2149
+ ...implProps,
2150
+ invitation: identityState.context.invitation
2151
+ }) : /* @__PURE__ */ React29.createElement(IdentityPanelImpl, implProps);
2152
+ };
2153
+
2154
+ // packages/sdk/shell/src/panels/JoinPanel/JoinPanel.tsx
2155
+ import React38, { useCallback as useCallback6, useEffect as useEffect6, useMemo as useMemo4 } from "react";
2156
+ import { log as log10 } from "@dxos/log";
2157
+ import { useClient as useClient8, useMulticastObservable } from "@dxos/react-client";
2158
+ import { useIdentity as useIdentity2 } from "@dxos/react-client/halo";
2159
+ import { useId as useId8, useThemeContext as useThemeContext5 } from "@dxos/react-ui";
2160
+
2161
+ // packages/sdk/shell/src/panels/JoinPanel/JoinHeading.tsx
2162
+ import { X as X4 } from "@phosphor-icons/react";
2163
+ import React30, { cloneElement, forwardRef as forwardRef9 } from "react";
2164
+ import { Button as Button10, useTranslation as useTranslation15 } from "@dxos/react-ui";
2165
+ import { descriptionText as descriptionText9, getSize as getSize14, mx as mx22 } from "@dxos/react-ui-theme";
2166
+ var JoinHeading = /* @__PURE__ */ forwardRef9(({ mode, titleId, exitActionParent, onExit }, forwardedRef) => {
2167
+ const { t } = useTranslation15("os");
2168
+ const exitButton = /* @__PURE__ */ React30.createElement(Button10, {
2169
+ variant: "ghost",
2170
+ ...onExit && {
2171
+ onClick: onExit
2172
+ },
2173
+ classNames: mx22(descriptionText9, "plb-0 pli-2 absolute block-start-0 inline-end-0 z-[1]"),
2174
+ "data-testid": "join-exit"
2175
+ }, /* @__PURE__ */ React30.createElement(X4, {
2176
+ weight: "bold",
2177
+ className: getSize14(4)
2178
+ }), /* @__PURE__ */ React30.createElement("span", {
2179
+ className: "sr-only"
2180
+ }, t("exit label")));
2181
+ return /* @__PURE__ */ React30.createElement(Heading, {
2182
+ ref: forwardedRef,
2183
+ titleId,
2184
+ title: t(mode === "halo-only" ? "selecting identity heading" : "joining space heading"),
2185
+ ...mode === "halo-only" ? {
2186
+ titleSrOnly: true
2187
+ } : {
2188
+ corner: exitActionParent ? /* @__PURE__ */ cloneElement(exitActionParent, {}, exitButton) : exitButton
2189
+ },
2190
+ titleSrOnly: mode === "halo-only"
2191
+ });
2192
+ });
2193
+
2194
+ // packages/sdk/shell/src/panels/JoinPanel/joinMachine.ts
2195
+ import { useMachine as useMachine2 } from "@xstate/react";
2196
+ import { useCallback as useCallback5 } from "react";
2197
+ import { assign as assign2, createMachine as createMachine2 } from "xstate";
2198
+ import { log as log7 } from "@dxos/log";
2199
+ import { AlreadyJoinedError } from "@dxos/react-client";
2200
+ import { Invitation as Invitation5, InvitationEncoder as InvitationEncoder3 } from "@dxos/react-client/invitations";
2201
+ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/JoinPanel/joinMachine.ts";
2202
+ var getInvitationSubscribable = (Kind, invitation) => {
2203
+ log7("[subscribing to invitation]", invitation, {
2204
+ F: __dxlog_file7,
2205
+ L: 90,
2206
+ S: void 0,
2207
+ C: (f, a) => f(...a)
2208
+ });
2209
+ return {
2210
+ subscribe: (next, onError, complete) => invitation.subscribe((invitation2) => {
2211
+ switch (invitation2.state) {
2212
+ case Invitation5.State.CONNECTING: {
2213
+ log7("[invitation connecting]", {
2214
+ Kind,
2215
+ invitation: invitation2
2216
+ }, {
2217
+ F: __dxlog_file7,
2218
+ L: 101,
2219
+ S: void 0,
2220
+ C: (f, a) => f(...a)
2221
+ });
2222
+ return next({
2223
+ type: `connecting${Kind}Invitation`,
2224
+ invitation: invitation2
2225
+ });
2226
+ }
2227
+ case Invitation5.State.CONNECTED: {
2228
+ log7("[invitation connected]", {
2229
+ Kind,
2230
+ invitation: invitation2
2231
+ }, {
2232
+ F: __dxlog_file7,
2233
+ L: 106,
2234
+ S: void 0,
2235
+ C: (f, a) => f(...a)
2236
+ });
2237
+ return next({
2238
+ type: `connected${Kind}Invitation`,
2239
+ invitation: invitation2
2240
+ });
2241
+ }
2242
+ case Invitation5.State.READY_FOR_AUTHENTICATION: {
2243
+ log7("[invitation ready for authentication]", {
2244
+ Kind,
2245
+ invitation: invitation2
2246
+ }, {
2247
+ F: __dxlog_file7,
2248
+ L: 111,
2249
+ S: void 0,
2250
+ C: (f, a) => f(...a)
2251
+ });
2252
+ return next({
2253
+ type: `readyForAuthentication${Kind}Invitation`,
2254
+ invitation: invitation2
2255
+ });
2256
+ }
2257
+ case Invitation5.State.AUTHENTICATING: {
2258
+ log7("[invitation authenticating]", {
2259
+ Kind,
2260
+ invitation: invitation2
2261
+ }, {
2262
+ F: __dxlog_file7,
2263
+ L: 116,
2264
+ S: void 0,
2265
+ C: (f, a) => f(...a)
2266
+ });
2267
+ return next({
2268
+ type: `authenticating${Kind}Invitation`,
2269
+ invitation: invitation2
2270
+ });
2271
+ }
2272
+ case Invitation5.State.SUCCESS: {
2273
+ log7("[invitation success]", {
2274
+ Kind,
2275
+ invitation: invitation2
2276
+ }, {
2277
+ F: __dxlog_file7,
2278
+ L: 121,
2279
+ S: void 0,
2280
+ C: (f, a) => f(...a)
2281
+ });
2282
+ next({
2283
+ type: `success${Kind}Invitation`,
2284
+ invitation: invitation2
2285
+ });
2286
+ return complete?.();
2287
+ }
2288
+ case Invitation5.State.CANCELLED: {
2289
+ log7.warn("[invitation cancelled]", {
2290
+ Kind
2291
+ }, {
2292
+ F: __dxlog_file7,
2293
+ L: 127,
2294
+ S: void 0,
2295
+ C: (f, a) => f(...a)
2296
+ });
2297
+ return next({
2298
+ type: `fail${Kind}Invitation`,
2299
+ reason: "cancelled"
2300
+ });
2301
+ }
2302
+ case Invitation5.State.TIMEOUT: {
2303
+ log7.error("[invitation timeout]", {
2304
+ Kind
2305
+ }, {
2306
+ F: __dxlog_file7,
2307
+ L: 132,
2308
+ S: void 0,
2309
+ C: (f, a) => f(...a)
2310
+ });
2311
+ return next({
2312
+ type: `fail${Kind}Invitation`,
2313
+ reason: "timeout"
2314
+ });
2315
+ }
2316
+ }
2317
+ }, (error) => {
2318
+ if (error instanceof AlreadyJoinedError) {
2319
+ log7("[already joined]", {
2320
+ Kind,
2321
+ error
2322
+ }, {
2323
+ F: __dxlog_file7,
2324
+ L: 139,
2325
+ S: void 0,
2326
+ C: (f, a) => f(...a)
2327
+ });
2328
+ next({
2329
+ type: `success${Kind}Invitation`,
2330
+ invitation: invitation.get()
2331
+ });
2332
+ return complete?.();
2333
+ }
2334
+ log7.error("[invitation errored]", {
2335
+ Kind,
2336
+ error
2337
+ }, {
2338
+ F: __dxlog_file7,
2339
+ L: 144,
2340
+ S: void 0,
2341
+ C: (f, a) => f(...a)
2342
+ });
2343
+ next({
2344
+ type: `fail${Kind}Invitation`,
2345
+ reason: "error"
2346
+ });
2347
+ return onError?.(error);
2348
+ })
2349
+ };
2350
+ };
2351
+ var acceptingInvitationTemplate = (Kind, successTarget) => {
2352
+ const config = {
2353
+ initial: `unknown${Kind}`,
2354
+ states: {
2355
+ [`unknown${Kind}`]: {
2356
+ always: [
2357
+ {
2358
+ cond: ({ mode }) => mode === "halo-only" && Kind === "Space",
2359
+ target: "#join.finishingJoiningHalo"
2360
+ },
2361
+ {
2362
+ cond: (context) => !!context[Kind.toLowerCase()].unredeemedCode,
2363
+ target: `acceptingRedeemed${Kind}Invitation`,
2364
+ actions: [
2365
+ `redeem${Kind}InvitationCode`,
2366
+ `invalidate${Kind}InvitationCode`,
2367
+ "log"
2368
+ ]
2369
+ },
2370
+ {
2371
+ target: `inputting${Kind}InvitationCode`,
2372
+ actions: "log"
2373
+ }
2374
+ ]
2375
+ },
2376
+ [`inputting${Kind}InvitationCode`]: {},
2377
+ [`acceptingRedeemed${Kind}Invitation`]: {
2378
+ invoke: {
2379
+ src: (context) => context[Kind.toLowerCase()].invitationSubscribable
2380
+ },
2381
+ initial: `unknown${Kind}Invitation`,
2382
+ states: {
2383
+ [`unknown${Kind}Invitation`]: {
2384
+ always: [
2385
+ {
2386
+ cond: (context) => {
2387
+ if (Kind !== "Space") {
2388
+ return false;
2389
+ } else {
2390
+ const spaceKey = context.space.invitation?.spaceKey?.toHex();
2391
+ const succeededKeys = context.space.succeededKeys;
2392
+ return spaceKey ? !!succeededKeys?.has(spaceKey) : false;
2393
+ }
2394
+ },
2395
+ target: successTarget,
2396
+ actions: "log"
2397
+ },
2398
+ {
2399
+ cond: (context) => {
2400
+ const invitation = context[Kind.toLowerCase()].invitation;
2401
+ return !invitation || invitation?.state === Invitation5.State.CONNECTING;
2402
+ },
2403
+ target: `connecting${Kind}Invitation`,
2404
+ actions: "log"
2405
+ },
2406
+ {
2407
+ target: `inputting${Kind}VerificationCode`,
2408
+ actions: "log"
2409
+ }
2410
+ ]
2411
+ },
2412
+ [`connecting${Kind}Invitation`]: {},
2413
+ [`inputting${Kind}VerificationCode`]: {},
2414
+ [`authenticating${Kind}VerificationCode`]: {
2415
+ on: {
2416
+ [`readyForAuthentication${Kind}Invitation`]: {
2417
+ target: `authenticationFailing${Kind}VerificationCode`,
2418
+ actions: [
2419
+ "setInvitation",
2420
+ "log"
2421
+ ]
2422
+ }
2423
+ }
2424
+ },
2425
+ [`authenticationFailing${Kind}VerificationCode`]: {},
2426
+ [`failing${Kind}Invitation`]: {},
2427
+ [`success${Kind}Invitation`]: {}
2428
+ },
2429
+ on: {
2430
+ [`reset${Kind}Invitation`]: {
2431
+ target: `#join${Kind === "Halo" ? ".choosingIdentity" : ""}.accepting${Kind}Invitation.unknown${Kind}`,
2432
+ actions: [
2433
+ "resetInvitation",
2434
+ "log"
2435
+ ]
2436
+ },
2437
+ [`connecting${Kind}Invitation`]: {
2438
+ target: `.connecting${Kind}Invitation`,
2439
+ actions: [
2440
+ "setInvitation",
2441
+ "log"
2442
+ ]
2443
+ },
2444
+ [`connected${Kind}Invitation`]: {
2445
+ target: `.connecting${Kind}Invitation`,
2446
+ actions: [
2447
+ "setInvitation",
2448
+ "log"
2449
+ ]
2450
+ },
2451
+ [`readyForAuthentication${Kind}Invitation`]: {
2452
+ target: `.inputting${Kind}VerificationCode`,
2453
+ actions: [
2454
+ "setInvitation",
2455
+ "log"
2456
+ ]
2457
+ },
2458
+ [`authenticating${Kind}Invitation`]: {
2459
+ target: `.authenticating${Kind}VerificationCode`,
2460
+ actions: [
2461
+ "setInvitation",
2462
+ "log"
2463
+ ]
2464
+ },
2465
+ [`success${Kind}Invitation`]: {
2466
+ target: successTarget,
2467
+ actions: [
2468
+ "setInvitation",
2469
+ "log"
2470
+ ]
2471
+ },
2472
+ [`fail${Kind}Invitation`]: {
2473
+ target: `.failing${Kind}Invitation`,
2474
+ actions: [
2475
+ assign2({
2476
+ [Kind.toLowerCase()]: (context, event) => ({
2477
+ ...context[Kind.toLowerCase()],
2478
+ failReason: event.reason
2479
+ })
2480
+ }),
2481
+ "log"
2482
+ ]
2483
+ }
2484
+ }
2485
+ }
2486
+ },
2487
+ on: {
2488
+ [`set${Kind}InvitationCode`]: {
2489
+ target: `.acceptingRedeemed${Kind}Invitation`,
2490
+ actions: [
2491
+ assign2({
2492
+ [Kind.toLowerCase()]: (context, event) => ({
2493
+ ...context[Kind.toLowerCase()],
2494
+ unredeemedCode: event.code,
2495
+ succeededKeys: event.succeededKeys
2496
+ })
2497
+ }),
2498
+ `redeem${Kind}InvitationCode`,
2499
+ `invalidate${Kind}InvitationCode`,
2500
+ "log"
2501
+ ]
2502
+ }
2503
+ }
2504
+ };
2505
+ return config;
2506
+ };
2507
+ var joinMachine = createMachine2({
2508
+ id: "join",
2509
+ predictableActionArguments: true,
2510
+ context: {
2511
+ initialDisposition: "default",
2512
+ mode: "default",
2513
+ identity: null,
2514
+ halo: {},
2515
+ space: {}
2516
+ },
2517
+ initial: "unknown",
2518
+ states: {
2519
+ unknown: {
2520
+ always: [
2521
+ {
2522
+ cond: "existingIdentity",
2523
+ target: "resettingIdentity",
2524
+ actions: "log"
2525
+ },
2526
+ {
2527
+ cond: "initiallyAcceptingHaloInvitation",
2528
+ target: "#join.choosingIdentity.acceptingHaloInvitation",
2529
+ actions: "log"
2530
+ },
2531
+ {
2532
+ cond: "initiallyRecoveringIdentity",
2533
+ target: "#join.choosingIdentity.recoveringIdentity",
2534
+ actions: "log"
2535
+ },
2536
+ {
2537
+ cond: "noSelectedIdentity",
2538
+ target: "choosingIdentity",
2539
+ actions: "log"
2540
+ },
2541
+ {
2542
+ target: "acceptingSpaceInvitation",
2543
+ actions: "log"
2544
+ }
2545
+ ]
2546
+ },
2547
+ // TODO(wittjosiah): Remove.
2548
+ choosingIdentity: {
2549
+ initial: "unknownAuthMethod",
2550
+ states: {
2551
+ unknownAuthMethod: {
2552
+ always: [
2553
+ {
2554
+ cond: "hasHaloUnredeemedCode",
2555
+ target: "acceptingHaloInvitation",
2556
+ actions: "log"
2557
+ },
2558
+ {
2559
+ target: "choosingAuthMethod",
2560
+ actions: "log"
2561
+ }
2562
+ ]
2563
+ },
2564
+ choosingAuthMethod: {},
2565
+ recoveringIdentity: {},
2566
+ creatingIdentity: {},
2567
+ acceptingHaloInvitation: acceptingInvitationTemplate("Halo", "#join.acceptingSpaceInvitation"),
2568
+ confirmingAddedIdentity: {}
2569
+ },
2570
+ on: {
2571
+ recoverIdentity: {
2572
+ target: ".recoveringIdentity",
2573
+ actions: "log"
2574
+ },
2575
+ createIdentity: {
2576
+ target: ".creatingIdentity",
2577
+ actions: "log"
2578
+ },
2579
+ acceptHaloInvitation: {
2580
+ target: ".acceptingHaloInvitation",
2581
+ actions: "log"
2582
+ },
2583
+ addIdentity: {
2584
+ target: ".confirmingAddedIdentity",
2585
+ actions: "log"
2586
+ },
2587
+ selectIdentity: {
2588
+ target: "acceptingSpaceInvitation",
2589
+ actions: [
2590
+ "setIdentity",
2591
+ "log"
2592
+ ]
2593
+ },
2594
+ deselectAuthMethod: {
2595
+ target: ".choosingAuthMethod",
2596
+ actions: "log"
2597
+ }
2598
+ }
2599
+ },
2600
+ // TODO(wittjosiah): Factor out to a machine handling recovery and device invitations.
2601
+ resettingIdentity: {},
2602
+ acceptingSpaceInvitation: acceptingInvitationTemplate("Space", "#join.finishingJoiningSpace"),
2603
+ finishingJoiningSpace: {
2604
+ type: "final"
2605
+ },
2606
+ finishingJoiningHalo: {
2607
+ type: "final"
2608
+ }
2609
+ },
2610
+ on: {
2611
+ resetIdentity: {
2612
+ target: "choosingIdentity",
2613
+ actions: "unsetIdentity"
2614
+ }
2615
+ }
2616
+ }, {
2617
+ guards: {
2618
+ existingIdentity: ({ identity, mode }, _event) => mode === "halo-only" && !!identity,
2619
+ noSelectedIdentity: ({ identity }, _event) => !identity,
2620
+ initiallyAcceptingHaloInvitation: ({ identity, initialDisposition }, _event) => !identity && initialDisposition === "accept-halo-invitation",
2621
+ initiallyRecoveringIdentity: ({ identity, initialDisposition }, _event) => !identity && initialDisposition === "recover-identity",
2622
+ hasHaloUnredeemedCode: ({ halo }, _event) => !!halo.unredeemedCode,
2623
+ noSpaceInvitation: ({ space }, _event) => !space.invitation && !space.unredeemedCode
2624
+ },
2625
+ actions: {
2626
+ setIdentity: assign2({
2627
+ identity: (context, event) => event.identity
2628
+ }),
2629
+ unsetIdentity: assign2({
2630
+ identity: () => null
2631
+ }),
2632
+ resetInvitation: assign2({
2633
+ halo: (context, event) => {
2634
+ if (event.type !== "resetHaloInvitation") {
2635
+ return context.halo;
2636
+ }
2637
+ if (context.halo.invitationObservable) {
2638
+ void context.halo.invitationObservable.cancel();
2639
+ }
2640
+ return {
2641
+ ...context.halo,
2642
+ invitation: void 0,
2643
+ invitationObservable: void 0,
2644
+ invitationSubscribable: void 0
2645
+ };
2646
+ },
2647
+ space: (context, event) => {
2648
+ if (event.type !== "resetSpaceInvitation") {
2649
+ return context.space;
2650
+ }
2651
+ if (context.space.invitationObservable) {
2652
+ void context.space.invitationObservable.cancel();
2653
+ }
2654
+ return {
2655
+ ...context.space,
2656
+ invitation: void 0,
2657
+ invitationObservable: void 0,
2658
+ invitationSubscribable: void 0
2659
+ };
2660
+ }
2661
+ }),
2662
+ setInvitation: assign2({
2663
+ halo: (context, event) => event.type.includes("Halo") ? {
2664
+ ...context.halo,
2665
+ invitation: event.invitation
2666
+ } : context.halo,
2667
+ space: (context, event) => event.type.includes("Space") ? {
2668
+ ...context.space,
2669
+ invitation: event.invitation
2670
+ } : context.space
2671
+ }),
2672
+ log: (context, event) => {
2673
+ log7("[transition]", {
2674
+ event,
2675
+ haloInvitation: context.halo.invitation,
2676
+ spaceInvitation: context.space.invitation
2677
+ }, {
2678
+ F: __dxlog_file7,
2679
+ L: 425,
2680
+ S: void 0,
2681
+ C: (f, a) => f(...a)
2682
+ });
2683
+ }
2684
+ }
2685
+ });
2686
+ var defaultCodeFromUrl = (invitationType, text) => {
2687
+ try {
2688
+ const searchParams = new URLSearchParams(text.substring(text.lastIndexOf("?")));
2689
+ return searchParams.get(`${invitationType}InvitationCode`) ?? searchParams.get(`${invitationType}Invitation`) ?? searchParams.get("invitationCode") ?? searchParams.get("invitation") ?? text;
2690
+ } catch (err) {
2691
+ log7.catch(err, void 0, {
2692
+ F: __dxlog_file7,
2693
+ L: 452,
2694
+ S: void 0,
2695
+ C: (f, a) => f(...a)
2696
+ });
2697
+ return text;
2698
+ }
2699
+ };
2700
+ var useJoinMachine = (client, options) => {
2701
+ const redeemHaloInvitationCode = useCallback5(({ halo }) => {
2702
+ if (halo.unredeemedCode) {
2703
+ try {
2704
+ const invitation = InvitationEncoder3.decode(defaultCodeFromUrl("halo", halo.unredeemedCode));
2705
+ const invitationObservable = client.halo.join(invitation);
2706
+ return {
2707
+ ...halo,
2708
+ invitationObservable,
2709
+ invitationSubscribable: getInvitationSubscribable("Halo", invitationObservable)
2710
+ };
2711
+ } catch (err) {
2712
+ log7.error("Could not redeem device invitation code", err, {
2713
+ F: __dxlog_file7,
2714
+ L: 473,
2715
+ S: void 0,
2716
+ C: (f, a) => f(...a)
2717
+ });
2718
+ return halo;
2719
+ }
2720
+ } else {
2721
+ return halo;
2722
+ }
2723
+ }, [
2724
+ client
2725
+ ]);
2726
+ const redeemSpaceInvitationCode = useCallback5(({ space }) => {
2727
+ if (space.unredeemedCode) {
2728
+ try {
2729
+ const invitation = InvitationEncoder3.decode(defaultCodeFromUrl("space", space.unredeemedCode));
2730
+ const invitationObservable = client.spaces.join(invitation);
2731
+ return {
2732
+ ...space,
2733
+ invitationObservable,
2734
+ invitationSubscribable: getInvitationSubscribable("Space", invitationObservable)
2735
+ };
2736
+ } catch (err) {
2737
+ log7.error("Could not redeem space invitation code", err, {
2738
+ F: __dxlog_file7,
2739
+ L: 495,
2740
+ S: void 0,
2741
+ C: (f, a) => f(...a)
2742
+ });
2743
+ return space;
2744
+ }
2745
+ } else {
2746
+ return space;
2747
+ }
2748
+ }, [
2749
+ client
2750
+ ]);
2751
+ const invalidateHaloInvitationCode = useCallback5(({ halo }) => {
2752
+ if (halo.unredeemedCode) {
2753
+ options?.onInvalidateInvitationCode?.(halo.unredeemedCode);
2754
+ return {
2755
+ ...halo,
2756
+ unredeemedCode: void 0
2757
+ };
2758
+ } else {
2759
+ return halo;
2760
+ }
2761
+ }, [
2762
+ options?.onInvalidateInvitationCode
2763
+ ]);
2764
+ const invalidateSpaceInvitationCode = useCallback5(({ space }) => {
2765
+ if (space.unredeemedCode) {
2766
+ options?.onInvalidateInvitationCode?.(space.unredeemedCode);
2767
+ return {
2768
+ ...space,
2769
+ unredeemedCode: void 0
2770
+ };
2771
+ } else {
2772
+ return space;
2773
+ }
2774
+ }, [
2775
+ options?.onInvalidateInvitationCode
2776
+ ]);
2777
+ return useMachine2(joinMachine, {
2778
+ ...options,
2779
+ actions: {
2780
+ ...options?.actions,
2781
+ redeemHaloInvitationCode: assign2({
2782
+ halo: redeemHaloInvitationCode
2783
+ }),
2784
+ redeemSpaceInvitationCode: assign2({
2785
+ space: redeemSpaceInvitationCode
2786
+ }),
2787
+ invalidateHaloInvitationCode: assign2({
2788
+ halo: invalidateHaloInvitationCode
2789
+ }),
2790
+ invalidateSpaceInvitationCode: assign2({
2791
+ space: invalidateSpaceInvitationCode
2792
+ })
2793
+ }
2794
+ });
2795
+ };
2796
+
2797
+ // packages/sdk/shell/src/panels/JoinPanel/steps/AdditionMethodChooser.tsx
2798
+ import { CaretRight as CaretRight2, Plus as Plus3, QrCode, Textbox } from "@phosphor-icons/react";
2799
+ import React31 from "react";
2800
+ import { useTranslation as useTranslation16 } from "@dxos/react-ui";
2801
+ import { getSize as getSize15 } from "@dxos/react-ui-theme";
2802
+ var AdditionMethodChooser = (viewStateProps) => {
2803
+ const disabled = !viewStateProps.active;
2804
+ const { send } = viewStateProps;
2805
+ const { t } = useTranslation16("os");
2806
+ const sharedButtonProps = {
2807
+ disabled,
2808
+ after: /* @__PURE__ */ React31.createElement(CaretRight2, {
2809
+ className: getSize15(4),
2810
+ weight: "bold"
2811
+ }),
2812
+ slots: {
2813
+ label: {
2814
+ className: "text-sm"
2815
+ }
2816
+ }
2817
+ };
2818
+ return /* @__PURE__ */ React31.createElement(React31.Fragment, null, /* @__PURE__ */ React31.createElement(StepHeading, null, t("addition method chooser title")), /* @__PURE__ */ React31.createElement("div", {
2819
+ role: "none",
2820
+ className: "flex flex-col gap-1 grow"
2821
+ }, /* @__PURE__ */ React31.createElement(CompoundButton, {
2822
+ ...sharedButtonProps,
2823
+ description: t("create identity description"),
2824
+ before: /* @__PURE__ */ React31.createElement(Plus3, {
2825
+ className: getSize15(6)
2826
+ }),
2827
+ onClick: () => send({
2828
+ type: "createIdentity"
2829
+ }),
2830
+ "data-autofocus": "choosingAuthMethod",
2831
+ "data-testid": "identity-chooser.create-identity"
2832
+ }, t("create identity label")), /* @__PURE__ */ React31.createElement(CompoundButton, {
2833
+ ...sharedButtonProps,
2834
+ description: t("join identity description"),
2835
+ before: /* @__PURE__ */ React31.createElement(QrCode, {
2836
+ className: getSize15(6)
2837
+ }),
2838
+ onClick: () => send({
2839
+ type: "acceptHaloInvitation"
2840
+ }),
2841
+ "data-testid": "identity-chooser.join-identity"
2842
+ }, t("join identity label")), /* @__PURE__ */ React31.createElement(CompoundButton, {
2843
+ ...sharedButtonProps,
2844
+ description: t("recover identity description"),
2845
+ before: /* @__PURE__ */ React31.createElement(Textbox, {
2846
+ className: getSize15(6)
2847
+ }),
2848
+ onClick: () => send({
2849
+ type: "recoverIdentity"
2850
+ }),
2851
+ "data-testid": "identity-chooser.recover-identity"
2852
+ }, t("recover identity label"))));
2853
+ };
2854
+
2855
+ // packages/sdk/shell/src/panels/JoinPanel/steps/IdentityAdded.tsx
2856
+ import React32, { cloneElement as cloneElement2 } from "react";
2857
+ import { generateName as generateName4 } from "@dxos/display-name";
2858
+ import { Avatar as Avatar7, useId as useId7, useTranslation as useTranslation17 } from "@dxos/react-ui";
2859
+ import { mx as mx23 } from "@dxos/react-ui-theme";
2860
+ import { hexToFallback } from "@dxos/util";
2861
+ var IdentityAdded = (props) => {
2862
+ const { mode, addedIdentity, active, send, onDone, doneActionParent } = props;
2863
+ const disabled = !active;
2864
+ const { t } = useTranslation17("os");
2865
+ const addedIdentityHex = addedIdentity?.identityKey.toHex() ?? "0";
2866
+ const fallbackValue = hexToFallback(addedIdentityHex);
2867
+ const labelId = useId7("identityListItem__label");
2868
+ const displayName = addedIdentity?.profile?.displayName ?? (addedIdentity && generateName4(addedIdentityHex));
2869
+ const doneAction = /* @__PURE__ */ React32.createElement(Action, {
2870
+ ...onDone && {
2871
+ onClick: () => onDone(null)
2872
+ },
2873
+ disabled,
2874
+ "data-autofocus": "confirmingAddedIdentity",
2875
+ "data-testid": "identity-added-done"
2876
+ }, /* @__PURE__ */ React32.createElement("span", null, t("done label")));
2877
+ return /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement(StepHeading, null, t("identity added label")), /* @__PURE__ */ React32.createElement("div", {
2878
+ role: "none",
2879
+ className: "grow flex flex-col items-center justify-center text-center gap-2"
2880
+ }, /* @__PURE__ */ React32.createElement(Avatar7.Root, {
2881
+ status: "active",
2882
+ labelId,
2883
+ hue: addedIdentity?.profile?.data?.hue || fallbackValue.hue
2884
+ }, /* @__PURE__ */ React32.createElement(Avatar7.Frame, null, /* @__PURE__ */ React32.createElement(Avatar7.Fallback, {
2885
+ text: addedIdentity?.profile?.data?.emoji || fallbackValue.emoji
2886
+ })), /* @__PURE__ */ React32.createElement(Avatar7.Label, {
2887
+ classNames: mx23("text-lg truncate", !addedIdentity?.profile?.displayName && "font-mono")
2888
+ }, displayName))), /* @__PURE__ */ React32.createElement(Actions, null, mode === "halo-only" ? doneActionParent ? /* @__PURE__ */ cloneElement2(doneActionParent, {}, doneAction) : doneAction : /* @__PURE__ */ React32.createElement(Action, {
2889
+ variant: "primary",
2890
+ disabled: disabled || !addedIdentity,
2891
+ onClick: () => addedIdentity && send({
2892
+ type: "selectIdentity",
2893
+ identity: addedIdentity
2894
+ }),
2895
+ "data-autofocus": "confirmingAddedIdentity"
2896
+ }, t("continue label"))));
2897
+ };
2898
+
2899
+ // packages/sdk/shell/src/panels/JoinPanel/steps/IdentityInput.tsx
2900
+ import React33, { useState as useState10 } from "react";
2901
+ import { log as log8 } from "@dxos/log";
2902
+ import { useClient as useClient7 } from "@dxos/react-client";
2903
+ import { useTranslation as useTranslation18 } from "@dxos/react-ui";
2904
+ var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/JoinPanel/steps/IdentityInput.tsx";
2905
+ var IdentityInput = (props) => {
2906
+ const { send, method } = props;
2907
+ const isRecover = method === "recover identity";
2908
+ const client = useClient7();
2909
+ const { t } = useTranslation18("os");
2910
+ const [validationMessage, setValidationMessage] = useState10("");
2911
+ const createIdentity = (value) => {
2912
+ if (isRecover) {
2913
+ void client.halo.recoverIdentity({
2914
+ seedphrase: value
2915
+ }).then((identity) => {
2916
+ send?.({
2917
+ type: "selectIdentity",
2918
+ identity
2919
+ });
2920
+ }, (error) => {
2921
+ log8.catch(error, void 0, {
2922
+ F: __dxlog_file8,
2923
+ L: 38,
2924
+ S: void 0,
2925
+ C: (f, a) => f(...a)
2926
+ });
2927
+ setValidationMessage(t("failed to recover identity message"));
2928
+ });
2929
+ } else {
2930
+ void client.halo.createIdentity({
2931
+ displayName: value
2932
+ }).then((identity) => {
2933
+ send?.({
2934
+ type: "selectIdentity",
2935
+ identity
2936
+ });
2937
+ }, (error) => {
2938
+ log8.catch(error, void 0, {
2939
+ F: __dxlog_file8,
2940
+ L: 48,
2941
+ S: void 0,
2942
+ C: (f, a) => f(...a)
2943
+ });
2944
+ setValidationMessage(t("failed to create identity message"));
2945
+ });
2946
+ }
2947
+ };
2948
+ return /* @__PURE__ */ React33.createElement(IdentityInputImpl, {
2949
+ ...props,
2950
+ onDisplayNameConfirm: createIdentity,
2951
+ validationMessage
2952
+ });
2953
+ };
2954
+ var IdentityInputImpl = (props) => {
2955
+ const { method, send, active, onDisplayNameConfirm, validationMessage } = props;
2956
+ const disabled = !active;
2957
+ const { t } = useTranslation18("os");
2958
+ const [inputValue, setInputValue] = useState10("");
2959
+ const isRecover = method === "recover identity";
2960
+ return /* @__PURE__ */ React33.createElement(React33.Fragment, null, /* @__PURE__ */ React33.createElement("div", {
2961
+ role: "none",
2962
+ className: "grow flex flex-col justify-center"
2963
+ }, /* @__PURE__ */ React33.createElement(Input, {
2964
+ validationMessage,
2965
+ label: /* @__PURE__ */ React33.createElement(StepHeading, null, t(isRecover ? "recover identity input label" : "new identity input label")),
2966
+ disabled,
2967
+ "data-testid": "identity-input",
2968
+ placeholder: isRecover ? "Type your recovery phrase" : "Type a display name",
2969
+ onChange: ({ target: { value } }) => setInputValue(value)
2970
+ })), /* @__PURE__ */ React33.createElement(Actions, null, /* @__PURE__ */ React33.createElement(Action, {
2971
+ variant: "ghost",
2972
+ disabled,
2973
+ onClick: () => send?.({
2974
+ type: "deselectAuthMethod"
2975
+ }),
2976
+ "data-testid": `${method === "recover identity" ? "recover" : "create"}-identity-input-back`
2977
+ }, t("back label")), /* @__PURE__ */ React33.createElement(Action, {
2978
+ variant: "primary",
2979
+ disabled,
2980
+ onClick: () => onDisplayNameConfirm?.(inputValue),
2981
+ "data-testid": `${method === "recover identity" ? "recover" : "create"}-identity-input-continue`
2982
+ }, t("continue label"))));
2983
+ };
2984
+
2985
+ // packages/sdk/shell/src/panels/JoinPanel/steps/InvitationAccepted.tsx
2986
+ import React34, { cloneElement as cloneElement3 } from "react";
2987
+ import { useTranslation as useTranslation19 } from "@dxos/react-ui";
2988
+
2989
+ // packages/sdk/shell/src/panels/JoinPanel/steps/InvitationInput.tsx
2990
+ import React35, { useState as useState11, useEffect as useEffect5, cloneElement as cloneElement4 } from "react";
2991
+ import { log as log9 } from "@dxos/log";
2992
+ import { useTranslation as useTranslation20 } from "@dxos/react-ui";
2993
+ var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/JoinPanel/steps/InvitationInput.tsx";
2994
+ var invitationCodeFromUrl = (text) => {
2995
+ try {
2996
+ const searchParams = new URLSearchParams(text.substring(text.lastIndexOf("?")));
2997
+ const invitation = searchParams.get("spaceInvitationCode") ?? searchParams.get("deviceInvitationCode");
2998
+ return invitation ?? text;
2999
+ } catch (err) {
3000
+ log9.catch(err, void 0, {
3001
+ F: __dxlog_file9,
3002
+ L: 25,
3003
+ S: void 0,
3004
+ C: (f, a) => f(...a)
3005
+ });
3006
+ return text;
3007
+ }
3008
+ };
3009
+ var InvitationInput = (props) => {
3010
+ const { Kind, active, send, unredeemedCode, onExit, exitActionParent, onDone, doneActionParent, succeededKeys } = props;
3011
+ const disabled = !active;
3012
+ const { t } = useTranslation20("os");
3013
+ const [inputValue, setInputValue] = useState11(unredeemedCode ?? "");
3014
+ useEffect5(() => {
3015
+ unredeemedCode && setInputValue(unredeemedCode ?? "");
3016
+ }, [
3017
+ unredeemedCode
3018
+ ]);
3019
+ const handleNext = () => {
3020
+ if (inputValue.trim().length === 0) {
3021
+ return;
3022
+ }
3023
+ send({
3024
+ type: `set${Kind}InvitationCode`,
3025
+ code: invitationCodeFromUrl(inputValue),
3026
+ ...Kind === "Space" && {
3027
+ succeededKeys
3028
+ }
3029
+ });
3030
+ };
3031
+ const exitAction = /* @__PURE__ */ React35.createElement(Action, {
3032
+ variant: "ghost",
3033
+ disabled,
3034
+ ...onExit ? {
3035
+ onClick: () => onExit()
3036
+ } : {
3037
+ onClick: () => onDone?.(null)
3038
+ },
3039
+ "data-testid": "join-exit"
3040
+ }, t("cancel label"));
3041
+ return /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement("div", {
3042
+ role: "none",
3043
+ className: "grow flex flex-col justify-center"
3044
+ }, /* @__PURE__ */ React35.createElement(Input, {
3045
+ label: /* @__PURE__ */ React35.createElement(StepHeading, null, t("invitation input label")),
3046
+ // TODO(burdon): Translation.
3047
+ placeholder: "Type an invitation code",
3048
+ disabled,
3049
+ value: inputValue,
3050
+ onChange: ({ target: { value } }) => setInputValue(value),
3051
+ "data-autofocus": `inputting${Kind}InvitationCode`,
3052
+ "data-testid": `${Kind.toLowerCase()}-invitation-input`,
3053
+ onKeyUp: ({ key }) => key === "Enter" && handleNext()
3054
+ })), /* @__PURE__ */ React35.createElement(Actions, null, Kind === "Halo" ? null : exitActionParent ? /* @__PURE__ */ cloneElement4(exitActionParent, {}, exitAction) : doneActionParent ? /* @__PURE__ */ cloneElement4(doneActionParent, {}, exitAction) : exitAction, /* @__PURE__ */ React35.createElement(Action, {
3055
+ variant: "primary",
3056
+ disabled: disabled || inputValue.trim().length === 0,
3057
+ onClick: handleNext,
3058
+ "data-testid": `${Kind.toLowerCase()}-invitation-input-continue`
3059
+ }, t("continue label"))));
3060
+ };
3061
+
3062
+ // packages/sdk/shell/src/panels/JoinPanel/steps/InvitationRescuer.tsx
3063
+ import React36 from "react";
3064
+ import { useTranslation as useTranslation21 } from "@dxos/react-ui";
3065
+ import { descriptionText as descriptionText10 } from "@dxos/react-ui-theme";
3066
+ var InvitationActions = ({
3067
+ // `invitationState` does report correct state, but here we evaluate whether `failReason` is a better source of truth
3068
+ // for the UI in particular.
3069
+ invitationState,
3070
+ onInvitationCancel,
3071
+ active,
3072
+ send,
3073
+ Kind,
3074
+ failReason
3075
+ }) => {
3076
+ const { t } = useTranslation21("os");
3077
+ if (failReason) {
3078
+ return /* @__PURE__ */ React36.createElement(React36.Fragment, null, /* @__PURE__ */ React36.createElement(StepHeading, {
3079
+ className: descriptionText10
3080
+ }, t(failReason === "timeout" ? "timeout status label" : failReason === "cancelled" ? "cancelled status label" : "error status label")), /* @__PURE__ */ React36.createElement("div", {
3081
+ role: "none",
3082
+ className: "grow"
3083
+ }), /* @__PURE__ */ React36.createElement(Actions, null, /* @__PURE__ */ React36.createElement(Action, {
3084
+ disabled: !active,
3085
+ onClick: () => send({
3086
+ type: `reset${Kind}Invitation`
3087
+ }),
3088
+ "data-testid": "invitation-rescuer-reset"
3089
+ }, t("reset label"))));
3090
+ } else {
3091
+ return /* @__PURE__ */ React36.createElement(React36.Fragment, null, /* @__PURE__ */ React36.createElement(StepHeading, {
3092
+ className: descriptionText10
3093
+ }, t("connecting status label")), /* @__PURE__ */ React36.createElement("div", {
3094
+ role: "none",
3095
+ className: "grow"
3096
+ }), /* @__PURE__ */ React36.createElement(Actions, null, /* @__PURE__ */ React36.createElement(Action, {
3097
+ disabled: true,
3098
+ classNames: "order-2",
3099
+ "data-testid": "next"
3100
+ }, t("next label")), /* @__PURE__ */ React36.createElement(Action, {
3101
+ disabled: !active,
3102
+ onClick: onInvitationCancel,
3103
+ "data-testid": "invitation-rescuer-cancel"
3104
+ }, t("cancel label"))));
3105
+ }
3106
+ };
3107
+ var InvitationRescuer = (props) => {
3108
+ const { Kind, invitationState, active, send } = props;
3109
+ const { t } = useTranslation21("os");
3110
+ return /* @__PURE__ */ React36.createElement(React36.Fragment, null, typeof invitationState === "undefined" ? /* @__PURE__ */ React36.createElement(React36.Fragment, null, /* @__PURE__ */ React36.createElement("div", {
3111
+ role: "none",
3112
+ className: "grow flex flex-col justify-center"
3113
+ }, /* @__PURE__ */ React36.createElement(StepHeading, {
3114
+ className: descriptionText10
3115
+ }, "There was a problem joining the space")), /* @__PURE__ */ React36.createElement(Actions, null, /* @__PURE__ */ React36.createElement(Action, {
3116
+ disabled: !active,
3117
+ "data-testid": "invitation-rescuer-blank-reset",
3118
+ onClick: () => send({
3119
+ type: `reset${Kind}Invitation`
3120
+ })
3121
+ }, t("reset label")))) : /* @__PURE__ */ React36.createElement(InvitationActions, props));
3122
+ };
3123
+
3124
+ // packages/sdk/shell/src/panels/JoinPanel/steps/InvitationAuthenticator.tsx
3125
+ import React37, { useState as useState12 } from "react";
3126
+ import { Invitation as Invitation6 } from "@dxos/react-client/invitations";
3127
+ import { Input as Input3, useTranslation as useTranslation22 } from "@dxos/react-ui";
3128
+ import { descriptionText as descriptionText11 } from "@dxos/react-ui-theme";
3129
+ import { hexToEmoji as hexToEmoji5 } from "@dxos/util";
3130
+ var pinLength = 6;
3131
+ var InvitationAuthenticator = ({ failed, Kind, authMethod, active, pending, invitationId, onInvitationAuthenticate, onInvitationCancel }) => {
3132
+ const disabled = !active || pending;
3133
+ const { t } = useTranslation22("os");
3134
+ const invitationType = Kind.toLowerCase();
3135
+ const [authCode, setAuthCode] = useState12("");
3136
+ const onChange = ({ target: { value } }) => {
3137
+ setAuthCode(value);
3138
+ if (value.length === pinLength) {
3139
+ document.querySelector(`[data-autofocus-pinlength="${invitationType}"]`)?.focus();
3140
+ }
3141
+ };
3142
+ return /* @__PURE__ */ React37.createElement(React37.Fragment, null, /* @__PURE__ */ React37.createElement("div", {
3143
+ role: "none",
3144
+ className: "grow flex flex-col justify-center gap-4"
3145
+ }, /* @__PURE__ */ React37.createElement(Input3.Root, failed && {
3146
+ validationValence: "error"
3147
+ }, /* @__PURE__ */ React37.createElement(Input3.Label, {
3148
+ asChild: true
3149
+ }, authMethod === Invitation6.AuthMethod.SHARED_SECRET ? /* @__PURE__ */ React37.createElement(StepHeading, null, t("auth code input label")) : /* @__PURE__ */ React37.createElement(React37.Fragment, null, /* @__PURE__ */ React37.createElement(StepHeading, {
3150
+ className: descriptionText11
3151
+ }, t("authenticating label")), /* @__PURE__ */ React37.createElement("div", {
3152
+ role: "none",
3153
+ className: "grow"
3154
+ }))), authMethod === Invitation6.AuthMethod.SHARED_SECRET && /* @__PURE__ */ React37.createElement(Input3.PinInput, {
3155
+ disabled,
3156
+ length: pinLength,
3157
+ onChange,
3158
+ inputMode: "numeric",
3159
+ autoComplete: "off",
3160
+ pattern: "\\d*",
3161
+ "data-autofocus": `connecting${Kind}Invitation inputting${Kind}VerificationCode authenticationFailing${Kind}VerificationCode authenticating${Kind}VerificationCode`,
3162
+ "data-prevent-ios-autofocus": true,
3163
+ "data-testid": `${invitationType}-auth-code-input`,
3164
+ "data-1p-ignore": true
3165
+ }), failed && /* @__PURE__ */ React37.createElement(Input3.DescriptionAndValidation, {
3166
+ classNames: "text-center"
3167
+ }, /* @__PURE__ */ React37.createElement(Input3.Validation, null, t("failed to authenticate message")))), invitationId && authMethod === Invitation6.AuthMethod.SHARED_SECRET && /* @__PURE__ */ React37.createElement(React37.Fragment, null, /* @__PURE__ */ React37.createElement(Label, null, t("auth other device emoji message")), /* @__PURE__ */ React37.createElement("div", {
3168
+ className: "flex justify-center"
3169
+ }, /* @__PURE__ */ React37.createElement(Emoji, {
3170
+ text: hexToEmoji5(invitationId)
3171
+ })))), /* @__PURE__ */ React37.createElement(Actions, null, /* @__PURE__ */ React37.createElement(Action, {
3172
+ variant: "ghost",
3173
+ disabled,
3174
+ onClick: () => onInvitationCancel?.(),
3175
+ "data-testid": `${invitationType}-invitation-authenticator-cancel`
3176
+ }, t("cancel label")), /* @__PURE__ */ React37.createElement(Action, {
3177
+ variant: "primary",
3178
+ disabled,
3179
+ onClick: () => onInvitationAuthenticate?.(authCode),
3180
+ "data-autofocus-pinlength": invitationType,
3181
+ "data-testid": `${invitationType}-invitation-authenticator-next`
3182
+ }, t("next label"))));
3183
+ };
3184
+
3185
+ // packages/sdk/shell/src/styles/panelStyles.ts
3186
+ var stepStyles = "pbs-1 pbe-3 pli-3";
3187
+
3188
+ // packages/sdk/shell/src/styles/invitationStatusStyles.ts
3189
+ import { Invitation as Invitation7 } from "@dxos/react-client/invitations";
3190
+ var inactiveBgColor = "bg-neutral-100 dark:bg-neutral-600";
3191
+ var activeBgColor = "bg-primary-500 dark:bg-primary-400";
3192
+ var successBgColor = "bg-success-500 dark:bg-success-400";
3193
+ var errorBgColor = "bg-error-500 dark:bg-error-400";
3194
+ var cancelledBgColor = "bg-warning-500 dark:bg-warning-400";
3195
+ var inactiveTextColor = "text-neutral-100 dark:text-neutral-600";
3196
+ var activeTextColor = "text-primary-400 dark:text-primary-500";
3197
+ var successTextColor = "text-success-400 dark:text-success-500";
3198
+ var errorTextColor = "text-error-400 dark:text-error-500";
3199
+ var cancelledTextColor = "text-warning-400 dark:text-warning-500";
3200
+ var inactiveStrokeColor = "stroke-neutral-100 dark:stroke-neutral-700";
3201
+ var activeStrokeColor = "stroke-primary-400 dark:stroke-primary-150";
3202
+ var successStrokeColor = "stroke-success-300 dark:stroke-primary-400";
3203
+ var errorStrokeColor = "stroke-error-300 dark:stroke-error-500";
3204
+ var cancelledStrokeColor = "stroke-warning-300 dark:stroke-warning-500";
3205
+ var resolvedStrokeColor = (status) => status === Invitation7.State.ERROR ? errorStrokeColor : status === Invitation7.State.CANCELLED || status === Invitation7.State.TIMEOUT ? cancelledStrokeColor : successStrokeColor;
3206
+ var resolvedBgColor = (status) => status === Invitation7.State.ERROR ? errorBgColor : status === Invitation7.State.CANCELLED || status === Invitation7.State.TIMEOUT ? cancelledBgColor : successBgColor;
3207
+ var resolvedTextColor = (status) => status === Invitation7.State.ERROR ? errorTextColor : status === Invitation7.State.CANCELLED || status === Invitation7.State.TIMEOUT ? cancelledTextColor : successTextColor;
3208
+
3209
+ // packages/sdk/shell/src/panels/JoinPanel/JoinPanel.tsx
3210
+ var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/JoinPanel/JoinPanel.tsx";
3211
+ var JoinPanelImpl = (props) => {
3212
+ const {
3213
+ titleId,
3214
+ send,
3215
+ activeView,
3216
+ failed,
3217
+ mode,
3218
+ unredeemedCodes,
3219
+ invitationIds,
3220
+ invitationStates,
3221
+ invitationAuthMethods,
3222
+ succeededKeys,
3223
+ failReasons,
3224
+ onExit,
3225
+ onHaloDone,
3226
+ // onSpaceDone,
3227
+ exitActionParent,
3228
+ doneActionParent,
3229
+ onHaloInvitationCancel,
3230
+ onSpaceInvitationCancel,
3231
+ onHaloInvitationAuthenticate,
3232
+ onSpaceInvitationAuthenticate,
3233
+ onCancelResetStorage,
3234
+ onConfirmResetStorage,
3235
+ IdentityInput: IdentityInputComponent = IdentityInput,
3236
+ ConfirmReset: ConfirmResetComponent = ConfirmReset
3237
+ } = props;
3238
+ return /* @__PURE__ */ React38.createElement(React38.Fragment, null, mode !== "halo-only" && /* @__PURE__ */ React38.createElement(JoinHeading, {
3239
+ titleId,
3240
+ mode,
3241
+ onExit,
3242
+ exitActionParent
3243
+ }), /* @__PURE__ */ React38.createElement(Viewport.Root, {
3244
+ focusManaged: true,
3245
+ activeView
3246
+ }, /* @__PURE__ */ React38.createElement(Viewport.Views, null, /* @__PURE__ */ React38.createElement(Viewport.View, {
3247
+ classNames: stepStyles,
3248
+ id: "addition method chooser"
3249
+ }, /* @__PURE__ */ React38.createElement(AdditionMethodChooser, {
3250
+ send,
3251
+ active: activeView === "addition method chooser"
3252
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3253
+ classNames: stepStyles,
3254
+ id: "reset storage confirmation"
3255
+ }, /* @__PURE__ */ React38.createElement(ConfirmResetComponent, {
3256
+ send,
3257
+ active: activeView === "reset storage confirmation",
3258
+ onCancel: onCancelResetStorage,
3259
+ onConfirm: onConfirmResetStorage
3260
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3261
+ classNames: stepStyles,
3262
+ id: "create identity input"
3263
+ }, /* @__PURE__ */ React38.createElement(IdentityInputComponent, {
3264
+ send,
3265
+ method: "create identity",
3266
+ active: activeView === "create identity input"
3267
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3268
+ classNames: stepStyles,
3269
+ id: "recover identity input"
3270
+ }, /* @__PURE__ */ React38.createElement(IdentityInputComponent, {
3271
+ send,
3272
+ method: "recover identity",
3273
+ active: activeView === "recover identity input"
3274
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3275
+ classNames: stepStyles,
3276
+ id: "halo invitation input"
3277
+ }, /* @__PURE__ */ React38.createElement(InvitationInput, {
3278
+ send,
3279
+ Kind: "Halo",
3280
+ active: activeView === "halo invitation input",
3281
+ ...unredeemedCodes?.Halo && {
3282
+ unredeemedCode: unredeemedCodes.Halo
3283
+ },
3284
+ ...succeededKeys?.Halo && {
3285
+ succeededKeys: succeededKeys.Halo
3286
+ }
3287
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3288
+ classNames: stepStyles,
3289
+ id: "halo invitation rescuer"
3290
+ }, /* @__PURE__ */ React38.createElement(InvitationRescuer, {
3291
+ send,
3292
+ Kind: "Halo",
3293
+ active: activeView === "halo invitation rescuer",
3294
+ invitationState: invitationStates?.Halo,
3295
+ onInvitationCancel: onHaloInvitationCancel,
3296
+ failReason: failReasons?.Halo
3297
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3298
+ classNames: stepStyles,
3299
+ id: "halo invitation authenticator"
3300
+ }, /* @__PURE__ */ React38.createElement(InvitationAuthenticator, {
3301
+ send,
3302
+ Kind: "Halo",
3303
+ invitationId: invitationIds?.Halo,
3304
+ authMethod: invitationAuthMethods?.Halo,
3305
+ active: activeView === "halo invitation authenticator",
3306
+ onInvitationCancel: onHaloInvitationCancel,
3307
+ onInvitationAuthenticate: onHaloInvitationAuthenticate,
3308
+ ...failed.has("Halo") && {
3309
+ failed: true
3310
+ }
3311
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3312
+ classNames: stepStyles,
3313
+ id: "identity added"
3314
+ }, /* @__PURE__ */ React38.createElement(IdentityAdded, {
3315
+ send,
3316
+ mode,
3317
+ active: activeView === "identity added",
3318
+ doneActionParent,
3319
+ onDone: onHaloDone
3320
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3321
+ classNames: stepStyles,
3322
+ id: "space invitation input"
3323
+ }, /* @__PURE__ */ React38.createElement(InvitationInput, {
3324
+ send,
3325
+ Kind: "Space",
3326
+ active: activeView === "space invitation input",
3327
+ ...unredeemedCodes?.Space && {
3328
+ unredeemedCode: unredeemedCodes.Space
3329
+ },
3330
+ ...succeededKeys?.Space && {
3331
+ succeededKeys: succeededKeys.Space
3332
+ },
3333
+ onExit,
3334
+ exitActionParent
3335
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3336
+ classNames: stepStyles,
3337
+ id: "space invitation rescuer"
3338
+ }, /* @__PURE__ */ React38.createElement(InvitationRescuer, {
3339
+ send,
3340
+ Kind: "Space",
3341
+ active: activeView === "space invitation rescuer",
3342
+ invitationState: invitationStates?.Space,
3343
+ onInvitationCancel: onSpaceInvitationCancel,
3344
+ failReason: failReasons?.Space
3345
+ })), /* @__PURE__ */ React38.createElement(Viewport.View, {
3346
+ classNames: stepStyles,
3347
+ id: "space invitation authenticator"
3348
+ }, /* @__PURE__ */ React38.createElement(InvitationAuthenticator, {
3349
+ send,
3350
+ Kind: "Space",
3351
+ invitationId: invitationIds?.Space,
3352
+ authMethod: invitationAuthMethods?.Space,
3353
+ active: activeView === "space invitation authenticator",
3354
+ onInvitationCancel: onSpaceInvitationCancel,
3355
+ onInvitationAuthenticate: onSpaceInvitationAuthenticate,
3356
+ ...failed.has("Space") && {
3357
+ failed: true
3358
+ }
3359
+ })))));
3360
+ };
3361
+ var JoinPanel = ({ titleId: propsTitleId, mode = "default", initialDisposition = "default", initialInvitationCode, exitActionParent, onExit, doneActionParent, onDone: propsOnDone, onCancelResetStorage }) => {
3362
+ const client = useClient8();
3363
+ const identity = useIdentity2();
3364
+ const { hasIosKeyboard } = useThemeContext5();
3365
+ const titleId = useId8("joinPanel__heading", propsTitleId);
3366
+ const [joinState, joinSend, joinService] = useJoinMachine(client, {
3367
+ context: {
3368
+ mode,
3369
+ initialDisposition,
3370
+ identity,
3371
+ ...initialInvitationCode && {
3372
+ [mode === "halo-only" ? "halo" : "space"]: {
3373
+ unredeemedCode: initialInvitationCode
3374
+ }
3375
+ }
3376
+ }
3377
+ });
3378
+ useEffect6(() => {
3379
+ const subscription = joinService.subscribe((state) => {
3380
+ log10("[state]", state, {
3381
+ F: __dxlog_file10,
3382
+ L: 210,
3383
+ S: void 0,
3384
+ C: (f, a) => f(...a)
3385
+ });
3386
+ });
3387
+ return subscription.unsubscribe;
3388
+ }, [
3389
+ joinService
3390
+ ]);
3391
+ useEffect6(() => {
3392
+ const stateStack = joinState.configuration[0].id.split(".");
3393
+ const innermostState = stateStack[stateStack.length - 1];
3394
+ const autoFocusValue = innermostState === "finishingJoining" ? "successSpaceInvitation" : innermostState;
3395
+ const $nextAutofocus = document.querySelector(`[data-autofocus~="${autoFocusValue}"]`);
3396
+ if ($nextAutofocus && !(hasIosKeyboard && $nextAutofocus.hasAttribute("data-prevent-ios-autofocus"))) {
3397
+ $nextAutofocus.focus();
3398
+ }
3399
+ }, [
3400
+ joinState.value,
3401
+ hasIosKeyboard
3402
+ ]);
3403
+ const activeView = useMemo4(() => {
3404
+ switch (true) {
3405
+ case joinState.matches({
3406
+ choosingIdentity: "choosingAuthMethod"
3407
+ }):
3408
+ return "addition method chooser";
3409
+ case joinState.matches("resettingIdentity"):
3410
+ return "reset storage confirmation";
3411
+ case joinState.matches({
3412
+ choosingIdentity: "creatingIdentity"
3413
+ }):
3414
+ return "create identity input";
3415
+ case joinState.matches({
3416
+ choosingIdentity: "recoveringIdentity"
3417
+ }):
3418
+ return "recover identity input";
3419
+ case joinState.matches({
3420
+ choosingIdentity: {
3421
+ acceptingHaloInvitation: "inputtingHaloInvitationCode"
3422
+ }
3423
+ }):
3424
+ return "halo invitation input";
3425
+ case [
3426
+ {
3427
+ choosingIdentity: {
3428
+ acceptingHaloInvitation: {
3429
+ acceptingRedeemedHaloInvitation: "connectingHaloInvitation"
3430
+ }
3431
+ }
3432
+ },
3433
+ {
3434
+ choosingIdentity: {
3435
+ acceptingHaloInvitation: {
3436
+ acceptingRedeemedHaloInvitation: "failingHaloInvitation"
3437
+ }
3438
+ }
3439
+ }
3440
+ ].some(joinState.matches):
3441
+ return "halo invitation rescuer";
3442
+ case [
3443
+ {
3444
+ choosingIdentity: {
3445
+ acceptingHaloInvitation: {
3446
+ acceptingRedeemedHaloInvitation: "inputtingHaloVerificationCode"
3447
+ }
3448
+ }
3449
+ },
3450
+ {
3451
+ choosingIdentity: {
3452
+ acceptingHaloInvitation: {
3453
+ acceptingRedeemedHaloInvitation: "authenticatingHaloVerificationCode"
3454
+ }
3455
+ }
3456
+ },
3457
+ {
3458
+ choosingIdentity: {
3459
+ acceptingHaloInvitation: {
3460
+ acceptingRedeemedHaloInvitation: "authenticationFailingHaloVerificationCode"
3461
+ }
3462
+ }
3463
+ }
3464
+ ].some(joinState.matches):
3465
+ return "halo invitation authenticator";
3466
+ case [
3467
+ {
3468
+ choosingIdentity: {
3469
+ acceptingHaloInvitation: {
3470
+ acceptingRedeemedHaloInvitation: "successHaloInvitation"
3471
+ }
3472
+ }
3473
+ },
3474
+ "finishingJoiningHalo"
3475
+ ].some(joinState.matches):
3476
+ return "halo invitation accepted";
3477
+ case joinState.matches({
3478
+ choosingIdentity: "confirmingAddedIdentity"
3479
+ }):
3480
+ return "identity added";
3481
+ case joinState.matches({
3482
+ acceptingSpaceInvitation: "inputtingSpaceInvitationCode"
3483
+ }):
3484
+ return "space invitation input";
3485
+ case [
3486
+ {
3487
+ acceptingSpaceInvitation: {
3488
+ acceptingRedeemedSpaceInvitation: "connectingSpaceInvitation"
3489
+ }
3490
+ },
3491
+ {
3492
+ acceptingSpaceInvitation: {
3493
+ acceptingRedeemedSpaceInvitation: "failingSpaceInvitation"
3494
+ }
3495
+ }
3496
+ ].some(joinState.matches):
3497
+ return "space invitation rescuer";
3498
+ case [
3499
+ {
3500
+ acceptingSpaceInvitation: {
3501
+ acceptingRedeemedSpaceInvitation: "inputtingSpaceVerificationCode"
3502
+ }
3503
+ },
3504
+ {
3505
+ acceptingSpaceInvitation: {
3506
+ acceptingRedeemedSpaceInvitation: "authenticatingSpaceVerificationCode"
3507
+ }
3508
+ },
3509
+ {
3510
+ acceptingSpaceInvitation: {
3511
+ acceptingRedeemedSpaceInvitation: "authenticationFailingSpaceVerificationCode"
3512
+ }
3513
+ }
3514
+ ].some(joinState.matches):
3515
+ return "space invitation authenticator";
3516
+ case joinState.matches("finishingJoiningSpace"):
3517
+ return "space invitation accepted";
3518
+ default:
3519
+ return "never";
3520
+ }
3521
+ }, [
3522
+ joinState
3523
+ ]);
3524
+ useEffect6(() => {
3525
+ switch (activeView) {
3526
+ case "halo invitation accepted":
3527
+ onHaloDone();
3528
+ break;
3529
+ case "space invitation accepted":
3530
+ onSpaceDone();
3531
+ break;
3532
+ }
3533
+ }, [
3534
+ activeView
3535
+ ]);
3536
+ const failed = useMemo4(() => {
3537
+ const result = /* @__PURE__ */ new Set();
3538
+ switch (true) {
3539
+ case joinState.matches({
3540
+ choosingIdentity: {
3541
+ acceptingHaloInvitation: {
3542
+ acceptingRedeemedHaloInvitation: "authenticationFailingHaloVerificationCode"
3543
+ }
3544
+ }
3545
+ }):
3546
+ result.add("Halo");
3547
+ break;
3548
+ case joinState.matches({
3549
+ acceptingSpaceInvitation: {
3550
+ acceptingRedeemedSpaceInvitation: "authenticationFailingSpaceVerificationCode"
3551
+ }
3552
+ }):
3553
+ result.add("Space");
3554
+ break;
3555
+ }
3556
+ return result;
3557
+ }, [
3558
+ joinState
3559
+ ]);
3560
+ const unredeemedCodes = useMemo4(() => ({
3561
+ Halo: joinState.context.halo.unredeemedCode,
3562
+ Space: joinState.context.space.unredeemedCode
3563
+ }), [
3564
+ joinState
3565
+ ]);
3566
+ const spaces = useMulticastObservable(client.spaces);
3567
+ const succeededKeys = useMemo4(() => ({
3568
+ Space: spaces ? new Set(spaces.map(({ key }) => key.toHex())) : void 0
3569
+ }), [
3570
+ spaces
3571
+ ]);
3572
+ const invitationStates = useMemo4(() => ({
3573
+ Halo: joinState.context.halo.invitationObservable?.get().state,
3574
+ Space: joinState.context.space.invitationObservable?.get().state
3575
+ }), [
3576
+ joinState
3577
+ ]);
3578
+ const invitationAuthMethods = useMemo4(() => ({
3579
+ Halo: joinState.context.halo.invitationObservable?.get().authMethod,
3580
+ Space: joinState.context.space.invitationObservable?.get().authMethod
3581
+ }), [
3582
+ joinState
3583
+ ]);
3584
+ const invitationIds = useMemo4(() => ({
3585
+ Halo: joinState.context.halo.invitationObservable?.get().invitationId,
3586
+ Space: joinState.context.space.invitationObservable?.get().invitationId
3587
+ }), [
3588
+ joinState
3589
+ ]);
3590
+ const failReasons = useMemo4(() => ({
3591
+ Halo: joinState.context.halo.failReason,
3592
+ Space: joinState.context.space.failReason
3593
+ }), [
3594
+ joinState
3595
+ ]);
3596
+ const onHaloDone = useCallback6(() => {
3597
+ propsOnDone?.({
3598
+ identityKey: joinState.context.halo.invitation?.identityKey ?? null,
3599
+ swarmKey: joinState.context.halo.invitation?.swarmKey ?? null,
3600
+ spaceKey: joinState.context.halo.invitation?.spaceKey ?? null,
3601
+ target: joinState.context.halo.invitation?.target ?? null
3602
+ });
3603
+ }, [
3604
+ joinState,
3605
+ propsOnDone
3606
+ ]);
3607
+ const onSpaceDone = useCallback6(() => {
3608
+ propsOnDone?.({
3609
+ identityKey: joinState.context.space.invitation?.identityKey ?? null,
3610
+ swarmKey: joinState.context.space.invitation?.swarmKey ?? null,
3611
+ spaceKey: joinState.context.space.invitation?.spaceKey ?? null,
3612
+ target: joinState.context.space.invitation?.target ?? null
3613
+ });
3614
+ }, [
3615
+ joinState,
3616
+ propsOnDone
3617
+ ]);
3618
+ const onConfirmResetStorage = useCallback6(() => client.reset().then(() => {
3619
+ joinSend({
3620
+ type: "resetIdentity"
3621
+ });
3622
+ }), [
3623
+ client,
3624
+ joinSend
3625
+ ]);
3626
+ return /* @__PURE__ */ React38.createElement(JoinPanelImpl, {
3627
+ titleId,
3628
+ mode,
3629
+ send: joinSend,
3630
+ activeView,
3631
+ failed,
3632
+ failReasons,
3633
+ pending: [
3634
+ "connecting",
3635
+ "authenticating"
3636
+ ].some((str) => joinState?.configuration[0].id.includes(str)),
3637
+ unredeemedCodes,
3638
+ invitationIds,
3639
+ invitationStates,
3640
+ invitationAuthMethods,
3641
+ succeededKeys,
3642
+ identity,
3643
+ onExit,
3644
+ exitActionParent,
3645
+ doneActionParent,
3646
+ onHaloDone,
3647
+ onSpaceDone,
3648
+ onHaloInvitationCancel: () => joinState.context.halo.invitationObservable?.cancel(),
3649
+ onSpaceInvitationCancel: () => joinState.context.space.invitationObservable?.cancel(),
3650
+ onHaloInvitationAuthenticate: (authCode) => {
3651
+ joinSend({
3652
+ type: "authenticateHaloVerificationCode"
3653
+ });
3654
+ return joinState.context.halo.invitationObservable?.authenticate(authCode);
3655
+ },
3656
+ onSpaceInvitationAuthenticate: (authCode) => {
3657
+ joinSend({
3658
+ type: "authenticateSpaceVerificationCode"
3659
+ });
3660
+ return joinState.context.space.invitationObservable?.authenticate(authCode);
3661
+ },
3662
+ onConfirmResetStorage,
3663
+ onCancelResetStorage
3664
+ });
3665
+ };
3666
+
3667
+ // packages/sdk/shell/src/panels/SpacePanel/SpacePanel.tsx
3668
+ import { Planet } from "@phosphor-icons/react";
3669
+ import React40, { useEffect as useEffect7, useMemo as useMemo5 } from "react";
3670
+ import { log as log13 } from "@dxos/log";
3671
+ import { useInvitationStatus as useInvitationStatus3 } from "@dxos/react-client/invitations";
3672
+ import { useId as useId9, useTranslation as useTranslation24 } from "@dxos/react-ui";
3673
+
3674
+ // packages/sdk/shell/src/panels/SpacePanel/spaceMachine.ts
3675
+ import { useMachine as useMachine3 } from "@xstate/react";
3676
+ import { assign as assign3, createMachine as createMachine3 } from "xstate";
3677
+ import { log as log11 } from "@dxos/log";
3678
+ var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/SpacePanel/spaceMachine.ts";
3679
+ var spaceMachine = createMachine3({
3680
+ id: "space",
3681
+ predictableActionArguments: true,
3682
+ context: {
3683
+ space: null
3684
+ },
3685
+ initial: "managingSpace",
3686
+ states: {
3687
+ managingSpace: {},
3688
+ managingSpaceInvitation: {}
3689
+ },
3690
+ on: {
3691
+ deselectInvitation: {
3692
+ target: ".managingSpace",
3693
+ actions: [
3694
+ "unsetInvitation",
3695
+ "log"
3696
+ ]
3697
+ },
3698
+ selectInvitation: {
3699
+ target: ".managingSpaceInvitation",
3700
+ actions: [
3701
+ "setInvitation",
3702
+ "log"
3703
+ ]
3704
+ }
3705
+ }
3706
+ }, {
3707
+ actions: {
3708
+ setInvitation: assign3({
3709
+ invitation: (context, event) => event?.invitation ?? null
3710
+ }),
3711
+ unsetInvitation: assign3({
3712
+ invitation: () => void 0
3713
+ }),
3714
+ log: (context, event) => {
3715
+ log11("[transition]", {
3716
+ event,
3717
+ context
3718
+ }, {
3719
+ F: __dxlog_file11,
3720
+ L: 53,
3721
+ S: void 0,
3722
+ C: (f, a) => f(...a)
3723
+ });
3724
+ }
3725
+ }
3726
+ });
3727
+ var useSpaceMachine = (options) => {
3728
+ return useMachine3(spaceMachine, {
3729
+ ...options,
3730
+ context: {
3731
+ ...options?.context
3732
+ }
3733
+ });
3734
+ };
3735
+
3736
+ // packages/sdk/shell/src/panels/SpacePanel/steps/SpaceManager.tsx
3737
+ import { Placeholder as Placeholder2, UserPlus, UsersThree } from "@phosphor-icons/react";
3738
+ import React39, { useCallback as useCallback7, useState as useState13 } from "react";
3739
+ import { log as log12 } from "@dxos/log";
3740
+ import { useConfig } from "@dxos/react-client";
3741
+ import { useSpaceInvitations as useSpaceInvitations2 } from "@dxos/react-client/echo";
3742
+ import { Invitation as Invitation8, InvitationEncoder as InvitationEncoder4 } from "@dxos/react-client/invitations";
3743
+ import { ScrollArea, useTranslation as useTranslation23 } from "@dxos/react-ui";
3744
+ import { descriptionText as descriptionText12, mx as mx24 } from "@dxos/react-ui-theme";
3745
+ var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/SpacePanel/steps/SpaceManager.tsx";
3746
+ var activeActionKey = "dxos:react-shell/space-manager/active-action";
3747
+ var handleInvitationEvent = (invitation, subscription) => {
3748
+ const invitationCode = InvitationEncoder4.encode(invitation);
3749
+ if (invitation.state === Invitation8.State.CONNECTING) {
3750
+ log12.info(JSON.stringify({
3751
+ invitationCode,
3752
+ authCode: invitation.authCode
3753
+ }), void 0, {
3754
+ F: __dxlog_file12,
3755
+ L: 40,
3756
+ S: void 0,
3757
+ C: (f, a) => f(...a)
3758
+ });
3759
+ subscription.unsubscribe();
3760
+ }
3761
+ };
3762
+ var SpaceManager = (props) => {
3763
+ const { space, target } = props;
3764
+ const { t } = useTranslation23("os");
3765
+ const config = useConfig();
3766
+ const invitations = useSpaceInvitations2(space?.key);
3767
+ const inviteActions = {
3768
+ inviteOne: {
3769
+ label: t("invite one label"),
3770
+ description: t("invite one description"),
3771
+ icon: UserPlus,
3772
+ testId: "spaces-panel.invite-one",
3773
+ onClick: useCallback7(() => {
3774
+ const invitation = space.share?.({
3775
+ type: Invitation8.Type.INTERACTIVE,
3776
+ authMethod: Invitation8.AuthMethod.SHARED_SECRET,
3777
+ multiUse: false,
3778
+ target
3779
+ });
3780
+ if (invitation && config.values.runtime?.app?.env?.DX_ENVIRONMENT !== "production") {
3781
+ const subscription = invitation.subscribe((invitation2) => handleInvitationEvent(invitation2, subscription));
3782
+ }
3783
+ }, [
3784
+ space,
3785
+ target
3786
+ ])
3787
+ },
3788
+ inviteMany: {
3789
+ label: t("invite many label"),
3790
+ description: t("invite many description"),
3791
+ icon: UsersThree,
3792
+ testId: "spaces-panel.invite-many",
3793
+ onClick: useCallback7(() => {
3794
+ const invitation = space.share?.({
3795
+ type: Invitation8.Type.DELEGATED,
3796
+ authMethod: Invitation8.AuthMethod.KNOWN_PUBLIC_KEY,
3797
+ multiUse: true,
3798
+ target
3799
+ });
3800
+ if (invitation && config.values.runtime?.app?.env?.DX_ENVIRONMENT !== "production") {
3801
+ const subscription = invitation.subscribe((invitation2) => handleInvitationEvent(invitation2, subscription));
3802
+ }
3803
+ }, [
3804
+ space,
3805
+ target
3806
+ ])
3807
+ }
3808
+ };
3809
+ return /* @__PURE__ */ React39.createElement(SpaceManagerImpl, {
3810
+ ...props,
3811
+ invitations,
3812
+ inviteActions
3813
+ });
3814
+ };
3815
+ var headingFragment = "pis-3 pie-1 plb-1 mbe-1 font-medium";
3816
+ var SpaceManagerImpl = (props) => {
3817
+ const { active, space, createInvitationUrl, send, inviteActions: propsInviteActions, invitations, showInactiveInvitations, SpaceMemberList: SpaceMemberListComponent = SpaceMemberList, InvitationList: InvitationListComponent = InvitationList } = props;
3818
+ const { t } = useTranslation23("os");
3819
+ const inviteActions = propsInviteActions ?? {
3820
+ noopInvite: {
3821
+ label: t("create space invitation label"),
3822
+ description: "",
3823
+ icon: Placeholder2,
3824
+ onClick: () => {
3825
+ }
3826
+ }
3827
+ };
3828
+ const [activeAction, setInternalActiveAction] = useState13(localStorage.getItem(activeActionKey) ?? "inviteMany");
3829
+ const setActiveAction = (nextAction) => {
3830
+ setInternalActiveAction(nextAction);
3831
+ localStorage.setItem(activeActionKey, nextAction);
3832
+ };
3833
+ const visibleInvitations = showInactiveInvitations ? invitations : invitations?.filter((invitation) => ![
3834
+ Invitation8.State.CANCELLED
3835
+ ].includes(invitation.get().state));
3836
+ return /* @__PURE__ */ React39.createElement(React39.Fragment, null, /* @__PURE__ */ React39.createElement(ScrollArea.Root, {
3837
+ classNames: "grow shrink basis-28 -mli-2"
3838
+ }, /* @__PURE__ */ React39.createElement(ScrollArea.Viewport, {
3839
+ classNames: "is-full pie-2"
3840
+ }, !!visibleInvitations?.length && /* @__PURE__ */ React39.createElement(React39.Fragment, null, /* @__PURE__ */ React39.createElement("h3", {
3841
+ className: mx24(headingFragment, descriptionText12)
3842
+ }, t("invitation list heading")), /* @__PURE__ */ React39.createElement(InvitationListComponent, {
3843
+ className: "mb-2",
3844
+ send,
3845
+ invitations: visibleInvitations ?? [],
3846
+ onClickRemove: (invitation) => invitation.cancel(),
3847
+ createInvitationUrl
3848
+ }), /* @__PURE__ */ React39.createElement("h3", {
3849
+ className: mx24(headingFragment, descriptionText12, "mbs-2")
3850
+ }, t("space member list heading"))), /* @__PURE__ */ React39.createElement(SpaceMemberListComponent, {
3851
+ spaceKey: space.key,
3852
+ includeSelf: true
3853
+ })), /* @__PURE__ */ React39.createElement(ScrollArea.Scrollbar, {
3854
+ orientation: "vertical"
3855
+ }, /* @__PURE__ */ React39.createElement(ScrollArea.Thumb, null))), /* @__PURE__ */ React39.createElement(Actions, null, /* @__PURE__ */ React39.createElement(BifurcatedAction, {
3856
+ disabled: !active,
3857
+ actions: inviteActions,
3858
+ activeAction,
3859
+ onChangeActiveAction: setActiveAction,
3860
+ "data-testid": "spaces-panel.create-invitation"
3861
+ })));
3862
+ };
3863
+
3864
+ // packages/sdk/shell/src/panels/SpacePanel/SpacePanel.tsx
3865
+ var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/panels/SpacePanel/SpacePanel.tsx";
3866
+ var SpacePanelHeading = ({ titleId, space, onDone }) => {
3867
+ const { t } = useTranslation24("os");
3868
+ const name = space.properties.name;
3869
+ return /* @__PURE__ */ React40.createElement(Heading, {
3870
+ titleId,
3871
+ title: t("space panel heading"),
3872
+ corner: /* @__PURE__ */ React40.createElement(CloseButton, {
3873
+ "data-testid": "identity-panel-done",
3874
+ onDone
3875
+ })
3876
+ }, /* @__PURE__ */ React40.createElement("div", {
3877
+ role: "none",
3878
+ className: "flex gap-4 items-center justify-center mlb-4"
3879
+ }, /* @__PURE__ */ React40.createElement(Planet, {
3880
+ size: 32,
3881
+ weight: "light"
3882
+ }), /* @__PURE__ */ React40.createElement("div", {
3883
+ className: "block text-start font-light text-xl"
3884
+ }, name ?? space.key.truncate())));
3885
+ };
3886
+ var SpacePanelImpl = (props) => {
3887
+ const { titleId, activeView, space, hideHeading, target, SpaceManager: SpaceManagerComponent = SpaceManager, InvitationManager: InvitationManagerComponent = InvitationManager, ...rest } = props;
3888
+ return /* @__PURE__ */ React40.createElement(React40.Fragment, null, !hideHeading && /* @__PURE__ */ React40.createElement(SpacePanelHeading, {
3889
+ ...rest,
3890
+ titleId,
3891
+ space
3892
+ }), /* @__PURE__ */ React40.createElement(Viewport.Root, {
3893
+ activeView
3894
+ }, /* @__PURE__ */ React40.createElement(Viewport.Views, null, /* @__PURE__ */ React40.createElement(Viewport.View, {
3895
+ id: "space manager",
3896
+ classNames: stepStyles
3897
+ }, /* @__PURE__ */ React40.createElement(SpaceManagerComponent, {
3898
+ active: activeView === "space manager",
3899
+ space,
3900
+ target,
3901
+ ...rest
3902
+ })), /* @__PURE__ */ React40.createElement(Viewport.View, {
3903
+ id: "space invitation manager",
3904
+ classNames: stepStyles
3905
+ }, /* @__PURE__ */ React40.createElement(InvitationManagerComponent, {
3906
+ active: activeView === "space invitation manager",
3907
+ ...rest,
3908
+ invitationUrl: props.invitationUrl
3909
+ })))));
3910
+ };
3911
+ var SpacePanelWithInvitationImpl = ({ invitation, ...props }) => {
3912
+ const invitationStatus = useInvitationStatus3(invitation);
3913
+ return /* @__PURE__ */ React40.createElement(SpacePanelImpl, {
3914
+ ...props,
3915
+ ...invitationStatus,
3916
+ invitationUrl: props.createInvitationUrl(invitationStatus.invitationCode)
3917
+ });
3918
+ };
3919
+ var SpacePanel = ({ titleId: propsTitleId, createInvitationUrl = (code) => code, ...props }) => {
3920
+ const titleId = useId9("spacePanel__heading", propsTitleId);
3921
+ const [spaceState, spaceSend, spaceService] = useSpaceMachine({
3922
+ context: {
3923
+ space: props.space
3924
+ }
3925
+ });
3926
+ useEffect7(() => {
3927
+ const subscription = spaceService.subscribe((state) => {
3928
+ log13("[state]", state, {
3929
+ F: __dxlog_file13,
3930
+ L: 95,
3931
+ S: void 0,
3932
+ C: (f, a) => f(...a)
3933
+ });
3934
+ });
3935
+ return subscription.unsubscribe;
3936
+ }, [
3937
+ spaceService
3938
+ ]);
3939
+ const activeView = useMemo5(() => {
3940
+ switch (true) {
3941
+ case spaceState.matches("managingSpace"):
3942
+ return "space manager";
3943
+ case spaceState.matches("managingSpaceInvitation"):
3944
+ return "space invitation manager";
3945
+ default:
3946
+ return "never";
3947
+ }
3948
+ }, [
3949
+ spaceState
3950
+ ]);
3951
+ const implProps = {
3952
+ ...props,
3953
+ activeView,
3954
+ send: spaceSend,
3955
+ titleId,
3956
+ createInvitationUrl
3957
+ };
3958
+ return spaceState.context.invitation ? (
3959
+ // TODO(wittjosiah): Unused? Remove?
3960
+ /* @__PURE__ */ React40.createElement(SpacePanelWithInvitationImpl, {
3961
+ ...implProps,
3962
+ invitation: spaceState.context.invitation
3963
+ })
3964
+ ) : /* @__PURE__ */ React40.createElement(SpacePanelImpl, implProps);
3965
+ };
3966
+
3967
+ // packages/sdk/shell/src/panels/StatusPanel/StatusPanel.tsx
3968
+ import React41 from "react";
3969
+ import { Status, useTranslation as useTranslation25 } from "@dxos/react-ui";
3970
+ var StatusPanel = ({ titleId }) => {
3971
+ const { t } = useTranslation25("os");
3972
+ return /* @__PURE__ */ React41.createElement("div", {
3973
+ className: "grid place-items-center p-2 gap-2"
3974
+ }, /* @__PURE__ */ React41.createElement("p", {
3975
+ id: titleId,
3976
+ className: "font-medium text-center"
3977
+ }, t("resetting message")), /* @__PURE__ */ React41.createElement(Status, {
3978
+ indeterminate: true
3979
+ }, t("resetting message")));
3980
+ };
3981
+
3982
+ // packages/sdk/shell/src/composites/IdentityDialog/IdentityDialog.tsx
3983
+ var IdentityDialog = (props) => {
3984
+ const titleId = useId10("identityDialog__title", props.title);
3985
+ return /* @__PURE__ */ React42.createElement(Dialog.Root, {
3986
+ defaultOpen: true,
3987
+ onOpenChange: (open) => open || props.onDone?.()
3988
+ }, /* @__PURE__ */ React42.createElement(Dialog.Portal, null, /* @__PURE__ */ React42.createElement(Dialog.Overlay, null, /* @__PURE__ */ React42.createElement(Dialog.Content, {
3989
+ "aria-labelledby": titleId,
3990
+ onOpenAutoFocus: (e) => e.preventDefault()
3991
+ }, /* @__PURE__ */ React42.createElement(ClipboardProvider, null, /* @__PURE__ */ React42.createElement(IdentityPanel, {
3992
+ ...props,
3993
+ titleId,
3994
+ doneActionParent: /* @__PURE__ */ React42.createElement(Dialog.Close, {
3995
+ asChild: true
3996
+ })
3997
+ }))))));
3998
+ };
3999
+
4000
+ // packages/sdk/shell/src/composites/JoinDialog/JoinDialog.tsx
4001
+ import React43 from "react";
4002
+ import { AlertDialog, useId as useId11, useVisualViewport } from "@dxos/react-ui";
4003
+ var JoinDialog = (joinPanelProps) => {
4004
+ const titleId = useId11("joinDialog__title");
4005
+ const { height } = useVisualViewport();
4006
+ return /* @__PURE__ */ React43.createElement(AlertDialog.Root, {
4007
+ defaultOpen: true,
4008
+ onOpenChange: (open) => open || (joinPanelProps.onExit ? joinPanelProps.onExit() : joinPanelProps.onDone?.(null))
4009
+ }, /* @__PURE__ */ React43.createElement(AlertDialog.Portal, null, /* @__PURE__ */ React43.createElement(AlertDialog.Overlay, {
4010
+ classNames: "backdrop-blur",
4011
+ ...height && {
4012
+ style: {
4013
+ blockSize: `${height}px`
4014
+ }
4015
+ }
4016
+ }, /* @__PURE__ */ React43.createElement(AlertDialog.Content, {
4017
+ "aria-labelledby": titleId
4018
+ }, /* @__PURE__ */ React43.createElement(JoinPanel, {
4019
+ ...joinPanelProps,
4020
+ titleId,
4021
+ exitActionParent: /* @__PURE__ */ React43.createElement(AlertDialog.Cancel, {
4022
+ asChild: true
4023
+ }),
4024
+ doneActionParent: /* @__PURE__ */ React43.createElement(AlertDialog.Action, {
4025
+ asChild: true
4026
+ })
4027
+ })))));
4028
+ };
4029
+
4030
+ // packages/sdk/shell/src/composites/Shell/run-shell.tsx
4031
+ import React47, { StrictMode } from "react";
4032
+ import { createRoot } from "react-dom/client";
4033
+ import { DEFAULT_CLIENT_CHANNEL, DEFAULT_SHELL_CHANNEL } from "@dxos/client-protocol";
4034
+ import { AgentHostingProvider, ClientProvider, ClientServicesProxy, Config, ShellDisplay as ShellDisplay2 } from "@dxos/react-client";
4035
+ import { Button as Button11, Dialog as Dialog3, ThemeProvider, Tooltip as Tooltip7, useTranslation as useTranslation26 } from "@dxos/react-ui";
4036
+ import { defaultTx } from "@dxos/react-ui-theme";
4037
+ import { createIFramePort } from "@dxos/rpc-tunnel";
4038
+
4039
+ // packages/sdk/shell/src/composites/Shell/Shell.tsx
4040
+ import React46, { useEffect as useEffect8, useState as useState14 } from "react";
4041
+ import { log as log14 } from "@dxos/log";
4042
+ import { useClient as useClient9 } from "@dxos/react-client";
4043
+ import { ShellDisplay, ShellLayout } from "@dxos/react-client";
4044
+ import { useSpace as useSpace2 } from "@dxos/react-client/echo";
4045
+
4046
+ // packages/sdk/shell/src/composites/SpaceDialog/SpaceDialog.tsx
4047
+ import React44 from "react";
4048
+ import { Dialog as Dialog2, useId as useId12 } from "@dxos/react-ui";
4049
+ var SpaceDialog = (spacePanelProps) => {
4050
+ const titleId = useId12("spaceDialog__title");
4051
+ return /* @__PURE__ */ React44.createElement(Dialog2.Root, {
4052
+ defaultOpen: true,
4053
+ onOpenChange: (open) => open || spacePanelProps.onDone?.()
4054
+ }, /* @__PURE__ */ React44.createElement(Dialog2.Portal, null, /* @__PURE__ */ React44.createElement(Dialog2.Overlay, null, /* @__PURE__ */ React44.createElement(Dialog2.Content, {
4055
+ "aria-labelledby": titleId
4056
+ }, /* @__PURE__ */ React44.createElement(ClipboardProvider, null, /* @__PURE__ */ React44.createElement(SpacePanel, {
4057
+ ...spacePanelProps,
4058
+ titleId,
4059
+ doneActionParent: /* @__PURE__ */ React44.createElement(Dialog2.Close, {
4060
+ asChild: true
4061
+ })
4062
+ }))))));
4063
+ };
4064
+
4065
+ // packages/sdk/shell/src/composites/StatusDialog/StatusDialog.tsx
4066
+ import React45 from "react";
4067
+ import { AlertDialog as AlertDialog2, useId as useId13 } from "@dxos/react-ui";
4068
+ var StatusDialog = () => {
4069
+ const titleId = useId13("statusDialog__title");
4070
+ return /* @__PURE__ */ React45.createElement(AlertDialog2.Root, {
4071
+ open: true
4072
+ }, /* @__PURE__ */ React45.createElement(AlertDialog2.Portal, null, /* @__PURE__ */ React45.createElement(AlertDialog2.Overlay, null, /* @__PURE__ */ React45.createElement(AlertDialog2.Content, {
4073
+ "aria-labelledby": titleId
4074
+ }, /* @__PURE__ */ React45.createElement(StatusPanel, {
4075
+ titleId
4076
+ })))));
4077
+ };
4078
+
4079
+ // packages/sdk/shell/src/composites/Shell/Shell.tsx
4080
+ var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/composites/Shell/Shell.tsx";
4081
+ var blurActiveElement = () => document.activeElement?.blur?.();
4082
+ var Shell = ({ runtime }) => {
4083
+ const [{ layout, invitationCode, spaceKey, spaceId, target }, setLayout] = useState14({
4084
+ layout: runtime.layout,
4085
+ invitationCode: runtime.invitationCode,
4086
+ spaceKey: runtime.spaceKey,
4087
+ spaceId: runtime.spaceId,
4088
+ target: runtime.target
4089
+ });
4090
+ const [{ invitationUrl, deviceInvitationParam, spaceInvitationParam }, setInvitationUrl] = useState14({
4091
+ invitationUrl: runtime.invitationUrl,
4092
+ deviceInvitationParam: runtime.deviceInvitationParam,
4093
+ spaceInvitationParam: runtime.spaceInvitationParam
4094
+ });
4095
+ const client = useClient9();
4096
+ const space = useSpace2(spaceId ?? spaceKey);
4097
+ const createDeviceInvitationUrl = (invitationCode2) => {
4098
+ const baseUrl = new URL(invitationUrl);
4099
+ baseUrl.searchParams.set(deviceInvitationParam, invitationCode2);
4100
+ return baseUrl.toString();
4101
+ };
4102
+ const createSpaceInvitationUrl = (invitationCode2) => {
4103
+ const baseUrl = new URL(invitationUrl);
4104
+ baseUrl.searchParams.set(spaceInvitationParam, invitationCode2);
4105
+ return baseUrl.toString();
4106
+ };
4107
+ useEffect8(() => {
4108
+ const unsubscribeLayout = runtime.layoutUpdate.on((request) => setLayout(request));
4109
+ const unsubscribeInvitationUrl = runtime.invitationUrlUpdate.on((request) => setInvitationUrl(request));
4110
+ return () => {
4111
+ unsubscribeLayout();
4112
+ unsubscribeInvitationUrl();
4113
+ };
4114
+ }, [
4115
+ runtime
4116
+ ]);
4117
+ useEffect8(() => {
4118
+ if (layout === ShellLayout.SPACE && !space) {
4119
+ log14.warn("No space found for shell space invitations.", void 0, {
4120
+ F: __dxlog_file14,
4121
+ L: 67,
4122
+ S: void 0,
4123
+ C: (f, a) => f(...a)
4124
+ });
4125
+ const timeout = setTimeout(async () => {
4126
+ await runtime.setAppContext({
4127
+ display: ShellDisplay.NONE
4128
+ });
4129
+ runtime.setLayout({
4130
+ layout: ShellLayout.DEFAULT
4131
+ });
4132
+ });
4133
+ return () => clearTimeout(timeout);
4134
+ }
4135
+ }, [
4136
+ runtime,
4137
+ layout,
4138
+ space
4139
+ ]);
4140
+ switch (layout) {
4141
+ case ShellLayout.STATUS:
4142
+ return /* @__PURE__ */ React46.createElement(StatusDialog, null);
4143
+ case ShellLayout.INITIALIZE_IDENTITY:
4144
+ case ShellLayout.INITIALIZE_IDENTITY_FROM_INVITATION:
4145
+ case ShellLayout.INITIALIZE_IDENTITY_FROM_RECOVERY:
4146
+ return /* @__PURE__ */ React46.createElement(JoinDialog, {
4147
+ mode: "halo-only",
4148
+ initialDisposition: layout === ShellLayout.INITIALIZE_IDENTITY_FROM_RECOVERY ? "recover-identity" : layout === ShellLayout.INITIALIZE_IDENTITY_FROM_INVITATION ? "accept-halo-invitation" : "default",
4149
+ initialInvitationCode: invitationCode,
4150
+ onCancelResetStorage: () => runtime.setLayout({
4151
+ layout: ShellLayout.IDENTITY
4152
+ }),
4153
+ onDone: async () => {
4154
+ blurActiveElement();
4155
+ await runtime.setAppContext({
4156
+ display: ShellDisplay.NONE
4157
+ });
4158
+ runtime.setLayout({
4159
+ layout: ShellLayout.DEFAULT
4160
+ });
4161
+ }
4162
+ });
4163
+ case ShellLayout.IDENTITY:
4164
+ case ShellLayout.SHARE_IDENTITY:
4165
+ case ShellLayout.EDIT_PROFILE:
4166
+ return /* @__PURE__ */ React46.createElement(IdentityDialog, {
4167
+ createInvitationUrl: createDeviceInvitationUrl,
4168
+ onResetStorage: async () => {
4169
+ runtime.setLayout({
4170
+ layout: ShellLayout.STATUS
4171
+ });
4172
+ await client.reset();
4173
+ return runtime.setAppContext({
4174
+ display: ShellDisplay.NONE,
4175
+ reset: true
4176
+ });
4177
+ },
4178
+ onRecover: async () => {
4179
+ runtime.setLayout({
4180
+ layout: ShellLayout.STATUS
4181
+ });
4182
+ await client.reset();
4183
+ return runtime.setAppContext({
4184
+ display: ShellDisplay.NONE,
4185
+ reset: true,
4186
+ target: "recoverIdentity"
4187
+ });
4188
+ },
4189
+ onJoinNewIdentity: async () => {
4190
+ runtime.setLayout({
4191
+ layout: ShellLayout.STATUS
4192
+ });
4193
+ await client.reset();
4194
+ return runtime.setAppContext({
4195
+ display: ShellDisplay.NONE,
4196
+ reset: true,
4197
+ target: "deviceInvitation"
4198
+ });
4199
+ },
4200
+ onDone: async () => {
4201
+ blurActiveElement();
4202
+ await runtime.setAppContext({
4203
+ display: ShellDisplay.NONE
4204
+ });
4205
+ runtime.setLayout({
4206
+ layout: ShellLayout.DEFAULT
4207
+ });
4208
+ },
4209
+ initialDisposition: layout === ShellLayout.SHARE_IDENTITY ? "manage-device-invitation" : "default"
4210
+ });
4211
+ case ShellLayout.SPACE:
4212
+ return space ? /* @__PURE__ */ React46.createElement(SpaceDialog, {
4213
+ space,
4214
+ target,
4215
+ createInvitationUrl: createSpaceInvitationUrl,
4216
+ onDone: async () => {
4217
+ blurActiveElement();
4218
+ await runtime.setAppContext({
4219
+ display: ShellDisplay.NONE
4220
+ });
4221
+ runtime.setLayout({
4222
+ layout: ShellLayout.DEFAULT
4223
+ });
4224
+ }
4225
+ }) : null;
4226
+ case ShellLayout.JOIN_SPACE:
4227
+ return /* @__PURE__ */ React46.createElement(JoinDialog, {
4228
+ initialInvitationCode: invitationCode,
4229
+ onDone: async (result) => {
4230
+ blurActiveElement();
4231
+ const target2 = result?.target ?? void 0;
4232
+ await runtime.setAppContext({
4233
+ display: ShellDisplay.NONE,
4234
+ spaceKey: result?.spaceKey ?? void 0,
4235
+ target: target2
4236
+ });
4237
+ runtime.setLayout({
4238
+ layout: ShellLayout.DEFAULT
4239
+ });
4240
+ },
4241
+ onExit: async () => {
4242
+ blurActiveElement();
4243
+ await runtime.setAppContext({
4244
+ display: ShellDisplay.NONE
4245
+ });
4246
+ runtime.setLayout({
4247
+ layout: ShellLayout.DEFAULT
4248
+ });
4249
+ }
4250
+ });
4251
+ default:
4252
+ return null;
4253
+ }
4254
+ };
4255
+
4256
+ // packages/sdk/shell/src/composites/Shell/shell-runtime.ts
4257
+ import { Event } from "@dxos/async";
4258
+ import { appServiceBundle, shellServiceBundle } from "@dxos/client-protocol";
4259
+ import { invariant as invariant4 } from "@dxos/invariant";
4260
+ import { ShellLayout as ShellLayout2 } from "@dxos/protocols/proto/dxos/iframe";
4261
+ import { createProtoRpcPeer } from "@dxos/rpc";
4262
+ var __dxlog_file15 = "/home/runner/work/dxos/dxos/packages/sdk/shell/src/composites/Shell/shell-runtime.ts";
4263
+ var ShellRuntimeImpl = class {
4264
+ constructor(_port) {
4265
+ this._port = _port;
4266
+ this.layoutUpdate = new Event();
4267
+ this.invitationUrlUpdate = new Event();
4268
+ this._layout = ShellLayout2.DEFAULT;
4269
+ this._invitationUrl = typeof window !== "undefined" ? window.location.origin : void 0;
4270
+ this._deviceInvitationParam = "deviceInvitationCode";
4271
+ this._spaceInvitationParam = "spaceInvitationCode";
4272
+ }
4273
+ get layout() {
4274
+ return this._layout;
4275
+ }
4276
+ get invitationCode() {
4277
+ return this._invitationCode;
4278
+ }
4279
+ /** @deprecated Use spaceId. */
4280
+ get spaceKey() {
4281
+ return this._spaceKey;
4282
+ }
4283
+ get spaceId() {
4284
+ return this._spaceId;
4285
+ }
4286
+ get invitationUrl() {
4287
+ return this._invitationUrl;
4288
+ }
4289
+ get deviceInvitationParam() {
4290
+ return this._deviceInvitationParam;
4291
+ }
4292
+ get spaceInvitationParam() {
4293
+ return this._spaceInvitationParam;
4294
+ }
4295
+ setLayout({ layout, invitationCode, spaceKey, spaceId }) {
4296
+ this._layout = layout;
4297
+ this._invitationCode = invitationCode;
4298
+ this._spaceKey = spaceKey;
4299
+ this._spaceId = spaceId;
4300
+ this.layoutUpdate.emit({
4301
+ layout,
4302
+ invitationCode,
4303
+ spaceKey,
4304
+ spaceId
4305
+ });
4306
+ }
4307
+ setInvitationUrl({ invitationUrl, deviceInvitationParam, spaceInvitationParam }) {
4308
+ this._invitationUrl = invitationUrl;
4309
+ this._deviceInvitationParam = deviceInvitationParam;
4310
+ this._spaceInvitationParam = spaceInvitationParam;
4311
+ this.invitationUrlUpdate.emit({
4312
+ invitationUrl,
4313
+ deviceInvitationParam,
4314
+ spaceInvitationParam
4315
+ });
4316
+ }
4317
+ async setAppContext(context) {
4318
+ invariant4(this._appRpc, "runtime not open", {
4319
+ F: __dxlog_file15,
4320
+ L: 83,
4321
+ S: this,
4322
+ A: [
4323
+ "this._appRpc",
4324
+ "'runtime not open'"
4325
+ ]
4326
+ });
4327
+ await this._appRpc.rpc.AppService.setContext(context);
4328
+ }
4329
+ async open() {
4330
+ this._appRpc = createProtoRpcPeer({
4331
+ requested: appServiceBundle,
4332
+ exposed: shellServiceBundle,
4333
+ handlers: {
4334
+ ShellService: {
4335
+ setLayout: async (request) => {
4336
+ this._layout = request.layout;
4337
+ this._invitationCode = request.invitationCode;
4338
+ this._spaceKey = request.spaceKey;
4339
+ this._spaceId = request.spaceId;
4340
+ this.layoutUpdate.emit(request);
4341
+ },
4342
+ setInvitationUrl: async (request) => {
4343
+ this._invitationUrl = request.invitationUrl;
4344
+ this._deviceInvitationParam = request.deviceInvitationParam;
4345
+ this._spaceInvitationParam = request.spaceInvitationParam;
4346
+ this.invitationUrlUpdate.emit(request);
4347
+ }
4348
+ }
4349
+ },
4350
+ port: this._port
4351
+ });
4352
+ await this._appRpc.open();
4353
+ }
4354
+ async close() {
4355
+ await this._appRpc?.close();
4356
+ this._appRpc = void 0;
4357
+ }
4358
+ };
4359
+
4360
+ // packages/sdk/shell/src/translations/locales/en-US.ts
4361
+ var en_US_exports = {};
4362
+ __export(en_US_exports, {
4363
+ os: () => os
4364
+ });
4365
+ var os = {
4366
+ "manage profile label": "Manage identity",
4367
+ "identity offline description": "Offline",
4368
+ "sidebar label": "DXOS sidebar",
4369
+ "copy invitation code label": "Copy URL",
4370
+ "copy success label": "Copied",
4371
+ "copy self public key label": "Copy public key",
4372
+ "open share panel label": "View QR code",
4373
+ "joining space heading": "Joining space",
4374
+ "join space heading": "Enter space invitation",
4375
+ "halo heading": "Initialize device identity",
4376
+ "exit label": "Exit",
4377
+ "identity selector title": "Join as",
4378
+ "identity radio group title": "Select an identity you\u2019ve associated with this device already",
4379
+ "add identity label": "Add",
4380
+ "continue label": "Continue",
4381
+ "back label": "Back",
4382
+ "next label": "Next",
4383
+ "close label": "Close",
4384
+ "auth choices label": "Choose an identity",
4385
+ "create identity label": "Create an identity",
4386
+ "create identity description": "Create a new identity.",
4387
+ "recover identity label": "Use a seed phrase",
4388
+ "recover identity description": "Enter your seed phrase to log in manually.",
4389
+ "join identity label": "Use another device",
4390
+ "join identity description": "Add this device to an identity you\u2019re already logged into on another device.",
4391
+ "deselect identity label": "Back to identities",
4392
+ "addition method chooser title": "An identity is required to continue",
4393
+ "new identity input label": "Set display name",
4394
+ "recover identity input label": "Type or paste your seed phrase",
4395
+ "failed to create identity message": "Failed to create an identity.",
4396
+ "failed to recover identity message": "Failed to recover an identity from the provided seed phrase.",
4397
+ "failed to authenticate message": "Incorrect code.",
4398
+ "identity added label": "Created identity & added to this device:",
4399
+ "join space as identity heading": "<part>as </part><part><icon/><label>{{labelValue}}</label></part>",
4400
+ "error status label": "Failed",
4401
+ "timeout status label": "Timed out",
4402
+ "cancelled status label": "Cancelled",
4403
+ "init status label": "Ready to connect",
4404
+ "connecting status label": "Connecting\u2026",
4405
+ "connected status label": "Enter authentication code",
4406
+ "authenticating status label": "Enter authentication code",
4407
+ "success status label": "Success",
4408
+ "cancel label": "Cancel",
4409
+ "done label": "Done",
4410
+ "reset label": "Start over",
4411
+ "auth code input label": "Enter the verification code",
4412
+ "invitation input label": "Paste an invitation code or URL",
4413
+ "create device invitation label": "Add device",
4414
+ "create space invitation label": "Invite",
4415
+ "qr label": "Scan to accept invitation",
4416
+ "empty invitations message": "No pending invitations",
4417
+ "empty device list message": "No devices authenticated other than this device.",
4418
+ "show all spaces label": "All spaces",
4419
+ "all spaces label": "All spaces",
4420
+ "create space label": "Create a new space",
4421
+ "join space label": "Join a space",
4422
+ "show current space label": "Current space",
4423
+ "view space invitations label": "View space invitations",
4424
+ "toggle sidebar label": "Open/close sidebar",
4425
+ "open sidebar label": "Open sidebar",
4426
+ "close sidebar label": "Close sidebar",
4427
+ "welcome message": "Welcome",
4428
+ "selecting identity heading": "Selecting identity",
4429
+ "devices heading": "Devices",
4430
+ "identity heading": "Profile settings",
4431
+ "choose add device label": "Add device",
4432
+ "choose devices label": "Manage devices",
4433
+ "choose profile label": "Edit profile",
4434
+ "choose sign out label": "Reset storage",
4435
+ "choose join new identity label": "Join existing device",
4436
+ "empty space members message": "There is nobody in this space yet.",
4437
+ "back to all invitations label": "Back to all invitations",
4438
+ "invitation heading": "Invitation",
4439
+ "invitation list heading": "Invitations",
4440
+ "device invitation list heading": "Pending device invitations",
4441
+ "space invitation list heading": "Pending invitations",
4442
+ "device list heading": "Devices",
4443
+ "space member list heading": "Members",
4444
+ "space panel heading": "Space membership",
4445
+ "auth code message": "Enter the following auth code on the joining device.",
4446
+ "auth other device emoji message": "Be sure the other device shows the following symbol:",
4447
+ "display name input label": "Display name",
4448
+ "display name input placeholder": "Enter a display name",
4449
+ "invite one label": "Single-use invitation",
4450
+ "invite one description": "Only one user may join.",
4451
+ "invite one qr label": "Single-use invitation",
4452
+ "invite one list item label": "Active single-use invitation",
4453
+ "invite many label": "Multi-use invitation",
4454
+ "invite many description": "Anyone with the link can join.",
4455
+ "invite many qr label": "Multi-use invitation",
4456
+ "invite many list item label": "Active multi-use invitation",
4457
+ "invite options label": "Change the active invite option.",
4458
+ "reset in progress label": "Resetting...",
4459
+ "confirm label": "Confirm",
4460
+ "reset storage input label": "WARNING: This will delete all data on this device. Type {{confirmationValue}} to continue.",
4461
+ "join new identity input label": "WARNING: To join an existing device all data on this device will be deleted. Type {{confirmationValue}} to continue.",
4462
+ "failed to reset identity message": "Failed to reset identity.",
4463
+ "confirmation value": "RESET",
4464
+ "confirmation placeholder": "Enter {{confirmationValue}} to continue.",
4465
+ "sign out chooser title": "Danger zone",
4466
+ "sign out chooser message": "Proceeding with the action below will erase all data on this device.",
4467
+ "join new identity label": "Join a new identity",
4468
+ "reset device label": "Reset storage",
4469
+ "reset device confirm message": "Are you sure you want to reset your device? All data will be lost.",
4470
+ "emoji and color label": "Emoji and color",
4471
+ "clear label": "Use default",
4472
+ "select emoji label": "Avatar emoji",
4473
+ "select hue label": "Avatar background color",
4474
+ "resetting message": "One moment while the device is reset\u2026",
4475
+ "red label": "Red",
4476
+ "orange label": "Orange",
4477
+ "amber label": "Amber",
4478
+ "yellow label": "Yellow",
4479
+ "lime label": "Lime",
4480
+ "green label": "Green",
4481
+ "emerald label": "Emerald",
4482
+ "teal label": "Teal",
4483
+ "cyan label": "Cyan",
4484
+ "sky label": "Sky",
4485
+ "blue label": "Blue",
4486
+ "indigo label": "Indigo",
4487
+ "violet label": "Violet",
4488
+ "purple label": "Purple",
4489
+ "fuchsia label": "Fuchsia",
4490
+ "pink label": "Pink",
4491
+ "rose label": "Rose",
4492
+ "current device tag label": "This device",
4493
+ "device name placeholder": "{{platform}} on {{os}}",
4494
+ "more options label": "More options",
4495
+ "disconnect label": "Go offline.",
4496
+ "connect label": "Go online.",
4497
+ "edit device label": "Edit device name & avatar",
4498
+ "agent heading": "Agent",
4499
+ "create agent clickwrap": 'By creating an agent, you agree to our <tosLink href="https://dxos.org/tos">Terms of\xA0Service</tosLink>.',
4500
+ "create agent description": "Creating an agent helps keep your devices and peers in-sync. An agent is like any other device, but since it\u2019s always online your changes will sync even when all your physical devices are\xA0asleep.",
4501
+ "create agent label": "Start an agent",
4502
+ "destroy agent label": "Shut down agent",
4503
+ "agent device label": "Your agent",
4504
+ "shell fallback title": "Shell failed to connect",
4505
+ "creating agent label": "Starting agent\u2026",
4506
+ "destroying agent label": "Stopping agent\u2026",
4507
+ "getting agent label": "Checking agent status\u2026",
4508
+ "agent requested label": "Agent requested",
4509
+ "agent requested description": "The agent service is creating an agent for you. Once the agent connects, it will display in the devices list.",
4510
+ "authenticating label": "Authenticating\u2026",
4511
+ "create recovery code label": "Create recovery code",
4512
+ "choose recover identity label": "Recover identity"
4513
+ };
4514
+
4515
+ // packages/sdk/shell/src/translations/index.ts
4516
+ var osTranslations = {
4517
+ "en-US": en_US_exports
4518
+ };
4519
+
4520
+ // packages/sdk/shell/src/composites/Shell/run-shell.tsx
4521
+ var runShell = async (config = new Config()) => {
4522
+ const runtime = new ShellRuntimeImpl(createIFramePort({
4523
+ channel: DEFAULT_SHELL_CHANNEL
4524
+ }));
4525
+ await runtime.open();
4526
+ try {
4527
+ const services = new ClientServicesProxy(createIFramePort({
4528
+ channel: DEFAULT_CLIENT_CHANNEL
4529
+ }));
4530
+ createRoot(document.getElementById("root")).render(/* @__PURE__ */ React47.createElement(StrictMode, null, /* @__PURE__ */ React47.createElement(ThemeProvider, {
4531
+ tx: defaultTx,
4532
+ resourceExtensions: [
4533
+ osTranslations
4534
+ ]
4535
+ }, /* @__PURE__ */ React47.createElement(ClientProvider, {
4536
+ config,
4537
+ services,
4538
+ noBanner: true
4539
+ }, /* @__PURE__ */ React47.createElement(ClipboardProvider, null, /* @__PURE__ */ React47.createElement(Tooltip7.Provider, null, /* @__PURE__ */ React47.createElement(AgentHostingProvider, null, /* @__PURE__ */ React47.createElement(Shell, {
4540
+ runtime
4541
+ }))))))));
4542
+ } catch {
4543
+ createRoot(document.getElementById("root")).render(/* @__PURE__ */ React47.createElement(StrictMode, null, /* @__PURE__ */ React47.createElement(ThemeProvider, {
4544
+ tx: defaultTx,
4545
+ resourceExtensions: [
4546
+ osTranslations
4547
+ ]
4548
+ }, /* @__PURE__ */ React47.createElement(Fallback, {
4549
+ onClose: () => runtime.setAppContext({
4550
+ display: ShellDisplay2.NONE
4551
+ })
4552
+ }))));
4553
+ }
4554
+ };
4555
+ var Fallback = ({ onClose }) => {
4556
+ const { t } = useTranslation26("os");
4557
+ return /* @__PURE__ */ React47.createElement(Dialog3.Root, {
4558
+ modal: true,
4559
+ open: true,
4560
+ onOpenChange: () => onClose?.()
4561
+ }, /* @__PURE__ */ React47.createElement(Dialog3.Overlay, null, /* @__PURE__ */ React47.createElement(Dialog3.Content, null, /* @__PURE__ */ React47.createElement(Dialog3.Title, null, t("shell fallback title")), /* @__PURE__ */ React47.createElement(Dialog3.Close, {
4562
+ asChild: true,
4563
+ onClick: () => onClose?.()
4564
+ }, /* @__PURE__ */ React47.createElement(Button11, {
4565
+ variant: "primary"
4566
+ }, t("close label"))))));
4567
+ };
4568
+
4569
+ // packages/sdk/shell/src/composites/Shell/ShellContext.tsx
4570
+ import React48, { createContext as createContext2, useCallback as useCallback8, useContext as useContext2, useEffect as useEffect9, useMemo as useMemo6, useState as useState15 } from "react";
4571
+ import { useClient as useClient10, ShellDisplay as ShellDisplay3, ShellLayout as ShellLayout4 } from "@dxos/react-client";
4572
+ import { useIdentity as useIdentity3 } from "@dxos/react-client/halo";
4573
+ import { mx as mx25 } from "@dxos/react-ui-theme";
4574
+
4575
+ // packages/sdk/shell/src/composites/Shell/memory-shell-runtime.ts
4576
+ import { Event as Event2 } from "@dxos/async";
4577
+ import { ShellLayout as ShellLayout3 } from "@dxos/react-client";
4578
+ var MemoryShellRuntime = class {
4579
+ constructor({ layout, invitationCode, spaceKey, invitationUrl, deviceInvitationParam, spaceInvitationParam } = {}) {
4580
+ this.layoutUpdate = new Event2();
4581
+ this.invitationUrlUpdate = new Event2();
4582
+ this.contextUpdate = new Event2();
4583
+ this._layout = layout ?? ShellLayout3.DEFAULT;
4584
+ this._invitationCode = invitationCode;
4585
+ this._spaceKey = spaceKey;
4586
+ this._invitationUrl = invitationUrl ?? window.location.origin;
4587
+ this._deviceInvitationParam = deviceInvitationParam ?? "deviceInvitationCode";
4588
+ this._spaceInvitationParam = spaceInvitationParam ?? "spaceInvitationCode";
4589
+ }
4590
+ get layout() {
4591
+ return this._layout;
4592
+ }
4593
+ get invitationCode() {
4594
+ return this._invitationCode;
4595
+ }
4596
+ get spaceKey() {
4597
+ return this._spaceKey;
4598
+ }
4599
+ get invitationUrl() {
4600
+ return this._invitationUrl;
4601
+ }
4602
+ get deviceInvitationParam() {
4603
+ return this._deviceInvitationParam;
4604
+ }
4605
+ get spaceInvitationParam() {
4606
+ return this._spaceInvitationParam;
4607
+ }
4608
+ setLayout(request) {
4609
+ this._layout = request.layout;
4610
+ this._invitationCode = request.invitationCode;
4611
+ this._spaceKey = request.spaceKey;
4612
+ this.layoutUpdate.emit(request);
4613
+ }
4614
+ setInvitationUrl(request) {
4615
+ this._invitationUrl = request.invitationUrl;
4616
+ this._deviceInvitationParam = request.deviceInvitationParam;
4617
+ this._spaceInvitationParam = request.spaceInvitationParam;
4618
+ this.invitationUrlUpdate.emit(request);
4619
+ }
4620
+ async setAppContext(context) {
4621
+ this.contextUpdate.emit(context);
4622
+ }
4623
+ };
4624
+
4625
+ // packages/sdk/shell/src/composites/Shell/ShellContext.tsx
4626
+ var ShellContext = /* @__PURE__ */ createContext2({});
4627
+ var useShell = () => {
4628
+ const client = useClient10();
4629
+ const { runtime, setDisplay } = useContext2(ShellContext);
4630
+ const setLayout = async (layout, options) => {
4631
+ if (runtime) {
4632
+ if (layout === ShellLayout4.DEFAULT) {
4633
+ setDisplay?.(ShellDisplay3.NONE);
4634
+ } else {
4635
+ setDisplay?.(ShellDisplay3.FULLSCREEN);
4636
+ }
4637
+ runtime.setLayout({
4638
+ layout,
4639
+ ...options
4640
+ });
4641
+ }
4642
+ await client.shell.open(layout, options);
4643
+ };
4644
+ return {
4645
+ setLayout
4646
+ };
4647
+ };
4648
+ var ShellProvider = ({ space, deviceInvitationCode, spaceInvitationCode, onJoinedSpace, children }) => {
4649
+ const client = useClient10();
4650
+ const identity = useIdentity3();
4651
+ const [display, setDisplay] = useState15(!identity || spaceInvitationCode || deviceInvitationCode ? ShellDisplay3.FULLSCREEN : ShellDisplay3.NONE);
4652
+ const shellRuntime = useMemo6(() => {
4653
+ if (client.config.get("runtime.app.env.DX_VAULT") !== "false") {
4654
+ return;
4655
+ }
4656
+ if (spaceInvitationCode) {
4657
+ return new MemoryShellRuntime({
4658
+ layout: ShellLayout4.JOIN_SPACE,
4659
+ invitationCode: spaceInvitationCode
4660
+ });
4661
+ }
4662
+ if (deviceInvitationCode) {
4663
+ return new MemoryShellRuntime({
4664
+ layout: ShellLayout4.INITIALIZE_IDENTITY,
4665
+ invitationCode: deviceInvitationCode
4666
+ });
4667
+ }
4668
+ return new MemoryShellRuntime({
4669
+ layout: identity ? ShellLayout4.DEFAULT : ShellLayout4.INITIALIZE_IDENTITY
4670
+ });
4671
+ }, [
4672
+ client,
4673
+ identity,
4674
+ spaceInvitationCode,
4675
+ deviceInvitationCode
4676
+ ]);
4677
+ const handleKeyDown = useCallback8((event) => {
4678
+ if (!space || !shellRuntime) {
4679
+ return;
4680
+ }
4681
+ const modifier = event.ctrlKey || event.metaKey;
4682
+ if (event.key === ">" && event.shiftKey && modifier) {
4683
+ shellRuntime.setLayout({
4684
+ layout: ShellLayout4.SHARE_IDENTITY
4685
+ });
4686
+ setDisplay(ShellDisplay3.FULLSCREEN);
4687
+ } else if (event.key === "." && modifier) {
4688
+ shellRuntime.setLayout({
4689
+ layout: ShellLayout4.SPACE,
4690
+ spaceKey: space.key
4691
+ });
4692
+ setDisplay(ShellDisplay3.FULLSCREEN);
4693
+ }
4694
+ }, [
4695
+ space,
4696
+ shellRuntime
4697
+ ]);
4698
+ useEffect9(() => {
4699
+ if (!shellRuntime) {
4700
+ return;
4701
+ }
4702
+ window.addEventListener("keydown", handleKeyDown);
4703
+ return () => window.removeEventListener("keydown", handleKeyDown);
4704
+ }, [
4705
+ shellRuntime,
4706
+ handleKeyDown
4707
+ ]);
4708
+ useEffect9(() => {
4709
+ if (!shellRuntime) {
4710
+ return;
4711
+ }
4712
+ return shellRuntime.contextUpdate.on(({ display: display2, spaceKey }) => {
4713
+ if (display2) {
4714
+ setDisplay(display2);
4715
+ }
4716
+ onJoinedSpace?.(spaceKey);
4717
+ });
4718
+ }, [
4719
+ shellRuntime
4720
+ ]);
4721
+ return /* @__PURE__ */ React48.createElement(React48.Fragment, null, shellRuntime && /* @__PURE__ */ React48.createElement("div", {
4722
+ className: mx25(display === ShellDisplay3.NONE ? "hidden" : "")
4723
+ }, /* @__PURE__ */ React48.createElement(Shell, {
4724
+ runtime: shellRuntime
4725
+ })), /* @__PURE__ */ React48.createElement(ShellContext.Provider, {
4726
+ value: {
4727
+ runtime: shellRuntime,
4728
+ setDisplay
4729
+ }
4730
+ }, children));
4731
+ };
4732
+ export {
4733
+ Action,
4734
+ Actions,
4735
+ AgentConfig,
4736
+ AuthCode,
4737
+ BifurcatedAction,
4738
+ Centered,
4739
+ ClipboardContext,
4740
+ ClipboardProvider,
4741
+ CloseButton,
4742
+ CompoundButton,
4743
+ ConfirmReset,
4744
+ ConfirmResetImpl,
4745
+ CopyButton,
4746
+ CopyButtonIconOnly,
4747
+ DeviceList,
4748
+ Emoji,
4749
+ EmojiPickerBlock,
4750
+ EmojiPickerToolbarButton,
4751
+ Heading,
4752
+ HuePickerBlock,
4753
+ HuePickerToolbarButton,
4754
+ IdentityDialog,
4755
+ IdentityListItem,
4756
+ IdentityPanel,
4757
+ IdentityPanelImpl,
4758
+ Input,
4759
+ InvitationList,
4760
+ InvitationListContainer,
4761
+ InvitationListItem,
4762
+ InvitationListItemImpl,
4763
+ InvitationManager,
4764
+ JoinDialog,
4765
+ JoinPanel,
4766
+ JoinPanelImpl,
4767
+ Label,
4768
+ Shell,
4769
+ ShellContext,
4770
+ ShellProvider,
4771
+ SpaceDialog,
4772
+ SpaceListItem,
4773
+ SpaceMemberList,
4774
+ SpaceMemberListImpl,
4775
+ SpacePanel,
4776
+ SpacePanelImpl,
4777
+ StatusPanel,
4778
+ StepHeading,
4779
+ Viewport,
4780
+ activeBgColor,
4781
+ activeStrokeColor,
4782
+ activeTextColor,
4783
+ cancelledBgColor,
4784
+ cancelledStrokeColor,
4785
+ cancelledTextColor,
4786
+ createViewportScope,
4787
+ errorBgColor,
4788
+ errorStrokeColor,
4789
+ errorTextColor,
4790
+ inactiveBgColor,
4791
+ inactiveStrokeColor,
4792
+ inactiveTextColor,
4793
+ osTranslations,
4794
+ resolvedBgColor,
4795
+ resolvedStrokeColor,
4796
+ resolvedTextColor,
4797
+ runShell,
4798
+ stepStyles,
4799
+ successBgColor,
4800
+ successStrokeColor,
4801
+ successTextColor,
4802
+ useClipboardContext,
4803
+ useShell,
4804
+ useViewportContext
4805
+ };
4806
+ //# sourceMappingURL=react.mjs.map