@netlify/spark-ui 1.31.0-alpha.2 → 1.31.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.
Files changed (94) hide show
  1. package/dist/components/index.d.ts +2 -2
  2. package/dist/components/preact/DropZone/DropZone.d.ts +28 -2
  3. package/dist/components/preact/DropZone/DropZone.js +58 -51
  4. package/dist/components/preact/DropZone/DropZone.test.d.ts +1 -0
  5. package/dist/components/preact/DropZone/index.d.ts +3 -3
  6. package/dist/components/preact/DropZone/index.js +25 -23
  7. package/dist/components/preact/DropZone/useDropDeploy.d.ts +11 -6
  8. package/dist/components/preact/DropZone/useDropDeploy.js +183 -129
  9. package/dist/components/preact/DropZone/useDropDeploy.test.d.ts +1 -0
  10. package/dist/components/preact/index.d.ts +2 -2
  11. package/dist/components/preact/index.js +25 -19
  12. package/dist/drop-core/analytics.d.ts +107 -0
  13. package/dist/drop-core/analytics.js +21 -0
  14. package/dist/drop-core/analytics.test.d.ts +1 -0
  15. package/dist/drop-core/authedApi.d.ts +55 -0
  16. package/dist/drop-core/authedApi.js +35 -0
  17. package/dist/drop-core/authedApi.test.d.ts +1 -0
  18. package/dist/drop-core/authedDropClient.d.ts +100 -0
  19. package/dist/drop-core/authedDropClient.js +109 -0
  20. package/dist/drop-core/authedDropClient.test.d.ts +1 -0
  21. package/dist/{components/preact/DropZone/drop-core → drop-core}/buildClient.d.ts +32 -26
  22. package/dist/drop-core/buildClient.js +84 -0
  23. package/dist/drop-core/buildClient.test.d.ts +1 -0
  24. package/dist/drop-core/buildStash.d.ts +37 -0
  25. package/dist/drop-core/buildStash.js +84 -0
  26. package/dist/drop-core/buildStash.test.d.ts +0 -0
  27. package/dist/{components/preact/DropZone/drop-core → drop-core}/deploy.d.ts +7 -0
  28. package/dist/drop-core/deploy.js +53 -0
  29. package/dist/drop-core/deploy.test.d.ts +1 -0
  30. package/dist/drop-core/detectBuild.test.d.ts +1 -0
  31. package/dist/drop-core/digest.test.d.ts +1 -0
  32. package/dist/{components/preact/DropZone/drop-core → drop-core}/errors.js +1 -1
  33. package/dist/drop-core/errors.test.d.ts +1 -0
  34. package/dist/drop-core/fileTypes.test.d.ts +1 -0
  35. package/dist/{components/preact/DropZone/drop-core → drop-core}/index.d.ts +3 -0
  36. package/dist/drop-core/index.js +51 -0
  37. package/dist/{components/preact/DropZone/drop-core → drop-core}/readFiles.js +2 -2
  38. package/dist/drop-core/readFiles.test.d.ts +1 -0
  39. package/dist/{components/preact/DropZone/drop-core → drop-core}/types.d.ts +10 -0
  40. package/dist/{components/preact/DropZone/drop-core → drop-core}/zip.js +1 -1
  41. package/dist/drop-core/zip.test.d.ts +1 -0
  42. package/package.json +4 -1
  43. package/packages/components/index.ts +19 -0
  44. package/packages/components/preact/DropZone/DropZone.test.ts +71 -0
  45. package/packages/components/preact/DropZone/DropZone.tsx +32 -2
  46. package/packages/components/preact/DropZone/index.tsx +14 -3
  47. package/packages/components/preact/DropZone/useDropDeploy.test.ts +376 -0
  48. package/packages/components/preact/DropZone/useDropDeploy.ts +305 -134
  49. package/packages/components/preact/index.ts +19 -2
  50. package/packages/drop-core/analytics.test.ts +17 -0
  51. package/packages/drop-core/analytics.ts +122 -0
  52. package/packages/drop-core/authedApi.test.ts +100 -0
  53. package/packages/drop-core/authedApi.ts +94 -0
  54. package/packages/drop-core/authedDropClient.test.ts +196 -0
  55. package/packages/drop-core/authedDropClient.ts +210 -0
  56. package/packages/drop-core/buildClient.test.ts +112 -0
  57. package/packages/{components/preact/DropZone/drop-core → drop-core}/buildClient.ts +55 -70
  58. package/packages/drop-core/buildStash.test.ts +85 -0
  59. package/packages/drop-core/buildStash.ts +185 -0
  60. package/packages/drop-core/deploy.test.ts +135 -0
  61. package/packages/{components/preact/DropZone/drop-core → drop-core}/deploy.ts +18 -4
  62. package/packages/drop-core/detectBuild.test.ts +139 -0
  63. package/packages/drop-core/digest.test.ts +24 -0
  64. package/packages/drop-core/errors.test.ts +69 -0
  65. package/packages/{components/preact/DropZone/drop-core → drop-core}/errors.ts +1 -1
  66. package/packages/drop-core/fileTypes.test.ts +37 -0
  67. package/packages/{components/preact/DropZone/drop-core → drop-core}/index.ts +3 -0
  68. package/packages/drop-core/readFiles.test.ts +125 -0
  69. package/packages/{components/preact/DropZone/drop-core → drop-core}/types.ts +12 -6
  70. package/packages/drop-core/zip.test.ts +92 -0
  71. package/dist/components/preact/DropZone/drop-core/authedDropClient.d.ts +0 -77
  72. package/dist/components/preact/DropZone/drop-core/authedDropClient.js +0 -97
  73. package/dist/components/preact/DropZone/drop-core/buildClient.js +0 -92
  74. package/dist/components/preact/DropZone/drop-core/deploy.js +0 -48
  75. package/dist/components/preact/DropZone/drop-core/index.js +0 -36
  76. package/packages/components/preact/DropZone/drop-core/authedDropClient.ts +0 -185
  77. /package/dist/{components/preact/DropZone/drop-core → drop-core}/client.d.ts +0 -0
  78. /package/dist/{components/preact/DropZone/drop-core → drop-core}/client.js +0 -0
  79. /package/dist/{components/preact/DropZone/drop-core → drop-core}/detectBuild.d.ts +0 -0
  80. /package/dist/{components/preact/DropZone/drop-core → drop-core}/detectBuild.js +0 -0
  81. /package/dist/{components/preact/DropZone/drop-core → drop-core}/digest.d.ts +0 -0
  82. /package/dist/{components/preact/DropZone/drop-core → drop-core}/digest.js +0 -0
  83. /package/dist/{components/preact/DropZone/drop-core → drop-core}/errors.d.ts +0 -0
  84. /package/dist/{components/preact/DropZone/drop-core → drop-core}/fileTypes.d.ts +0 -0
  85. /package/dist/{components/preact/DropZone/drop-core → drop-core}/fileTypes.js +0 -0
  86. /package/dist/{components/preact/DropZone/drop-core → drop-core}/readFiles.d.ts +0 -0
  87. /package/dist/{components/preact/DropZone/drop-core → drop-core}/types.js +0 -0
  88. /package/dist/{components/preact/DropZone/drop-core → drop-core}/zip.d.ts +0 -0
  89. /package/packages/{components/preact/DropZone/drop-core → drop-core}/client.ts +0 -0
  90. /package/packages/{components/preact/DropZone/drop-core → drop-core}/detectBuild.ts +0 -0
  91. /package/packages/{components/preact/DropZone/drop-core → drop-core}/digest.ts +0 -0
  92. /package/packages/{components/preact/DropZone/drop-core → drop-core}/fileTypes.ts +0 -0
  93. /package/packages/{components/preact/DropZone/drop-core → drop-core}/readFiles.ts +0 -0
  94. /package/packages/{components/preact/DropZone/drop-core → drop-core}/zip.ts +0 -0
