@netlify/spark-ui 1.26.0-alpha.2 → 1.26.0-alpha.4

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.
@@ -1 +1 @@
1
- .n-fadeIn{opacity:0;animation:fadeIn var(--animation-duration, .3s) ease-out forwards}.n-fadeInUp{opacity:0;transform:translateY(var(--animation-transformY, 5px));animation:fadeInUp var(--animation-duration, .3s) ease-out forwards}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInUp{to{opacity:1;transform:translateY(0)}}.n-dropzone{--n-dropzone-accent: var(--color-brand-primary, #0e7fe1);--n-dropzone-radius: var(--radius-2xl, 1rem);box-sizing:border-box;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-s);width:100%;height:100%;min-height:18rem;padding:var(--space-2xl, 2.5rem) var(--space-l, 1.5rem);text-align:center;color:var(--color-text-default, #14161a);background:var(--color-bg, #fff);border:2px dashed var(--color-border-default, rgba(0, 0, 0, .15));border-radius:var(--n-dropzone-radius);transition:border-color .2s ease-out,background-color .2s ease-out,box-shadow .2s ease-out}.n-dropzone.is-active{border-color:var(--n-dropzone-accent);background:var(--color-bg-2, #f6f8fa);box-shadow:0 0 0 4px color-mix(in srgb,var(--n-dropzone-accent) 18%,transparent)}.n-dropzone.is-busy{border-style:solid;border-color:var(--color-border-subtle, rgba(0, 0, 0, .08))}.n-dropzone:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;background:radial-gradient(120% 120% at 50% 0%,color-mix(in srgb,var(--n-dropzone-accent) 8%,transparent),transparent 60%);opacity:0;transition:opacity .2s ease-out;pointer-events:none}.n-dropzone.is-active:before{opacity:1}.n-dropzone-panel{display:flex;flex-direction:column;align-items:center;gap:var(--space-xs, .75rem);width:100%;animation:dropPanelIn .32s cubic-bezier(.22,1,.36,1) both}@keyframes dropPanelIn{0%{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}.n-dropzone-title{margin:0;font-size:1.125rem;font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-snug, 1.3)}.n-dropzone-title--error{color:var(--color-invalid-text, #d00)}.n-dropzone-subtitle{margin:0;max-width:30rem;font-size:.9375rem;color:var(--color-text-weak, #5c6570);line-height:var(--line-height-text, 1.5)}.n-dropzone-glyph{display:grid;place-items:center;width:3.5rem;height:3.5rem;color:var(--n-dropzone-accent)}.n-dropzone-glyph svg{width:100%;height:100%}.n-dropzone-glyph-arrow{animation:dropArrowBob 2.4s ease-in-out infinite}.n-dropzone.is-active .n-dropzone-glyph-arrow{animation-duration:.9s}@keyframes dropArrowBob{0%,to{transform:translateY(0)}50%{transform:translateY(-3px)}}.n-dropzone-glyph--success{color:var(--color-success-text, #108b46)}.n-dropzone-check-ring{stroke-dasharray:126;stroke-dashoffset:126;animation:dropDraw .5s ease-out 80ms forwards}.n-dropzone-check-mark{stroke-dasharray:32;stroke-dashoffset:32;animation:dropDraw .32s ease-out .46s forwards}@keyframes dropDraw{to{stroke-dashoffset:0}}.n-dropzone-loading{display:flex;flex-direction:column;align-items:center;gap:var(--space-s, 1rem)}.n-dropzone-spinner{width:2.25rem;height:2.25rem;border-radius:var(--radius-pill, 999px);border:3px solid color-mix(in srgb,var(--n-dropzone-accent) 22%,transparent);border-top-color:var(--n-dropzone-accent);animation:dropSpin .72s linear infinite}@keyframes dropSpin{to{transform:rotate(360deg)}}.n-dropzone-nudge{display:block;font-size:.8125rem;color:var(--color-text-weaker, #8a929c)}.n-dropzone-progress{width:min(22rem,100%);height:.5rem;border-radius:var(--radius-pill, 999px);background:var(--color-bg-3, rgba(0, 0, 0, .08));overflow:hidden}.n-dropzone-progress-bar{height:100%;border-radius:inherit;background:var(--n-dropzone-accent);transition:width .3s cubic-bezier(.22,1,.36,1)}.n-dropzone-link{display:inline-flex;align-items:center;gap:var(--space-3xs, .35rem);font-size:1rem;font-weight:var(--font-weight-semibold, 600);color:var(--color-link, #0e7fe1);text-decoration:none}.n-dropzone-link:hover{text-decoration:underline}.n-dropzone-link-icon{width:.9em;height:.9em}.n-dropzone-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:var(--space-s, 1rem);margin-block-start:var(--space-2xs, .5rem)}.n-dropzone-browse{display:inline-flex;align-items:center;justify-content:center;padding:var(--space-2xs, .5rem) var(--space-m, 1.25rem);border:none;border-radius:var(--radius-pill, 999px);background:var(--n-dropzone-accent);color:var(--neutral-000, #fff);font-size:.9375rem;font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-none, 1);text-decoration:none;cursor:pointer;transition:background-color .15s ease-out,transform .12s ease-out}.n-dropzone-browse:hover{background:var(--color-brand-primary-hover, #0b6bc0);transform:translateY(-1px)}.n-dropzone-browse:active{transform:translateY(0)}.n-dropzone-reset{padding:var(--space-2xs, .5rem) var(--space-m, 1.25rem);border:1px solid var(--color-border-default, rgba(0, 0, 0, .15));border-radius:var(--radius-pill, 999px);background:transparent;color:var(--color-text-default, #14161a);font-size:.9375rem;font-weight:var(--font-weight-semibold, 600);cursor:pointer;transition:background-color .15s ease-out}.n-dropzone-reset:hover{background:var(--color-bg-2, #f6f8fa)}.n-dropzone-warning{display:flex;align-items:center;gap:var(--space-2xs, .5rem);margin:0;margin-block-start:var(--space-xs, .75rem);padding:var(--space-2xs, .5rem) var(--space-s, 1rem);max-width:32rem;border-radius:var(--radius-m, .5rem);background:var(--color-warning-bg, #fdf3d7);color:var(--color-warning-text, #7a5b00);font-size:.8125rem;text-align:left}.n-dropzone-warning-icon{flex:none;width:1rem;height:1rem}@media (prefers-reduced-motion: reduce){.n-dropzone,.n-dropzone-panel,.n-dropzone-glyph-arrow,.n-dropzone-spinner,.n-dropzone-progress-bar,.n-dropzone-check-ring,.n-dropzone-check-mark{animation:none!important;transition:none!important}.n-dropzone-check-ring,.n-dropzone-check-mark{stroke-dashoffset:0}.n-dropzone-spinner{border-top-color:var(--n-dropzone-accent)}}
1
+ .n-fadeIn{opacity:0;animation:fadeIn var(--animation-duration, .3s) ease-out forwards}.n-fadeInUp{opacity:0;transform:translateY(var(--animation-transformY, 5px));animation:fadeInUp var(--animation-duration, .3s) ease-out forwards}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInUp{to{opacity:1;transform:translateY(0)}}.n-dropzone{--n-dropzone-accent: var(--color-brand-primary, #0e7fe1);--n-dropzone-radius: var(--radius-2xl, 1rem);box-sizing:border-box;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-s);width:100%;height:100%;min-height:18rem;padding:var(--space-2xl, 2.5rem) var(--space-l, 1.5rem);text-align:center;color:var(--color-text-default, #14161a);background:var(--color-bg, #fff);border:2px dashed var(--color-border-default, rgba(0, 0, 0, .15));border-radius:var(--n-dropzone-radius);transition:border-color .2s ease-out,background-color .2s ease-out,box-shadow .2s ease-out}.n-dropzone.is-active{border-color:var(--n-dropzone-accent);background:var(--color-bg-2, #f6f8fa);box-shadow:0 0 0 4px color-mix(in srgb,var(--n-dropzone-accent) 18%,transparent)}.n-dropzone.is-busy{border-style:solid;border-color:var(--color-border-subtle, rgba(0, 0, 0, .08))}.n-dropzone:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;background:radial-gradient(120% 120% at 50% 0%,color-mix(in srgb,var(--n-dropzone-accent) 8%,transparent),transparent 60%);opacity:0;transition:opacity .2s ease-out;pointer-events:none}.n-dropzone.is-active:before{opacity:1}.n-dropzone-panel{display:flex;flex-direction:column;align-items:center;gap:var(--space-xs, .75rem);width:100%;animation:dropPanelIn .32s cubic-bezier(.22,1,.36,1) both}@keyframes dropPanelIn{0%{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}.n-dropzone-title{margin:0;font-size:1.125rem;font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-snug, 1.3)}.n-dropzone-title--error{color:var(--color-invalid-text, #d00)}.n-dropzone-subtitle{margin:0;max-width:30rem;font-size:.9375rem;color:var(--color-text-weak, #5c6570);line-height:var(--line-height-text, 1.5)}.n-dropzone-glyph{display:grid;place-items:center;width:3.5rem;height:3.5rem;color:var(--n-dropzone-accent)}.n-dropzone-glyph svg{width:100%;height:100%}.n-dropzone-glyph-arrow{animation:dropArrowBob 2.4s ease-in-out infinite}.n-dropzone.is-active .n-dropzone-glyph-arrow{animation-duration:.9s}@keyframes dropArrowBob{0%,to{transform:translateY(0)}50%{transform:translateY(-3px)}}.n-dropzone-loading{display:flex;flex-direction:column;align-items:center;gap:var(--space-s, 1rem)}.n-dropzone-spinner{width:2.25rem;height:2.25rem;border-radius:var(--radius-pill, 999px);border:3px solid color-mix(in srgb,var(--n-dropzone-accent) 22%,transparent);border-top-color:var(--n-dropzone-accent);animation:dropSpin .72s linear infinite}@keyframes dropSpin{to{transform:rotate(360deg)}}.n-dropzone-nudge{display:block;font-size:.8125rem;color:var(--color-text-weaker, #8a929c)}.n-dropzone-progress{width:min(22rem,100%);height:.5rem;border-radius:var(--radius-pill, 999px);background:var(--color-bg-3, rgba(0, 0, 0, .08));overflow:hidden}.n-dropzone-progress-bar{height:100%;border-radius:inherit;background:var(--n-dropzone-accent);transition:width .3s cubic-bezier(.22,1,.36,1)}.n-dropzone-browse{display:inline-flex;align-items:center;justify-content:center;padding:var(--space-2xs, .5rem) var(--space-m, 1.25rem);border:none;border-radius:var(--radius-pill, 999px);background:var(--n-dropzone-accent);color:var(--neutral-000, #fff);font-size:.9375rem;font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-none, 1);text-decoration:none;cursor:pointer;transition:background-color .15s ease-out,transform .12s ease-out}.n-dropzone-browse:hover{background:var(--color-brand-primary-hover, #0b6bc0);transform:translateY(-1px)}.n-dropzone-browse:active{transform:translateY(0)}.n-dropzone-warning{display:flex;align-items:center;gap:var(--space-2xs, .5rem);margin:0;margin-block-start:var(--space-xs, .75rem);padding:var(--space-2xs, .5rem) var(--space-s, 1rem);max-width:32rem;border-radius:var(--radius-m, .5rem);background:var(--color-warning-bg, #fdf3d7);color:var(--color-warning-text, #7a5b00);font-size:.8125rem;text-align:left}.n-dropzone-warning-icon{flex:none;width:1rem;height:1rem}@media (prefers-reduced-motion: reduce){.n-dropzone,.n-dropzone-panel,.n-dropzone-glyph-arrow,.n-dropzone-spinner,.n-dropzone-progress-bar{animation:none!important;transition:none!important}.n-dropzone-spinner{border-top-color:var(--n-dropzone-accent)}}
@@ -7,5 +7,5 @@ export { default as SearchToggle } from './preact/SearchModal/components/SearchT
7
7
  export { default as SearchModal } from './preact/SearchModal/components/SearchModal/SearchModal';
8
8
  export { default as DropZone } from './preact/DropZone/DropZone';
9
9
  export { AnonymousDropClient, deployFiles, readDataTransfer, readFileList, } from './preact/DropZone/drop-core';
10
- export type { DropClient, Deploy, Digest, DeployResult, DeployProgress, DeployPhase, ProcessedFile, } from './preact/DropZone/drop-core';
10
+ export type { DropClient, DropResponse, Digest, DeployResult, DeployProgress, DeployPhase, ProcessedFile, } from './preact/DropZone/drop-core';
11
11
  export { type IconName } from './preact/Icon';
@@ -1,11 +1,11 @@
1
1
  import { u as e } from "../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
2
- import { d as k, A as I } from "../../../chunks/hooks.module.DRcxknIz.js";
3
- import b from "../Icon/index.js";
4
- import { getSingleNonIndexHtmlFileName as $, hasMultipleHtmlFilesWithoutIndex as D, readDataTransfer as F, readFileList as T } from "./drop-core/readFiles.js";
2
+ import { d as m, A as C } from "../../../chunks/hooks.module.DRcxknIz.js";
3
+ import I from "../Icon/index.js";
4
+ import { getSingleNonIndexHtmlFileName as N, hasMultipleHtmlFilesWithoutIndex as D, readDataTransfer as F, readFileList as T } from "./drop-core/readFiles.js";
5
5
  import { AnonymousDropClient as M } from "./drop-core/client.js";
6
6
  import { deployFiles as P } from "./drop-core/deploy.js";
7
- import { Fragment as p } from "preact";
8
- import '../../../assets/DropZone.css';const U = (n) => `https://app.netlify.com/drop/${n}/claim`;
7
+ import { Fragment as k } from "preact";
8
+ import '../../../assets/DropZone.css';const U = (n) => `https://app.netlify.com/drop/${n}`;
9
9
  function A(n) {
10
10
  switch (n.phase) {
11
11
  case "creating":
@@ -17,75 +17,74 @@ function A(n) {
17
17
  return { kind: "processing" };
18
18
  }
19
19
  }
20
- function Y({
20
+ function O({
21
21
  apiBase: n,
22
- client: h,
23
- claimUrl: d = U,
24
- onDeploy: s,
25
- className: l
22
+ client: p,
23
+ claimUrl: u = U,
24
+ onDeploy: i,
25
+ className: s
26
26
  }) {
27
- const [o, t] = k({ kind: "idle" }), [w, c] = k(null), [C, g] = k(!1), x = I(h ?? new M(n)).current, f = o.kind !== "idle" && o.kind !== "done" && o.kind !== "error";
28
- async function z(i) {
29
- c(null), t({ kind: "reading" });
27
+ const [o, a] = m({ kind: "idle" }), [w, d] = m(null), [v, g] = m(!1), z = C(p ?? new M(n)).current, h = o.kind !== "idle" && o.kind !== "error";
28
+ async function y(t) {
29
+ d(null), a({ kind: "reading" });
30
30
  try {
31
- const r = await i();
31
+ const r = await t();
32
32
  if (!r.length) {
33
- t({ kind: "error", message: "No files found to deploy." });
33
+ a({ kind: "error", message: "No files found to deploy." });
34
34
  return;
35
35
  }
36
- const y = $(r);
37
- y ? c(`No index.html found — "${y}" won’t be served at the site root.`) : D(r) && c("No index.html found — your site may not have a landing page.");
38
- const { url: v, token: m, deploy: a } = await P(x, r, {
39
- onProgress: (S) => t(A(S))
36
+ const b = N(r);
37
+ b ? d(`No index.html found — "${b}" won’t be served at the site root.`) : D(r) && d("No index.html found — your site may not have a landing page.");
38
+ const { url: $, token: f, deploy: c } = await P(z, r, {
39
+ onProgress: (x) => a(A(x))
40
40
  });
41
41
  try {
42
- localStorage.setItem("drop-token", m), localStorage.setItem("dropSiteName", a.subdomain);
42
+ localStorage.setItem("drop-token", f), localStorage.setItem("dropSiteName", c.subdomain);
43
43
  } catch {
44
44
  }
45
- t({ kind: "done", url: v, token: m, siteName: a.subdomain, siteId: a.id }), s == null || s({ url: v, token: m, siteName: a.subdomain, siteId: a.id });
45
+ a({ kind: "redirecting" }), i == null || i({ url: $, token: f, siteName: c.subdomain, siteId: c.id }), window.location.assign(`${u(c.subdomain)}#drop_token=${f}`);
46
46
  } catch (r) {
47
- t({ kind: "error", message: r instanceof Error ? r.message : String(r) });
47
+ a({ kind: "error", message: r instanceof Error ? r.message : String(r) });
48
48
  }
49
49
  }
50
- function N() {
51
- c(null), t({ kind: "idle" });
50
+ function S() {
51
+ d(null), a({ kind: "idle" });
52
52
  }
53
53
  return /* @__PURE__ */ e(
54
54
  "div",
55
55
  {
56
- class: `n-dropzone${C ? " is-active" : ""}${f ? " is-busy" : ""}${l ? ` ${l}` : ""}`,
56
+ class: `n-dropzone${v ? " is-active" : ""}${h ? " is-busy" : ""}${s ? ` ${s}` : ""}`,
57
57
  "data-state": o.kind,
58
- onDragOver: (i) => {
59
- f || (i.preventDefault(), g(!0));
58
+ onDragOver: (t) => {
59
+ h || (t.preventDefault(), g(!0));
60
60
  },
61
- onDragLeave: (i) => {
62
- i.currentTarget === i.target && g(!1);
61
+ onDragLeave: (t) => {
62
+ t.currentTarget === t.target && g(!1);
63
63
  },
64
- onDrop: (i) => {
65
- if (i.preventDefault(), g(!1), f) return;
66
- const r = i.dataTransfer;
67
- r && z(() => F(r));
64
+ onDrop: (t) => {
65
+ if (t.preventDefault(), g(!1), h) return;
66
+ const r = t.dataTransfer;
67
+ r && y(() => F(r));
68
68
  },
69
69
  children: [
70
- /* @__PURE__ */ e("div", { class: "n-dropzone-panel", children: /* @__PURE__ */ e(B, { status: o, claimUrl: d, onReset: N, onFiles: z }) }, o.kind),
70
+ /* @__PURE__ */ e("div", { class: "n-dropzone-panel", children: /* @__PURE__ */ e(L, { status: o, onReset: S, onFiles: y }) }, o.kind),
71
71
  w && o.kind !== "error" && /* @__PURE__ */ e("p", { class: "n-dropzone-warning n-fadeIn", role: "status", children: [
72
- /* @__PURE__ */ e(b, { name: "lightbulb", className: "n-dropzone-warning-icon" }),
72
+ /* @__PURE__ */ e(I, { name: "lightbulb", className: "n-dropzone-warning-icon" }),
73
73
  w
74
74
  ] })
75
75
  ]
76
76
  }
77
77
  );
78
78
  }
79
- function B({
79
+ function L({
80
80
  status: n,
81
- claimUrl: h,
82
- onReset: d,
83
- onFiles: s
81
+ onReset: p,
82
+ onFiles: u
84
83
  }) {
85
84
  switch (n.kind) {
86
85
  case "idle":
87
- return /* @__PURE__ */ e(p, { children: [
88
- /* @__PURE__ */ e(L, {}),
86
+ return /* @__PURE__ */ e(k, { children: [
87
+ /* @__PURE__ */ e(R, {}),
89
88
  /* @__PURE__ */ e("p", { class: "n-dropzone-title", children: "Drag & drop your site folder or zip" }),
90
89
  /* @__PURE__ */ e("p", { class: "n-dropzone-subtitle", children: "Deploys instantly to a live URL — no account needed." }),
91
90
  /* @__PURE__ */ e("label", { class: "n-dropzone-browse", children: [
@@ -98,50 +97,39 @@ function B({
98
97
  multiple: !0,
99
98
  webkitdirectory: "",
100
99
  directory: "",
101
- onChange: (l) => {
102
- var t;
103
- const o = l.currentTarget;
104
- (t = o.files) != null && t.length && s(() => T(o.files));
100
+ onChange: (i) => {
101
+ var o;
102
+ const s = i.currentTarget;
103
+ (o = s.files) != null && o.length && u(() => T(s.files));
105
104
  }
106
105
  }
107
106
  )
108
107
  ] })
109
108
  ] });
110
109
  case "reading":
111
- return /* @__PURE__ */ e(u, { label: "Reading files…" });
110
+ return /* @__PURE__ */ e(l, { label: "Reading files…" });
112
111
  case "creating":
113
- return /* @__PURE__ */ e(u, { label: "Creating deploy…" });
112
+ return /* @__PURE__ */ e(l, { label: "Creating deploy…" });
114
113
  case "processing":
115
- return /* @__PURE__ */ e(u, { label: "Processing — almost live…" });
114
+ return /* @__PURE__ */ e(l, { label: "Processing — almost live…" });
115
+ case "redirecting":
116
+ return /* @__PURE__ */ e(l, { label: "Site’s live — taking you to claim it…" });
116
117
  case "uploading": {
117
- const l = n.total ? Math.round(n.uploaded / n.total * 100) : 0;
118
- return /* @__PURE__ */ e(p, { children: [
119
- /* @__PURE__ */ e(u, { label: `Uploading ${n.uploaded}/${n.total} files…` }),
120
- /* @__PURE__ */ e("div", { class: "n-dropzone-progress", role: "progressbar", "aria-valuenow": l, children: /* @__PURE__ */ e("div", { class: "n-dropzone-progress-bar", style: { width: `${l}%` } }) })
118
+ const i = n.total ? Math.round(n.uploaded / n.total * 100) : 0;
119
+ return /* @__PURE__ */ e(k, { children: [
120
+ /* @__PURE__ */ e(l, { label: `Uploading ${n.uploaded}/${n.total} files…` }),
121
+ /* @__PURE__ */ e("div", { class: "n-dropzone-progress", role: "progressbar", "aria-valuenow": i, children: /* @__PURE__ */ e("div", { class: "n-dropzone-progress-bar", style: { width: `${i}%` } }) })
121
122
  ] });
122
123
  }
123
- case "done":
124
- return /* @__PURE__ */ e(p, { children: [
125
- /* @__PURE__ */ e(j, {}),
126
- /* @__PURE__ */ e("p", { class: "n-dropzone-title", children: "Your site is live!" }),
127
- /* @__PURE__ */ e("a", { class: "n-dropzone-link", href: n.url, target: "_blank", rel: "noopener noreferrer", children: [
128
- n.url.replace(/^https?:\/\//, ""),
129
- /* @__PURE__ */ e(b, { name: "link", className: "n-dropzone-link-icon" })
130
- ] }),
131
- /* @__PURE__ */ e("div", { class: "n-dropzone-actions", children: [
132
- /* @__PURE__ */ e("a", { class: "n-dropzone-browse", href: h(n.siteName), children: "Claim this site" }),
133
- /* @__PURE__ */ e("button", { type: "button", class: "n-dropzone-reset", onClick: d, children: "Deploy another" })
134
- ] })
135
- ] });
136
124
  case "error":
137
- return /* @__PURE__ */ e(p, { children: [
125
+ return /* @__PURE__ */ e(k, { children: [
138
126
  /* @__PURE__ */ e("p", { class: "n-dropzone-title n-dropzone-title--error", children: "Something went wrong" }),
139
127
  /* @__PURE__ */ e("p", { class: "n-dropzone-subtitle", role: "alert", children: n.message }),
140
- /* @__PURE__ */ e("button", { type: "button", class: "n-dropzone-browse", onClick: d, children: "Try again" })
128
+ /* @__PURE__ */ e("button", { type: "button", class: "n-dropzone-browse", onClick: p, children: "Try again" })
141
129
  ] });
142
130
  }
143
131
  }
144
- function u({ label: n }) {
132
+ function l({ label: n }) {
145
133
  return /* @__PURE__ */ e("div", { class: "n-dropzone-loading", children: [
146
134
  /* @__PURE__ */ e("span", { class: "n-dropzone-spinner", "aria-hidden": "true" }),
147
135
  /* @__PURE__ */ e("p", { class: "n-dropzone-subtitle", "aria-live": "polite", children: [
@@ -151,7 +139,7 @@ function u({ label: n }) {
151
139
  ] })
152
140
  ] });
153
141
  }
154
- function L() {
142
+ function R() {
155
143
  return /* @__PURE__ */ e("span", { class: "n-dropzone-glyph", "aria-hidden": "true", children: /* @__PURE__ */ e("svg", { viewBox: "0 0 48 48", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
156
144
  /* @__PURE__ */ e(
157
145
  "path",
@@ -176,32 +164,6 @@ function L() {
176
164
  )
177
165
  ] }) });
178
166
  }
179
- function j() {
180
- return /* @__PURE__ */ e("span", { class: "n-dropzone-glyph n-dropzone-glyph--success", "aria-hidden": "true", children: /* @__PURE__ */ e("svg", { viewBox: "0 0 48 48", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
181
- /* @__PURE__ */ e(
182
- "circle",
183
- {
184
- class: "n-dropzone-check-ring",
185
- cx: "24",
186
- cy: "24",
187
- r: "20",
188
- stroke: "currentColor",
189
- "stroke-width": "3"
190
- }
191
- ),
192
- /* @__PURE__ */ e(
193
- "path",
194
- {
195
- class: "n-dropzone-check-mark",
196
- d: "M15 24.5 21 30.5 33 18",
197
- stroke: "currentColor",
198
- "stroke-width": "3",
199
- "stroke-linecap": "round",
200
- "stroke-linejoin": "round"
201
- }
202
- )
203
- ] }) });
204
- }
205
167
  export {
206
- Y as default
168
+ O as default
207
169
  };
@@ -1,9 +1,9 @@
1
- import { Deploy, Digest } from './types';
1
+ import { DropResponse, Digest } from './types';
2
2
  export interface DropClient {
3
3
  getToken(): Promise<string>;
4
- createDeploy(digest: Digest, token: string): Promise<Deploy>;
4
+ createDeploy(digest: Digest, token: string): Promise<DropResponse>;
5
5
  uploadFile(deployId: string, path: string, content: ArrayBuffer, token: string): Promise<void>;
6
- waitUntilReady(deploy: Deploy, token: string): Promise<void>;
6
+ waitUntilReady(deploy: DropResponse, token: string): Promise<void>;
7
7
  }
8
8
  /**
9
9
  * Unauthenticated drop client. Authorized server-side by the Referer header,
@@ -13,7 +13,7 @@ export declare class AnonymousDropClient implements DropClient {
13
13
  private apiBase;
14
14
  constructor(apiBase?: string);
15
15
  getToken(): Promise<string>;
16
- createDeploy(files: Digest, token: string): Promise<Deploy>;
16
+ createDeploy(files: Digest, token: string): Promise<DropResponse>;
17
17
  uploadFile(deployId: string, path: string, content: ArrayBuffer, token: string): Promise<void>;
18
- waitUntilReady(deploy: Deploy, token: string): Promise<void>;
18
+ waitUntilReady(deploy: DropResponse, token: string): Promise<void>;
19
19
  }
@@ -27,7 +27,7 @@ class n {
27
27
  }
28
28
  async waitUntilReady(e, o) {
29
29
  for (let t = 0; t < 600; t++) {
30
- const a = await fetch(`${this.apiBase}/deploys/${e.id}`, {
30
+ const a = await fetch(`${this.apiBase}/deploys/${e.deploy_id}`, {
31
31
  headers: { Authorization: `Bearer ${o}` }
32
32
  });
33
33
  if (a.ok && (await a.json()).state === "ready") return;
@@ -579,7 +579,10 @@ async function U(x) {
579
579
  ), p = [];
580
580
  for (const [v, s] of Object.entries(b)) {
581
581
  if (v.endsWith("/") || /(^|\/)(__MACOSX\/|\.)/.test(v)) continue;
582
- const g = s.buffer.slice(s.byteOffset, s.byteOffset + s.byteLength);
582
+ const g = s.buffer.slice(
583
+ s.byteOffset,
584
+ s.byteOffset + s.byteLength
585
+ );
583
586
  p.push(k(v, g, v.split("/").pop()));
584
587
  }
585
588
  return O(p);
@@ -8,8 +8,17 @@ export interface ProcessedFile {
8
8
  name: string;
9
9
  }
10
10
  export type Digest = Record<string, string>;
11
- export interface Deploy {
11
+ /**
12
+ * Response body of `POST /api/v1/drop`. Not a canonical Deploy resource —
13
+ * it's a mixed shape carrying both the anonymous site and the initial deploy
14
+ * so the client has everything it needs to upload, poll, and hand off to the
15
+ * user in one round trip.
16
+ */
17
+ export interface DropResponse {
18
+ /** site id (UUID) — surfaced to callers so they can build claim links */
12
19
  id: string;
20
+ /** deploy id (BSON) — used for `/deploys/{deploy_id}` reads and file PUTs */
21
+ deploy_id: string;
13
22
  /** the *.netlify.app subdomain assigned to the anonymous site */
14
23
  subdomain: string;
15
24
  /** SHAs the backend does NOT yet have — only these get uploaded */
@@ -17,7 +26,7 @@ export interface Deploy {
17
26
  state?: string;
18
27
  }
19
28
  export interface DeployResult {
20
- deploy: Deploy;
29
+ deploy: DropResponse;
21
30
  /** drop token — persist this to later claim the site into an account */
22
31
  token: string;
23
32
  url: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@netlify/spark-ui",
3
3
  "description": "Assets, design tokens, components, and utilities",
4
- "version": "1.26.0-alpha.2",
4
+ "version": "1.26.0-alpha.4",
5
5
  "type": "module",
6
6
  "main": "dist/components/preact/index.js",
7
7
  "types": "dist/components/preact/index.d.ts",
@@ -15,7 +15,7 @@ export {
15
15
  } from './preact/DropZone/drop-core';
16
16
  export type {
17
17
  DropClient,
18
- Deploy,
18
+ DropResponse,
19
19
  Digest,
20
20
  DeployResult,
21
21
  DeployProgress,
@@ -138,31 +138,6 @@
138
138
  }
139
139
  }
140
140
 
141
- /* ----------------------------- */
142
- /* Success glyph (draws in) */
143
- /* ----------------------------- */
144
- .n-dropzone-glyph--success {
145
- color: var(--color-success-text, #108b46);
146
- }
147
-
148
- .n-dropzone-check-ring {
149
- stroke-dasharray: 126;
150
- stroke-dashoffset: 126;
151
- animation: dropDraw 500ms ease-out 80ms forwards;
152
- }
153
-
154
- .n-dropzone-check-mark {
155
- stroke-dasharray: 32;
156
- stroke-dashoffset: 32;
157
- animation: dropDraw 320ms ease-out 460ms forwards;
158
- }
159
-
160
- @keyframes dropDraw {
161
- to {
162
- stroke-dashoffset: 0;
163
- }
164
- }
165
-
166
141
  /* ----------------------------- */
167
142
  /* Loading / spinner */
168
143
  /* ----------------------------- */
@@ -212,37 +187,6 @@
212
187
  transition: width 300ms cubic-bezier(0.22, 1, 0.36, 1);
213
188
  }
214
189
 
215
- /* ----------------------------- */
216
- /* Done state links & actions */
217
- /* ----------------------------- */
218
- .n-dropzone-link {
219
- display: inline-flex;
220
- align-items: center;
221
- gap: var(--space-3xs, 0.35rem);
222
- font-size: 1rem;
223
- font-weight: var(--font-weight-semibold, 600);
224
- color: var(--color-link, #0e7fe1);
225
- text-decoration: none;
226
- }
227
-
228
- .n-dropzone-link:hover {
229
- text-decoration: underline;
230
- }
231
-
232
- .n-dropzone-link-icon {
233
- width: 0.9em;
234
- height: 0.9em;
235
- }
236
-
237
- .n-dropzone-actions {
238
- display: flex;
239
- flex-wrap: wrap;
240
- align-items: center;
241
- justify-content: center;
242
- gap: var(--space-s, 1rem);
243
- margin-block-start: var(--space-2xs, 0.5rem);
244
- }
245
-
246
190
  /* ----------------------------- */
247
191
  /* Buttons */
248
192
  /* ----------------------------- */
@@ -274,22 +218,6 @@
274
218
  transform: translateY(0);
275
219
  }
276
220
 
277
- .n-dropzone-reset {
278
- padding: var(--space-2xs, 0.5rem) var(--space-m, 1.25rem);
279
- border: 1px solid var(--color-border-default, rgba(0, 0, 0, 0.15));
280
- border-radius: var(--radius-pill, 999px);
281
- background: transparent;
282
- color: var(--color-text-default, #14161a);
283
- font-size: 0.9375rem;
284
- font-weight: var(--font-weight-semibold, 600);
285
- cursor: pointer;
286
- transition: background-color 150ms ease-out;
287
- }
288
-
289
- .n-dropzone-reset:hover {
290
- background: var(--color-bg-2, #f6f8fa);
291
- }
292
-
293
221
  /* ----------------------------- */
294
222
  /* Warning banner */
295
223
  /* ----------------------------- */
@@ -322,18 +250,11 @@
322
250
  .n-dropzone-panel,
323
251
  .n-dropzone-glyph-arrow,
324
252
  .n-dropzone-spinner,
325
- .n-dropzone-progress-bar,
326
- .n-dropzone-check-ring,
327
- .n-dropzone-check-mark {
253
+ .n-dropzone-progress-bar {
328
254
  animation: none !important;
329
255
  transition: none !important;
330
256
  }
331
257
 
332
- .n-dropzone-check-ring,
333
- .n-dropzone-check-mark {
334
- stroke-dashoffset: 0;
335
- }
336
-
337
258
  .n-dropzone-spinner {
338
259
  border-top-color: var(--n-dropzone-accent);
339
260
  }
@@ -20,7 +20,7 @@ type Status =
20
20
  | { kind: 'creating' }
21
21
  | { kind: 'uploading'; uploaded: number; total: number }
22
22
  | { kind: 'processing' }
23
- | { kind: 'done'; url: string; token: string; siteName: string; siteId: string }
23
+ | { kind: 'redirecting' }
24
24
  | { kind: 'error'; message: string };
25
25
 
26
26
  interface Props {
@@ -35,7 +35,7 @@ interface Props {
35
35
  className?: string;
36
36
  }
37
37
 
38
- const defaultClaimUrl = (siteName: string) => `https://app.netlify.com/drop/${siteName}/claim`;
38
+ const defaultClaimUrl = (siteName: string) => `https://app.netlify.com/drop/${siteName}`;
39
39
 
40
40
  function progressPhaseToStatus(e: DeployProgress): Status {
41
41
  switch (e.phase) {
@@ -61,7 +61,7 @@ export default function DropZone({
61
61
  const [active, setActive] = useState(false);
62
62
  const dropClient = useRef(client ?? new AnonymousDropClient(apiBase)).current;
63
63
 
64
- const busy = status.kind !== 'idle' && status.kind !== 'done' && status.kind !== 'error';
64
+ const busy = status.kind !== 'idle' && status.kind !== 'error';
65
65
 
66
66
  async function run(read: () => Promise<ProcessedFile[]>) {
67
67
  setWarning(null);
@@ -85,7 +85,10 @@ export default function DropZone({
85
85
  onProgress: e => setStatus(progressPhaseToStatus(e)),
86
86
  });
87
87
 
88
- // Persist for the claim step after signup (mirrors the dashboard).
88
+ // Best-effort local persistence. Note this does NOT reach the dashboard:
89
+ // localStorage is per-origin, so a token written here (e.g. www.netlify.com)
90
+ // is invisible to app.netlify.com. The cross-origin handoff is the URL
91
+ // fragment below; this only helps if the drop and claim share an origin.
89
92
  try {
90
93
  localStorage.setItem('drop-token', token);
91
94
  localStorage.setItem('dropSiteName', deploy.subdomain);
@@ -93,8 +96,13 @@ export default function DropZone({
93
96
  /* private mode / storage disabled — non-fatal */
94
97
  }
95
98
 
96
- setStatus({ kind: 'done', url, token, siteName: deploy.subdomain, siteId: deploy.id });
99
+ setStatus({ kind: 'redirecting' });
97
100
  onDeploy?.({ url, token, siteName: deploy.subdomain, siteId: deploy.id });
101
+
102
+ // Hand the drop token to the dashboard via the URL fragment — localStorage
103
+ // does not cross origins. The dashboard's /drop/:name page reads
104
+ // `#drop_token=` and persists it for the claim + post-signup steps.
105
+ window.location.assign(`${claimUrl(deploy.subdomain)}#drop_token=${token}`);
98
106
  } catch (err) {
99
107
  setStatus({ kind: 'error', message: err instanceof Error ? err.message : String(err) });
100
108
  }
@@ -131,7 +139,7 @@ export default function DropZone({
131
139
  >
132
140
  {/* keyed so each state change remounts and replays its enter animation */}
133
141
  <div class="n-dropzone-panel" key={status.kind}>
134
- <StatusView status={status} claimUrl={claimUrl} onReset={reset} onFiles={run} />
142
+ <StatusView status={status} onReset={reset} onFiles={run} />
135
143
  </div>
136
144
 
137
145
  {warning && status.kind !== 'error' && (
@@ -146,12 +154,10 @@ export default function DropZone({
146
154
 
147
155
  function StatusView({
148
156
  status,
149
- claimUrl,
150
157
  onReset,
151
158
  onFiles,
152
159
  }: {
153
160
  status: Status;
154
- claimUrl: (siteName: string) => string;
155
161
  onReset: () => void;
156
162
  onFiles: (read: () => Promise<ProcessedFile[]>) => void;
157
163
  }) {
@@ -186,6 +192,8 @@ function StatusView({
186
192
  return <Spinner label="Creating deploy…" />;
187
193
  case 'processing':
188
194
  return <Spinner label="Processing — almost live…" />;
195
+ case 'redirecting':
196
+ return <Spinner label="Site’s live — taking you to claim it…" />;
189
197
 
190
198
  case 'uploading': {
191
199
  const pct = status.total ? Math.round((status.uploaded / status.total) * 100) : 0;
@@ -199,26 +207,6 @@ function StatusView({
199
207
  );
200
208
  }
201
209
 
202
- case 'done':
203
- return (
204
- <>
205
- <SuccessGlyph />
206
- <p class="n-dropzone-title">Your site is live!</p>
207
- <a class="n-dropzone-link" href={status.url} target="_blank" rel="noopener noreferrer">
208
- {status.url.replace(/^https?:\/\//, '')}
209
- <Icon name="link" className="n-dropzone-link-icon" />
210
- </a>
211
- <div class="n-dropzone-actions">
212
- <a class="n-dropzone-browse" href={claimUrl(status.siteName)}>
213
- Claim this site
214
- </a>
215
- <button type="button" class="n-dropzone-reset" onClick={onReset}>
216
- Deploy another
217
- </button>
218
- </div>
219
- </>
220
- );
221
-
222
210
  case 'error':
223
211
  return (
224
212
  <>
@@ -268,28 +256,3 @@ function UploadGlyph() {
268
256
  </span>
269
257
  );
270
258
  }
271
-
272
- function SuccessGlyph() {
273
- return (
274
- <span class="n-dropzone-glyph n-dropzone-glyph--success" aria-hidden="true">
275
- <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
276
- <circle
277
- class="n-dropzone-check-ring"
278
- cx="24"
279
- cy="24"
280
- r="20"
281
- stroke="currentColor"
282
- stroke-width="3"
283
- />
284
- <path
285
- class="n-dropzone-check-mark"
286
- d="M15 24.5 21 30.5 33 18"
287
- stroke="currentColor"
288
- stroke-width="3"
289
- stroke-linecap="round"
290
- stroke-linejoin="round"
291
- />
292
- </svg>
293
- </span>
294
- );
295
- }
@@ -1,10 +1,10 @@
1
- import type { Deploy, Digest } from './types';
1
+ import type { DropResponse, Digest } from './types';
2
2
 
3
3
  export interface DropClient {
4
4
  getToken(): Promise<string>;
5
- createDeploy(digest: Digest, token: string): Promise<Deploy>;
5
+ createDeploy(digest: Digest, token: string): Promise<DropResponse>;
6
6
  uploadFile(deployId: string, path: string, content: ArrayBuffer, token: string): Promise<void>;
7
- waitUntilReady(deploy: Deploy, token: string): Promise<void>;
7
+ waitUntilReady(deploy: DropResponse, token: string): Promise<void>;
8
8
  }
9
9
 
10
10
  const API = 'https://api.netlify.com/api/v1';
@@ -22,7 +22,7 @@ export class AnonymousDropClient implements DropClient {
22
22
  return (await res.json()).token;
23
23
  }
24
24
 
25
- async createDeploy(files: Digest, token: string): Promise<Deploy> {
25
+ async createDeploy(files: Digest, token: string): Promise<DropResponse> {
26
26
  const res = await fetch(`${this.apiBase}/drop`, {
27
27
  method: 'POST',
28
28
  headers: { 'Content-Type': 'application/json' },
@@ -47,10 +47,13 @@ export class AnonymousDropClient implements DropClient {
47
47
  if (!res.ok) throw new Error(`upload ${path} failed: ${res.status}`);
48
48
  }
49
49
 
50
- async waitUntilReady(deploy: Deploy, token: string): Promise<void> {
50
+ async waitUntilReady(deploy: DropResponse, token: string): Promise<void> {
51
51
  // Poll the deploy with the drop token until ready.
52
+ // Note: `/deploys/{id}` expects the deploy_id (BSON), not the site id (UUID)
53
+ // that lives at `deploy.id`. See drop_controller.rb; Deploy.find(uuid) is nil
54
+ // and the request 401s misleadingly via require_current_actor!.
52
55
  for (let i = 0; i < 600; i++) {
53
- const res = await fetch(`${this.apiBase}/deploys/${deploy.id}`, {
56
+ const res = await fetch(`${this.apiBase}/deploys/${deploy.deploy_id}`, {
54
57
  headers: { Authorization: `Bearer ${token}` },
55
58
  });
56
59
  if (res.ok && (await res.json()).state === 'ready') return;
@@ -99,7 +99,12 @@ export async function readZip(zip: File): Promise<ProcessedFile[]> {
99
99
  // fflate uses a trailing slash to signal directory entries; also skip the
100
100
  // usual junk (macOS metadata, dotfiles at any depth).
101
101
  if (path.endsWith('/') || /(^|\/)(__MACOSX\/|\.)/.test(path)) continue;
102
- const content = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
102
+ // `bytes.buffer` is ArrayBufferLike; fflate always backs entries with a plain
103
+ // ArrayBuffer, so narrow it for toProcessedFile's ArrayBuffer parameter.
104
+ const content = bytes.buffer.slice(
105
+ bytes.byteOffset,
106
+ bytes.byteOffset + bytes.byteLength,
107
+ ) as ArrayBuffer;
103
108
  out.push(toProcessedFile(path, content, path.split('/').pop()!));
104
109
  }
105
110
  return normalizeFiles(out);
@@ -10,8 +10,17 @@ export interface ProcessedFile {
10
10
 
11
11
  export type Digest = Record<string, string>; // { "/index.html": "<sha1>" }
12
12
 
13
- export interface Deploy {
13
+ /**
14
+ * Response body of `POST /api/v1/drop`. Not a canonical Deploy resource —
15
+ * it's a mixed shape carrying both the anonymous site and the initial deploy
16
+ * so the client has everything it needs to upload, poll, and hand off to the
17
+ * user in one round trip.
18
+ */
19
+ export interface DropResponse {
20
+ /** site id (UUID) — surfaced to callers so they can build claim links */
14
21
  id: string;
22
+ /** deploy id (BSON) — used for `/deploys/{deploy_id}` reads and file PUTs */
23
+ deploy_id: string;
15
24
  /** the *.netlify.app subdomain assigned to the anonymous site */
16
25
  subdomain: string;
17
26
  /** SHAs the backend does NOT yet have — only these get uploaded */
@@ -20,7 +29,7 @@ export interface Deploy {
20
29
  }
21
30
 
22
31
  export interface DeployResult {
23
- deploy: Deploy;
32
+ deploy: DropResponse;
24
33
  /** drop token — persist this to later claim the site into an account */
25
34
  token: string;
26
35
  url: string; // https://<subdomain>.netlify.app