@jobber/components 7.10.0 → 7.10.1-JOB-163813-14f3dc5.2

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.
@@ -21,10 +21,12 @@ require('../floating-ui.react-dom-cjs.js');
21
21
  require('../useFormFieldFocus-cjs.js');
22
22
  require('../maxHeight-cjs.js');
23
23
  require('../useRenderElement-cjs.js');
24
- require('../BottomSheet-cjs.js');
25
- require('../DrawerRoot-cjs.js');
26
24
  require('../OverlaySeparator-cjs.js');
27
25
  require('../Separator-cjs.js');
26
+ require('../BottomSheet-cjs.js');
27
+ require('../DrawerRoot-cjs.js');
28
+ require('../HelperText-cjs.js');
29
+ require('../Text-cjs.js');
28
30
  require('../MenuSubmenuTrigger-cjs.js');
29
31
 
30
32
 
@@ -19,8 +19,10 @@ import '../floating-ui.react-dom-es.js';
19
19
  import '../useFormFieldFocus-es.js';
20
20
  import '../maxHeight-es.js';
21
21
  import '../useRenderElement-es.js';
22
- import '../BottomSheet-es.js';
23
- import '../DrawerRoot-es.js';
24
22
  import '../OverlaySeparator-es.js';
25
23
  import '../Separator-es.js';
24
+ import '../BottomSheet-es.js';
25
+ import '../DrawerRoot-es.js';
26
+ import '../HelperText-es.js';
27
+ import '../Text-es.js';
26
28
  import '../MenuSubmenuTrigger-es.js';
@@ -22,10 +22,12 @@ require('../floating-ui.react-dom-cjs.js');
22
22
  require('../useFormFieldFocus-cjs.js');
23
23
  require('../maxHeight-cjs.js');
24
24
  require('../useRenderElement-cjs.js');
25
- require('../BottomSheet-cjs.js');
26
- require('../DrawerRoot-cjs.js');
27
25
  require('../OverlaySeparator-cjs.js');
28
26
  require('../Separator-cjs.js');
27
+ require('../BottomSheet-cjs.js');
28
+ require('../DrawerRoot-cjs.js');
29
+ require('../HelperText-cjs.js');
30
+ require('../Text-cjs.js');
29
31
  require('../MenuSubmenuTrigger-cjs.js');
30
32
  require('../Content-cjs.js');
31
33
  require('../Emphasis-cjs.js');
@@ -20,10 +20,12 @@ import '../floating-ui.react-dom-es.js';
20
20
  import '../useFormFieldFocus-es.js';
21
21
  import '../maxHeight-es.js';
22
22
  import '../useRenderElement-es.js';
23
- import '../BottomSheet-es.js';
24
- import '../DrawerRoot-es.js';
25
23
  import '../OverlaySeparator-es.js';
26
24
  import '../Separator-es.js';
25
+ import '../BottomSheet-es.js';
26
+ import '../DrawerRoot-es.js';
27
+ import '../HelperText-es.js';
28
+ import '../Text-es.js';
27
29
  import '../MenuSubmenuTrigger-es.js';
28
30
  import '../Content-es.js';
29
31
  import '../Emphasis-es.js';
@@ -23,13 +23,14 @@ export interface GalleryProps {
23
23
  */
24
24
  onDelete?(file: GalleryFile): void;
25
25
  }
26
- export interface GalleryFile extends Pick<FileUpload, "key" | "name" | "type" | "size" | "progress"> {
26
+ export interface GalleryFile extends Pick<FileUpload, "key" | "name" | "type" | "size" | "progress" | "getObjectUrl"> {
27
27
  /**
28
28
  * The thumbnail url of the file.
29
29
  */
30
30
  readonly thumbnailSrc?: string;
31
31
  /**
32
- * The data url of the file.
32
+ * The data url of the file. For in-memory files,
33
+ * prefer using `getObjectUrl`.
33
34
  */
34
35
  readonly src: string | (() => Promise<string>);
35
36
  }
@@ -38,12 +38,21 @@ function Gallery({ files, size = "base", max, onDelete }) {
38
38
  React.createElement(LightBox.LightBox, { open: lightboxOpen, images: images, imageIndex: lightboxIndex, onRequestClose: handleLightboxClose })));