@@ -0,0 +1,51 @@
1
+ import { getDigest as o } from "./digest.js";
2
+ import { getSingleNonIndexHtmlFileName as i, hasMultipleHtmlFilesWithoutIndex as l, readDataTransfer as p, readFileList as a, renameSingleNonIndexHtmlToIndex as d } from "./readFiles.js";
3
+ import { getFileTypes as m } from "./fileTypes.js";
4
+ import { detectBuild as u, inferBuildSettings as s } from "./detectBuild.js";
5
+ import { AnonymousDropClient as f, apiError as D } from "./client.js";
6
+ import { DEFAULT_API_BASE as A, DEFAULT_POLL_INTERVAL_MS as T, DEFAULT_PROXY_BASE as h, DEFAULT_TIMEOUT_MS as F, createSiteInAccount as B, pollDeployUntilSettled as _ } from "./authedApi.js";
7
+ import { AuthenticatedDropClient as g } from "./authedDropClient.js";
8
+ import { AuthenticatedBuildClient as L } from "./buildClient.js";
9
+ import { generateNetlifyToml as y, zipFiles as U } from "./zip.js";
10
+ import { clearDropStash as M, hasDropStashMarker as O, loadDropStash as P, saveDropStash as H } from "./buildStash.js";
11
+ import { deployBuild as z, deployFiles as V, deployZippedBuild as Z } from "./deploy.js";
12
+ import { BuildCreateError as v, BuildFailedError as W, BuildTimeoutError as X, NotAuthenticatedError as Y, SiteCreateError as b, UnsupportedDropError as j, humanizeDropError as q } from "./errors.js";
13
+ import { DROPZONE_EVENTS as G } from "./analytics.js";
14
+ export {
15
+ f as AnonymousDropClient,
16
+ L as AuthenticatedBuildClient,
17
+ g as AuthenticatedDropClient,
18
+ v as BuildCreateError,
19
+ W as BuildFailedError,
20
+ X as BuildTimeoutError,
21
+ A as DEFAULT_API_BASE,
22
+ T as DEFAULT_POLL_INTERVAL_MS,
23
+ h as DEFAULT_PROXY_BASE,
24
+ F as DEFAULT_TIMEOUT_MS,
25
+ G as DROPZONE_EVENTS,
26
+ Y as NotAuthenticatedError,
27
+ b as SiteCreateError,
28
+ j as UnsupportedDropError,
29
+ D as apiError,
30
+ M as clearDropStash,
31
+ B as createSiteInAccount,
32
+ z as deployBuild,
33
+ V as deployFiles,
34
+ Z as deployZippedBuild,
35
+ u as detectBuild,
36
+ y as generateNetlifyToml,
37
+ o as getDigest,
38
+ m as getFileTypes,
39
+ i as getSingleNonIndexHtmlFileName,
40
+ O as hasDropStashMarker,
41
+ l as hasMultipleHtmlFilesWithoutIndex,
42
+ q as humanizeDropError,
43
+ s as inferBuildSettings,
44
+ P as loadDropStash,
45
+ _ as pollDeployUntilSettled,
46
+ p as readDataTransfer,
47
+ a as readFileList,
48
+ d as renameSingleNonIndexHtmlToIndex,
49
+ H as saveDropStash,
50
+ U as zipFiles
51
+ };
@@ -1,4 +1,4 @@
1
- import { g as P } from "../../../../chunks/_commonjsHelpers.C6fGbg64.js";
1
+ import { g as P } from "../chunks/_commonjsHelpers.C6fGbg64.js";
2
2
  import { UnsupportedDropError as U } from "./errors.js";
