@domainkit/react 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,14 +1,17 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { Dialog } from "@base-ui/react/dialog";
2
+ import { AlertDialog } from "@base-ui/react/alert-dialog";
3
3
  import { RegistryProvider, useAtomSet, useAtomValue } from "@effect/atom-react";
4
4
  import { Transport } from "domainkit";
5
5
  import * as Data from "effect/Data";
6
6
  import * as Effect from "effect/Effect";
7
7
  import * as Atom from "effect/unstable/reactivity/Atom";
8
- import { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
8
+ import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
9
9
  import { useRender } from "@base-ui/react/use-render";
10
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
+ import { Dialog } from "@base-ui/react/dialog";
11
12
  import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
13
+ import { Menu } from "@base-ui/react/menu";
14
+ import { Popover } from "@base-ui/react/popover";
12
15
  //#region src/atom.ts
13
16
  const Failure = Data.taggedEnum();
14
17
  const failureFromError = (error) => Failure.Failure({
@@ -96,12 +99,12 @@ const english = {
96
99
  applyCleanup: "Remove records",
97
100
  applyDns: "Add records",
98
101
  applyingDns: "Adding records…",
102
+ authenticationAlternative: "or",
99
103
  automaticUnavailable: "Automatic connection is not available for this domain",
100
104
  cancel: "Cancel",
101
105
  checkAgain: "Check again",
102
106
  checkingDns: "Checking DNS…",
103
107
  checkDns: "Check DNS",
104
- cleanupComplete: "DNS cleanup complete",
105
108
  cleanupConsent: "Only records proven by the apply receipt will be deleted.",
106
109
  cleanupPartial: "Some DNS records could not be deleted. Review and retry safely.",
107
110
  cleaningDns: "Removing records…",
@@ -112,15 +115,17 @@ const english = {
112
115
  close: "Close",
113
116
  detectingProvider: "Detecting DNS provider…",
114
117
  disconnectDomain: "Disconnect",
118
+ disconnectConsent: "The provider connection will be removed. Existing DNS records will be preserved.",
115
119
  disconnecting: "Disconnecting…",
120
+ disconnectTitle: (provider) => `Disconnect ${provider}?`,
116
121
  domainDisconnected: "Domain disconnected. DNS records were preserved.",
117
122
  dialogDescription: (domain) => `Authorize DNS changes for ${domain}.`,
118
123
  dialogTitle: (provider) => `Connect ${provider}`,
119
124
  openingAuthorization: "Opening provider authorization…",
125
+ moreActions: "More connection actions",
120
126
  planConsent: "Review the exact DNS operations before approving this plan.",
121
127
  planningCleanup: "Preparing cleanup…",
122
128
  planningDns: "Preparing DNS changes…",
123
- recordsApplied: "DNS changes applied",
124
129
  recordsPartiallyApplied: "Some DNS changes failed. Review and retry safely.",
125
130
  reviewCleanup: "Remove records",
126
131
  reviewDns: "Review changes",
@@ -138,9 +143,11 @@ var theme_exports = /* @__PURE__ */ __exportAll({ toStyle: () => toStyle });
138
143
  const variables = {
139
144
  accent: "--domainkit-accent",
140
145
  accentContrast: "--domainkit-accent-contrast",
146
+ backdrop: "--domainkit-backdrop",
141
147
  background: "--domainkit-background",
142
148
  border: "--domainkit-border",
143
149
  danger: "--domainkit-danger",
150
+ dangerContrast: "--domainkit-danger-contrast",
144
151
  fill: "--domainkit-fill",
145
152
  fontFamily: "--domainkit-font-family",
146
153
  muted: "--domainkit-muted",
@@ -181,8 +188,17 @@ const usePortalContainer = (container) => {
181
188
  const getSnapshot = useCallback(() => resolvePortalContainer(container, ownerDocument), [container, ownerDocument]);
182
189
  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
183
190
  };
184
- function Root$6({ children, colorScheme = "inherit", icons, marks = {}, messages, navigate = navigateInBrowser, portalContainer = null, theme, transport, ...props }) {
191
+ function Root$6({ children, colorScheme = "inherit", icons, marks = {}, messages, navigate = navigateInBrowser, onEvent, portalContainer = null, theme, transport, ...props }) {
185
192
  const runtime = useMemo(() => Atom.runtime(transport), [transport]);
193
+ const onEventRef = useRef(onEvent);
194
+ useLayoutEffect(() => {
195
+ onEventRef.current = onEvent;
196
+ }, [onEvent]);
197
+ const emit = useCallback((event) => {
198
+ try {
199
+ onEventRef.current?.(event);
200
+ } catch {}
201
+ }, []);
186
202
  const themeStyle = toStyle(theme);
187
203
  const resolvedPortalContainer = usePortalContainer(portalContainer);
188
204
  const portalContainerRef = useMemo(() => ({ current: resolvedPortalContainer }), [resolvedPortalContainer]);
@@ -195,6 +211,7 @@ function Root$6({ children, colorScheme = "inherit", icons, marks = {}, messages
195
211
  return /* @__PURE__ */ jsx(RegistryProvider, { children: /* @__PURE__ */ jsx(Context.Provider, {
196
212
  value: {
197
213
  colorScheme,
214
+ emit,
198
215
  marks,
199
216
  messages: merge(messages),
200
217
  navigate,
@@ -214,6 +231,10 @@ function useDomainKit() {
214
231
  return value;
215
232
  }
216
233
  //#endregion
234
+ //#region src/lifecycle.ts
235
+ var lifecycle_exports = /* @__PURE__ */ __exportAll({ Event: () => Event });
236
+ const Event = Data.taggedEnum();
237
+ //#endregion
217
238
  //#region src/operations.tsx
218
239
  var operations_exports = /* @__PURE__ */ __exportAll({
219
240
  Item: () => Item,
@@ -288,17 +309,22 @@ var cleanup_exports = /* @__PURE__ */ __exportAll({
288
309
  });
289
310
  const State$3 = Data.taggedEnum();
290
311
  const Command$3 = Data.taggedEnum();
291
- function useModel$3(connection, receiptId) {
292
- const { runtime } = useDomainKit();
312
+ function useModel$3(connection, receiptId, onCleaned) {
313
+ const { emit, runtime } = useDomainKit();
314
+ const onCleanedRef = useRef(onCleaned);
315
+ onCleanedRef.current = onCleaned;
293
316
  return useMemo(() => {
294
317
  const state = Atom.make(State$3.Idle());
295
318
  return {
296
319
  command: runtime.fn()((command, get) => {
320
+ const current = get(state);
297
321
  if (command._tag === "Dismiss") {
322
+ if (current._tag === "Planning" || current._tag === "Cleaning") return Effect.void;
298
323
  get.set(state, State$3.Idle());
299
324
  return Effect.void;
300
325
  }
301
326
  if (command._tag === "Plan") {
327
+ if (current._tag === "Planning" || current._tag === "Cleaning") return Effect.void;
302
328
  get.set(state, State$3.Planning());
303
329
  return Effect.flatMap(Transport.Service, (transport) => transport.cleanup.plan({
304
330
  connectionId: connection.connectionId,
@@ -306,7 +332,6 @@ function useModel$3(connection, receiptId) {
306
332
  receiptId
307
333
  })).pipe(Effect.tap((plan) => Effect.sync(() => get.set(state, State$3.Review({ plan })))), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
308
334
  }
309
- const current = get(state);
310
335
  if (current._tag !== "Review" || current.plan.operations.some((operation) => operation._tag === "Blocked")) return Effect.void;
311
336
  const plan = current.plan;
312
337
  get.set(state, State$3.Cleaning({ plan }));
@@ -315,25 +340,43 @@ function useModel$3(connection, receiptId) {
315
340
  domain: connection.domain,
316
341
  planDigest: plan.digest,
317
342
  receiptId
318
- })).pipe(Effect.tap((result) => Effect.sync(() => get.set(state, result._tag === "Cleaned" ? State$3.Cleaned({ result }) : result._tag === "Partial" ? State$3.Partial({ result }) : result))), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
343
+ })).pipe(Effect.tap((result) => Effect.sync(() => {
344
+ if (result._tag === "Cleaned") {
345
+ get.set(state, State$3.Cleaned({ result }));
346
+ onCleanedRef.current?.(result);
347
+ emit(Event.RecordsCleaned({
348
+ connection,
349
+ result
350
+ }));
351
+ } else if (result._tag === "Partial") {
352
+ get.set(state, State$3.Partial({ result }));
353
+ onCleanedRef.current?.(result);
354
+ emit(Event.RecordsPartiallyCleaned({
355
+ connection,
356
+ result
357
+ }));
358
+ } else get.set(state, result);
359
+ })), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
319
360
  }),
320
361
  state
321
362
  };
322
363
  }, [
323
364
  connection.connectionId,
324
365
  connection.domain,
366
+ emit,
325
367
  receiptId,
326
368
  runtime
327
369
  ]);
328
370
  }
329
- function useController$3(connection, receiptId) {
330
- const model = useModel$3(connection, receiptId);
371
+ function useController$3(connection, receiptId, onCleaned) {
372
+ const model = useModel$3(connection, receiptId, onCleaned);
331
373
  const state = useAtomValue(model.state);
332
374
  const execute = useAtomSet(model.command);
333
375
  return {
334
376
  apply: () => execute(Command$3.Apply()),
335
377
  dismiss: () => execute(Command$3.Dismiss()),
336
378
  plan: () => execute(Command$3.Plan()),
379
+ retry: () => execute(Command$3.Plan()),
337
380
  state
338
381
  };
339
382
  }
@@ -345,11 +388,6 @@ function Root$4({ status, ...props }) {
345
388
  }
346
389
  function Outcome$2({ state }) {
347
390
  const { messages } = useDomainKit();
348
- if (state._tag === "Cleaned") return /* @__PURE__ */ jsx("p", {
349
- "data-domainkit-part": "flow-outcome",
350
- "data-tone": "success",
351
- children: messages.cleanupComplete
352
- });
353
391
  if (state._tag === "Partial" || state._tag === "Failure" || state._tag === "Stale") return /* @__PURE__ */ jsx("p", {
354
392
  "data-domainkit-part": "flow-outcome",
355
393
  "data-tone": "danger",
@@ -358,23 +396,40 @@ function Outcome$2({ state }) {
358
396
  });
359
397
  return null;
360
398
  }
361
- function Dialog$3({ controller }) {
399
+ function Dialog$3({ controller, onOpenChange, onOpenChangeComplete, trigger }) {
362
400
  const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
363
401
  const state = controller.state;
364
- const plan = state._tag === "Review" || state._tag === "Cleaning" ? state.plan : void 0;
365
- return /* @__PURE__ */ jsxs(Dialog.Root, {
366
- onOpenChange: (open) => {
367
- if (!open) controller.dismiss();
402
+ const planRef = useRef(void 0);
403
+ if (state._tag === "Idle") planRef.current = void 0;
404
+ if (state._tag === "Review" || state._tag === "Cleaning") planRef.current = state.plan;
405
+ const plan = planRef.current;
406
+ const busy = state._tag === "Planning" || state._tag === "Cleaning";
407
+ const open = state._tag !== "Idle" && state._tag !== "Cleaned";
408
+ return /* @__PURE__ */ jsxs(AlertDialog.Root, {
409
+ onOpenChange: (nextOpen, eventDetails) => {
410
+ if (!nextOpen && busy) {
411
+ eventDetails.cancel();
412
+ return;
413
+ }
414
+ if (!nextOpen) controller.dismiss();
415
+ onOpenChange?.(nextOpen);
368
416
  },
369
- open: plan !== void 0,
370
- children: [/* @__PURE__ */ jsx(Dialog.Trigger, {
417
+ onOpenChangeComplete,
418
+ open,
419
+ children: [trigger === null ? null : /* @__PURE__ */ jsx(AlertDialog.Trigger, {
371
420
  "data-domainkit-part": "cleanup-trigger",
372
- disabled: state._tag === "Planning" || state._tag === "Cleaning",
421
+ disabled: state._tag !== "Idle",
373
422
  onClick: () => controller.plan(),
374
- children: state._tag === "Planning" ? messages.planningCleanup : messages.reviewCleanup
375
- }), plan === void 0 ? null : /* @__PURE__ */ jsxs(Dialog.Portal, {
376
- container: portalContainer ?? void 0,
377
- children: [/* @__PURE__ */ jsx(Dialog.Backdrop, { "data-domainkit-part": "dialog-backdrop" }), /* @__PURE__ */ jsxs(Dialog.Popup, {
423
+ ...trigger === void 0 ? {} : { render: trigger },
424
+ children: messages.reviewCleanup
425
+ }), /* @__PURE__ */ jsxs(AlertDialog.Portal, {
426
+ container: portalContainer,
427
+ children: [/* @__PURE__ */ jsx(AlertDialog.Backdrop, {
428
+ "data-color-scheme": colorScheme,
429
+ "data-domainkit-part": "dialog-backdrop",
430
+ "data-domainkit-root": "",
431
+ style: themeStyle
432
+ }), /* @__PURE__ */ jsxs(AlertDialog.Popup, {
378
433
  "data-color-scheme": colorScheme,
379
434
  "data-domainkit-part": "cleanup-dialog",
380
435
  "data-domainkit-root": "",
@@ -384,138 +439,108 @@ function Dialog$3({ controller }) {
384
439
  "data-domainkit-part": "dialog-header",
385
440
  children: [/* @__PURE__ */ jsxs("div", {
386
441
  "data-domainkit-part": "dialog-heading",
387
- children: [/* @__PURE__ */ jsx(Dialog.Title, {
442
+ children: [/* @__PURE__ */ jsx(AlertDialog.Title, {
388
443
  "data-domainkit-part": "dialog-title",
389
444
  children: messages.reviewCleanup
390
- }), /* @__PURE__ */ jsx(Dialog.Description, {
445
+ }), /* @__PURE__ */ jsx(AlertDialog.Description, {
391
446
  "data-domainkit-part": "dialog-description",
392
447
  children: messages.cleanupConsent
393
448
  })]
394
- }), /* @__PURE__ */ jsx(Dialog.Close, {
449
+ }), busy ? null : /* @__PURE__ */ jsx(AlertDialog.Close, {
395
450
  "aria-label": messages.close,
396
451
  "data-domainkit-part": "dialog-close",
397
452
  children: "×"
398
453
  })]
399
454
  }),
400
- /* @__PURE__ */ jsx("div", {
455
+ /* @__PURE__ */ jsxs("div", {
401
456
  "data-domainkit-part": "dialog-body",
402
- children: /* @__PURE__ */ jsx(List, {
457
+ children: [plan === void 0 ? /* @__PURE__ */ jsx("p", {
458
+ "data-domainkit-part": "dialog-progress",
459
+ role: "status",
460
+ children: messages.planningCleanup
461
+ }) : /* @__PURE__ */ jsx(List, {
403
462
  lifecycle: "cleanup",
404
463
  operations: plan.operations
405
- })
464
+ }), /* @__PURE__ */ jsx(Outcome$2, { state })]
406
465
  }),
407
- /* @__PURE__ */ jsxs("div", {
466
+ /* @__PURE__ */ jsx("div", {
408
467
  "data-domainkit-part": "dialog-footer",
409
- children: [/* @__PURE__ */ jsx(Dialog.Close, {
468
+ children: busy ? /* @__PURE__ */ jsx("button", {
469
+ "data-domainkit-part": "cleanup-apply",
470
+ disabled: true,
471
+ type: "button",
472
+ children: state._tag === "Cleaning" ? messages.cleaningDns : messages.planningCleanup
473
+ }) : state._tag === "Review" && plan !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AlertDialog.Close, {
410
474
  "data-domainkit-part": "dialog-cancel",
411
475
  children: messages.cancel
412
476
  }), /* @__PURE__ */ jsx("button", {
413
477
  "data-domainkit-part": "cleanup-apply",
414
- disabled: state._tag === "Cleaning" || plan.operations.some((operation) => operation._tag === "Blocked"),
478
+ disabled: plan.operations.some((operation) => operation._tag === "Blocked"),
415
479
  onClick: () => controller.apply(),
416
480
  type: "button",
417
- children: state._tag === "Cleaning" ? messages.cleaningDns : messages.applyCleanup
418
- })]
481
+ children: messages.applyCleanup
482
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AlertDialog.Close, {
483
+ "data-domainkit-part": "dialog-cancel",
484
+ children: messages.close
485
+ }), /* @__PURE__ */ jsx("button", {
486
+ "data-domainkit-part": "cleanup-retry",
487
+ onClick: () => controller.retry(),
488
+ type: "button",
489
+ children: messages.retry
490
+ })] })
419
491
  })
420
492
  ]
421
493
  })]
422
494
  })]
423
495
  });
424
496
  }
425
- function Flow$3({ connection, receiptId, ...props }) {
426
- const controller = useController$3(connection, receiptId);
497
+ function Flow$3({ connection, onCleaned, receiptId, trigger, ...props }) {
498
+ const controller = useController$3(connection, receiptId, onCleaned);
427
499
  const state = controller.state;
428
- return /* @__PURE__ */ jsxs(Root$4, {
500
+ return /* @__PURE__ */ jsx(Root$4, {
429
501
  status: state._tag,
430
502
  ...props,
431
- children: [/* @__PURE__ */ jsx(Outcome$2, { state }), /* @__PURE__ */ jsx(Dialog$3, { controller })]
503
+ children: /* @__PURE__ */ jsx(Dialog$3, {
504
+ controller,
505
+ ...trigger === void 0 ? {} : { trigger }
506
+ })
432
507
  });
433
508
  }
434
509
  //#endregion
435
510
  //#region src/provider.tsx
436
511
  var provider_exports = /* @__PURE__ */ __exportAll({ Mark: () => Mark });
437
- const logoHosts = {
438
- aws: "amazonaws.com",
439
- bluehost: "bluehost.com",
440
- cloudflare: "cloudflare.com",
441
- digitalocean: "digitalocean.com",
442
- dnsimple: "dnsimple.com",
443
- dreamhost: "dreamhost.com",
444
- dynadot: "dynadot.com",
445
- gandi: "gandi.net",
446
- godaddy: "godaddy.com",
447
- google: "cloud.google.com",
448
- googlecloud: "cloud.google.com",
449
- googleclouddns: "cloud.google.com",
450
- hostgator: "hostgator.com",
451
- hostinger: "hostinger.com",
452
- hover: "hover.com",
453
- ionos: "ionos.com",
454
- namecheap: "namecheap.com",
455
- namecom: "name.com",
456
- netlify: "netlify.com",
457
- ns1: "ns1.com",
458
- ovh: "ovh.com",
459
- porkbun: "porkbun.com",
460
- spaceship: "spaceship.com",
461
- squarespace: "squarespace.com",
462
- vercel: "vercel.com"
463
- };
464
512
  const logoKey = (providerId) => providerId.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
465
- const logoHost = (providerId) => logoHosts[logoKey(providerId)];
466
513
  const letterMark = (provider) => provider.name.trim().charAt(0).toUpperCase() || "?";
467
- /** Official AWS architecture glyph (white "53" in nested circles). */
468
- const route53Glyph = "M48.692,40.6795109 C49.431,41.3627732 49.801,42.2781246 49.801,43.4275659 C49.801,44.678046 49.351,45.6764293 48.452,46.4227159 C47.552,47.1700028 46.343,47.543146 44.826,47.543146 C43.627,47.543146 42.44,47.2870477 41.266,46.7768518 L41.266,45.2452638 C42.657,45.7054405 43.843,45.9345284 44.826,45.9345284 C45.796,45.9345284 46.542,45.7174451 47.065,45.2842788 C47.588,44.8501121 47.849,44.2308744 47.849,43.4275659 C47.849,41.8829729 46.874,41.1106764 44.921,41.1106764 C44.309,41.1106764 43.703,41.1426887 43.103,41.2057129 L43.103,39.9432282 L47.123,35.5585448 L41.458,35.5585448 L41.458,33.9889422 L49.247,33.9889422 L49.247,35.5015229 L45.304,39.6751253 C45.369,39.6621203 45.431,39.656118 45.496,39.656118 L45.687,39.656118 C46.951,39.656118 47.952,39.9972489 48.692,40.6795109 M37.574,40.3453826 C38.351,41.0726618 38.74,42.0740463 38.74,43.349536 C38.74,44.6010165 38.288,45.6124048 37.381,46.3847013 C36.475,47.1569978 35.283,47.543146 33.803,47.543146 C32.503,47.543146 31.284,47.2870477 30.148,46.7768518 L30.148,45.2452638 C31.564,45.7054405 32.776,45.9345284 33.784,45.9345284 C34.754,45.9345284 35.497,45.7154443 36.013,45.2742749 C36.53,44.834106 36.789,44.1998624 36.789,43.3695437 C36.789,42.4631957 36.546,41.8059434 36.061,41.3977867 C35.576,40.9896299 34.785,40.7845512 33.688,40.7845512 C32.897,40.7845512 31.909,40.8495762 30.722,40.976625 L30.722,39.7131399 L31.086,33.9889422 L38.071,33.9889422 L38.071,35.5585448 L32.693,35.5585448 L32.444,39.4450369 C33.146,39.3179882 33.777,39.2539636 34.338,39.2539636 C35.716,39.2539636 36.795,39.617103 37.574,40.3453826 M51.957,54.37777 C47.103,55.250105 42.852,57.2268639 40,58.8374822 C37.147,57.2268639 32.896,55.250105 28.043,54.37777 C26.677,54.1326759 19.869,52.7111302 19.869,48.7756192 C19.869,46.951919 20.522,45.7424547 21.776,43.5826255 C23.274,40.9996338 25.138,37.7843994 25.138,33.1556222 C25.138,29.8473521 24.271,26.6751342 22.559,23.7149977 C22.76,23.4669025 22.965,23.2158061 23.171,22.9627089 C25.707,24.2301955 28.347,24.8724421 31.031,24.8724421 C34.311,24.8724421 37.325,24.0111114 40,22.3114589 C42.674,24.0111114 45.688,24.8724421 48.968,24.8724421 C51.652,24.8724421 54.293,24.2301955 56.829,22.9627089 C57.034,23.2158061 57.239,23.4669025 57.44,23.7149977 C55.728,26.6751342 54.861,29.8473521 54.861,33.1556222 C54.861,37.7843994 56.725,40.9996338 58.226,43.586627 C59.477,45.7424547 60.13,46.951919 60.13,48.7756192 C60.13,52.7111302 53.322,54.1326759 51.957,54.37777 M56.861,33.1556222 C56.861,29.9974097 57.752,26.9702475 59.507,24.1581679 C59.735,23.7950284 59.706,23.3278491 59.434,22.9957216 C58.926,22.3734827 58.393,21.7182311 57.867,21.0669811 C57.562,20.6898363 57.032,20.5857963 56.606,20.8198862 C54.143,22.1814089 51.574,22.8716739 48.968,22.8716739 C45.824,22.8716739 43.077,22.0263494 40.569,20.2886823 C40.227,20.0515912 39.772,20.0515912 39.43,20.2886823 C36.922,22.0263494 34.175,22.8716739 31.031,22.8716739 C28.425,22.8716739 25.856,22.1814089 23.393,20.8198862 C22.968,20.5857963 22.437,20.6898363 22.132,21.0669811 C21.606,21.7182311 21.073,22.3734827 20.565,22.9957216 C20.294,23.3278491 20.264,23.7950284 20.492,24.1581679 C22.248,26.9702475 23.138,29.9974097 23.138,33.1556222 C23.138,37.2461927 21.423,40.2023277 20.045,42.581241 C18.695,44.9041328 17.869,46.4467251 17.869,48.7756192 C17.869,54.1646882 25.385,55.9343677 27.689,56.3475263 C32.549,57.2208616 36.793,59.2806524 39.497,60.8542565 C39.652,60.9452915 39.826,60.9903088 40,60.9903088 C40.173,60.9903088 40.347,60.9452915 40.503,60.8542565 C43.207,59.2806524 47.45,57.2208616 52.31,56.3475263 C54.614,55.9343677 62.13,54.1646882 62.13,48.7756192 C62.13,46.4467251 61.304,44.9041328 59.954,42.5782399 C58.576,40.2023277 56.861,37.2461927 56.861,33.1556222 M52.994,60.1569888 C46.863,61.2594121 41.723,64.556678 40,65.7641416 C38.276,64.556678 33.136,61.2594121 27.005,60.1569888 C14.937,57.9891566 14,50.8974338 14,48.7756192 C14,45.2852792 15.371,42.9233724 16.697,40.6374948 C17.961,38.4596586 19.268,36.2067937 19.268,33.1556222 C19.268,28.3357718 16.485,24.9314648 15.112,23.5459328 C16.556,21.7892584 20.204,17.3415508 22.003,15.0236609 C24.729,17.5966487 27.898,19.0001876 31.031,19.0001876 C34.509,19.0001876 37.385,17.5846441 40,14.5644846 C42.614,17.5846441 45.49,19.0001876 48.968,19.0001876 C52.101,19.0001876 55.27,17.5966487 57.997,15.0236609 C59.796,17.3415508 63.443,21.7892584 64.887,23.5459328 C63.514,24.9314648 60.731,28.3357718 60.731,33.1556222 C60.731,36.2067937 62.039,38.4596586 63.302,40.6374948 C64.629,42.9233724 66,45.2852792 66,48.7756192 C66,50.8974338 65.062,57.9891566 52.994,60.1569888 M65.032,39.6341095 C63.797,37.5052922 62.731,35.6675867 62.731,33.1556222 C62.731,27.867592 66.847,24.4472789 66.887,24.4152666 C67.094,24.2472021 67.226,24.0031083 67.254,23.7370062 C67.28,23.470904 67.2,23.2058022 67.03,22.9997231 C66.963,22.9196924 60.408,14.9726413 58.906,12.9138509 C58.73,12.6727583 58.457,12.5227007 58.159,12.5046938 C57.86,12.4826853 57.572,12.601731 57.368,12.8198148 C54.848,15.5148495 51.866,16.9994194 48.968,16.9994194 C45.764,16.9994194 43.244,15.5718713 40.794,12.3706423 C40.415,11.8764526 39.585,11.8764526 39.206,12.3706423 C36.755,15.5718713 34.235,16.9994194 31.031,16.9994194 C28.133,16.9994194 25.151,15.5148495 22.631,12.8198148 C22.427,12.601731 22.137,12.4776834 21.84,12.5046938 C21.543,12.5227007 21.269,12.6727583 21.093,12.9138509 C19.591,14.9726413 13.036,22.9196924 12.969,22.9997231 C12.8,23.2058022 12.72,23.470904 12.747,23.7360058 C12.773,24.0011076 12.904,24.2452013 13.11,24.4132658 C13.152,24.4472789 17.268,27.867592 17.268,33.1556222 C17.268,35.6675867 16.202,37.5052922 14.967,39.6341095 C13.576,42.0310298 12,44.7470725 12,48.7756192 C12,55.487196 17.477,60.4781121 26.652,62.1267451 C33.559,63.3682217 39.334,67.7489036 39.391,67.7939209 C39.57,67.9309735 39.785,68 40,68 C40.214,68 40.429,67.9309735 40.609,67.7929205 C40.667,67.7489036 46.422,63.3712229 53.347,62.1267451 C62.522,60.4781121 68,55.487196 68,48.7756192 C68,44.7470725 66.423,42.0310298 65.032,39.6341095";
469
- function Route53Mark() {
470
- const gradientId = `dk-r53-${useId().replaceAll(":", "")}`;
514
+ function CloudflareMark() {
471
515
  return /* @__PURE__ */ jsxs("svg", {
472
516
  "aria-hidden": "true",
473
- viewBox: "0 0 80 80",
474
- children: [
475
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", {
476
- id: gradientId,
477
- x1: "0%",
478
- x2: "100%",
479
- y1: "100%",
480
- y2: "0%",
481
- children: [/* @__PURE__ */ jsx("stop", {
482
- offset: "0%",
483
- stopColor: "#4D27A8"
484
- }), /* @__PURE__ */ jsx("stop", {
485
- offset: "100%",
486
- stopColor: "#A166FF"
487
- })]
488
- }) }),
489
- /* @__PURE__ */ jsx("rect", {
490
- fill: `url(#${gradientId})`,
491
- height: "80",
492
- width: "80"
493
- }),
494
- /* @__PURE__ */ jsx("path", {
495
- d: route53Glyph,
496
- fill: "#fff"
497
- })
498
- ]
517
+ viewBox: "0 0 48 32",
518
+ children: [/* @__PURE__ */ jsx("path", {
519
+ d: "M30.2 24.6H7.7a6.2 6.2 0 0 1 .5-12.4 9.7 9.7 0 0 1 18.5-2.8 7.7 7.7 0 0 1 3.5 15.2Z",
520
+ fill: "#f48120"
521
+ }), /* @__PURE__ */ jsx("path", {
522
+ d: "M33.1 16.2h1.3a5.2 5.2 0 0 1 .3 10.4H18.2l1.2-3.4h12.9l.8-7Z",
523
+ fill: "#faad3d"
524
+ })]
525
+ });
526
+ }
527
+ function VercelMark() {
528
+ return /* @__PURE__ */ jsx("svg", {
529
+ "aria-hidden": "true",
530
+ viewBox: "0 0 32 32",
531
+ children: /* @__PURE__ */ jsx("path", {
532
+ d: "m16 5 13 22H3L16 5Z",
533
+ fill: "currentColor"
534
+ })
499
535
  });
500
536
  }
501
- const logoMarks = {
502
- amazonroute53: Route53Mark,
503
- route53: Route53Mark
537
+ const builtInMarks = {
538
+ cloudflare: CloudflareMark,
539
+ vercel: VercelMark
504
540
  };
505
541
  function DefaultMark({ provider }) {
506
- const BuiltIn = logoMarks[logoKey(provider.id)];
507
- const host = logoHost(provider.id);
508
- const [failed, setFailed] = useState(false);
509
- if (BuiltIn !== void 0) return /* @__PURE__ */ jsx(BuiltIn, {});
510
- if (host === void 0 || failed) return letterMark(provider);
511
- return /* @__PURE__ */ jsx("img", {
512
- alt: "",
513
- height: 32,
514
- onError: () => setFailed(true),
515
- referrerPolicy: "no-referrer",
516
- src: `https://integrations.sh/logo/${host}?sz=64`,
517
- width: 32
518
- });
542
+ const BuiltIn = builtInMarks[logoKey(provider.id)];
543
+ return BuiltIn === void 0 ? letterMark(provider) : /* @__PURE__ */ jsx(BuiltIn, {});
519
544
  }
520
545
  function Mark({ provider, ...props }) {
521
546
  const { marks } = useDomainKit();
@@ -531,11 +556,13 @@ function Mark({ provider, ...props }) {
531
556
  //#endregion
532
557
  //#region src/connection.tsx
533
558
  var connection_exports = /* @__PURE__ */ __exportAll({
559
+ Card: () => Card$1,
560
+ CardActions: () => CardActions,
561
+ CardIdentity: () => CardIdentity,
534
562
  Command: () => Command$2,
535
563
  ConnectTrigger: () => ConnectTrigger,
536
564
  Dialog: () => Dialog$2,
537
- DisconnectAction: () => DisconnectAction,
538
- DisconnectState: () => DisconnectState,
565
+ DisconnectDialog: () => DisconnectDialog,
539
566
  Flow: () => Flow$2,
540
567
  OAuthAction: () => OAuthAction,
541
568
  RetryAction: () => RetryAction$1,
@@ -546,13 +573,12 @@ var connection_exports = /* @__PURE__ */ __exportAll({
546
573
  TokenAction: () => TokenAction,
547
574
  Trigger: () => Trigger,
548
575
  useController: () => useController$2,
549
- useDisconnect: () => useDisconnect,
550
576
  useModel: () => useModel$2
551
577
  });
552
578
  const State$2 = Data.taggedEnum();
553
579
  const Command$2 = Data.taggedEnum();
554
580
  function useModel$2(domain) {
555
- const { navigate, runtime } = useDomainKit();
581
+ const { emit, navigate, runtime } = useDomainKit();
556
582
  return useMemo(() => {
557
583
  const actionState = Atom.make(void 0);
558
584
  const inspect = runtime.atom(Effect.flatMap(Transport.Service, (transport) => transport.connection.inspect({ domain })));
@@ -575,31 +601,61 @@ function useModel$2(domain) {
575
601
  return Effect.void;
576
602
  }
577
603
  const snapshot = get(state);
604
+ if (input._tag === "Disconnect") {
605
+ if (snapshot._tag !== "Connected") return Effect.void;
606
+ get.set(actionState, State$2.Disconnecting({ snapshot }));
607
+ return Effect.flatMap(Transport.Service, (transport) => transport.connection.removeDomain({
608
+ connectionId: snapshot.connectionId,
609
+ domain: snapshot.domain,
610
+ preserveDns: true
611
+ })).pipe(Effect.tap((result) => Effect.sync(() => {
612
+ get.set(actionState, {
613
+ _tag: "Disconnected",
614
+ domain: snapshot.domain,
615
+ provider: snapshot.provider,
616
+ ...result.remainingDomainCount > 0 ? { reusableConnection: {
617
+ connectionId: result.connectionId,
618
+ label: snapshot.provider.name
619
+ } } : {}
620
+ });
621
+ emit(Event.DomainDisconnected({
622
+ connection: snapshot,
623
+ result
624
+ }));
625
+ })), Effect.catch((error) => Effect.sync(() => get.set(actionState, failureFromError(error)))), Effect.asVoid);
626
+ }
578
627
  if (snapshot._tag !== "Disconnected") return Effect.void;
579
628
  const reusableConnection = snapshot.reusableConnection;
580
629
  if (input._tag === "Reuse" && reusableConnection === void 0) return Effect.void;
581
630
  get.set(actionState, State$2.Submitting({ snapshot }));
582
- const complete = (request) => request.pipe(Effect.tap((result) => Effect.sync(() => {
631
+ const complete = (request, source) => request.pipe(Effect.tap((result) => Effect.sync(() => {
583
632
  if (result._tag === "Redirect") {
584
633
  get.set(actionState, State$2.Redirecting({ snapshot }));
585
634
  navigate(result.authorizationUrl);
586
- } else get.set(actionState, result);
635
+ } else {
636
+ get.set(actionState, result);
637
+ emit(Event.ConnectionEstablished({
638
+ connection: result,
639
+ source
640
+ }));
641
+ }
587
642
  })), Effect.catch((error) => Effect.sync(() => get.set(actionState, failureFromError(error)))), Effect.asVoid);
588
643
  if (input._tag === "Connect") return complete(Effect.flatMap(Transport.Service, (transport) => transport.connection.connect({
589
644
  domain,
590
645
  method: input.method,
591
646
  providerId: snapshot.provider.id
592
- })));
647
+ })), "connect");
593
648
  if (reusableConnection === void 0) return Effect.void;
594
649
  return complete(Effect.flatMap(Transport.Service, (transport) => transport.connection.reuse({
595
650
  connectionId: reusableConnection.connectionId,
596
651
  domain
597
- })));
652
+ })), "reuse");
598
653
  }),
599
654
  state
600
655
  };
601
656
  }, [
602
657
  domain,
658
+ emit,
603
659
  navigate,
604
660
  runtime
605
661
  ]);
@@ -610,6 +666,7 @@ function useController$2(domain) {
610
666
  const execute = useAtomSet(model.command);
611
667
  return {
612
668
  connect: (method) => execute(Command$2.Connect({ method })),
669
+ disconnect: () => execute(Command$2.Disconnect()),
613
670
  retry: () => execute(Command$2.Retry()),
614
671
  reuse: () => execute(Command$2.Reuse()),
615
672
  state
@@ -623,7 +680,7 @@ function Root$3({ children, status = "Loading", ...props }) {
623
680
  }
624
681
  function Status$2({ children, state, ...props }) {
625
682
  const { messages } = useDomainKit();
626
- const text = state._tag === "Loading" ? messages.detectingProvider : state._tag === "Connected" ? messages.connected(state.provider.name) : state._tag === "Unsupported" ? messages.automaticUnavailable : state._tag === "Failure" ? state.message : state._tag === "Redirecting" ? messages.openingAuthorization : state._tag === "Submitting" ? messages.connecting : messages.providerAvailable(state.provider.name);
683
+ const text = state._tag === "Loading" ? messages.detectingProvider : state._tag === "Connected" ? messages.connected(state.provider.name) : state._tag === "Disconnecting" ? messages.disconnecting : state._tag === "Unsupported" ? messages.automaticUnavailable : state._tag === "Failure" ? state.message : state._tag === "Redirecting" ? messages.openingAuthorization : state._tag === "Submitting" ? messages.connecting : messages.providerAvailable(state.provider.name);
627
684
  return usePart("div", props, { status: state._tag }, {
628
685
  children: children ?? text,
629
686
  "data-domainkit-part": "connection-status",
@@ -652,6 +709,7 @@ function OAuthAction({ controller, label, ...props }) {
652
709
  return usePart("button", props, { authentication: "oauth" }, {
653
710
  children: label,
654
711
  "data-domainkit-part": "oauth-connect",
712
+ disabled: controller.state._tag === "Submitting" || controller.state._tag === "Redirecting",
655
713
  onClick: () => controller.connect(Transport.Method.OAuth()),
656
714
  type: "button"
657
715
  });
@@ -660,12 +718,14 @@ function ReuseAction({ controller, label, ...props }) {
660
718
  return usePart("button", props, { authentication: "reuse" }, {
661
719
  children: label,
662
720
  "data-domainkit-part": "reuse-connection",
721
+ disabled: controller.state._tag === "Submitting" || controller.state._tag === "Redirecting",
663
722
  onClick: () => void controller.reuse(),
664
723
  type: "button"
665
724
  });
666
725
  }
667
726
  function TokenAction({ controller, method, ...props }) {
668
727
  const { messages } = useDomainKit();
728
+ const pending = controller.state._tag === "Submitting" || controller.state._tag === "Redirecting";
669
729
  const [token, setToken] = useState("");
670
730
  const [parameters, setParameters] = useState({});
671
731
  const submit = (event) => {
@@ -685,6 +745,7 @@ function TokenAction({ controller, method, ...props }) {
685
745
  parameter.label,
686
746
  /* @__PURE__ */ jsx("input", {
687
747
  name: parameter.key,
748
+ disabled: pending,
688
749
  onChange: (event) => {
689
750
  const value = event.currentTarget.value;
690
751
  setParameters((current) => ({
@@ -701,6 +762,7 @@ function TokenAction({ controller, method, ...props }) {
701
762
  ] }, parameter.key)),
702
763
  /* @__PURE__ */ jsxs("label", { children: [messages.tokenLabel, /* @__PURE__ */ jsx("input", {
703
764
  autoComplete: "off",
765
+ disabled: pending,
704
766
  name: "token",
705
767
  onChange: (event) => setToken(event.currentTarget.value),
706
768
  placeholder: method.placeholder,
@@ -708,7 +770,7 @@ function TokenAction({ controller, method, ...props }) {
708
770
  value: token
709
771
  })] }),
710
772
  /* @__PURE__ */ jsx("button", {
711
- disabled: token.length === 0 || missingRequiredParameter === true,
773
+ disabled: pending || token.length === 0 || missingRequiredParameter === true,
712
774
  type: "submit",
713
775
  children: method.label
714
776
  })
@@ -719,9 +781,18 @@ function TokenAction({ controller, method, ...props }) {
719
781
  }
720
782
  function Dialog$2({ controller, snapshot }) {
721
783
  const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
784
+ const pending = controller.state._tag === "Submitting" || controller.state._tag === "Redirecting";
785
+ const oauthMethods = snapshot.provider.authentication.filter((method) => method._tag === "OAuth");
786
+ const tokenMethods = snapshot.provider.authentication.filter((method) => method._tag === "Token");
787
+ const hasProviderAccountPath = oauthMethods.length > 0 || snapshot.reusableConnection !== void 0;
722
788
  return /* @__PURE__ */ jsxs(Dialog.Portal, {
723
789
  container: portalContainer,
724
- children: [/* @__PURE__ */ jsx(Dialog.Backdrop, { "data-domainkit-part": "dialog-backdrop" }), /* @__PURE__ */ jsxs(Dialog.Popup, {
790
+ children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {
791
+ "data-color-scheme": colorScheme,
792
+ "data-domainkit-part": "dialog-backdrop",
793
+ "data-domainkit-root": "",
794
+ style: themeStyle
795
+ }), /* @__PURE__ */ jsxs(Dialog.Popup, {
725
796
  "data-domainkit-part": "connection-dialog",
726
797
  "data-domainkit-root": "",
727
798
  "data-color-scheme": colorScheme,
@@ -741,7 +812,7 @@ function Dialog$2({ controller, snapshot }) {
741
812
  children: messages.dialogDescription(snapshot.domain)
742
813
  })]
743
814
  }),
744
- /* @__PURE__ */ jsx(Dialog.Close, {
815
+ pending ? null : /* @__PURE__ */ jsx(Dialog.Close, {
745
816
  "aria-label": messages.close,
746
817
  "data-domainkit-part": "dialog-close",
747
818
  children: "×"
@@ -751,21 +822,32 @@ function Dialog$2({ controller, snapshot }) {
751
822
  /* @__PURE__ */ jsxs("div", {
752
823
  "data-domainkit-part": "dialog-body",
753
824
  children: [
754
- snapshot.provider.authentication.map((method) => method._tag === "OAuth" ? /* @__PURE__ */ jsx(OAuthAction, {
755
- controller,
756
- label: method.label
757
- }, method._tag) : null),
758
- snapshot.reusableConnection === void 0 ? null : /* @__PURE__ */ jsx(ReuseAction, {
759
- controller,
760
- label: messages.reuseConnection(snapshot.reusableConnection.label)
761
- }),
762
- snapshot.provider.authentication.map((method) => method._tag === "Token" ? /* @__PURE__ */ jsx(TokenAction, {
825
+ hasProviderAccountPath ? /* @__PURE__ */ jsxs("div", {
826
+ "data-domainkit-part": "provider-authentication",
827
+ children: [oauthMethods.map((method) => /* @__PURE__ */ jsx(OAuthAction, {
828
+ controller,
829
+ label: method.label
830
+ }, method._tag)), snapshot.reusableConnection === void 0 ? null : /* @__PURE__ */ jsx(ReuseAction, {
831
+ controller,
832
+ label: messages.reuseConnection(snapshot.reusableConnection.label)
833
+ })]
834
+ }) : null,
835
+ hasProviderAccountPath && tokenMethods.length > 0 ? /* @__PURE__ */ jsx("div", {
836
+ "aria-label": messages.authenticationAlternative,
837
+ "data-domainkit-part": "authentication-separator",
838
+ role: "separator",
839
+ children: /* @__PURE__ */ jsx("span", {
840
+ "aria-hidden": "true",
841
+ children: messages.authenticationAlternative
842
+ })
843
+ }) : null,
844
+ tokenMethods.map((method) => /* @__PURE__ */ jsx(TokenAction, {
763
845
  controller,
764
846
  method
765
- }, method._tag) : null)
847
+ }, method._tag))
766
848
  ]
767
849
  }),
768
- /* @__PURE__ */ jsx("div", {
850
+ pending ? null : /* @__PURE__ */ jsx("div", {
769
851
  "data-domainkit-part": "dialog-footer",
770
852
  children: /* @__PURE__ */ jsx(Dialog.Close, {
771
853
  "data-domainkit-part": "dialog-cancel",
@@ -789,10 +871,15 @@ function Flow$2({ domain, ...props }) {
789
871
  controller,
790
872
  kind: state.retry === "after-user-action" ? "after-user-action" : "retry"
791
873
  }) : null,
792
- snapshot === void 0 ? null : /* @__PURE__ */ jsxs(Dialog.Root, { children: [/* @__PURE__ */ jsx(ConnectTrigger, { provider: snapshot.provider }), /* @__PURE__ */ jsx(Dialog$2, {
793
- controller,
794
- snapshot
795
- })] })
874
+ snapshot === void 0 ? null : /* @__PURE__ */ jsxs(Dialog.Root, {
875
+ onOpenChange: (open, eventDetails) => {
876
+ if (!open && (state._tag === "Submitting" || state._tag === "Redirecting")) eventDetails.cancel();
877
+ },
878
+ children: [/* @__PURE__ */ jsx(ConnectTrigger, { provider: snapshot.provider }), /* @__PURE__ */ jsx(Dialog$2, {
879
+ controller,
880
+ snapshot
881
+ })]
882
+ })
796
883
  ]
797
884
  });
798
885
  }
@@ -805,60 +892,89 @@ function RetryAction$1({ controller, kind = "retry", ...props }) {
805
892
  type: "button"
806
893
  });
807
894
  }
808
- const DisconnectState = Data.taggedEnum();
809
- function useDisconnect(connection) {
810
- const { runtime } = useDomainKit();
811
- const controller = useMemo(() => {
812
- const state = Atom.make(DisconnectState.Idle());
813
- return {
814
- disconnect: runtime.fn()((_, get) => {
815
- get.set(state, DisconnectState.Disconnecting());
816
- return Effect.flatMap(Transport.Service, (transport) => transport.connection.removeDomain({
817
- connectionId: connection.connectionId,
818
- domain: connection.domain,
819
- preserveDns: true
820
- })).pipe(Effect.tap((result) => Effect.sync(() => get.set(state, result))), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
821
- }),
822
- state
823
- };
824
- }, [
825
- connection.connectionId,
826
- connection.domain,
827
- runtime
828
- ]);
829
- const state = useAtomValue(controller.state);
830
- const disconnect = useAtomSet(controller.disconnect);
831
- return {
832
- disconnect: () => disconnect(),
833
- state
834
- };
895
+ function Card$1({ status, ...props }) {
896
+ return usePart("div", props, { status }, {
897
+ "data-domainkit-part": "connected-card",
898
+ "data-state": status
899
+ });
835
900
  }
836
- function DisconnectAction({ connection, ...props }) {
837
- const controller = useDisconnect(connection);
838
- const { messages } = useDomainKit();
839
- const state = controller.state;
840
- return usePart("div", props, { status: state._tag }, {
841
- children: /* @__PURE__ */ jsxs(Fragment, { children: [
842
- state._tag === "Removed" ? /* @__PURE__ */ jsx("p", {
843
- "data-domainkit-part": "flow-outcome",
844
- "data-tone": "success",
845
- children: messages.domainDisconnected
846
- }) : null,
847
- state._tag === "Failure" ? /* @__PURE__ */ jsx("p", {
848
- "data-domainkit-part": "flow-outcome",
849
- "data-tone": "danger",
850
- role: "alert",
851
- children: state.message
852
- }) : null,
853
- state._tag === "Removed" ? null : /* @__PURE__ */ jsx("button", {
854
- "data-domainkit-part": "disconnect-action",
855
- disabled: state._tag === "Disconnecting",
856
- onClick: () => void controller.disconnect(),
857
- type: "button",
858
- children: state._tag === "Disconnecting" ? messages.disconnecting : messages.disconnectDomain
859
- })
860
- ] }),
861
- "data-domainkit-part": "disconnect"
901
+ function CardIdentity({ status, ...props }) {
902
+ return usePart("div", props, { status }, {
903
+ "data-domainkit-part": "connected-identity",
904
+ "data-state": status
905
+ });
906
+ }
907
+ function CardActions({ status, ...props }) {
908
+ return usePart("div", props, { status }, {
909
+ "data-domainkit-part": "connected-actions",
910
+ "data-state": status
911
+ });
912
+ }
913
+ function DisconnectDialog({ connection, controller, onOpenChange, open: openProp, trigger }) {
914
+ const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
915
+ const [internalOpen, setInternalOpen] = useState(false);
916
+ const open = openProp ?? internalOpen;
917
+ const setOpen = (nextOpen) => {
918
+ if (openProp === void 0) setInternalOpen(nextOpen);
919
+ onOpenChange?.(nextOpen);
920
+ };
921
+ const disconnecting = controller.state._tag === "Disconnecting";
922
+ return /* @__PURE__ */ jsxs(AlertDialog.Root, {
923
+ onOpenChange: (nextOpen, eventDetails) => {
924
+ if (!nextOpen && disconnecting) {
925
+ eventDetails.cancel();
926
+ return;
927
+ }
928
+ setOpen(nextOpen);
929
+ },
930
+ open,
931
+ children: [trigger === null ? null : /* @__PURE__ */ jsx(AlertDialog.Trigger, {
932
+ "data-domainkit-part": "disconnect-trigger",
933
+ ...trigger === void 0 ? {} : { render: trigger },
934
+ children: messages.disconnectDomain
935
+ }), /* @__PURE__ */ jsxs(AlertDialog.Portal, {
936
+ container: portalContainer,
937
+ children: [/* @__PURE__ */ jsx(AlertDialog.Backdrop, {
938
+ "data-color-scheme": colorScheme,
939
+ "data-domainkit-part": "dialog-backdrop",
940
+ "data-domainkit-root": "",
941
+ style: themeStyle
942
+ }), /* @__PURE__ */ jsxs(AlertDialog.Popup, {
943
+ "data-color-scheme": colorScheme,
944
+ "data-domainkit-part": "disconnect-dialog",
945
+ "data-domainkit-root": "",
946
+ style: themeStyle,
947
+ children: [/* @__PURE__ */ jsxs("div", {
948
+ "data-domainkit-part": "dialog-header",
949
+ children: [/* @__PURE__ */ jsxs("div", {
950
+ "data-domainkit-part": "dialog-heading",
951
+ children: [/* @__PURE__ */ jsx(AlertDialog.Title, {
952
+ "data-domainkit-part": "dialog-title",
953
+ children: messages.disconnectTitle(connection.provider.name)
954
+ }), /* @__PURE__ */ jsx(AlertDialog.Description, {
955
+ "data-domainkit-part": "dialog-description",
956
+ children: messages.disconnectConsent
957
+ })]
958
+ }), disconnecting ? null : /* @__PURE__ */ jsx(AlertDialog.Close, {
959
+ "aria-label": messages.close,
960
+ "data-domainkit-part": "dialog-close",
961
+ children: "×"
962
+ })]
963
+ }), /* @__PURE__ */ jsxs("div", {
964
+ "data-domainkit-part": "dialog-footer",
965
+ children: [disconnecting ? null : /* @__PURE__ */ jsx(AlertDialog.Close, {
966
+ "data-domainkit-part": "dialog-cancel",
967
+ children: messages.cancel
968
+ }), /* @__PURE__ */ jsx("button", {
969
+ "data-domainkit-part": "disconnect-action",
970
+ disabled: disconnecting,
971
+ onClick: () => controller.disconnect(),
972
+ type: "button",
973
+ children: disconnecting ? messages.disconnecting : messages.disconnectDomain
974
+ })]
975
+ })]
976
+ })]
977
+ })]
862
978
  });
863
979
  }
864
980
  //#endregion
@@ -1128,7 +1244,7 @@ var provisioning_exports = /* @__PURE__ */ __exportAll({
1128
1244
  const State$1 = Data.taggedEnum();
1129
1245
  const Command$1 = Data.taggedEnum();
1130
1246
  function useModel$1(connection, records, onApplied) {
1131
- const { runtime } = useDomainKit();
1247
+ const { emit, runtime } = useDomainKit();
1132
1248
  const recordKey = recordsIdentity(records);
1133
1249
  const onAppliedRef = useRef(onApplied);
1134
1250
  onAppliedRef.current = onApplied;
@@ -1136,11 +1252,14 @@ function useModel$1(connection, records, onApplied) {
1136
1252
  const state = Atom.make(State$1.Idle());
1137
1253
  return {
1138
1254
  command: runtime.fn()((command, get) => {
1255
+ const current = get(state);
1139
1256
  if (command._tag === "Dismiss") {
1257
+ if (current._tag === "Planning" || current._tag === "Applying") return Effect.void;
1140
1258
  get.set(state, State$1.Idle());
1141
1259
  return Effect.void;
1142
1260
  }
1143
1261
  if (command._tag === "Plan") {
1262
+ if (current._tag === "Planning" || current._tag === "Applying") return Effect.void;
1144
1263
  get.set(state, State$1.Planning());
1145
1264
  return Effect.flatMap(Transport.Service, (transport) => transport.provisioning.plan({
1146
1265
  connectionId: connection.connectionId,
@@ -1148,7 +1267,6 @@ function useModel$1(connection, records, onApplied) {
1148
1267
  records
1149
1268
  })).pipe(Effect.tap((plan) => Effect.sync(() => get.set(state, State$1.Review({ plan })))), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
1150
1269
  }
1151
- const current = get(state);
1152
1270
  if (current._tag !== "Review" || current.plan.operations.some((operation) => operation._tag === "Conflict")) return Effect.void;
1153
1271
  const plan = current.plan;
1154
1272
  get.set(state, State$1.Applying({ plan }));
@@ -1159,9 +1277,17 @@ function useModel$1(connection, records, onApplied) {
1159
1277
  })).pipe(Effect.tap((result) => Effect.sync(() => {
1160
1278
  if (result._tag === "Applied") {
1161
1279
  get.set(state, State$1.Complete({ result }));
1280
+ emit(Event.RecordsApplied({
1281
+ connection,
1282
+ result
1283
+ }));
1162
1284
  onAppliedRef.current?.(result);
1163
1285
  } else if (result._tag === "Partial") {
1164
1286
  get.set(state, State$1.Partial({ result }));
1287
+ emit(Event.RecordsPartiallyApplied({
1288
+ connection,
1289
+ result
1290
+ }));
1165
1291
  onAppliedRef.current?.(result);
1166
1292
  } else get.set(state, result);
1167
1293
  })), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
@@ -1171,6 +1297,7 @@ function useModel$1(connection, records, onApplied) {
1171
1297
  }, [
1172
1298
  connection.connectionId,
1173
1299
  connection.domain,
1300
+ emit,
1174
1301
  recordKey,
1175
1302
  runtime
1176
1303
  ]);
@@ -1195,11 +1322,6 @@ function Root$1({ status, ...props }) {
1195
1322
  }
1196
1323
  function Outcome$1({ state }) {
1197
1324
  const { messages } = useDomainKit();
1198
- if (state._tag === "Complete") return /* @__PURE__ */ jsx("p", {
1199
- "data-domainkit-part": "flow-outcome",
1200
- "data-tone": "success",
1201
- children: messages.recordsApplied
1202
- });
1203
1325
  if (state._tag === "Partial" || state._tag === "Failure" || state._tag === "Stale") return /* @__PURE__ */ jsx("p", {
1204
1326
  "data-domainkit-part": "flow-outcome",
1205
1327
  "data-tone": "danger",
@@ -1208,23 +1330,38 @@ function Outcome$1({ state }) {
1208
1330
  });
1209
1331
  return null;
1210
1332
  }
1211
- function Dialog$1({ controller }) {
1333
+ function Dialog$1({ controller, trigger }) {
1212
1334
  const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
1213
1335
  const state = controller.state;
1214
- const plan = state._tag === "Review" || state._tag === "Applying" ? state.plan : void 0;
1336
+ const planRef = useRef(void 0);
1337
+ if (state._tag === "Idle") planRef.current = void 0;
1338
+ if (state._tag === "Review" || state._tag === "Applying") planRef.current = state.plan;
1339
+ const plan = planRef.current;
1340
+ const busy = state._tag === "Planning" || state._tag === "Applying";
1341
+ const open = state._tag !== "Idle" && state._tag !== "Complete";
1215
1342
  return /* @__PURE__ */ jsxs(Dialog.Root, {
1216
- onOpenChange: (open) => {
1217
- if (!open) controller.dismiss();
1343
+ onOpenChange: (nextOpen, eventDetails) => {
1344
+ if (!nextOpen && busy) {
1345
+ eventDetails.cancel();
1346
+ return;
1347
+ }
1348
+ if (!nextOpen) controller.dismiss();
1218
1349
  },
1219
- open: plan !== void 0,
1350
+ open,
1220
1351
  children: [/* @__PURE__ */ jsx(Dialog.Trigger, {
1221
1352
  "data-domainkit-part": "plan-trigger",
1222
- disabled: state._tag === "Planning" || state._tag === "Applying",
1353
+ disabled: state._tag !== "Idle",
1223
1354
  onClick: () => controller.plan(),
1224
- children: state._tag === "Planning" ? messages.planningDns : messages.reviewDns
1225
- }), plan === void 0 ? null : /* @__PURE__ */ jsxs(Dialog.Portal, {
1226
- container: portalContainer ?? void 0,
1227
- children: [/* @__PURE__ */ jsx(Dialog.Backdrop, { "data-domainkit-part": "dialog-backdrop" }), /* @__PURE__ */ jsxs(Dialog.Popup, {
1355
+ ...trigger === void 0 ? {} : { render: trigger },
1356
+ children: messages.reviewDns
1357
+ }), /* @__PURE__ */ jsxs(Dialog.Portal, {
1358
+ container: portalContainer,
1359
+ children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {
1360
+ "data-color-scheme": colorScheme,
1361
+ "data-domainkit-part": "dialog-backdrop",
1362
+ "data-domainkit-root": "",
1363
+ style: themeStyle
1364
+ }), /* @__PURE__ */ jsxs(Dialog.Popup, {
1228
1365
  "data-color-scheme": colorScheme,
1229
1366
  "data-domainkit-part": "plan-dialog",
1230
1367
  "data-domainkit-root": "",
@@ -1241,31 +1378,48 @@ function Dialog$1({ controller }) {
1241
1378
  "data-domainkit-part": "dialog-description",
1242
1379
  children: messages.planConsent
1243
1380
  })]
1244
- }), /* @__PURE__ */ jsx(Dialog.Close, {
1381
+ }), busy ? null : /* @__PURE__ */ jsx(Dialog.Close, {
1245
1382
  "aria-label": messages.close,
1246
1383
  "data-domainkit-part": "dialog-close",
1247
1384
  children: "×"
1248
1385
  })]
1249
1386
  }),
1250
- /* @__PURE__ */ jsx("div", {
1387
+ /* @__PURE__ */ jsxs("div", {
1251
1388
  "data-domainkit-part": "dialog-body",
1252
- children: /* @__PURE__ */ jsx(List, {
1389
+ children: [plan === void 0 ? /* @__PURE__ */ jsx("p", {
1390
+ "data-domainkit-part": "dialog-progress",
1391
+ role: "status",
1392
+ children: messages.planningDns
1393
+ }) : /* @__PURE__ */ jsx(List, {
1253
1394
  lifecycle: "provisioning",
1254
1395
  operations: plan.operations
1255
- })
1396
+ }), /* @__PURE__ */ jsx(Outcome$1, { state })]
1256
1397
  }),
1257
- /* @__PURE__ */ jsxs("div", {
1398
+ /* @__PURE__ */ jsx("div", {
1258
1399
  "data-domainkit-part": "dialog-footer",
1259
- children: [/* @__PURE__ */ jsx(Dialog.Close, {
1400
+ children: busy ? /* @__PURE__ */ jsx("button", {
1401
+ "data-domainkit-part": "plan-apply",
1402
+ disabled: true,
1403
+ type: "button",
1404
+ children: state._tag === "Applying" ? messages.applyingDns : messages.planningDns
1405
+ }) : state._tag === "Review" && plan !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Dialog.Close, {
1260
1406
  "data-domainkit-part": "dialog-cancel",
1261
1407
  children: messages.cancel
1262
1408
  }), /* @__PURE__ */ jsx("button", {
1263
1409
  "data-domainkit-part": "plan-apply",
1264
- disabled: state._tag === "Applying" || plan.operations.some((operation) => operation._tag === "Conflict"),
1410
+ disabled: plan.operations.some((operation) => operation._tag === "Conflict"),
1265
1411
  onClick: () => controller.apply(),
1266
1412
  type: "button",
1267
- children: state._tag === "Applying" ? messages.applyingDns : messages.applyDns
1268
- })]
1413
+ children: messages.applyDns
1414
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Dialog.Close, {
1415
+ "data-domainkit-part": "dialog-cancel",
1416
+ children: messages.close
1417
+ }), /* @__PURE__ */ jsx("button", {
1418
+ "data-domainkit-part": "provisioning-retry",
1419
+ onClick: () => controller.retry(),
1420
+ type: "button",
1421
+ children: messages.retry
1422
+ })] })
1269
1423
  })
1270
1424
  ]
1271
1425
  })]
@@ -1283,18 +1437,16 @@ function RetryAction({ controller }) {
1283
1437
  children: messages.retry
1284
1438
  });
1285
1439
  }
1286
- function Flow$1({ connection, onApplied, records, showRecords = true, ...props }) {
1440
+ function Flow$1({ connection, onApplied, records, showRecords = true, trigger, ...props }) {
1287
1441
  const controller = useController$1(connection, records, onApplied);
1288
1442
  const state = controller.state;
1289
1443
  return /* @__PURE__ */ jsxs(Root$1, {
1290
1444
  status: state._tag,
1291
1445
  ...props,
1292
- children: [
1293
- showRecords ? /* @__PURE__ */ jsx(Table, { records }) : null,
1294
- /* @__PURE__ */ jsx(Outcome$1, { state }),
1295
- /* @__PURE__ */ jsx(Dialog$1, { controller }),
1296
- /* @__PURE__ */ jsx(RetryAction, { controller })
1297
- ]
1446
+ children: [showRecords ? /* @__PURE__ */ jsx(Table, { records }) : null, /* @__PURE__ */ jsx(Dialog$1, {
1447
+ controller,
1448
+ ...trigger === void 0 ? {} : { trigger }
1449
+ })]
1298
1450
  });
1299
1451
  }
1300
1452
  //#endregion
@@ -1325,7 +1477,10 @@ function useModel(config) {
1325
1477
  get.set(state, State.Idle());
1326
1478
  return Effect.void;
1327
1479
  }
1328
- get.set(state, State.Observing());
1480
+ const current = get(state);
1481
+ if (current._tag === "Observing") return Effect.void;
1482
+ const previous = current._tag === "Observation" ? current : current._tag === "Failed" ? current.previous : void 0;
1483
+ get.set(state, State.Observing({ ...previous === void 0 ? {} : { previous } }));
1329
1484
  return Effect.flatMap(Transport.Service, (transport) => transport.verification.observe({
1330
1485
  ...config.connection === void 0 ? {} : { connectionId: config.connection.connectionId },
1331
1486
  domain: config.domain,
@@ -1334,7 +1489,10 @@ function useModel(config) {
1334
1489
  provider,
1335
1490
  publicDns
1336
1491
  }
1337
- })).pipe(Effect.tap((observation) => Effect.sync(() => get.set(state, observation))), Effect.catch((error) => Effect.sync(() => get.set(state, failureFromError(error)))), Effect.asVoid);
1492
+ })).pipe(Effect.tap((observation) => Effect.sync(() => get.set(state, observation))), Effect.catch((error) => Effect.sync(() => get.set(state, State.Failed({
1493
+ failure: failureFromError(error),
1494
+ ...previous === void 0 ? {} : { previous }
1495
+ })))), Effect.asVoid);
1338
1496
  }),
1339
1497
  state
1340
1498
  };
@@ -1386,7 +1544,7 @@ function Evidence({ observation }) {
1386
1544
  "data-domainkit-part": "observation-list",
1387
1545
  children: observationGroups(observation).map((group) => /* @__PURE__ */ jsxs("section", {
1388
1546
  "data-domainkit-part": "observation-group",
1389
- children: [/* @__PURE__ */ jsx("p", {
1547
+ children: [/* @__PURE__ */ jsx("h3", {
1390
1548
  "data-domainkit-part": "observation-source",
1391
1549
  children: group.label
1392
1550
  }), /* @__PURE__ */ jsx("ul", { children: group.evidence.map((evidence, index) => {
@@ -1406,114 +1564,259 @@ function Evidence({ observation }) {
1406
1564
  });
1407
1565
  }
1408
1566
  function Outcome({ state }) {
1409
- if (state._tag !== "Failure") return null;
1567
+ if (state._tag !== "Failed") return null;
1410
1568
  return /* @__PURE__ */ jsx("p", {
1411
1569
  "data-domainkit-part": "flow-outcome",
1412
1570
  "data-tone": "danger",
1413
1571
  role: "alert",
1414
- children: state.message
1572
+ children: state.failure.message
1415
1573
  });
1416
1574
  }
1417
- function ObserveAction({ controller }) {
1575
+ function ObserveAction({ controller, ...props }) {
1418
1576
  const { messages } = useDomainKit();
1419
- return /* @__PURE__ */ jsx("button", {
1577
+ const observing = controller.state._tag === "Observing";
1578
+ return usePart("button", props, { status: controller.state._tag }, {
1579
+ "aria-busy": observing,
1580
+ children: messages.checkDns,
1420
1581
  "data-domainkit-part": "observe-action",
1421
- disabled: controller.state._tag === "Observing",
1582
+ "data-loading": observing ? "" : void 0,
1583
+ disabled: observing,
1422
1584
  onClick: () => controller.observe(),
1423
- type: "button",
1424
- children: controller.state._tag === "Observing" ? messages.checkingDns : messages.checkDns
1585
+ type: "button"
1425
1586
  });
1426
1587
  }
1427
1588
  function Status({ config, ...props }) {
1589
+ const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
1428
1590
  const controller = useController(config);
1429
1591
  const state = controller.state;
1430
- return /* @__PURE__ */ jsxs(Root, {
1592
+ const observation = state._tag === "Observation" ? state : state._tag === "Observing" || state._tag === "Failed" ? state.previous : void 0;
1593
+ return /* @__PURE__ */ jsx(Root, {
1431
1594
  status: state._tag,
1432
1595
  ...props,
1433
- children: [
1434
- state._tag === "Observation" ? /* @__PURE__ */ jsx(Evidence, { observation: state }) : null,
1435
- /* @__PURE__ */ jsx(Outcome, { state }),
1436
- /* @__PURE__ */ jsx(ObserveAction, { controller })
1437
- ]
1596
+ children: /* @__PURE__ */ jsxs(Popover.Root, { children: [/* @__PURE__ */ jsx(Popover.Trigger, { render: /* @__PURE__ */ jsx(ObserveAction, { controller }) }), /* @__PURE__ */ jsx(Popover.Portal, {
1597
+ container: portalContainer,
1598
+ children: /* @__PURE__ */ jsx(Popover.Positioner, {
1599
+ align: "end",
1600
+ "data-domainkit-part": "verification-positioner",
1601
+ sideOffset: 6,
1602
+ children: /* @__PURE__ */ jsxs(Popover.Popup, {
1603
+ "aria-label": messages.checkDns,
1604
+ "aria-busy": state._tag === "Observing",
1605
+ "data-color-scheme": colorScheme,
1606
+ "data-domainkit-part": "verification-popover",
1607
+ "data-domainkit-root": "",
1608
+ style: themeStyle,
1609
+ children: [
1610
+ /* @__PURE__ */ jsx(Popover.Arrow, { "data-domainkit-part": "verification-arrow" }),
1611
+ state._tag === "Observing" ? /* @__PURE__ */ jsx("p", {
1612
+ "data-domainkit-part": "verification-progress",
1613
+ role: "status",
1614
+ children: messages.checkingDns
1615
+ }) : null,
1616
+ observation === void 0 ? null : /* @__PURE__ */ jsx(Evidence, { observation }),
1617
+ /* @__PURE__ */ jsx(Outcome, { state })
1618
+ ]
1619
+ })
1620
+ })
1621
+ })] })
1438
1622
  });
1439
1623
  }
1440
1624
  //#endregion
1441
1625
  //#region src/domain.tsx
1442
1626
  var domain_exports = /* @__PURE__ */ __exportAll({ Flow: () => Flow });
1443
1627
  function Flow({ domain, receiptId, records }) {
1444
- const connection = useController$2(domain);
1445
- const state = connection.state;
1628
+ const controller = useController$2(domain);
1629
+ const state = controller.state;
1630
+ const connected = state._tag === "Connected" ? state : state._tag === "Disconnecting" ? state.snapshot : void 0;
1446
1631
  return /* @__PURE__ */ jsxs(Root$3, {
1447
1632
  status: state._tag,
1448
1633
  children: [
1449
- state._tag === "Connected" ? null : /* @__PURE__ */ jsx(Status$2, { state }),
1450
- state._tag === "Failure" && (state.retry === "safe" || state.retry === "unknown") ? /* @__PURE__ */ jsx(RetryAction$1, { controller: connection }) : null,
1451
- state._tag === "Disconnected" ? /* @__PURE__ */ jsxs(Dialog.Root, { children: [/* @__PURE__ */ jsx(ConnectTrigger, { provider: state.provider }), /* @__PURE__ */ jsx(Dialog$2, {
1452
- controller: connection,
1453
- snapshot: state
1454
- })] }) : null,
1455
- state._tag === "Connected" ? /* @__PURE__ */ jsx("div", {
1456
- "data-domainkit-part": "connected-shell",
1457
- children: /* @__PURE__ */ jsx(ConnectedFlow, {
1458
- connection: state,
1459
- ...receiptId === void 0 ? {} : { initialReceiptId: receiptId },
1460
- records
1461
- })
1462
- }) : null
1634
+ state._tag === "Connected" || state._tag === "Disconnecting" ? /* @__PURE__ */ jsx(ConnectedCard, {
1635
+ connection: state._tag === "Connected" ? state : state.snapshot,
1636
+ controller,
1637
+ ...receiptId === void 0 ? {} : { initialReceiptId: receiptId },
1638
+ records,
1639
+ status: state._tag
1640
+ }) : /* @__PURE__ */ jsx(AvailableCard, {
1641
+ controller,
1642
+ state
1643
+ }),
1644
+ /* @__PURE__ */ jsx(Table, { records }),
1645
+ /* @__PURE__ */ jsx(Status, { config: {
1646
+ ...connected === void 0 ? {} : { connection: connected },
1647
+ domain,
1648
+ records
1649
+ } })
1463
1650
  ]
1464
1651
  });
1465
1652
  }
1466
- function ConnectedFlow({ connection, initialReceiptId, records }) {
1467
- const [appliedReceipt, setAppliedReceipt] = useState();
1468
- const receiptSource = initialReceiptId ?? null;
1469
- const receiptEpoch = useRef({
1470
- source: receiptSource,
1471
- value: 0
1653
+ function AvailableCard({ controller, state }) {
1654
+ const { messages } = useDomainKit();
1655
+ const snapshot = state._tag === "Disconnected" ? state : state._tag === "Submitting" || state._tag === "Redirecting" ? state.snapshot : void 0;
1656
+ return /* @__PURE__ */ jsxs(Card$1, {
1657
+ status: state._tag,
1658
+ children: [/* @__PURE__ */ jsxs(CardIdentity, {
1659
+ status: state._tag,
1660
+ children: [snapshot === void 0 ? null : /* @__PURE__ */ jsx(Mark, { provider: snapshot.provider }), /* @__PURE__ */ jsx(Status$2, { state })]
1661
+ }), /* @__PURE__ */ jsxs(CardActions, {
1662
+ status: state._tag,
1663
+ children: [state._tag === "Failure" && state.retry !== "never" ? /* @__PURE__ */ jsx(RetryAction$1, {
1664
+ controller,
1665
+ kind: state.retry === "after-user-action" ? "after-user-action" : "retry"
1666
+ }) : null, snapshot === void 0 ? null : /* @__PURE__ */ jsxs(Dialog.Root, {
1667
+ onOpenChange: (open, eventDetails) => {
1668
+ if (!open && (state._tag === "Submitting" || state._tag === "Redirecting")) eventDetails.cancel();
1669
+ },
1670
+ children: [/* @__PURE__ */ jsx(ConnectTrigger, {
1671
+ disabled: state._tag === "Submitting" || state._tag === "Redirecting",
1672
+ provider: snapshot.provider,
1673
+ children: messages.connectProvider(snapshot.provider.name)
1674
+ }), /* @__PURE__ */ jsx(Dialog$2, {
1675
+ controller,
1676
+ snapshot
1677
+ })]
1678
+ })]
1679
+ })]
1680
+ });
1681
+ }
1682
+ function ConnectedCard({ connection, controller, initialReceiptId, records, status }) {
1683
+ const [receipt, setReceipt] = useState({
1684
+ host: initialReceiptId,
1685
+ value: initialReceiptId
1472
1686
  });
1473
- const epoch = receiptEpoch.current.source === receiptSource ? receiptEpoch.current.value : receiptEpoch.current.value + 1;
1474
- useEffect(() => {
1475
- if (receiptEpoch.current.source === receiptSource) return;
1476
- receiptEpoch.current = {
1477
- source: receiptSource,
1478
- value: receiptEpoch.current.value + 1
1479
- };
1480
- setAppliedReceipt(void 0);
1481
- }, [receiptSource]);
1482
- const receiptId = appliedReceipt !== void 0 && appliedReceipt.epoch === epoch ? appliedReceipt.receiptId : initialReceiptId;
1483
- const rememberReceipt = (result) => {
1484
- setAppliedReceipt({
1485
- epoch,
1486
- receiptId: result.receiptId
1487
- });
1488
- };
1687
+ if (receipt.host !== initialReceiptId) setReceipt({
1688
+ host: initialReceiptId,
1689
+ value: initialReceiptId
1690
+ });
1691
+ const receiptId = receipt.host === initialReceiptId ? receipt.value : initialReceiptId;
1692
+ const disabled = status === "Disconnecting";
1693
+ const actionsTriggerRef = useRef(null);
1694
+ return /* @__PURE__ */ jsxs(Card$1, {
1695
+ status,
1696
+ children: [/* @__PURE__ */ jsxs(CardIdentity, {
1697
+ status,
1698
+ children: [/* @__PURE__ */ jsx(Mark, { provider: connection.provider }), /* @__PURE__ */ jsx(Status$2, { state: status === "Connected" ? connection : controller.state })]
1699
+ }), /* @__PURE__ */ jsxs(CardActions, {
1700
+ status,
1701
+ children: [/* @__PURE__ */ jsx(Flow$1, {
1702
+ connection,
1703
+ onApplied: (result) => setReceipt({
1704
+ host: initialReceiptId,
1705
+ value: result.receiptId
1706
+ }),
1707
+ records,
1708
+ showRecords: false
1709
+ }), receiptId === void 0 ? /* @__PURE__ */ jsx(ProviderActions, {
1710
+ actionsTriggerRef,
1711
+ connection,
1712
+ controller,
1713
+ disabled
1714
+ }) : /* @__PURE__ */ jsx(ProviderActionsWithCleanup, {
1715
+ actionsTriggerRef,
1716
+ connection,
1717
+ controller,
1718
+ disabled,
1719
+ onCleaned: () => setReceipt({
1720
+ host: initialReceiptId,
1721
+ value: void 0
1722
+ }),
1723
+ receiptId
1724
+ }, receiptId)]
1725
+ })]
1726
+ });
1727
+ }
1728
+ function ProviderActionsWithCleanup({ actionsTriggerRef, connection, controller, disabled, onCleaned, receiptId }) {
1729
+ const [cleaned, setCleaned] = useState(false);
1730
+ const cleanup = useController$3(connection, receiptId, (result) => {
1731
+ if (result._tag === "Cleaned") setCleaned(true);
1732
+ });
1733
+ return /* @__PURE__ */ jsx(ProviderActions, {
1734
+ actionsTriggerRef,
1735
+ cleanup,
1736
+ connection,
1737
+ controller,
1738
+ disabled,
1739
+ onCleanupCloseComplete: () => {
1740
+ if (cleaned) onCleaned();
1741
+ }
1742
+ });
1743
+ }
1744
+ function ProviderActions({ actionsTriggerRef: actionsTriggerRefProp, cleanup, connection, controller, disabled, onCleanupCloseComplete }) {
1745
+ const { colorScheme, messages, portalContainer, themeStyle } = useDomainKit();
1746
+ const fallbackActionsTriggerRef = useRef(null);
1747
+ const actionsTriggerRef = actionsTriggerRefProp ?? fallbackActionsTriggerRef;
1748
+ const [menuOpen, setMenuOpen] = useState(false);
1749
+ const [disconnectOpen, setDisconnectOpen] = useState(false);
1489
1750
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1490
- /* @__PURE__ */ jsxs("div", {
1491
- "data-domainkit-part": "connected-card",
1492
- children: [/* @__PURE__ */ jsxs("div", {
1493
- "data-domainkit-part": "connected-identity",
1494
- children: [/* @__PURE__ */ jsx(Mark, { provider: connection.provider }), /* @__PURE__ */ jsx(Status$2, { state: connection })]
1495
- }), /* @__PURE__ */ jsxs("div", {
1496
- "data-domainkit-part": "connected-actions",
1497
- children: [
1498
- /* @__PURE__ */ jsx(Flow$1, {
1499
- connection,
1500
- onApplied: rememberReceipt,
1501
- records,
1502
- showRecords: false
1503
- }),
1504
- /* @__PURE__ */ jsx(Status, { config: {
1505
- connection,
1506
- domain: connection.domain,
1507
- records
1508
- } }),
1509
- /* @__PURE__ */ jsx(DisconnectAction, { connection })
1510
- ]
1751
+ /* @__PURE__ */ jsxs(Menu.Root, {
1752
+ disabled,
1753
+ modal: false,
1754
+ onOpenChange: setMenuOpen,
1755
+ open: menuOpen,
1756
+ children: [/* @__PURE__ */ jsx(Menu.Trigger, {
1757
+ "aria-label": messages.moreActions,
1758
+ "data-domainkit-part": "actions-trigger",
1759
+ ref: actionsTriggerRef,
1760
+ children: /* @__PURE__ */ jsx("span", {
1761
+ "aria-hidden": "true",
1762
+ children: "⋯"
1763
+ })
1764
+ }), /* @__PURE__ */ jsx(Menu.Portal, {
1765
+ container: portalContainer,
1766
+ keepMounted: true,
1767
+ children: /* @__PURE__ */ jsx(Menu.Positioner, {
1768
+ align: "end",
1769
+ sideOffset: 6,
1770
+ children: /* @__PURE__ */ jsxs(Menu.Popup, {
1771
+ "data-color-scheme": colorScheme,
1772
+ "data-domainkit-part": "actions-menu",
1773
+ "data-domainkit-root": "",
1774
+ style: themeStyle,
1775
+ children: [cleanup === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Menu.Item, {
1776
+ closeOnClick: false,
1777
+ "data-domainkit-part": "actions-item",
1778
+ nativeButton: true,
1779
+ onClickCapture: () => {
1780
+ setMenuOpen(false);
1781
+ queueMicrotask(() => cleanup.plan());
1782
+ },
1783
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
1784
+ children: messages.reviewCleanup
1785
+ }), /* @__PURE__ */ jsx(Menu.Separator, { "data-domainkit-part": "actions-separator" })] }), /* @__PURE__ */ jsx(Menu.Item, {
1786
+ closeOnClick: false,
1787
+ "data-domainkit-part": "actions-item",
1788
+ "data-tone": "danger",
1789
+ nativeButton: true,
1790
+ onClickCapture: () => {
1791
+ setMenuOpen(false);
1792
+ queueMicrotask(() => setDisconnectOpen(true));
1793
+ },
1794
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
1795
+ children: messages.disconnectDomain
1796
+ })]
1797
+ })
1798
+ })
1511
1799
  })]
1512
1800
  }),
1513
- /* @__PURE__ */ jsx(Table, { records }),
1514
- receiptId === void 0 ? null : /* @__PURE__ */ jsx(Flow$3, {
1801
+ cleanup === void 0 ? null : /* @__PURE__ */ jsx(Dialog$3, {
1802
+ controller: cleanup,
1803
+ onOpenChangeComplete: (open) => {
1804
+ if (!open) {
1805
+ onCleanupCloseComplete?.();
1806
+ queueMicrotask(() => actionsTriggerRef.current?.focus());
1807
+ }
1808
+ },
1809
+ trigger: null
1810
+ }),
1811
+ /* @__PURE__ */ jsx(DisconnectDialog, {
1515
1812
  connection,
1516
- receiptId
1813
+ controller,
1814
+ onOpenChange: (open) => {
1815
+ setDisconnectOpen(open);
1816
+ if (!open) queueMicrotask(() => actionsTriggerRef.current?.focus());
1817
+ },
1818
+ open: disconnectOpen,
1819
+ trigger: null
1517
1820
  })
1518
1821
  ] });
1519
1822
  }
@@ -1651,6 +1954,6 @@ function makeFakeTransport(options) {
1651
1954
  return Object.assign(Transport.layerFromAsync(transport), transport, { calls });
1652
1955
  }
1653
1956
  //#endregion
1654
- export { cleanup_exports as Cleanup, connection_exports as Connection, domain_exports as Domain, domain_kit_exports as DomainKit, messages_exports as Messages, operations_exports as Operations, provider_exports as Provider, provisioning_exports as Provisioning, records_exports as Records, testing_exports as Testing, theme_exports as Theme, verification_exports as Verification };
1957
+ export { cleanup_exports as Cleanup, connection_exports as Connection, domain_exports as Domain, domain_kit_exports as DomainKit, lifecycle_exports as Lifecycle, messages_exports as Messages, operations_exports as Operations, provider_exports as Provider, provisioning_exports as Provisioning, records_exports as Records, testing_exports as Testing, theme_exports as Theme, verification_exports as Verification };
1655
1958
 
1656
1959
  //# sourceMappingURL=index.mjs.map