@arbidocs/blocks 0.4.156 → 0.4.157

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 (72) hide show
  1. package/dist/ConnectedNativeDocxComparison-2PLOOXSH.js +1 -1
  2. package/dist/ConnectedNativeDocxComparison-S25BPUH5.cjs +1 -1
  3. package/dist/ConnectedNativeDocxEditor-JJAGMHZC.js +1 -1
  4. package/dist/ConnectedNativeDocxEditor-YA4HWLY4.cjs +1 -1
  5. package/dist/ConnectedStreamedWordArtifact-EXYZAU4Y.cjs +1 -1
  6. package/dist/ConnectedStreamedWordArtifact-YAAXY5KY.js +1 -1
  7. package/dist/agents/index.cjs +238 -238
  8. package/dist/agents/index.js +4 -4
  9. package/dist/chat/index.cjs +1 -1
  10. package/dist/chat/index.js +1 -1
  11. package/dist/{chunk-6HMCF4AJ.js → chunk-5ZIYPZYE.js} +1033 -5
  12. package/dist/chunk-5ZIYPZYE.js.map +1 -0
  13. package/dist/{chunk-O3FB62T5.cjs → chunk-6QAAIDQQ.cjs} +47 -47
  14. package/dist/{chunk-O3FB62T5.cjs.map → chunk-6QAAIDQQ.cjs.map} +1 -1
  15. package/dist/{chunk-UKT3WH5Z.cjs → chunk-B3FMUFAW.cjs} +3 -3
  16. package/dist/{chunk-UKT3WH5Z.cjs.map → chunk-B3FMUFAW.cjs.map} +1 -1
  17. package/dist/{chunk-W7CWGURO.js → chunk-FTZ45WHY.js} +6 -685
  18. package/dist/chunk-FTZ45WHY.js.map +1 -0
  19. package/dist/{chunk-HDJRSCRE.cjs → chunk-GC2FSPSQ.cjs} +6 -6
  20. package/dist/{chunk-HDJRSCRE.cjs.map → chunk-GC2FSPSQ.cjs.map} +1 -1
  21. package/dist/{chunk-UKCCV63X.js → chunk-MNG7N6M2.js} +4 -4
  22. package/dist/{chunk-UKCCV63X.js.map → chunk-MNG7N6M2.js.map} +1 -1
  23. package/dist/{chunk-MUDEL7UL.cjs → chunk-NPLGB4LI.cjs} +4 -703
  24. package/dist/chunk-NPLGB4LI.cjs.map +1 -0
  25. package/dist/{chunk-UPMADXDU.js → chunk-P6RIBIVN.js} +3 -3
  26. package/dist/{chunk-UPMADXDU.js.map → chunk-P6RIBIVN.js.map} +1 -1
  27. package/dist/{chunk-WV4TD2HZ.cjs → chunk-QJFJ5JBF.cjs} +1055 -2
  28. package/dist/chunk-QJFJ5JBF.cjs.map +1 -0
  29. package/dist/{chunk-6HG56GCT.js → chunk-QKR5LWDO.js} +4 -4
  30. package/dist/{chunk-6HG56GCT.js.map → chunk-QKR5LWDO.js.map} +1 -1
  31. package/dist/{chunk-YMQDDUKW.js → chunk-WU34CHU5.js} +3 -3
  32. package/dist/{chunk-YMQDDUKW.js.map → chunk-WU34CHU5.js.map} +1 -1
  33. package/dist/{chunk-FEGXFABZ.cjs → chunk-YF3QUHKN.cjs} +3 -3
  34. package/dist/{chunk-FEGXFABZ.cjs.map → chunk-YF3QUHKN.cjs.map} +1 -1
  35. package/dist/connect/docx.cjs +1 -1
  36. package/dist/connect/docx.js +1 -1
  37. package/dist/connect/index.cjs +730 -170
  38. package/dist/connect/index.cjs.map +1 -1
  39. package/dist/connect/index.js +571 -16
  40. package/dist/connect/index.js.map +1 -1
  41. package/dist/connect/viewer.cjs +45 -45
  42. package/dist/connect/viewer.js +7 -7
  43. package/dist/connection/files/index.d.ts +5 -0
  44. package/dist/connection/files/support.d.ts +2 -0
  45. package/dist/connection/files/upload/AddFromAccountsButton.d.ts +16 -0
  46. package/dist/connection/files/upload/ConnectedUpload.d.ts +36 -0
  47. package/dist/connection/files/upload/ConnectedUploadDropzone.d.ts +36 -0
  48. package/dist/connection/files/upload/EmptyWorkspaceUpload.d.ts +13 -0
  49. package/dist/connection/files/upload/useAddFromUrls.d.ts +13 -0
  50. package/dist/document-tools/index.cjs +1 -1
  51. package/dist/document-tools/index.js +1 -1
  52. package/dist/facts/index.cjs +54 -54
  53. package/dist/facts/index.js +4 -4
  54. package/dist/files/PrivacyExplainerModal.d.ts +8 -0
  55. package/dist/files/ShareToggle.d.ts +8 -0
  56. package/dist/files/UrlInputDialog.d.ts +24 -0
  57. package/dist/files/index.cjs +298 -278
  58. package/dist/files/index.d.ts +4 -0
  59. package/dist/files/index.js +2 -2
  60. package/dist/files/media-preview.d.ts +24 -0
  61. package/dist/index.cjs +347 -347
  62. package/dist/index.js +8 -8
  63. package/dist/studio/index.cjs +1 -1
  64. package/dist/studio/index.js +1 -1
  65. package/dist/workflow-canvas/index.cjs +16 -16
  66. package/dist/workflow-canvas/index.js +4 -4
  67. package/node_modules/@arbidocs/coedit/package.json +1 -1
  68. package/package.json +5 -5
  69. package/dist/chunk-6HMCF4AJ.js.map +0 -1
  70. package/dist/chunk-MUDEL7UL.cjs.map +0 -1
  71. package/dist/chunk-W7CWGURO.js.map +0 -1
  72. package/dist/chunk-WV4TD2HZ.cjs.map +0 -1
@@ -5,6 +5,7 @@ var chunkFAXXN7KI_cjs = require('./chunk-FAXXN7KI.cjs');
5
5
  var chunk3VULDTNL_cjs = require('./chunk-3VULDTNL.cjs');
6
6
  var chunk32HW2Q33_cjs = require('./chunk-32HW2Q33.cjs');
7
7
  var chunkMHVNT4J3_cjs = require('./chunk-MHVNT4J3.cjs');
8
+ var chunkULWRNGGE_cjs = require('./chunk-ULWRNGGE.cjs');
8
9
  var chunkKDG6FER6_cjs = require('./chunk-KDG6FER6.cjs');
9
10
  var lucideReact = require('lucide-react');
10
11
  var ui = require('@arbidocs/react/ui');
