@unicitylabs/sphere-ui 0.1.24 → 0.1.26

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.d.ts CHANGED
@@ -334,8 +334,18 @@ interface MediaGalleryProps {
334
334
  onChange: (items: MediaItem[]) => void;
335
335
  uploadFn: MediaUploadFn;
336
336
  max?: number;
337
+ /**
338
+ * Defer mode: do NOT upload on select. Each chosen screenshot is kept locally
339
+ * (a File + blob preview) and the current File list is emitted via
340
+ * onFilesChange, so the parent can upload them AFTER the owner entity exists
341
+ * (e.g. project create, before there is an ownerId — mirrors MediaUploader's
342
+ * deferUpload for logo/banner). In this mode `items`/`onChange` are unused for
343
+ * screenshots; the parent owns the upload + persistence.
344
+ */
345
+ deferUpload?: boolean;
346
+ onFilesChange?: (files: File[]) => void;
337
347
  }
338
- declare function MediaGallery({ ownerType, ownerId, items, onChange, uploadFn, max }: MediaGalleryProps): react.JSX.Element;
348
+ declare function MediaGallery({ ownerType, ownerId, items, onChange, uploadFn, max, deferUpload, onFilesChange }: MediaGalleryProps): react.JSX.Element;
339
349
 
340
350
  interface MarketplaceProjectCardProps {
341
351
  name: string;
package/dist/index.js CHANGED
@@ -1691,7 +1691,7 @@ function MediaUploader({
1691
1691
  }
1692
1692
 
1693
1693
  // src/components/media/MediaGallery.tsx
1694
- import { useState as useState8 } from "react";
1694
+ import { useEffect as useEffect6, useState as useState8 } from "react";
1695
1695
  import {
1696
1696
  DndContext,
1697
1697
  closestCenter
@@ -1725,14 +1725,34 @@ function SortableTile({ item, onRemove }) {
1725
1725
  )
1726
1726
  ] });
1727
1727
  }
1728
- function MediaGallery({ ownerType, ownerId, items, onChange, uploadFn, max = 10 }) {
1728
+ function MediaGallery({ ownerType, ownerId, items, onChange, uploadFn, max = 10, deferUpload, onFilesChange }) {
1729
1729
  const [adding, setAdding] = useState8(false);
1730
+ const [pending, setPending] = useState8([]);
1731
+ useEffect6(
1732
+ () => () => {
1733
+ pending.forEach((p) => URL.revokeObjectURL(p.preview));
1734
+ },
1735
+ []
1736
+ // eslint-disable-line react-hooks/exhaustive-deps
1737
+ );
1738
+ const emitPending = (next) => {
1739
+ setPending(next);
1740
+ onFilesChange?.(next.map((p) => p.file));
1741
+ };
1730
1742
  function handleDragEnd(e) {
1731
1743
  if (!e.over || e.active.id === e.over.id) return;
1732
- const oldIndex = items.findIndex((i) => i.url === e.active.id);
1733
- const newIndex = items.findIndex((i) => i.url === e.over.id);
1734
- onChange(arrayMove(items, oldIndex, newIndex));
1744
+ if (deferUpload) {
1745
+ const oldIndex = pending.findIndex((p) => p.preview === e.active.id);
1746
+ const newIndex = pending.findIndex((p) => p.preview === e.over.id);
1747
+ emitPending(arrayMove(pending, oldIndex, newIndex));
1748
+ } else {
1749
+ const oldIndex = items.findIndex((i) => i.url === e.active.id);
1750
+ const newIndex = items.findIndex((i) => i.url === e.over.id);
1751
+ onChange(arrayMove(items, oldIndex, newIndex));
1752
+ }
1735
1753
  }
1754
+ const count = deferUpload ? pending.length : items.length;
1755
+ const tileIds = deferUpload ? pending.map((p) => p.preview) : items.map((i) => i.url);
1736
1756
  return /* @__PURE__ */ jsxs19(
1737
1757
  "div",
1738
1758
  {
@@ -1742,13 +1762,23 @@ function MediaGallery({ ownerType, ownerId, items, onChange, uploadFn, max = 10
1742
1762
  children: [
1743
1763
  /* @__PURE__ */ jsxs19("div", { className: "text-sm text-neutral-700 dark:text-white/70", children: [
1744
1764
  "Screenshots (",
1745
- items.length,
1765
+ count,
1746
1766
  "/",
1747
1767
  max,
1748
1768
  ")"
1749
1769
  ] }),
1750
- /* @__PURE__ */ jsx24(DndContext, { collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx24(SortableContext, { items: items.map((i) => i.url), strategy: horizontalListSortingStrategy, children: /* @__PURE__ */ jsxs19("div", { className: "flex flex-wrap gap-2", children: [
1751
- items.map((item, i) => /* @__PURE__ */ jsx24(
1770
+ /* @__PURE__ */ jsx24(DndContext, { collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx24(SortableContext, { items: tileIds, strategy: horizontalListSortingStrategy, children: /* @__PURE__ */ jsxs19("div", { className: "flex flex-wrap gap-2", children: [
1771
+ deferUpload ? pending.map((p, i) => /* @__PURE__ */ jsx24(
1772
+ SortableTile,
1773
+ {
1774
+ item: { type: "screenshot", url: p.preview },
1775
+ onRemove: () => {
1776
+ URL.revokeObjectURL(p.preview);
1777
+ emitPending(pending.filter((_, j) => j !== i));
1778
+ }
1779
+ },
1780
+ p.preview
1781
+ )) : items.map((item, i) => /* @__PURE__ */ jsx24(
1752
1782
  SortableTile,
1753
1783
  {
1754
1784
  item,
@@ -1756,7 +1786,7 @@ function MediaGallery({ ownerType, ownerId, items, onChange, uploadFn, max = 10
1756
1786
  },
1757
1787
  item.url
1758
1788
  )),
1759
- items.length < max && !adding && /* @__PURE__ */ jsx24(
1789
+ count < max && !adding && /* @__PURE__ */ jsx24(
1760
1790
  "button",
1761
1791
  {
1762
1792
  type: "button",
@@ -1775,7 +1805,16 @@ function MediaGallery({ ownerType, ownerId, items, onChange, uploadFn, max = 10
1775
1805
  ownerType,
1776
1806
  ownerId,
1777
1807
  uploadFn,
1778
- onChange: (url) => {
1808
+ deferUpload,
1809
+ onFileSelected: deferUpload ? (file) => {
1810
+ if (file) {
1811
+ const preview = URL.createObjectURL(file);
1812
+ emitPending([...pending, { file, preview }]);
1813
+ }
1814
+ setAdding(false);
1815
+ } : void 0,
1816
+ onChange: deferUpload ? () => {
1817
+ } : (url) => {
1779
1818
  if (url) {
1780
1819
  const isDuplicate = items.some((i) => i.url === url);
1781
1820
  if (!isDuplicate) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unicitylabs/sphere-ui",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",