3
3
  var L = { exports: {} }, G = L.exports, D;
4
4
  function J() {
@@ -579,7 +579,7 @@ async function Q(y) {
579
579
  return M(w);
580
580
  }
581
581
  async function I(y) {
582
- const { unzip: m } = await import("../../../../chunks/browser.Ca2rTNTu.js"), w = new Uint8Array(await y.arrayBuffer()), _ = await new Promise(
582
+ const { unzip: m } = await import("../chunks/browser.Ca2rTNTu.js"), w = new Uint8Array(await y.arrayBuffer()), _ = await new Promise(
583
583
  (v, s) => m(w, (g, u) => g ? s(g) : v(u))
584
584
  ), h = [];
585
585
  for (const [v, s] of Object.entries(_)) {
@@ -0,0 +1 @@
1
+ export {};
@@ -41,3 +41,13 @@ export interface DeployProgress {
41
41
  uploaded?: number;
42
42
  total?: number;
43
43
  }
44
+ /** The subset of a Netlify Site the drop flow needs to redirect and report. */
45
+ export interface BuildSite {
46
+ /** site id (UUID) */
47
+ id: string;
48
+ /** the *.netlify.app subdomain, also the app's URL segment */
49
+ name: string;
50
+ /** https://<name>.netlify.app */
51
+ ssl_url?: string;
52
+ url?: string;
53
+ }
@@ -29,7 +29,7 @@ async function $(e, { name: i = "source.zip", synthesizeNetlifyToml: p = !0 } =
29
29
  ${n}` : n;
30
30
  l["netlify.toml"] = m.encode(c);
31
31
  }
32
- const { zip: f } = await import("../../../../chunks/browser.Ca2rTNTu.js"), o = await new Promise(
32
+ const { zip: f } = await import("../chunks/browser.Ca2rTNTu.js"), o = await new Promise(
33
33
  (t, n) => f(l, { level: 6 }, (c, s) => c ? n(c) : t(s))
34
34
  ), u = o.buffer.slice(
35
35
  o.byteOffset,
@@ -0,0 +1 @@
1
+ export {};
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.31.0-alpha.2",
4
+ "version": "1.31.0-alpha.4",
5
5
  "type": "module",
6
6
  "main": "dist/components/preact/index.js",
7
7
  "types": "dist/components/preact/index.d.ts",
@@ -26,6 +26,7 @@
26
26
  ],
27
27
  "exports": {
28
28
  "./preact": "./dist/components/preact/index.js",
29
+ "./drop-core": "./dist/drop-core/index.js",
29
30
  "./assets/*.css": "./dist/assets/*.css",
30
31
  "./assets/icons/*.svg": "./packages/assets/icons/*.svg",
31
32
  "./logos/*.svg": "./packages/assets/logos/*.svg",
@@ -61,7 +62,9 @@
61
62
  "eslint": "^10.0.0",
62
63
  "eslint-config-prettier": "^10.1.1",
63
64
  "eslint-plugin-astro": "^1.3.1",
65
+ "fake-indexeddb": "^6.2.5",
64
66
  "glob": "^11.0.1",
67
+ "happy-dom": "^20.11.6",
65
68
  "jsdom": "^30.0.0",
66
69
  "preact": "^10.26.4",
67
70
  "prettier": "^3.5.3",
@@ -11,6 +11,15 @@ export {
11
11
  AnonymousDropClient,
12
12
  AuthenticatedBuildClient,
13
13
  AuthenticatedDropClient,
14
+ BuildCreateError,
15
+ BuildFailedError,
16
+ BuildTimeoutError,
17
+ DROPZONE_EVENTS,
18
+ getFileTypes,
19
+ humanizeDropError,
20
+ NotAuthenticatedError,
21
+ SiteCreateError,
22
+ UnsupportedDropError,
14
23
  deployBuild,
15
24
  deployFiles,
16
25
  detectBuild,
@@ -23,6 +32,16 @@ export type {
23
32
  AuthenticatedBuildClientConfig,
24
33
  AuthenticatedDropClientConfig,
25
34
  BuildClient,
35
+ BuildDeployOptions,
36
+ BuildReason,
37
+ BuildResponse,
38
+ DeployError,
39
+ DeployStatus,
40
+ DropZoneEventName,
41
+ DropZoneEventProperties,
42
+ TrackFn,
43
+ ZipOptions,
44
+ ZipResult,
26
45
  BuildDeployResult,
27
46
  BuildDetection,
28
47
  BuildSite,
@@ -0,0 +1,71 @@
1
+ // @vitest-environment happy-dom
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import { h, render } from 'preact';
4
+ import DropZone from './DropZone';
5
+
6
+ function mountZone(props: Record<string, unknown> = {}) {
7
+ const events: Array<{ event: string; props: Record<string, unknown> | undefined }> = [];
8
+ const container = document.createElement('div');
9
+ document.body.appendChild(container);
10
+ render(
11
+ h(DropZone as never, {
12
+ onTrack: (event: string, properties?: Record<string, unknown>) =>
13
+ void events.push({ event, props: properties }),
14
+ ...props,
15
+ }),
16
+ container
17
+ );
18
+ const zone = container.querySelector<HTMLElement>('.n-dropzone')!;
19
+ return {
20
+ events,
21
+ zone,
22
+ unmount: () => {
23
+ render(null, container);
24
+ container.remove();
25
+ },
26
+ };
27
+ }
28
+
29
+ afterEach(() => vi.restoreAllMocks());
30
+
31
+ describe('DropZone', () => {
32
+ it('opens the picker from the keyboard and tracks it as such', () => {
33
+ const { zone, events, unmount } = mountZone();
34
+ zone.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
35
+ expect(events).toEqual([{ event: 'dropzone_browse_opened', props: { method: 'keyboard' } }]);
36
+ unmount();
37
+ });
38
+
39
+ it("opens the picker from a click on the zone's own empty area", () => {
40
+ const { zone, events, unmount } = mountZone();
41
+ zone.dispatchEvent(new MouseEvent('click', { bubbles: true }));
42
+ expect(events).toEqual([{ event: 'dropzone_browse_opened', props: { method: 'click' } }]);
43
+ unmount();
44
+ });
45
+
46
+ it('stamps dropzone_id onto every event when analyticsId is set — and only then', () => {
47
+ const tagged = mountZone({ analyticsId: 'homepage_hero' });
48
+ tagged.zone.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true }));
49
+ expect(tagged.events[0].props).toEqual({ dropzone_id: 'homepage_hero', method: 'keyboard' });
50
+ tagged.unmount();
51
+
52
+ const untagged = mountZone();
53
+ untagged.zone.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true }));
54
+ expect(untagged.events[0].props).not.toHaveProperty('dropzone_id');
55
+ untagged.unmount();
56
+ });
57
+
58
+ it('mirrors the deploy status on data-state for bare-mode consumers', () => {
59
+ const { zone, unmount } = mountZone({ showStatus: false });
60
+ // Idle at rest — the attribute CSS keys off (`[data-state='error']` etc.).
61
+ expect(zone.getAttribute('data-state')).toBe('idle');
62
+ expect(zone.className).toContain('is-bare');
63
+ unmount();
64
+ });
65
+
66
+ it('renders no overlay until there is something to show', () => {
67
+ const { zone, unmount } = mountZone();
68
+ expect(zone.querySelector('.n-dropzone-overlay')).toBeNull();
69
+ unmount();
70
+ });
71
+ });
@@ -1,13 +1,14 @@
1
1
  import { useEffect, useRef, useState } from 'preact/hooks';
2
2
  import type { ComponentChildren } from 'preact';
3
3
  import {
4
+ DROPZONE_EVENTS,
4
5
  getFileTypes,
5
6
  readDataTransfer,
6
7
  readFileList,
7
8
  type BuildClient,
8
9
  type BuildDetection,
9
10
  type DropClient,
10
- } from './drop-core';
11
+ } from '../../../drop-core';
11
12
  import {
12
13
  useDropDeploy,
13
14
  type DeployedBuild,
@@ -93,6 +94,13 @@ interface Props {
93
94
  * static path. Distinct from `client`, which is the anonymous fallback.
94
95
  */
95
96
  authenticatedDropClient?: DropClient;
97
+ /**
98
+ * API root for the authenticated paths' JSON calls, which go through your
99
+ * access-control rewrite so the session cookie authorizes them. Defaults to
100
+ * `/access-control/bb-api/api/v1`. (Uploads always go direct to
101
+ * `api.netlify.com` — the proxy can't carry bodies that large.)
102
+ */
103
+ proxyBase?: string;
96
104
  /** Create the visitor's new project in this account. Omit for their default account. */
97
105
  accountSlug?: string;
98
106
  /**
@@ -116,6 +124,22 @@ interface Props {
116
124
  * redirects. The static drop path is unaffected either way.
117
125
  */
118
126
  onBuildRequired?: (info: BuildDetection) => void;
127
+ /**
128
+ * Called instead of the `buildSignupUrl` redirect when a build-required drop
129
+ * can't be built here (no session). By this point the drop has been stashed
130
+ * on this origin (`stashed` says whether that succeeded) — own the hand-off
131
+ * however fits your auth flow, e.g. open a signup popup that keeps the
132
+ * visitor on the page. Once they're back authenticated, a remount of the
133
+ * zone deploys the stash automatically.
134
+ */
135
+ onBuildSignupHandoff?: (info: { stashed: boolean; detection: BuildDetection }) => void;
136
+ /**
137
+ * Deploy a previously stashed build drop automatically when the zone mounts
138
+ * with an authenticated visitor (default `true`). The stash is written when a
139
+ * logged-out build drop is handed to signup; see
140
+ * [Signup hand-off and auto-resume](#signup-hand-off-and-auto-resume).
141
+ */
142
+ resumeStashedBuilds?: boolean;
119
143
  /** Called once the deploy is live. */
120
144
  onDeploy?: (result: DeployedSite) => void;
121
145
  /**
@@ -180,10 +204,13 @@ export default function DropZone({
180
204
  getUploadToken,
181
205
  buildClient,
182
206
  authenticatedDropClient,
207
+ proxyBase,
183
208
  accountSlug,
184
209
  buildDeployUrl = defaultBuildDeployUrl,
185
210
  waitForBuild,
186
211
  onBuildRequired,
212
+ onBuildSignupHandoff,
213
+ resumeStashedBuilds,
187
214
  onDeploy,
188
215
  onBuildDeploy,
189
216
  onError,
@@ -206,10 +233,13 @@ export default function DropZone({
206
233
  getUploadToken,
207
234
  buildClient,
208
235
  authenticatedDropClient,
236
+ proxyBase,
209
237
  accountSlug,
210
238
  buildDeployUrl,
211
239
  waitForBuild,
212
240
  onBuildRequired,
241
+ onBuildSignupHandoff,
242
+ resumeStashedBuilds,
213
243
  onDeploy,
214
244
  onBuildDeploy,
215
245
  onError,
@@ -220,7 +250,7 @@ export default function DropZone({
220
250
 
221
251
  const inputRef = useRef<HTMLInputElement>(null);
222
252
  const openPicker = (method: 'keyboard' | 'click') => {
223
- track('dropzone_browse_opened', { method });
253
+ track(DROPZONE_EVENTS.BROWSE_OPENED, { method });
224
254
  inputRef.current?.click();
225
255
  };
226
256
 
@@ -1,6 +1,7 @@
1
1
  export { default as DropZone } from './DropZone';
2
2
  export {
3
3
  AnonymousDropClient,
4
+ DROPZONE_EVENTS,
4
5
  AuthenticatedBuildClient,
5
6
  AuthenticatedDropClient,
6
7
  BuildCreateError,
@@ -18,9 +19,13 @@ export {
18
19
  SiteCreateError,
19
20
  UnsupportedDropError,
20
21
  zipFiles,
21
- } from './drop-core';
22
+ } from '../../../drop-core';
22
23
  export type {
23
24
  AuthenticatedBuildClientConfig,
25
+ DropMethod,
26
+ DropZoneEventName,
27
+ DropZoneEventProperties,
28
+ TrackFn,
24
29
  AuthenticatedDropClientConfig,
25
30
  BuildClient,
26
31
  BuildDeployOptions,
@@ -39,5 +44,11 @@ export type {
39
44
  ProcessedFile,
40
45
  ZipOptions,
41
46
  ZipResult,
42
- } from './drop-core';
43
- export type { DeployedBuild, DeployedSite, DeployError, DeployStatus } from './useDropDeploy';
47
+ } from '../../../drop-core';
48
+ export type {
49
+ DeployedBuild,
50
+ DeployedSite,
51
+ DeployError,
52
+ DeploySource,
53
+ DeployStatus,
54
+ } from './useDropDeploy';