@@ -1716,11 +1717,1042 @@ function visibilityToggleTooltip(shared) {
1716
1717
  const workspace = ui.getEntityLabel("WORKSPACE").toLowerCase();
1717
1718
  return shared ? `${visibilityAudience(true)}: everyone in it can see this file. Click to make it private to you.` : `${visibilityAudience(false)}: only you can see this file. Click to share it with the ${workspace}.`;
1718
1719
  }
1720
+ var DEFAULT_UPLOAD_PARTS_LABELS = {
1721
+ rejectedReasons: {
1722
+ too_large: "The following files exceed the 1 GB size limit:",
1723
+ unsupported: "The following files are not in a supported format (PDF, DOC(X), PPT(X), XLS(X), RTF, TXT, MD, HTML, images, audio, video, email, Outlook archive (.pst/.ost), or ZIP):",
1724
+ empty: "The following files are empty (0 bytes):",
1725
+ no_extension: "The following files have no file extension:",
1726
+ empty_zip: "The following ZIP archives contain no supported files:",
1727
+ zip_error: "The following ZIP archives could not be processed:"
1728
+ },
1729
+ rejectedFallback: "The following files cannot be uploaded:",
1730
+ clearRejected: "Clear rejected files",
1731
+ selectedFiles: (count) => `Selected Files (${count})`,
1732
+ total: (size) => `Total: ${size}`,
1733
+ clearAll: "Clear All",
1734
+ remove: (fileName) => `Remove ${fileName}`,
1735
+ uploadComplete: (entity) => `Upload complete! Processing ${entity} in the background...`,
1736
+ uploading: (count, entity) => `Uploading ${count} ${entity}...`,
1737
+ uploadedIndexing: "Files uploaded successfully. ARBI is now indexing them in the background.",
1738
+ afterUpload: "After upload completes, ARBI will index files in the background."
1739
+ };
1740
+ function mergeUploadLabels(labels) {
1741
+ return {
1742
+ ...DEFAULT_UPLOAD_PARTS_LABELS,
1743
+ ...labels,
1744
+ rejectedReasons: {
1745
+ ...DEFAULT_UPLOAD_PARTS_LABELS.rejectedReasons,
1746
+ ...labels?.rejectedReasons
1747
+ }
1748
+ };
1749
+ }
1750
+ function UploadErrorMessage({
1751
+ message,
1752
+ className,
1753
+ testId
1754
+ }) {
1755
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1756
+ "div",
1757
+ {
1758
+ role: "alert",
1759
+ className: ui.cn("mt-6 flex items-center gap-2 rounded-lg bg-red-bg p-3", className),
1760
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "error-message" }),
1761
+ children: [
1762
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "size-5 shrink-0 text-red-text" }),
1763
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-red-text", children: message })
1764
+ ]
1765
+ }
1766
+ );
1767
+ }
1768
+ function RejectedFilesList({ files, onClear, labels, testIds }) {
1769
+ if (files.length === 0) return null;
1770
+ const l = mergeUploadLabels(labels);
1771
+ const byReason = /* @__PURE__ */ new Map();
1772
+ for (const file of files) {
1773
+ const reason = typeof file === "string" ? "unsupported" : file.reason || "unsupported";
1774
+ const name = typeof file === "string" ? file : file.name;
1775
+ byReason.set(reason, [...byReason.get(reason) ?? [], name]);
1776
+ }
1777
+ return /* @__PURE__ */ jsxRuntime.jsx(
1778
+ "div",
1779
+ {
1780
+ className: "mt-4 rounded-lg bg-red-bg p-3",
1781
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.root, { testId: "rejected-files-list" }),
1782
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
1783
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "mt-0.5 size-5 shrink-0 text-red-text" }),
1784
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: Array.from(byReason.entries()).map(([reason, names], groupIndex) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: groupIndex > 0 ? "mt-3" : "", children: [
1785
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-sm font-medium text-red-text", children: l.rejectedReasons[reason] ?? l.rejectedFallback }),
1786
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: names.map((name, index) => /* @__PURE__ */ jsxRuntime.jsx(
1787
+ "div",
1788
+ {
1789
+ className: "rounded-md bg-background/60 p-2",
1790
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.item?.(groupIndex, index), {
1791
+ testId: `rejected-file-item-${groupIndex}-${index}`
1792
+ }),
1793
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-red-text", children: name })
1794
+ },
1795
+ index
1796
+ )) })
1797
+ ] }, reason)) }),
1798
+ /* @__PURE__ */ jsxRuntime.jsx(
1799
+ ui.Button,
1800
+ {
1801
+ variant: "ghost",
1802
+ size: "icon",
1803
+ onClick: onClear,
1804
+ "aria-label": l.clearRejected,
1805
+ className: "size-6 text-red-text hover:text-red-text pointer-coarse:size-11",
1806
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.clear, { testId: "clear-rejected-files-button" }),
1807
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
1808
+ }
1809
+ )
1810
+ ] })
1811
+ }
1812
+ );
1813
+ }
1814
+ function folderPathOf(file) {
1815
+ const rel = file.webkitRelativePath;
1816
+ if (!rel) return null;
1817
+ const slash = rel.lastIndexOf("/");
1818
+ return slash > 0 ? rel.substring(0, slash) : null;
1819
+ }
1820
+ function SelectedFilesList({
1821
+ files,
1822
+ onRemoveFile,
1823
+ onClearAll,
1824
+ formatFileSize,
1825
+ renderFileIcon,
1826
+ labels,
1827
+ testIds
1828
+ }) {
1829
+ if (files.length === 0) return null;
1830
+ const l = mergeUploadLabels(labels);
1831
+ const total = files.reduce((sum, f) => sum + f.size, 0);
1832
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1833
+ "div",
1834
+ {
1835
+ className: "mt-2 sm:mt-6",
1836
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.root, { testId: "selected-files-list" }),
1837
+ children: [
1838
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between gap-3", children: [
1839
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col sm:flex-row sm:items-center sm:gap-4", children: [
1840
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-base font-medium", children: l.selectedFiles(files.length) }),
1841
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.total(formatFileSize(total)) })
1842
+ ] }),
1843
+ onClearAll && /* @__PURE__ */ jsxRuntime.jsxs(
1844
+ ui.Button,
1845
+ {
1846
+ variant: "ghost",
1847
+ size: "sm",
1848
+ onClick: onClearAll,
1849
+ className: "h-8 shrink-0 whitespace-nowrap text-muted-foreground hover:text-foreground pointer-coarse:h-11",
1850
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.clearAll, { testId: "clear-all-files-button" }),
1851
+ children: [
1852
+ l.clearAll,
1853
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "ml-1 hidden size-4 sm:block" })
1854
+ ]
1855
+ }
1856
+ )
1857
+ ] }),
1858
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1 overflow-y-auto overscroll-contain pr-1 sm:max-h-[300px]", children: files.map((file, index) => {
1859
+ const folder = folderPathOf(file);
1860
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1861
+ "div",
1862
+ {
1863
+ className: "flex min-w-0 items-center gap-2 rounded-lg bg-muted p-3",
1864
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.item?.(index), {
1865
+ testId: `selected-file-item-${index}`
1866
+ }),
1867
+ children: [
1868
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: renderFileIcon(file.name) }),
1869
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
1870
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-base", title: file.name, children: file.name }),
1871
+ folder && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
1872
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpen, { className: "size-3" }),
1873
+ folder
1874
+ ] })
1875
+ ] }),
1876
+ /* @__PURE__ */ jsxRuntime.jsx(
1877
+ ui.Button,
1878
+ {
1879
+ variant: "ghost",
1880
+ size: "icon",
1881
+ onClick: () => onRemoveFile(index),
1882
+ "aria-label": l.remove(file.name),
1883
+ className: "size-6 shrink-0 pointer-coarse:size-11",
1884
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.remove?.(index), {
1885
+ testId: `remove-file-button-${index}`
1886
+ }),
1887
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
1888
+ }
1889
+ )
1890
+ ]
1891
+ },
1892
+ index
1893
+ );
1894
+ }) })
1895
+ ]
1896
+ }
1897
+ );
1898
+ }
1899
+ function UploadProgress({
1900
+ fileCount,
1901
+ entityLabel,
1902
+ percentage,
1903
+ batchInfo,
1904
+ labels,
1905
+ testId
1906
+ }) {
1907
+ const l = mergeUploadLabels(labels);
1908
+ const isComplete = percentage >= 100;
1909
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "upload-progress" }), children: [
1910
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-2 text-lg font-medium", children: isComplete ? l.uploadComplete(entityLabel) : l.uploading(fileCount, entityLabel) }),
1911
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto mb-4 max-w-md", children: [
1912
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1913
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Progress, { value: percentage, className: "h-3" }),
1914
+ batchInfo && batchInfo.total > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-0", "aria-hidden": "true", children: Array.from({ length: batchInfo.total - 1 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx(
1915
+ "span",
1916
+ {
1917
+ className: "absolute top-0 h-full w-px bg-background/50",
1918
+ style: { left: `${(i + 1) / batchInfo.total * 100}%` }
1919
+ },
1920
+ i
1921
+ )) })
1922
+ ] }),
1923
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 flex items-center justify-center text-sm text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1924
+ Math.round(percentage),
1925
+ "%"
1926
+ ] }) })
1927
+ ] }),
1928
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: isComplete ? l.uploadedIndexing : l.afterUpload })
1929
+ ] });
1930
+ }
1931
+ var DEFAULT_UPLOAD_FOOTER_LABELS = {
1932
+ skipDuplicates: "Skip duplicates",
1933
+ skipDuplicatesActive: "Skip identical files already in the workspace",
1934
+ skipDuplicatesInactive: "Allow uploading identical files",
1935
+ autoRename: "Auto-rename",
1936
+ autoRenameActive: "Generate a descriptive title via AI instead of using the filename",
1937
+ autoRenameInactive: "Keep the original filename",
1938
+ titleInstruction: "Title instruction",
1939
+ titleInstructionPlaceholder: "Optional: how should AI name these documents?"
1940
+ };
1941
+ function UploadContainer({
1942
+ children,
1943
+ className = "p-4 sm:p-6",
1944
+ testId
1945
+ }) {
1946
+ return /* @__PURE__ */ jsxRuntime.jsx(
1947
+ "div",
1948
+ {
1949
+ className,
1950
+ "data-slot": "upload-container",
1951
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "upload-container" }),
1952
+ children
1953
+ }
1954
+ );
1955
+ }
1956
+ function UploadShareNote({
1957
+ description,
1958
+ children,
1959
+ compact = false,
1960
+ testId
1961
+ }) {
1962
+ const id = chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "share-toggle" });
1963
+ if (compact) {
1964
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
1965
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": id, children }) }),
1966
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipContent, { side: "top", className: "max-w-xs", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: description }) })
1967
+ ] });
1968
+ }
1969
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-muted p-4", "data-testid": id, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
1970
+ children,
1971
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: description })
1972
+ ] }) });
1973
+ }
1974
+ var TOGGLE_COLORS = { text: "text-primary", bg: "bg-primary" };
1975
+ function UploadFooterBar({
1976
+ skipDuplicates,
1977
+ onSkipDuplicatesChange,
1978
+ autoRename,
1979
+ onAutoRenameChange,
1980
+ autoRenameInstruction,
1981
+ onAutoRenameInstructionChange,
1982
+ shareToggle,
1983
+ children,
1984
+ className,
1985
+ labels,
1986
+ testIds
1987
+ }) {
1988
+ const l = { ...DEFAULT_UPLOAD_FOOTER_LABELS, ...labels };
1989
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1990
+ /* @__PURE__ */ jsxRuntime.jsxs(
1991
+ "div",
1992
+ {
1993
+ className: ui.cn(
1994
+ "flex shrink-0 flex-wrap items-center gap-x-3 gap-y-2 border-t border-border bg-background px-4 py-3 sm:px-6",
1995
+ className
1996
+ ),
1997
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.bar, { testId: "upload-footer-bar" }),
1998
+ children: [
1999
+ /* @__PURE__ */ jsxRuntime.jsx(
2000
+ ui.IconToggle,
2001
+ {
2002
+ icon: lucideReact.CopyX,
2003
+ isActive: skipDuplicates,
2004
+ onToggle: onSkipDuplicatesChange,
2005
+ colors: TOGGLE_COLORS,
2006
+ showLabel: true,
2007
+ label: l.skipDuplicates,
2008
+ tooltipActive: l.skipDuplicatesActive,
2009
+ tooltipInactive: l.skipDuplicatesInactive,
2010
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.skipDuplicates, { testId: "toggle-skip-duplicates" })
2011
+ }
2012
+ ),
2013
+ /* @__PURE__ */ jsxRuntime.jsx(
2014
+ ui.IconToggle,
2015
+ {
2016
+ icon: lucideReact.Sparkles,
2017
+ isActive: autoRename,
2018
+ onToggle: onAutoRenameChange,
2019
+ colors: TOGGLE_COLORS,
2020
+ showLabel: true,
2021
+ label: l.autoRename,
2022
+ tooltipActive: l.autoRenameActive,
2023
+ tooltipInactive: l.autoRenameInactive,
2024
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.autoRename, { testId: "toggle-auto-rename" })
2025
+ }
2026
+ ),
2027
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden flex-1 sm:block" }),
2028
+ shareToggle,
2029
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full sm:w-auto max-sm:[&>button]:w-full", children })
2030
+ ]
2031
+ }
2032
+ ),
2033
+ autoRename && /* @__PURE__ */ jsxRuntime.jsxs(
2034
+ "div",
2035
+ {
2036
+ className: "shrink-0 border-t border-border bg-background px-4 py-3 sm:px-6",
2037
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.settingsPanel, { testId: "upload-settings-panel" }),
2038
+ children: [
2039
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "auto-rename-instruction", className: "text-sm font-medium", children: l.titleInstruction }),
2040
+ /* @__PURE__ */ jsxRuntime.jsx(
2041
+ ui.Textarea,
2042
+ {
2043
+ id: "auto-rename-instruction",
2044
+ value: autoRenameInstruction,
2045
+ onChange: (e) => onAutoRenameInstructionChange(e.target.value),
2046
+ placeholder: l.titleInstructionPlaceholder,
2047
+ className: "mt-1 min-h-[60px] text-sm",
2048
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.instruction, { testId: "auto-rename-instruction" })
2049
+ }
2050
+ )
2051
+ ]
2052
+ }
2053
+ )
2054
+ ] });
2055
+ }
2056
+ function ShareToggle({
2057
+ isVisible,
2058
+ onToggle,
2059
+ workspaceEntityLabel,
2060
+ compact = false
2061
+ }) {
2062
+ const doc = ui.getEntityLabel("DOCUMENT", "PLURAL").toLowerCase();
2063
+ const workspace = workspaceEntityLabel.toLowerCase();
2064
+ const description = isVisible ? `Uploaded ${doc} will be shared with this ${workspace} \u2014 everyone in it, now and in the future.` : `Uploaded ${doc} stay private to you \u2014 not shared with this ${workspace}. You can change this later.`;
2065
+ const audience = visibilityAudience(isVisible, workspaceEntityLabel);
2066
+ const toggle = /* @__PURE__ */ jsxRuntime.jsx(
2067
+ ui.VisibilityToggle,
2068
+ {
2069
+ items: { shared: isVisible },
2070
+ onToggle,
2071
+ showLabel: true,
2072
+ label: audience,
2073
+ showTooltip: false
2074
+ }
2075
+ );
2076
+ if (compact) {
2077
+ const summary = isVisible ? `Everyone in this ${workspace} can see uploaded ${doc}.` : `Only you can see uploaded ${doc}.`;
2078
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-testid": "share-toggle", className: "flex max-w-[15rem] flex-col items-end gap-1", children: [
2079
+ toggle,
2080
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-right text-xs text-muted-foreground", children: summary })
2081
+ ] });
2082
+ }
2083
+ return /* @__PURE__ */ jsxRuntime.jsx(UploadShareNote, { description, compact: false, children: toggle });
2084
+ }
2085
+ var DEFAULT_UPLOAD_SOURCES_LABELS = {
2086
+ uploadFiles: "Choose files",
2087
+ uploadFolder: "Choose a folder"
2088
+ };
2089
+ function UploadFrame({ isCompact, isDimmed, className, children }) {
2090
+ return /* @__PURE__ */ jsxRuntime.jsx(
2091
+ "div",
2092
+ {
2093
+ "data-slot": "upload-frame",
2094
+ className: ui.cn(
2095
+ "relative flex w-full flex-col items-center",
2096
+ isCompact ? "gap-4" : "gap-6",
2097
+ isDimmed && "opacity-50",
2098
+ className
2099
+ ),
2100
+ children
2101
+ }
2102
+ );
2103
+ }
2104
+ function UploadDropArea({
2105
+ isActive,
2106
+ isDisabled,
2107
+ isProcessing,
2108
+ processingMessage,
2109
+ isCompact,
2110
+ title,
2111
+ subtitle,
2112
+ onDrag,
2113
+ onDrop,
2114
+ onClick,
2115
+ actions,
2116
+ testId = "upload-dropzone-area"
2117
+ }) {
2118
+ const active = isActive && !isDisabled;
2119
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2120
+ "div",
2121
+ {
2122
+ "data-slot": "upload-drop-area",
2123
+ "data-testid": testId,
2124
+ onDragEnter: onDrag,
2125
+ onDragLeave: onDrag,
2126
+ onDragOver: onDrag,
2127
+ onDrop,
2128
+ onClick,
2129
+ className: ui.cn(
2130
+ "relative flex w-full flex-col items-center justify-center rounded-lg border text-center transition-colors",
2131
+ active ? "border-dashed border-primary bg-accent" : "border-border bg-card shadow-xs hover:border-ring/50 hover:bg-accent/40",
2132
+ isDisabled || isProcessing ? "cursor-not-allowed" : "cursor-pointer",
2133
+ isCompact ? "min-h-[150px] p-4" : "min-h-[200px] p-5",
2134
+ // Touch screens cannot drag files in: the area stays in the DOM (assistive tech, e2e) but
2135
+ // the "Choose files / folder" buttons are the whole affordance.
2136
+ "pointer-coarse:sr-only"
2137
+ ),
2138
+ children: [
2139
+ isProcessing && /* @__PURE__ */ jsxRuntime.jsxs(
2140
+ "div",
2141
+ {
2142
+ role: "status",
2143
+ className: "absolute inset-0 z-10 flex flex-col items-center justify-center rounded-lg bg-background/80",
2144
+ children: [
2145
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mb-3 size-8 animate-spin text-primary" }),
2146
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "progress-bar-processing mb-3 h-1.5 w-48 rounded-sm" }),
2147
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: processingMessage })
2148
+ ]
2149
+ }
2150
+ ),
2151
+ /* @__PURE__ */ jsxRuntime.jsx(
2152
+ "div",
2153
+ {
2154
+ className: ui.cn(
2155
+ "mb-2 flex items-center justify-center rounded-full bg-muted text-muted-foreground",
2156
+ isCompact ? "size-11" : "size-10",
2157
+ active && "bg-primary/10 text-primary"
2158
+ ),
2159
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "size-5" })
2160
+ }
2161
+ ),
2162
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-semibold text-foreground", children: title }),
2163
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: subtitle }),
2164
+ actions
2165
+ ]
2166
+ }
2167
+ );
2168
+ }
2169
+ function UploadBrowseButtons({
2170
+ onFiles,
2171
+ onFolder,
2172
+ isDisabled,
2173
+ layout = "inline",
2174
+ labels
2175
+ }) {
2176
+ const l = { ...DEFAULT_UPLOAD_SOURCES_LABELS, ...labels };
2177
+ const isInline = layout === "inline";
2178
+ const size = isInline ? "sm" : "default";
2179
+ const width = isInline ? void 0 : "w-full";
2180
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2181
+ "div",
2182
+ {
2183
+ "data-slot": "upload-browse-buttons",
2184
+ className: isInline ? "mt-3 flex flex-wrap items-center justify-center gap-2" : "grid grid-cols-1 gap-2 sm:grid-cols-2",
2185
+ children: [
2186
+ /* @__PURE__ */ jsxRuntime.jsxs(
2187
+ ui.Button,
2188
+ {
2189
+ variant: isInline ? "outline" : "default",
2190
+ size,
2191
+ className: width,
2192
+ onClick: onFiles,
2193
+ disabled: isDisabled,
2194
+ "data-testid": "upload-files-button",
2195
+ children: [
2196
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "mr-2 size-4" }),
2197
+ l.uploadFiles
2198
+ ]
2199
+ }
2200
+ ),
2201
+ /* @__PURE__ */ jsxRuntime.jsxs(
2202
+ ui.Button,
2203
+ {
2204
+ variant: "outline",
2205
+ size,
2206
+ className: width,
2207
+ onClick: onFolder,
2208
+ disabled: isDisabled,
2209
+ "data-testid": "upload-folder-button",
2210
+ children: [
2211
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderPlus, { className: "mr-2 size-4" }),
2212
+ l.uploadFolder
2213
+ ]
2214
+ }
2215
+ )
2216
+ ]
2217
+ }
2218
+ );
2219
+ }
2220
+ function UploadSourcePicker({ options, isDisabled }) {
2221
+ return /* @__PURE__ */ jsxRuntime.jsx(
2222
+ "div",
2223
+ {
2224
+ "data-slot": "upload-source-picker",
2225
+ className: "flex w-full flex-col gap-2",
2226
+ "data-testid": "upload-source-picker",
2227
+ children: options.map((o) => {
2228
+ const button = /* @__PURE__ */ jsxRuntime.jsxs(
2229
+ ui.Button,
2230
+ {
2231
+ variant: "outline",
2232
+ onClick: o.onClick,
2233
+ disabled: isDisabled,
2234
+ "data-testid": `upload-source-pick-${o.key}`,
2235
+ className: "h-auto w-full justify-start gap-3 px-4 py-3 text-left",
2236
+ children: [
2237
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground [&_svg]:size-5", children: o.icon }),
2238
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col", children: [
2239
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: o.label }),
2240
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-normal text-muted-foreground", children: o.description })
2241
+ ] })
2242
+ ]
2243
+ }
2244
+ );
2245
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "contents", children: o.wrap ? o.wrap(button) : button }, o.key);
2246
+ })
2247
+ }
2248
+ );
2249
+ }
2250
+ function UploadUrlButton({
2251
+ isCompact,
2252
+ isDisabled,
2253
+ label = "Add from URL",
2254
+ onClick
2255
+ }) {
2256
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2257
+ ui.Button,
2258
+ {
2259
+ variant: "outline",
2260
+ size: isCompact ? "sm" : "default",
2261
+ disabled: isDisabled,
2262
+ onClick,
2263
+ "data-testid": "upload-url-button",
2264
+ children: [
2265
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "mr-2 size-4" }),
2266
+ label
2267
+ ]
2268
+ }
2269
+ );
2270
+ }
2271
+ function UploadSourceSection({
2272
+ testId,
2273
+ className,
2274
+ isIsolated,
2275
+ children
2276
+ }) {
2277
+ return /* @__PURE__ */ jsxRuntime.jsx(
2278
+ "div",
2279
+ {
2280
+ "data-slot": "upload-source-section",
2281
+ "data-testid": testId,
2282
+ className,
2283
+ onClick: isIsolated ? (e) => e.stopPropagation() : void 0,
2284
+ children
2285
+ }
2286
+ );
2287
+ }
2288
+ var DEFAULT_URL_INPUT_DIALOG_LABELS = {
2289
+ title: "Add from the internet",
2290
+ description: "Enter one or more URLs to download documents \u2014 paste several separated by commas or new lines.",
2291
+ supports: "Supports PDF, Word, PowerPoint, Excel, RTF, TXT, MD, HTML, ZIP, and audio/video links (YouTube et al.).",
2292
+ url: (position) => position === null ? "URL " : `URL ${position}`,
2293
+ placeholder: "https://example.com/document.pdf or a YouTube / audio / video link",
2294
+ removeUrl: (position) => `Remove URL ${position}`,
2295
+ addAnother: "Add Another URL",
2296
+ adding: "Adding\u2026",
2297
+ addDocuments: "Add Documents",
2298
+ mediaPreview: "Media preview"
2299
+ };
2300
+ function UrlInputDialogView({
2301
+ open,
2302
+ onOpenChange,
2303
+ trigger,
2304
+ title,
2305
+ urls,
2306
+ errors,
2307
+ onUrlChange,
2308
+ onUrlPaste,
2309
+ onAddUrl,
2310
+ onRemoveUrl,
2311
+ renderPreview,
2312
+ submitError,
2313
+ isSubmitting,
2314
+ onSubmit,
2315
+ labels,
2316
+ testIds
2317
+ }) {
2318
+ const l = { ...DEFAULT_URL_INPUT_DIALOG_LABELS, ...labels };
2319
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Dialog, { open, onOpenChange, children: [
2320
+ trigger !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.DialogTrigger, { asChild: true, children: trigger }),
2321
+ /* @__PURE__ */ jsxRuntime.jsxs(
2322
+ ui.DialogContent,
2323
+ {
2324
+ presentation: "sheet",
2325
+ className: "flex flex-col gap-0 overflow-hidden p-0 sm:max-w-[525px]",
2326
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.modal, { testId: "upload-modal-internet" }),
2327
+ children: [
2328
+ /* @__PURE__ */ jsxRuntime.jsx(chunkULWRNGGE_cjs.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: title ?? l.title }) }),
2329
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 pb-6", children: [
2330
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogDescription, { className: "pt-4 text-sm text-muted-foreground", children: [
2331
+ l.description,
2332
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 block text-xs", children: l.supports })
2333
+ ] }),
2334
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 py-4", children: [
2335
+ urls.map((url, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2336
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2337
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
2338
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: `url-${index}`, className: "text-sm", children: l.url(urls.length > 1 ? index + 1 : null) }),
2339
+ /* @__PURE__ */ jsxRuntime.jsx(
2340
+ ui.Input,
2341
+ {
2342
+ id: `url-${index}`,
2343
+ type: "text",
2344
+ placeholder: l.placeholder,
2345
+ value: url,
2346
+ onChange: (e) => onUrlChange(index, e.target.value),
2347
+ onPaste: (e) => {
2348
+ e.preventDefault();
2349
+ onUrlPaste(index, e.clipboardData.getData("text"));
2350
+ },
2351
+ className: ui.cn(errors[index] && "border-red-border")
2352
+ }
2353
+ ),
2354
+ errors[index] && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-red-text", children: errors[index] })
2355
+ ] }),
2356
+ urls.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
2357
+ ui.Button,
2358
+ {
2359
+ type: "button",
2360
+ variant: "ghost",
2361
+ size: "icon",
2362
+ onClick: () => onRemoveUrl(index),
2363
+ className: "mt-6",
2364
+ "aria-label": l.removeUrl(index + 1),
2365
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
2366
+ }
2367
+ )
2368
+ ] }),
2369
+ renderPreview?.(url, index)
2370
+ ] }, index)),
2371
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { type: "button", variant: "outline", size: "sm", onClick: onAddUrl, className: "w-full", children: [
2372
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "mr-2 h-4 w-4" }),
2373
+ l.addAnother
2374
+ ] })
2375
+ ] }),
2376
+ submitError && /* @__PURE__ */ jsxRuntime.jsx(
2377
+ "p",
2378
+ {
2379
+ className: "text-sm text-red-text",
2380
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.submitError, { testId: "url-submit-error" }),
2381
+ children: submitError
2382
+ }
2383
+ ),
2384
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
2385
+ ui.Button,
2386
+ {
2387
+ onClick: onSubmit,
2388
+ disabled: isSubmitting,
2389
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.submit, { testId: "url-submit-button" }),
2390
+ children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2391
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
2392
+ l.adding
2393
+ ] }) : l.addDocuments
2394
+ }
2395
+ ) })
2396
+ ] })
2397
+ ]
2398
+ }
2399
+ )
2400
+ ] });
2401
+ }
2402
+ function UrlDialogTitle({ icon, workspaceName, labels }) {
2403
+ const l = { ...DEFAULT_URL_INPUT_DIALOG_LABELS, ...labels };
2404
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex min-w-0 items-center", icon ? "gap-3" : "gap-2"), children: [
2405
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: icon }),
2406
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", title: workspaceName, children: workspaceName }),
2407
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-muted-foreground", children: "/" }),
2408
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: l.title })
2409
+ ] });
2410
+ }
2411
+ function MediaPreviewView({ kind, src, testId, labels }) {
2412
+ const l = { ...DEFAULT_URL_INPUT_DIALOG_LABELS, ...labels };
2413
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 overflow-hidden rounded-md border", "data-testid": testId, children: [
2414
+ kind === "youtube" && /* @__PURE__ */ jsxRuntime.jsx(
2415
+ "iframe",
2416
+ {
2417
+ className: "aspect-video w-full",
2418
+ src,
2419
+ title: l.mediaPreview,
2420
+ allow: "accelerometer; encrypted-media; picture-in-picture",
2421
+ allowFullScreen: true
2422
+ }
2423
+ ),
2424
+ kind === "video" && /* @__PURE__ */ jsxRuntime.jsx("video", { className: "max-h-56 w-full bg-black", src, controls: true, preload: "metadata" }),
2425
+ kind === "audio" && /* @__PURE__ */ jsxRuntime.jsx("audio", { className: "w-full p-2", src, controls: true, preload: "metadata" })
2426
+ ] });
2427
+ }
2428
+
2429
+ // src/files/media-preview.ts
2430
+ var MEDIA_HOSTS = [
2431
+ "youtube.com",
2432
+ "youtu.be",
2433
+ "vimeo.com",
2434
+ "soundcloud.com",
2435
+ "dailymotion.com",
2436
+ "twitch.tv"
2437
+ ];
2438
+ var VIDEO_EXTENSIONS = [".mp4", ".mpeg", ".mpg", ".webm", ".mov", ".avi", ".mkv", ".ogv"];
2439
+ var AUDIO_EXTENSIONS = [".mp3", ".wav", ".m4a", ".aac", ".flac", ".ogg", ".oga"];
2440
+ function normalizeHost(hostname) {
2441
+ return hostname.toLowerCase().replace(/^(www|m)\./, "");
2442
+ }
2443
+ function getYoutubeId(url) {
2444
+ const host = normalizeHost(url.hostname);
2445
+ if (host === "youtu.be") return url.pathname.slice(1).split("/")[0] || null;
2446
+ if (host === "youtube.com" || host.endsWith(".youtube.com")) {
2447
+ if (url.pathname === "/watch") return url.searchParams.get("v");
2448
+ const segments = url.pathname.split("/").filter(Boolean);
2449
+ if (segments[0] === "embed" || segments[0] === "shorts" || segments[0] === "v") {
2450
+ return segments[1] ?? null;
2451
+ }
2452
+ }
2453
+ return null;
2454
+ }
2455
+ function getExtension(pathname) {
2456
+ const lower = pathname.toLowerCase();
2457
+ const lastDot = lower.lastIndexOf(".");
2458
+ const lastSlash = lower.lastIndexOf("/");
2459
+ return lastDot > lastSlash ? lower.slice(lastDot) : "";
2460
+ }
2461
+ function getMediaPreview(rawUrl) {
2462
+ let url;
2463
+ try {
2464
+ url = new URL(rawUrl);
2465
+ } catch {
2466
+ return null;
2467
+ }
2468
+ const youtubeId = getYoutubeId(url);
2469
+ if (youtubeId) {
2470
+ return { kind: "youtube", embedUrl: `https://www.youtube.com/embed/${youtubeId}` };
2471
+ }
2472
+ const extension = getExtension(url.pathname);
2473
+ if (VIDEO_EXTENSIONS.includes(extension)) return { kind: "video", src: rawUrl };
2474
+ if (AUDIO_EXTENSIONS.includes(extension)) return { kind: "audio", src: rawUrl };
2475
+ return null;
2476
+ }
2477
+ function isMediaUrl(rawUrl) {
2478
+ if (getMediaPreview(rawUrl)) return true;
2479
+ try {
2480
+ const host = normalizeHost(new URL(rawUrl).hostname);
2481
+ return MEDIA_HOSTS.some((mediaHost) => host === mediaHost || host.endsWith(`.${mediaHost}`));
2482
+ } catch {
2483
+ return false;
2484
+ }
2485
+ }
2486
+ function UrlInputDialog({
2487
+ onUrlsSubmit,
2488
+ trigger,
2489
+ processing = false,
2490
+ open: controlledOpen,
2491
+ onOpenChange,
2492
+ titleWorkspaceName,
2493
+ titleIcon
2494
+ }) {
2495
+ const [uncontrolledOpen, setUncontrolledOpen] = react.useState(false);
2496
+ const open = controlledOpen ?? uncontrolledOpen;
2497
+ const setOpen = (next) => {
2498
+ onOpenChange?.(next);
2499
+ if (controlledOpen === void 0) setUncontrolledOpen(next);
2500
+ };
2501
+ const [urls, setUrls] = react.useState([""]);
2502
+ const [errors, setErrors] = react.useState([]);
2503
+ const [submitting, setSubmitting] = react.useState(false);
2504
+ const [submitError, setSubmitError] = react.useState(null);
2505
+ const preprocessUrl = (url) => {
2506
+ let processedUrl = url.trim();
2507
+ if (processedUrl && !processedUrl.match(/^https?:\/\//i)) {
2508
+ processedUrl = "https://" + processedUrl;
2509
+ }
2510
+ try {
2511
+ new URL(processedUrl);
2512
+ processedUrl = processedUrl.replace(/ /g, "%20");
2513
+ return processedUrl;
2514
+ } catch {
2515
+ return processedUrl.replace(/ /g, "%20");
2516
+ }
2517
+ };
2518
+ const validateUrl = (url) => {
2519
+ try {
2520
+ const urlObj = new URL(url);
2521
+ if (isMediaUrl(url)) {
2522
+ return { valid: true };
2523
+ }
2524
+ const pathname = urlObj.pathname.toLowerCase();
2525
+ const supportedExtensions = [
2526
+ ".pdf",
2527
+ ".txt",
2528
+ ".md",
2529
+ ".html",
2530
+ ".doc",
2531
+ ".docx",
2532
+ ".rtf",
2533
+ ".ppt",
2534
+ ".pptx",
2535
+ ".xls",
2536
+ ".xlsx",
2537
+ // .zip is fetched from the URL by the browser and extracted by the
2538
+ // frontend zip worker; each entry is then uploaded as a normal file.
2539
+ ".zip"
2540
+ ];
2541
+ const hasFileExtension = pathname.includes(".") && pathname.lastIndexOf(".") > pathname.lastIndexOf("/");
2542
+ const hasValidExtension = !hasFileExtension || supportedExtensions.some((ext) => pathname.endsWith(ext));
2543
+ if (!hasValidExtension) {
2544
+ return {
2545
+ valid: false,
2546
+ error: "File type not supported. Supported formats: PDF, DOC(X), PPT(X), XLS(X), RTF, TXT, MD, HTML, ZIP."
2547
+ };
2548
+ }
2549
+ return { valid: true };
2550
+ } catch {
2551
+ return { valid: false, error: "Invalid URL format" };
2552
+ }
2553
+ };
2554
+ const addUrlField = () => {
2555
+ setUrls([...urls, ""]);
2556
+ setErrors([...errors, ""]);
2557
+ };
2558
+ const removeUrlField = (index) => {
2559
+ setUrls(urls.filter((_, i) => i !== index));
2560
+ setErrors(errors.filter((_, i) => i !== index));
2561
+ };
2562
+ const updateUrl = (index, value) => {
2563
+ if (submitError) setSubmitError(null);
2564
+ const delimiters = /[,\n]+/;
2565
+ if (delimiters.test(value)) {
2566
+ const urlList = value.split(delimiters).map((u) => u.trim()).filter((u) => u.length > 0);
2567
+ if (urlList.length > 1) {
2568
+ const newUrls2 = [...urls];
2569
+ newUrls2.splice(index, 1, ...urlList);
2570
+ if (index === urls.length - 1) {
2571
+ newUrls2.push("");
2572
+ }
2573
+ setUrls(newUrls2);
2574
+ const newErrors = [...errors];
2575
+ urlList.forEach((_, i) => {
2576
+ newErrors[index + i] = "";
2577
+ });
2578
+ setErrors(newErrors);
2579
+ return;
2580
+ }
2581
+ }
2582
+ const newUrls = [...urls];
2583
+ newUrls[index] = value;
2584
+ setUrls(newUrls);
2585
+ if (errors[index]) {
2586
+ const newErrors = [...errors];
2587
+ newErrors[index] = "";
2588
+ setErrors(newErrors);
2589
+ }
2590
+ };
2591
+ const handleSubmit = async () => {
2592
+ const newErrors = [];
2593
+ const validUrls = [];
2594
+ urls.forEach((url, index) => {
2595
+ const trimmedUrl = url.trim();
2596
+ if (!trimmedUrl) {
2597
+ newErrors[index] = "URL is required";
2598
+ } else {
2599
+ const processedUrl = preprocessUrl(trimmedUrl);
2600
+ const validation = validateUrl(processedUrl);
2601
+ if (!validation.valid) {
2602
+ newErrors[index] = validation.error || "Invalid URL";
2603
+ } else {
2604
+ newErrors[index] = "";
2605
+ validUrls.push(processedUrl);
2606
+ }
2607
+ }
2608
+ });
2609
+ setErrors(newErrors);
2610
+ if (validUrls.length > 0 && !newErrors.some((error) => error)) {
2611
+ setSubmitError(null);
2612
+ setSubmitting(true);
2613
+ let ok;
2614
+ try {
2615
+ ok = await onUrlsSubmit(validUrls);
2616
+ } catch {
2617
+ ok = false;
2618
+ }
2619
+ setSubmitting(false);
2620
+ if (ok === false) {
2621
+ setSubmitError("Failed to upload documents from URLs. Please check the URLs and try again.");
2622
+ return;
2623
+ }
2624
+ setOpen(false);
2625
+ setUrls([""]);
2626
+ setErrors([]);
2627
+ }
2628
+ };
2629
+ const showTrigger = trigger !== void 0 || controlledOpen === void 0;
2630
+ const title = titleWorkspaceName ? /* @__PURE__ */ jsxRuntime.jsx(UrlDialogTitle, { icon: titleIcon, workspaceName: titleWorkspaceName }) : void 0;
2631
+ return /* @__PURE__ */ jsxRuntime.jsx(
2632
+ UrlInputDialogView,
2633
+ {
2634
+ open,
2635
+ onOpenChange: setOpen,
2636
+ trigger: showTrigger ? trigger || /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { variant: "outline", size: "sm", disabled: processing, children: [
2637
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link, { className: "w-4 h-4 mr-2" }),
2638
+ processing ? "Processing..." : "Add from URL"
2639
+ ] }) : void 0,
2640
+ title,
2641
+ urls,
2642
+ errors,
2643
+ onUrlChange: updateUrl,
2644
+ onUrlPaste: updateUrl,
2645
+ onAddUrl: addUrlField,
2646
+ onRemoveUrl: removeUrlField,
2647
+ renderPreview: (url, index) => {
2648
+ const trimmed = url.trim();
2649
+ const preview = trimmed ? getMediaPreview(preprocessUrl(trimmed)) : null;
2650
+ if (!preview) return null;
2651
+ return /* @__PURE__ */ jsxRuntime.jsx(
2652
+ MediaPreviewView,
2653
+ {
2654
+ kind: preview.kind,
2655
+ src: preview.kind === "youtube" ? preview.embedUrl : preview.src,
2656
+ testId: `url-media-preview-${index}`
2657
+ }
2658
+ );
2659
+ },
2660
+ submitError,
2661
+ isSubmitting: submitting,
2662
+ onSubmit: handleSubmit
2663
+ }
2664
+ );
2665
+ }
2666
+ var POINTS = [
2667
+ {
2668
+ icon: lucideReact.KeyRound,
2669
+ heading: "Only you hold the key",
2670
+ body: "You choose who to invite to a workspace and the role they hold. Each workspace is encrypted with its own key, held only by its members \u2014 so no one outside it, including ARBI administrators, can access its confidential data."
2671
+ },
2672
+ {
2673
+ icon: lucideReact.Eye,
2674
+ heading: "You decide what to share",
2675
+ body: "Within a workspace, conversations are private by default and documents are shared with collaborators. Anything you keep private stays invisible to other members, even the owner."
2676
+ },
2677
+ {
2678
+ icon: lucideReact.ShieldCheck,
2679
+ heading: "Your data stays in the UK",
2680
+ body: "By default, the AI that processes your files runs on ARBI's own infrastructure in the United Kingdom. Third-party models (OpenAI, Anthropic or Google) are optional; we select providers with the strongest data-protection terms, but recommend reviewing each provider's data-retention policy before enabling one."
2681
+ },
2682
+ {
2683
+ icon: lucideReact.BrainCircuit,
2684
+ heading: "We never train AI on your data",
2685
+ body: "Your files and conversations are never used to train AI models."
2686
+ }
2687
+ ];
2688
+ function PrivacyExplainerModal() {
2689
+ const [open, setOpen] = react.useState(false);
2690
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2691
+ /* @__PURE__ */ jsxRuntime.jsxs(
2692
+ ui.Button,
2693
+ {
2694
+ type: "button",
2695
+ variant: "ghost",
2696
+ size: "sm",
2697
+ onClick: () => setOpen(true),
2698
+ className: "gap-1.5 text-primary hover:text-primary",
2699
+ "data-testid": "privacy-explainer-button",
2700
+ children: [
2701
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "w-4 h-4" }),
2702
+ "Privacy Guarantee",
2703
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3.5 h-3.5 opacity-70" })
2704
+ ]
2705
+ }
2706
+ ),
2707
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { className: "sm:max-w-lg", "data-testid": "privacy-explainer-dialog", children: [
2708
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogHeader, { children: [
2709
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogTitle, { className: "flex items-center gap-2", children: [
2710
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "h-5 w-5 text-primary" }),
2711
+ "Your data, your keys"
2712
+ ] }),
2713
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: "How ARBI protects confidentiality." })
2714
+ ] }),
2715
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-5 py-1", children: POINTS.map(({ icon: Icon, heading, body }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
2716
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "mt-0.5 h-5 w-5 shrink-0 text-primary" }),
2717
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
2718
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold leading-none", children: heading }),
2719
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: body })
2720
+ ] })
2721
+ ] }, heading)) }),
2722
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 pt-1", children: [
2723
+ /* @__PURE__ */ jsxRuntime.jsx(
2724
+ "a",
2725
+ {
2726
+ href: "https://arbicity.com/ARBI-Security-Whitepaper.pdf",
2727
+ target: "_blank",
2728
+ rel: "noopener noreferrer",
2729
+ className: "text-sm font-medium text-primary hover:underline",
2730
+ "data-testid": "privacy-explainer-whitepaper-link",
2731
+ children: "Full security details \u2192"
2732
+ }
2733
+ ),
2734
+ /* @__PURE__ */ jsxRuntime.jsx(
2735
+ ui.Button,
2736
+ {
2737
+ type: "button",
2738
+ onClick: () => setOpen(false),
2739
+ "data-testid": "privacy-explainer-dismiss",
2740
+ children: "Got it"
2741
+ }
2742
+ )
2743
+ ] })
2744
+ ] }) })
2745
+ ] });
2746
+ }
1719
2747
 