39
39
  function handleThumbnailClicked(index) {
40
40
  return tslib_es6.__awaiter(this, void 0, void 0, function* () {
41
- if (Thumbnail.isPreviewableImage(files[index].type)) {
41
+ const file = files[index];
42
+ if (Thumbnail.isPreviewableImage(file.type)) {
42
43
  handleLightboxOpen(index);
44
+ return;
43
45
  }
44
- else {
45
- window.open(yield getFileSrc(files[index]), "_blank");
46
+ if (file.getObjectUrl) {
47
+ // Schedule revoke for the next frame so the new tab has time to begin
48
+ // loading the resource before the URL is invalidated.
49
+ const { url, revoke } = file.getObjectUrl();
50
+ window.open(url, "_blank");
51
+ requestAnimationFrame(revoke);
52
+ return;
46
53
  }
54
+ // Fallback for GalleryFile objects without getObjectUrl.
55
+ window.open(yield getFileSrc(file), "_blank");
47
56
  });
48
57
  }
49
58
  function handleLightboxOpen(index) {
@@ -36,12 +36,21 @@ function Gallery({ files, size = "base", max, onDelete }) {
36
36
  React__default.createElement(LightBox, { open: lightboxOpen, images: images, imageIndex: lightboxIndex, onRequestClose: handleLightboxClose })));
37
37
  function handleThumbnailClicked(index) {
38
38
  return __awaiter(this, void 0, void 0, function* () {
39
- if (isPreviewableImage(files[index].type)) {
39
+ const file = files[index];
40
+ if (isPreviewableImage(file.type)) {
40
41
  handleLightboxOpen(index);
42
+ return;
41
43
  }
42
- else {
43
- window.open(yield getFileSrc(files[index]), "_blank");
44
+ if (file.getObjectUrl) {
45
+ // Schedule revoke for the next frame so the new tab has time to begin
46
+ // loading the resource before the URL is invalidated.
47
+ const { url, revoke } = file.getObjectUrl();
48
+ window.open(url, "_blank");
49
+ requestAnimationFrame(revoke);
50
+ return;
44
51
  }
52
+ // Fallback for GalleryFile objects without getObjectUrl.
53
+ window.open(yield getFileSrc(file), "_blank");
45
54
  });
46
55
  }
47
56
  function handleLightboxOpen(index) {
@@ -33,9 +33,18 @@ export interface FileUpload {
33
33
  */
34
34
  readonly uploadUrl?: string;
35
35
  /**
36
- * The data url of the file.
36
+ * The data url of the file. For in-memory files, prefer using `getObjectUrl`.
37
37
  */
38
38
  src(): Promise<string>;
39
+ /**
40
+ * Returns a blob object URL for the file, paired with a `revoke` function to
41
+ * release it. Call `revoke` once you are done with the URL. Preferred over
42
+ * `src()`.
43
+ */
44
+ getObjectUrl?(): {
45
+ url: string;
46
+ revoke: () => void;
47
+ };
39
48
  /**
40
49
  * Callback for when the image file fails to load.
41
50
  *
@@ -1713,6 +1713,7 @@ function getFileUpload(file, key, uploadUrl) {
1713
1713
  size: file.size,
1714
1714
  progress: 0,
1715
1715
  src: getSrc,
1716
+ getObjectUrl,
1716
1717
  uploadUrl,
1717
1718
  };
1718
1719
  function getSrc() {
@@ -1732,6 +1733,10 @@ function getFileUpload(file, key, uploadUrl) {
1732
1733
  });
1733
1734
  return promise;
1734
1735
  }
1736
+ function getObjectUrl() {
1737
+ const url = URL.createObjectURL(file);
1738
+ return { url, revoke: () => URL.revokeObjectURL(url) };
1739
+ }
1735
1740
  }
1736
1741
  /**
1737
1742
  * Upsert a given `FileUpload` into an array of `FileUpload`s.
@@ -1711,6 +1711,7 @@ function getFileUpload(file, key, uploadUrl) {
1711
1711
  size: file.size,
1712
1712
  progress: 0,
1713
1713
  src: getSrc,
1714
+ getObjectUrl,
1714
1715
  uploadUrl,
1715
1716
  };
1716
1717
  function getSrc() {
@@ -1730,6 +1731,10 @@ function getFileUpload(file, key, uploadUrl) {
1730
1731
  });
1731
1732
  return promise;
1732
1733
  }
1734
+ function getObjectUrl() {
1735
+ const url = URL.createObjectURL(file);
1736
+ return { url, revoke: () => URL.revokeObjectURL(url) };
1737
+ }
1733
1738
  }
1734
1739
  /**
1735
1740
  * Upsert a given `FileUpload` into an array of `FileUpload`s.
@@ -19,10 +19,12 @@ require('../Typography-cjs.js');
19
19
  require('../useFormFieldFocus-cjs.js');
20
20
  require('../maxHeight-cjs.js');
21
21
  require('../useRenderElement-cjs.js');
22
- require('../BottomSheet-cjs.js');
23
- require('../DrawerRoot-cjs.js');
24
22
  require('../OverlaySeparator-cjs.js');
25
23
  require('../Separator-cjs.js');
24
+ require('../BottomSheet-cjs.js');
25
+ require('../DrawerRoot-cjs.js');
26
+ require('../HelperText-cjs.js');
27
+ require('../Text-cjs.js');
26
28
  require('../MenuSubmenuTrigger-cjs.js');
27
29
 
28
30
 
@@ -17,8 +17,10 @@ import '../Typography-es.js';
17
17
  import '../useFormFieldFocus-es.js';
18
18
  import '../maxHeight-es.js';
19
19
  import '../useRenderElement-es.js';
20
- import '../BottomSheet-es.js';
21
- import '../DrawerRoot-es.js';
22
20
  import '../OverlaySeparator-es.js';
23
21
  import '../Separator-es.js';
22
+ import '../BottomSheet-es.js';
23
+ import '../DrawerRoot-es.js';
24
+ import '../HelperText-es.js';
25
+ import '../Text-es.js';
24
26
  import '../MenuSubmenuTrigger-es.js';
package/dist/Menu-cjs.js CHANGED
@@ -13,8 +13,9 @@ var maxHeight = require('./maxHeight-cjs.js');
13
13
  var floatingUi_reactDom = require('./floating-ui.react-dom-cjs.js');
14
14
  var tslib_es6 = require('./tslib.es6-cjs.js');
15
15
  var useRenderElement = require('./useRenderElement-cjs.js');
16
- var BottomSheet = require('./BottomSheet-cjs.js');
17
16
  var OverlaySeparator = require('./OverlaySeparator-cjs.js');
17
+ var BottomSheet = require('./BottomSheet-cjs.js');
18
+ require('./HelperText-cjs.js');
18
19
  var MenuSubmenuTrigger$1 = require('./MenuSubmenuTrigger-cjs.js');
19
20
 
20
21
  var styles$2 = {"wrapper":"h-nk89U2n6Q-","floatingContainer":"krpkWzoaVcc-","menu":"_7sU7mp1w0jM-","legacySection":"_4x-vvEmn4gM-","separator":"i0QNcs4S-wk-","triggerWrapper":"_7CsejipGrzM-","ariaMenu":"bO7lGVQC42c-","ariaItem":"u6fDgbWmPck-","ariaSection":"-TSNrZBKZJI-","ariaSectionHeader":"zs7dS2pKjEw-","sectionHeader":"MZJgunQcmdQ-","legacyAction":"_-1GOlrzd098-","action":"NYXV5w4pd0c-","destructive":"baYK2zQ6-GA-","overlay":"A7T14ALVEKg-","fullWidth":"Lgbn9IRPI5Y-","screenReaderOnly":"o-ps580KdWI-","spinning":"f1oTdSTeUOM-"};
package/dist/Menu-es.js CHANGED
@@ -11,8 +11,9 @@ import { c as calculateMaxHeight } from './maxHeight-es.js';
11
11
  import { o as offset, f as flip, d as size, b as autoUpdate } from './floating-ui.react-dom-es.js';
12
12
  import { _ as __rest } from './tslib.es6-es.js';
13
13
  import { m as mergeProps } from './useRenderElement-es.js';
14
- import { B as BottomSheet } from './BottomSheet-es.js';
15
14
  import { O as OverlaySeparator } from './OverlaySeparator-es.js';
15
+ import { B as BottomSheet } from './BottomSheet-es.js';
16
+ import './HelperText-es.js';
16
17
  import { D as DrawerTrigger, a as DrawerTitle, b as DrawerClose, M as MenuTrigger$1, c as MenuLinkItem, d as MenuItem$1, e as MenuRadioItem$1, f as MenuRadioItemIndicator, g as MenuSubmenuTrigger$1, h as MenuRoot$1, i as MenuPortal$1, j as MenuPositioner, k as MenuPopup, l as MenuRadioGroup$1, m as MenuGroup$1, n as MenuSubmenuRoot, o as MenuGroupLabel$1 } from './MenuSubmenuTrigger-es.js';
17
18
 
18
19
  var styles$2 = {"wrapper":"h-nk89U2n6Q-","floatingContainer":"krpkWzoaVcc-","menu":"_7sU7mp1w0jM-","legacySection":"_4x-vvEmn4gM-","separator":"i0QNcs4S-wk-","triggerWrapper":"_7CsejipGrzM-","ariaMenu":"bO7lGVQC42c-","ariaItem":"u6fDgbWmPck-","ariaSection":"-TSNrZBKZJI-","ariaSectionHeader":"zs7dS2pKjEw-","sectionHeader":"MZJgunQcmdQ-","legacyAction":"_-1GOlrzd098-","action":"NYXV5w4pd0c-","destructive":"baYK2zQ6-GA-","overlay":"A7T14ALVEKg-","fullWidth":"Lgbn9IRPI5Y-","screenReaderOnly":"o-ps580KdWI-","spinning":"f1oTdSTeUOM-"};
@@ -26,10 +26,11 @@ require('../floating-ui.react-dom-cjs.js');
26
26
  require('../useFormFieldFocus-cjs.js');
27
27
  require('../maxHeight-cjs.js');
28
28
  require('../useRenderElement-cjs.js');
29
- require('../BottomSheet-cjs.js');
30
- require('../DrawerRoot-cjs.js');
31
29
  require('../OverlaySeparator-cjs.js');
32
30
  require('../Separator-cjs.js');
31
+ require('../BottomSheet-cjs.js');
32
+ require('../DrawerRoot-cjs.js');
33
+ require('../HelperText-cjs.js');
33
34
  require('../MenuSubmenuTrigger-cjs.js');
34
35
  require('../filterDataAttributes-cjs.js');
35
36
 
@@ -24,9 +24,10 @@ import '../floating-ui.react-dom-es.js';
24
24
  import '../useFormFieldFocus-es.js';
25
25
  import '../maxHeight-es.js';
26
26
  import '../useRenderElement-es.js';
27
- import '../BottomSheet-es.js';
28
- import '../DrawerRoot-es.js';
29
27
  import '../OverlaySeparator-es.js';
30
28
  import '../Separator-es.js';
29
+ import '../BottomSheet-es.js';
30
+ import '../DrawerRoot-es.js';
31
+ import '../HelperText-es.js';
31
32
  import '../MenuSubmenuTrigger-es.js';
32
33
  import '../filterDataAttributes-es.js';
@@ -24,6 +24,17 @@ beside each other before wrapping subsequent thumbnails to a new line.
24
24
  Each of the thumbnails the Gallery displays are tab navigatable. A hover state
25
25
  will also slightly dim a particular thumbnail when the cursor hovers over it.
26
26
 
27
+ ## Previewing non-image files
28
+
29
+ When a user clicks an image thumbnail, Gallery opens it in an in-page LightBox.
30
+ For non-image files (PDF, Word, etc.) Gallery instead opens the file in a new
31
+ tab.
32
+
33
+ For files produced by `<InputFile>`, Gallery uses the file's `getObjectUrl()`
34
+ method to produce a navigation-safe object URL, opens the new tab, then revokes
35
+ the URL on the next animation frame. Consumers passing `FileUpload` objects from
36
+ `<InputFile>` directly to `<Gallery>` get this behavior automatically.
37
+
27
38
  ## Mockup
28
39
 
29
40
 
@@ -58,6 +58,54 @@ updating an array of `FileUpload`s based on their `key` as uploads progress.
58
58
  export function updateFiles(updatedFile: FileUpload, files: FileUpload[]);
59
59
  ```
60
60
 
61
+ ### Producing URLs for a `FileUpload`
62
+
63
+ #### `getObjectUrl()` — preferred
64
+
65
+ `getObjectUrl()` returns an object URL paired with a `revoke` function. The URL
66
+ works anywhere a URL is consumed — `<img>`, `background-image`, fetch, download
67
+ links — and is also valid for top-frame navigation (`window.open`,
68
+ `<a target="_blank">`), where data URLs are blocked. This is the recommended
69
+ method for new code.
70
+
71
+ **Always call `revoke()` when you no longer need the URL**, regardless of how
72
+ you used it. Object URLs pin the underlying file in memory until revoked. The
73
+ browser auto-revokes on document unload as a safety net, so short-lived flows
74
+ don't leak meaningfully — but explicit revocation keeps memory bounded in
75
+ long-lived flows (e.g., chat-style attachment composers).
76
+
77
+ Pick the revoke timing that matches the usage:
78
+
79
+ ```tsx
80
+ // Navigation: schedule revoke after the new tab has time to begin loading
81
+ const { url, revoke } = file.getObjectUrl();
82
+ window.open(url, "_blank");
83
+ requestAnimationFrame(revoke);
84
+ ```
85
+
86
+ ```tsx
87
+ // Long-lived state: revoke when the consumer is done with the file
88
+ useEffect(() => {
89
+ const { url, revoke } = file.getObjectUrl();
90
+ setPreviewUrl(url);
91
+ return revoke;
92
+ }, [file]);
93
+ ```
94
+
95
+ Atlantis `<Gallery>` uses `getObjectUrl()` internally on its non-image preview
96
+ path — passing `FileUpload` objects directly to `<Gallery>` enables PDF and
97
+ other non-image attachment previews without any consumer-side workaround.
98
+
99
+ #### `src()` — existing usage
100
+
101
+ `src()` resolves to a `data:` URL with the file's bytes embedded inline. It
102
+ works for `<img>` rendering and other inline use, but is **blocked** by browsers
103
+ from top-frame navigation (`window.open`, `<a target="_blank">`).
104
+
105
+ Existing callers of `src()` continue to work. For new code, prefer
106
+ `getObjectUrl()` — it covers the same use cases plus navigation, and we are
107
+ moving away from the `src()` pattern over time.
108
+
61
109
  ### validator
62
110
 
63
111
  InputFile can accept a `validator` function as a prop. This will allow you to
package/dist/index.cjs CHANGED
@@ -183,10 +183,11 @@ require('filesize');
183
183
  require('./GridCell-cjs.js');
184
184
  require('axios');
185
185
  require('./useRenderElement-cjs.js');
186
- require('./BottomSheet-cjs.js');
187
- require('./DrawerRoot-cjs.js');
188
186
  require('./OverlaySeparator-cjs.js');
189
187
  require('./Separator-cjs.js');
188
+ require('./BottomSheet-cjs.js');
189
+ require('./DrawerRoot-cjs.js');
190
+ require('./HelperText-cjs.js');
190
191
  require('./MenuSubmenuTrigger-cjs.js');
191
192
  require('./AtlantisPortalContent-cjs.js');
192
193
  require('@jobber/formatters');
package/dist/index.mjs CHANGED
@@ -181,10 +181,11 @@ import 'filesize';
181
181
  import './GridCell-es.js';
182
182
  import 'axios';
183
183
  import './useRenderElement-es.js';
184
- import './BottomSheet-es.js';
185
- import './DrawerRoot-es.js';
186
184
  import './OverlaySeparator-es.js';
187
185
  import './Separator-es.js';
186
+ import './BottomSheet-es.js';
187
+ import './DrawerRoot-es.js';
188
+ import './HelperText-es.js';
188
189
  import './MenuSubmenuTrigger-es.js';
189
190
  import './AtlantisPortalContent-es.js';
190
191
  import '@jobber/formatters';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "7.10.0",
3
+ "version": "7.10.1-JOB-163813-14f3dc5.2+14f3dc56f",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -502,7 +502,7 @@
502
502
  "@base-ui/react": "1.3.0",
503
503
  "@floating-ui/react": "^0.27.5",
504
504
  "@floating-ui/utils": "0.2.11",
505
- "@jobber/formatters": "^0.5.0",
505
+ "@jobber/formatters": "^0.5.1-JOB-163813-14f3dc5.414+14f3dc56f",
506
506
  "@react-types/overlays": "^3.9.4",
507
507
  "@tanstack/react-table": "8.5.13",
508
508
  "@types/color": "^3.0.1",
@@ -528,8 +528,8 @@
528
528
  "devDependencies": {
529
529
  "@apollo/client": "^3.7.10",
530
530
  "@csstools/postcss-global-data": "^1.0.3",
531
- "@jobber/design": "0.99.0",
532
- "@jobber/hooks": "2.19.4",
531
+ "@jobber/design": "0.99.1-JOB-163813-14f3dc5.18+14f3dc56f",
532
+ "@jobber/hooks": "2.19.5-JOB-163813-14f3dc5.41+14f3dc56f",
533
533
  "@rollup/plugin-alias": "^5.1.0",
534
534
  "@rollup/plugin-commonjs": "^25.0.7",
535
535
  "@rollup/plugin-node-resolve": "15.2.3",
@@ -583,5 +583,5 @@
583
583
  "> 1%",
584
584
  "IE 10"
585
585
  ],
586
- "gitHead": "348d1293520051687a9b2d178cf4c5757136e9bf"
586
+ "gitHead": "14f3dc56f82f04ef2c9460089c4e26987286d94f"
587
587
  }