1720
2748
  exports.CHROME = CHROME;
1721
2749
  exports.DEFAULT_EXPLORER_LABELS = DEFAULT_EXPLORER_LABELS;
1722
2750
  exports.DEFAULT_FOLDER_FILTER_LABELS = DEFAULT_FOLDER_FILTER_LABELS;
1723
2751
  exports.DEFAULT_FOLDER_PICKER_LABELS = DEFAULT_FOLDER_PICKER_LABELS;
2752
+ exports.DEFAULT_UPLOAD_FOOTER_LABELS = DEFAULT_UPLOAD_FOOTER_LABELS;
2753
+ exports.DEFAULT_UPLOAD_PARTS_LABELS = DEFAULT_UPLOAD_PARTS_LABELS;
2754
+ exports.DEFAULT_UPLOAD_SOURCES_LABELS = DEFAULT_UPLOAD_SOURCES_LABELS;
2755
+ exports.DEFAULT_URL_INPUT_DIALOG_LABELS = DEFAULT_URL_INPUT_DIALOG_LABELS;
1724
2756
  exports.ExplorerDragPreview = ExplorerDragPreview;
1725
2757
  exports.ExplorerDropOverlay = ExplorerDropOverlay;
1726
2758
  exports.ExplorerEmpty = ExplorerEmpty;
@@ -1755,11 +2787,30 @@ exports.FolderTree = FolderTree;
1755
2787
  exports.LINE_PX = LINE_PX;
1756
2788
  exports.MAX_LINES = MAX_LINES;
1757
2789
  exports.MIN_LINES = MIN_LINES;
2790
+ exports.MediaPreviewView = MediaPreviewView;
2791
+ exports.PrivacyExplainerModal = PrivacyExplainerModal;
1758
2792
  exports.RECENTLY_DELETED_HINT = RECENTLY_DELETED_HINT;
1759
2793
  exports.RECENTLY_DELETED_HINT_PLURAL = RECENTLY_DELETED_HINT_PLURAL;
1760
2794
  exports.ROW_MIN = ROW_MIN;
2795
+ exports.RejectedFilesList = RejectedFilesList;
1761
2796
  exports.RowDensityControl = RowDensityControl;
2797
+ exports.SelectedFilesList = SelectedFilesList;
2798
+ exports.ShareToggle = ShareToggle;
1762
2799
  exports.StatusPill = StatusPill;
2800
+ exports.UploadBrowseButtons = UploadBrowseButtons;
2801
+ exports.UploadContainer = UploadContainer;
2802
+ exports.UploadDropArea = UploadDropArea;
2803
+ exports.UploadErrorMessage = UploadErrorMessage;
2804
+ exports.UploadFooterBar = UploadFooterBar;
2805
+ exports.UploadFrame = UploadFrame;
2806
+ exports.UploadProgress = UploadProgress;
2807
+ exports.UploadShareNote = UploadShareNote;
2808
+ exports.UploadSourcePicker = UploadSourcePicker;
2809
+ exports.UploadSourceSection = UploadSourceSection;
2810
+ exports.UploadUrlButton = UploadUrlButton;
2811
+ exports.UrlDialogTitle = UrlDialogTitle;
2812
+ exports.UrlInputDialog = UrlInputDialog;
2813
+ exports.UrlInputDialogView = UrlInputDialogView;
1763
2814
  exports.VendorLogo = VendorLogo;
1764
2815
  exports.buildExplorerEntries = buildExplorerEntries;
1765
2816
  exports.canChangeVisibility = canChangeVisibility;
@@ -1769,8 +2820,10 @@ exports.collectFolderDocs = collectFolderDocs;
1769
2820
  exports.confirmHideFromMembers = confirmHideFromMembers;
1770
2821
  exports.formatFolderSegment = formatFolderSegment;
1771
2822
  exports.getExplorerDisplayName = getExplorerDisplayName;
2823
+ exports.getMediaPreview = getMediaPreview;
1772
2824
  exports.hasFolderProviderIcon = hasFolderProviderIcon;
1773
2825
  exports.isExplorerDocument = isExplorerDocument;
2826
+ exports.isMediaUrl = isMediaUrl;
1774
2827
  exports.joinFolderPath = joinFolderPath;
1775
2828
  exports.linesForRowHeight = linesForRowHeight;
1776
2829
  exports.parseFolderSegments = parseFolderSegments;
@@ -1781,5 +2834,5 @@ exports.shareTooltipFor = shareTooltipFor;
1781
2834
  exports.sortExplorerFiles = sortExplorerFiles;
1782
2835
  exports.visibilityAudience = visibilityAudience;
1783
2836
  exports.visibilityToggleTooltip = visibilityToggleTooltip;
1784
- //# sourceMappingURL=chunk-WV4TD2HZ.cjs.map
1785
- //# sourceMappingURL=chunk-WV4TD2HZ.cjs.map
2837
+ //# sourceMappingURL=chunk-QJFJ5JBF.cjs.map
2838
+ //# sourceMappingURL=chunk-QJFJ5JBF.cjs.map