@px-ui/core 4.0.0 → 4.1.0

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.js CHANGED
@@ -70,7 +70,7 @@ function cn(...inputs) {
70
70
 
71
71
  //#endregion
72
72
  //#region src/components/button.tsx
73
- const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap transition-colors disabled:cursor-not-allowed shrink-0 [&_svg]:shrink-0 outline-none rounded-ppx-s font-medium focus-visible:ring-3 focus-visible:ring-ppx-neutral-17/30", {
73
+ const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap transition-colors cursor-pointer disabled:cursor-not-allowed shrink-0 [&_svg]:shrink-0 outline-none rounded-ppx-s font-medium focus-visible:ring-3 focus-visible:ring-ppx-neutral-17/30", {
74
74
  variants: {
75
75
  variant: {
76
76
  default: "bg-ppx-neutral-11 text-white shadow-xs not-disabled:hover:bg-ppx-neutral-10 not-disabled:active:bg-ppx-neutral-11 disabled:bg-ppx-neutral-6",
@@ -79,7 +79,7 @@ const buttonVariants = cva("inline-flex items-center justify-center gap-2 whites
79
79
  outline: "shadow-xs not-disabled:hover:bg-ppx-neutral-2 not-disabled:active:bg-ppx-neutral-3 disabled:border-ppx-neutral-7 border border-ppx-neutral-11 text-ppx-neutral-11 disabled:text-ppx-neutral-7",
80
80
  "primary-outline": "shadow-xs not-disabled:hover:bg-ppx-primary-1 not-disabled:active:bg-ppx-primary-2/50 disabled:text-ppx-primary-2 disabled:border-ppx-primary-2 border border-ppx-primary-5 text-ppx-primary-5",
81
81
  ghost: "not-disabled:hover:bg-ppx-neutral-2 not-disabled:active:bg-ppx-neutral-3 not-disabled:hover:text-black text-ppx-neutral-12 disabled:opacity-70",
82
- link: "text-ppx-neutral-12 underline-offset-4 underline cursor-pointer not-disabled:hover:bg-ppx-neutral-2 not-disabled:active:bg-ppx-neutral-3 disabled:opacity-70"
82
+ link: "text-ppx-neutral-12 underline-offset-4 underline not-disabled:hover:bg-ppx-neutral-2 not-disabled:active:bg-ppx-neutral-3 disabled:opacity-70"
83
83
  },
84
84
  size: {
85
85
  default: "px-4 py-2 h-10 has-[>svg]:px-3 text-ppx-base",
@@ -138,7 +138,7 @@ var dialog_exports = /* @__PURE__ */ __export({
138
138
  Portal: () => Portal$1,
139
139
  Root: () => Root$11,
140
140
  Title: () => Title$3,
141
- Trigger: () => Trigger$8
141
+ Trigger: () => Trigger$7
142
142
  });
143
143
  function Root$11({ ...props }) {
144
144
  return /* @__PURE__ */ jsx(Dialog.Root, {
@@ -152,7 +152,7 @@ function Portal$1({ ...props }) {
152
152
  ...props
153
153
  });
154
154
  }
155
- function Trigger$8({ ...props }) {
155
+ function Trigger$7({ ...props }) {
156
156
  return /* @__PURE__ */ jsx(Dialog.Trigger, {
157
157
  "data-slot": "dialog-trigger",
158
158
  ...props
@@ -247,7 +247,7 @@ var popover_exports = /* @__PURE__ */ __export({
247
247
  Header: () => Header$2,
248
248
  Root: () => Root$10,
249
249
  Title: () => Title$2,
250
- Trigger: () => Trigger$7
250
+ Trigger: () => Trigger$6
251
251
  });
252
252
  function Root$10(props) {
253
253
  return /* @__PURE__ */ jsx(Popover.Root, {
@@ -261,7 +261,7 @@ function Portal(props) {
261
261
  ...props
262
262
  });
263
263
  }
264
- function Trigger$7(props) {
264
+ function Trigger$6(props) {
265
265
  return /* @__PURE__ */ jsx(Popover.Trigger, {
266
266
  "data-slot": "popover-trigger",
267
267
  ...props
@@ -691,20 +691,20 @@ var combobox_exports = /* @__PURE__ */ __export({
691
691
  Chip: () => Chip,
692
692
  ChipsTrigger: () => ChipsTrigger,
693
693
  Content: () => Content$4,
694
- Item: () => Item$7,
695
- List: () => List$2,
694
+ Item: () => Item$6,
695
+ List: () => List$3,
696
696
  LoadingIndicator: () => LoadingIndicator,
697
697
  MultiItem: () => MultiItem$1,
698
698
  Root: () => Root$8,
699
699
  Search: () => Search,
700
700
  SearchableTrigger: () => SearchableTrigger,
701
701
  SearchableTriggerDropdownAddon: () => SearchableTriggerDropdownAddon,
702
- Trigger: () => Trigger$6,
702
+ Trigger: () => Trigger$5,
703
703
  Value: () => Value$2,
704
704
  useComboboxContext: () => useComboboxContext
705
705
  });
706
706
  const SINGLE_TEXT_CONTENT_CN = "px-4 py-2 text-ppx-sm min-h-11 flex items-center justify-center text-ppx-muted-foreground";
707
- const List$2 = Combobox.List;
707
+ const List$3 = Combobox.List;
708
708
  const ComboboxContext = React$1.createContext({});
709
709
  function Root$8({ children, ...props }) {
710
710
  const chipsTriggerRef = React$1.useRef(null);
@@ -786,7 +786,7 @@ function Content$4({ empty = "No options", portalProps, positionerProps, popupPr
786
786
  })
787
787
  });
788
788
  }
789
- function Item$7({ className, ...props }) {
789
+ function Item$6({ className, ...props }) {
790
790
  return /* @__PURE__ */ jsx(Combobox.Item, {
791
791
  className: cn(DROPDOWN_ITEM_CN, className),
792
792
  ...props,
@@ -863,7 +863,7 @@ function SearchableTriggerDropdownAddon() {
863
863
  ]
864
864
  });
865
865
  }
866
- function Trigger$6({ size, widthVariant, children, className, ...props }) {
866
+ function Trigger$5({ size, widthVariant, children, className, ...props }) {
867
867
  const { isLoading, invalid } = useComboboxContext();
868
868
  return /* @__PURE__ */ jsxs(Combobox.Trigger, {
869
869
  "aria-label": "Open popup",
@@ -969,12 +969,12 @@ const BaseCombobox = Combobox;
969
969
  var select_exports = /* @__PURE__ */ __export({
970
970
  BaseSelect: () => BaseSelect,
971
971
  Content: () => Content$3,
972
- Item: () => Item$6,
973
- List: () => List$1,
972
+ Item: () => Item$5,
973
+ List: () => List$2,
974
974
  MultiItem: () => MultiItem,
975
975
  MultiSelectedValue: () => MultiSelectedValue,
976
976
  Root: () => Root$7,
977
- Trigger: () => Trigger$5,
977
+ Trigger: () => Trigger$4,
978
978
  Value: () => Value$1
979
979
  });
980
980
  const SelectContext = React$1.createContext({});
@@ -1007,8 +1007,8 @@ function Content$3({ portalProps, positionerProps, popupProps, children, widthVa
1007
1007
  })
1008
1008
  });
1009
1009
  }
1010
- const List$1 = Select.List;
1011
- function Item$6({ className, ...props }) {
1010
+ const List$2 = Select.List;
1011
+ function Item$5({ className, ...props }) {
1012
1012
  return /* @__PURE__ */ jsx(Select.Item, {
1013
1013
  className: cn(DROPDOWN_ITEM_CN, className),
1014
1014
  ...props,
@@ -1031,7 +1031,7 @@ function ItemIndicator(props) {
1031
1031
  children: /* @__PURE__ */ jsx(Select.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, {}) })
1032
1032
  });
1033
1033
  }
1034
- function Trigger$5({ size, widthVariant, ...props }) {
1034
+ function Trigger$4({ size, widthVariant, ...props }) {
1035
1035
  const { invalid } = useSelectContext();
1036
1036
  return /* @__PURE__ */ jsxs(Select.Trigger, {
1037
1037
  "aria-label": "Open popup",
@@ -1086,15 +1086,15 @@ var menu_exports = /* @__PURE__ */ __export({
1086
1086
  DropdownIndicator: () => DropdownIndicator,
1087
1087
  Group: () => Group$3,
1088
1088
  GroupLabel: () => GroupLabel,
1089
- Item: () => Item$5,
1089
+ Item: () => Item$4,
1090
1090
  RadioGroup: () => RadioGroup$1,
1091
1091
  RadioItem: () => RadioItem,
1092
1092
  Root: () => Root$6,
1093
1093
  Separator: () => Separator$1,
1094
- Trigger: () => Trigger$4
1094
+ Trigger: () => Trigger$3
1095
1095
  });
1096
1096
  const Root$6 = Menu.Root;
1097
- function Trigger$4({ className, children, size, widthVariant = "fit", ...props }) {
1097
+ function Trigger$3({ className, children, size, widthVariant = "fit", ...props }) {
1098
1098
  return /* @__PURE__ */ jsxs(Menu.Trigger, {
1099
1099
  className: cn(triggerVariants({
1100
1100
  size,
@@ -1123,7 +1123,7 @@ function Content$2({ portalProps, positionerProps, popupProps, children, widthVa
1123
1123
  function DropdownIndicator() {
1124
1124
  return /* @__PURE__ */ jsx(ChevronDownIcon, { className: "data-popup-open:rotate-180" });
1125
1125
  }
1126
- function Item$5({ className, children, ...props }) {
1126
+ function Item$4({ className, children, ...props }) {
1127
1127
  return /* @__PURE__ */ jsx(Menu.Item, {
1128
1128
  className: cn(DROPDOWN_ITEM_CN, className),
1129
1129
  ...props,
@@ -1203,7 +1203,7 @@ const BaseProgress = Progress;
1203
1203
  //#endregion
1204
1204
  //#region src/components/segmented-control.tsx
1205
1205
  var segmented_control_exports = /* @__PURE__ */ __export({
1206
- Item: () => Item$4,
1206
+ Item: () => Item$3,
1207
1207
  Root: () => Root$4
1208
1208
  });
1209
1209
  const segmentedControlItemVariants = cva("relative flex items-center justify-center px-4 py-2 text-sm font-medium transition-all duration-200 ease-in-out cursor-pointer rounded-full whitespace-nowrap outline-none focus-visible:ring-2 focus-visible:ring-ppx-primary-5 focus-visible:ring-offset-2 data-disabled:cursor-not-allowed data-disabled:opacity-50", {
@@ -1227,7 +1227,7 @@ function Root$4({ className, ...props }) {
1227
1227
  ...props
1228
1228
  });
1229
1229
  }
1230
- function Item$4({ children, className, variant, size, ...props }) {
1230
+ function Item$3({ children, className, variant, size, ...props }) {
1231
1231
  return /* @__PURE__ */ jsx(Radio.Root, {
1232
1232
  "data-slot": "segmented-control-item",
1233
1233
  className: cn(segmentedControlItemVariants({
@@ -1244,9 +1244,9 @@ function Item$4({ children, className, variant, size, ...props }) {
1244
1244
  //#region src/components/tabs.tsx
1245
1245
  var tabs_exports = /* @__PURE__ */ __export({
1246
1246
  Content: () => Content$1,
1247
- List: () => List,
1247
+ List: () => List$1,
1248
1248
  Root: () => Root$3,
1249
- Trigger: () => Trigger$3
1249
+ Trigger: () => Trigger$2
1250
1250
  });
1251
1251
  const TabsContext = React$1.createContext(null);
1252
1252
  const useTabs = () => {
@@ -1264,7 +1264,7 @@ function Root$3({ variant = "underline", className, ...props }) {
1264
1264
  })
1265
1265
  });
1266
1266
  }
1267
- function List({ className, children, ...props }) {
1267
+ function List$1({ className, children, ...props }) {
1268
1268
  return /* @__PURE__ */ jsxs(Tabs.List, {
1269
1269
  "data-slot": "tabs-list",
1270
1270
  className: cn("text-muted-foreground h-9 gap-x-1 p-1 relative z-0 inline-flex w-fit items-center justify-center", className),
@@ -1276,7 +1276,7 @@ function List({ className, children, ...props }) {
1276
1276
  ]
1277
1277
  });
1278
1278
  }
1279
- function Trigger$3({ className, ...props }) {
1279
+ function Trigger$2({ className, ...props }) {
1280
1280
  return /* @__PURE__ */ jsx(Tabs.Tab, {
1281
1281
  "data-slot": "tabs-trigger",
1282
1282
  className: cn("focus-visible:ring-ring/50 [&_svg:not([class*='size-'])] gap-1.5 px-2 py-1 text-sm font-medium z-[1] flex-1 items-center justify-center text-nowrap whitespace-nowrap text-ppx-neutral-18 not-data-selected:hover:text-ppx-neutral-12 focus-visible:ring-[3px] data-selected:text-ppx-primary-b-5 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", className),
@@ -1306,7 +1306,7 @@ var tooltip_exports = /* @__PURE__ */ __export({
1306
1306
  BaseRoot: () => BaseRoot,
1307
1307
  Content: () => Content,
1308
1308
  Root: () => Root$2,
1309
- Trigger: () => Trigger$2
1309
+ Trigger: () => Trigger$1
1310
1310
  });
1311
1311
  function TooltipProvider(props) {
1312
1312
  return /* @__PURE__ */ jsx(Tooltip.Provider, {
@@ -1340,7 +1340,7 @@ function Root$2({ ...props }) {
1340
1340
  }
1341
1341
  const BaseRoot = Tooltip.Root;
1342
1342
  const BaseProvider = Tooltip.Provider;
1343
- function Trigger$2({ ...props }) {
1343
+ function Trigger$1({ ...props }) {
1344
1344
  return /* @__PURE__ */ jsx(Tooltip.Trigger, {
1345
1345
  "data-slot": "tooltip-trigger",
1346
1346
  ...props
@@ -1437,7 +1437,7 @@ var block_checkbox_group_exports = /* @__PURE__ */ __export({
1437
1437
  Description: () => Description$1,
1438
1438
  Group: () => Group$2,
1439
1439
  Header: () => Header$1,
1440
- Item: () => Item$3,
1440
+ Item: () => Item$2,
1441
1441
  Title: () => Title$1
1442
1442
  });
1443
1443
  function Group$2({ className, ...props }) {
@@ -1446,7 +1446,7 @@ function Group$2({ className, ...props }) {
1446
1446
  ...props
1447
1447
  });
1448
1448
  }
1449
- function Item$3({ className, invalid, children, ...rest }) {
1449
+ function Item$2({ className, invalid, children, ...rest }) {
1450
1450
  return /* @__PURE__ */ jsxs("label", {
1451
1451
  className: cn("rounded-ppx-s border-ppx-neutral-3 has-not-data-disabled:hover:border-ppx-neutral-6 has-data-disabled:cursor-not-allowed has-data-disabled:opacity-60 has-data-disabled:hover:border-ppx-neutral-3 has-aria-invalid:shadow-ppx-red-2 has-data-checked:border-ppx-primary-5! flex min-h-[155px] justify-between gap-2 border-2 p-5 shadow-[0px_0px_12px_#0000001F] transition-colors duration-300", className),
1452
1452
  children: [/* @__PURE__ */ jsx("div", {
@@ -1483,7 +1483,7 @@ function Description$1(props) {
1483
1483
  //#region src/components/radio-group.tsx
1484
1484
  var radio_group_exports = /* @__PURE__ */ __export({
1485
1485
  Group: () => Group$1,
1486
- Item: () => Item$1
1486
+ Item: () => Item
1487
1487
  });
1488
1488
  function Group$1({ className, ...props }) {
1489
1489
  return /* @__PURE__ */ jsx(RadioGroup, {
@@ -1506,7 +1506,7 @@ const radioVariants = cva("relative inline-flex bg-ppx-background aria-invalid:b
1506
1506
  size: "default"
1507
1507
  }
1508
1508
  });
1509
- function Item$1({ className, variant, size, ...props }) {
1509
+ function Item({ className, variant, size, ...props }) {
1510
1510
  return /* @__PURE__ */ jsx(Radio.Root, {
1511
1511
  "data-slot": "radio-group-item",
1512
1512
  className: cn(radioVariants({
@@ -1545,7 +1545,7 @@ var block_radio_group_exports = /* @__PURE__ */ __export({
1545
1545
  Description: () => Description,
1546
1546
  Group: () => Group,
1547
1547
  Header: () => Header,
1548
- Item: () => Item$2,
1548
+ Item: () => Item$1,
1549
1549
  Title: () => Title
1550
1550
  });
1551
1551
  function Group({ className, ...props }) {
@@ -1555,13 +1555,13 @@ function Group({ className, ...props }) {
1555
1555
  ...props
1556
1556
  });
1557
1557
  }
1558
- function Item$2({ className, invalid, children, ...rest }) {
1558
+ function Item$1({ className, invalid, children, ...rest }) {
1559
1559
  return /* @__PURE__ */ jsxs("label", {
1560
1560
  className: cn("rounded-ppx-s border-ppx-neutral-3 has-not-data-disabled:hover:border-ppx-neutral-6 has-data-disabled:cursor-not-allowed has-data-disabled:opacity-60 has-data-disabled:hover:border-ppx-neutral-3 has-aria-invalid:shadow-ppx-red-2 has-data-checked:border-ppx-primary-5! flex min-h-[155px] justify-between gap-2 border-2 p-5 shadow-[0px_0px_12px_#0000001F] transition-colors duration-300", className),
1561
1561
  children: [/* @__PURE__ */ jsx("div", {
1562
1562
  className: "flex-1",
1563
1563
  children
1564
- }), /* @__PURE__ */ jsx(Item$1, {
1564
+ }), /* @__PURE__ */ jsx(Item, {
1565
1565
  ...rest,
1566
1566
  className: "ml-auto shrink-0 self-start",
1567
1567
  size: "lg",
@@ -1653,7 +1653,7 @@ var collapsible_exports = /* @__PURE__ */ __export({
1653
1653
  Panel: () => Panel,
1654
1654
  Root: () => Root$1,
1655
1655
  ToggleIcon: () => ToggleIcon,
1656
- Trigger: () => Trigger$1
1656
+ Trigger: () => Trigger
1657
1657
  });
1658
1658
  function Root$1({ className, ...props }) {
1659
1659
  return /* @__PURE__ */ jsx(Collapsible.Root, {
@@ -1662,7 +1662,7 @@ function Root$1({ className, ...props }) {
1662
1662
  ...props
1663
1663
  });
1664
1664
  }
1665
- function Trigger$1(props) {
1665
+ function Trigger(props) {
1666
1666
  return /* @__PURE__ */ jsx(Collapsible.Trigger, {
1667
1667
  "data-slot": "collapsible-trigger",
1668
1668
  ...props,
@@ -2186,7 +2186,7 @@ const replaceSizeInUrl = (url, size) => {
2186
2186
  function Avatar(props) {
2187
2187
  return /* @__PURE__ */ jsxs(Root$2, {
2188
2188
  disabled: props.hideTooltip,
2189
- children: [/* @__PURE__ */ jsx(Trigger$2, { render: (tooltipProps) => /* @__PURE__ */ jsx(AvatarImpl, {
2189
+ children: [/* @__PURE__ */ jsx(Trigger$1, { render: (tooltipProps) => /* @__PURE__ */ jsx(AvatarImpl, {
2190
2190
  ...props,
2191
2191
  avatarRootProps: tooltipProps
2192
2192
  }) }), /* @__PURE__ */ jsx(Content, { children: props.name })]
@@ -2231,7 +2231,7 @@ function AvatarGroup({ max = 4, avatars, className }) {
2231
2231
  return /* @__PURE__ */ jsx(BaseProvider, { children: /* @__PURE__ */ jsxs("div", {
2232
2232
  className: cn("flex items-center", className),
2233
2233
  "data-slot": "avatar-group",
2234
- children: [avatars.map((avatar, index) => /* @__PURE__ */ jsx(React.Fragment, { children: /* @__PURE__ */ jsxs(BaseRoot, { children: [/* @__PURE__ */ jsx(Trigger$2, { render: (tooltipProps) => /* @__PURE__ */ jsx("div", {
2234
+ children: [avatars.map((avatar, index) => /* @__PURE__ */ jsx(React.Fragment, { children: /* @__PURE__ */ jsxs(BaseRoot, { children: [/* @__PURE__ */ jsx(Trigger$1, { render: (tooltipProps) => /* @__PURE__ */ jsx("div", {
2235
2235
  className: "relative",
2236
2236
  style: {
2237
2237
  marginLeft: index > 0 ? `-${parseInt(avatar.size ?? "100px") * .25}px` : "0",
@@ -2248,7 +2248,7 @@ function AvatarGroup({ max = 4, avatars, className }) {
2248
2248
  marginLeft: `-${parseInt(avatars[0].size ?? "100px") * .25}px`,
2249
2249
  zIndex: 0
2250
2250
  },
2251
- children: /* @__PURE__ */ jsxs(Root$10, { children: [/* @__PURE__ */ jsx(Trigger$7, {
2251
+ children: /* @__PURE__ */ jsxs(Root$10, { children: [/* @__PURE__ */ jsx(Trigger$6, {
2252
2252
  openOnHover: true,
2253
2253
  children: /* @__PURE__ */ jsxs("div", {
2254
2254
  className: cn("bg-ppx-neutral-3 text-ppx-neutral-18 hover:bg-ppx-neutral-4 flex cursor-pointer items-center justify-center font-medium transition-colors", avatars[0].variant === "rounded" ? "rounded-full" : "rounded-ppx-s"),
@@ -2342,7 +2342,7 @@ function DatePicker({ triggerProps, placeholder = "Pick a date", format: format$
2342
2342
  open,
2343
2343
  onOpenChange: setOpen,
2344
2344
  ...popoverRootProps,
2345
- children: [/* @__PURE__ */ jsxs(Trigger$7, {
2345
+ children: [/* @__PURE__ */ jsxs(Trigger$6, {
2346
2346
  disabled: triggerProps?.disabled,
2347
2347
  className: cn(triggerVariants({
2348
2348
  size: triggerProps?.size,
@@ -2408,32 +2408,6 @@ function RetryIcon(props) {
2408
2408
  });
2409
2409
  }
2410
2410
 
2411
- //#endregion
2412
- //#region src/icons/upload-icon.tsx
2413
- function UploadIcon(props) {
2414
- return /* @__PURE__ */ jsxs("svg", {
2415
- xmlns: "http://www.w3.org/2000/svg",
2416
- viewBox: "0 0 24 24",
2417
- fill: "none",
2418
- stroke: "currentColor",
2419
- strokeWidth: 2,
2420
- strokeLinecap: "round",
2421
- strokeLinejoin: "round",
2422
- ...props,
2423
- className: cn("shrink-0", props.className),
2424
- children: [
2425
- /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
2426
- /* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
2427
- /* @__PURE__ */ jsx("line", {
2428
- x1: "12",
2429
- y1: "3",
2430
- x2: "12",
2431
- y2: "15"
2432
- })
2433
- ]
2434
- });
2435
- }
2436
-
2437
2411
  //#endregion
2438
2412
  //#region src/hooks/use-file-upload.ts
2439
2413
  const formatBytes = (bytes, decimals = 2) => {
@@ -2454,22 +2428,51 @@ const formatBytes = (bytes, decimals = 2) => {
2454
2428
  const i = Math.floor(Math.log(bytes) / Math.log(k));
2455
2429
  return Number.parseFloat((bytes / k ** i).toFixed(dm)) + sizes[i];
2456
2430
  };
2431
+ /**
2432
+ * Extract error message from various error formats, including S3 XML errors
2433
+ */
2434
+ function extractErrorMessage(error) {
2435
+ if (typeof error === "string") return error;
2436
+ if (error instanceof Error) {
2437
+ const xmlMatch = error.message.match(/<Message>(.*?)<\/Message>/);
2438
+ if (xmlMatch) return xmlMatch[1];
2439
+ return error.message;
2440
+ }
2441
+ if (error && typeof error === "object") {
2442
+ if ("responseText" in error && typeof error.responseText === "string") {
2443
+ const xmlMatch = error.responseText.match(/<Message>(.*?)<\/Message>/);
2444
+ if (xmlMatch) return xmlMatch[1];
2445
+ }
2446
+ if ("body" in error && typeof error.body === "string") {
2447
+ const xmlMatch = error.body.match(/<Message>(.*?)<\/Message>/);
2448
+ if (xmlMatch) return xmlMatch[1];
2449
+ }
2450
+ if ("message" in error && typeof error.message === "string") return error.message;
2451
+ if ("error" in error) return extractErrorMessage(error.error);
2452
+ }
2453
+ return "Upload failed";
2454
+ }
2457
2455
  const useFileUpload = (options = {}) => {
2458
2456
  const { upload, ...baseOptions } = options;
2459
2457
  const autoUpload = upload?.autoUpload ?? true;
2460
- const [files, setFiles] = useState((baseOptions.initialFiles ?? []).map((file) => ({
2458
+ const [files, setFilesState] = useState((baseOptions.initialFiles ?? []).map((file) => ({
2461
2459
  file,
2462
2460
  id: file.id,
2463
2461
  preview: file.url,
2464
2462
  progress: 100,
2465
- status: "success",
2463
+ status: "complete",
2466
2464
  uploadedUrl: file.url
2467
2465
  })));
2468
2466
  const [isUploading, setIsUploading] = useState(false);
2469
2467
  const [isDragging, setIsDragging] = useState(false);
2470
2468
  const [errors, setErrors] = useState([]);
2469
+ const [instanceKey, setInstanceKey] = useState(0);
2471
2470
  const inputRef = useRef(null);
2472
2471
  const abortControllersRef = useRef(/* @__PURE__ */ new Map());
2472
+ const cancelAllUploads = useCallback(() => {
2473
+ for (const controller of abortControllersRef.current.values()) controller.abort();
2474
+ abortControllersRef.current.clear();
2475
+ }, []);
2473
2476
  const { maxFiles = Number.POSITIVE_INFINITY, maxSize = Number.POSITIVE_INFINITY, accept = "*", multiple = false, onFilesChange, onFilesAdded } = baseOptions;
2474
2477
  const validateFile = useCallback((file) => {
2475
2478
  if (file.size > maxSize) return `File "${file.name}" exceeds the maximum size of ${formatBytes(maxSize)}.`;
@@ -2503,13 +2506,13 @@ const useFileUpload = (options = {}) => {
2503
2506
  const file = fileWithStatus.file;
2504
2507
  if (!(file instanceof File)) return {
2505
2508
  ...fileWithStatus,
2506
- status: "success",
2509
+ status: "complete",
2507
2510
  progress: 100
2508
2511
  };
2509
2512
  const abortController = new AbortController();
2510
2513
  abortControllersRef.current.set(fileWithStatus.id, abortController);
2511
2514
  try {
2512
- setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2515
+ setFilesState((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2513
2516
  ...f,
2514
2517
  status: "uploading",
2515
2518
  progress: 0
@@ -2521,25 +2524,30 @@ const useFileUpload = (options = {}) => {
2521
2524
  signal: abortController.signal
2522
2525
  });
2523
2526
  if (presignedError || !presignedResult) throw presignedError || /* @__PURE__ */ new Error("Failed to get presigned URL");
2524
- setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2527
+ setFilesState((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2525
2528
  ...f,
2526
2529
  progress: 10
2527
2530
  } : f));
2528
2531
  const { result: uploadResult, error: uploadError } = await upload.uploadFile(presignedResult.url, file, presignedResult, (progress) => {
2529
- const scaledProgress = 10 + progress * .9;
2530
- setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2532
+ const scaledProgress = Math.min(10 + progress * .89, 99);
2533
+ setFilesState((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2531
2534
  ...f,
2532
2535
  progress: Math.round(scaledProgress)
2533
2536
  } : f));
2534
2537
  }, abortController.signal);
2535
2538
  if (uploadError) throw uploadError;
2539
+ setFilesState((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2540
+ ...f,
2541
+ progress: 100
2542
+ } : f));
2543
+ await new Promise((resolve) => setTimeout(resolve, 150));
2536
2544
  const uploadedFile = {
2537
2545
  ...fileWithStatus,
2538
- status: "success",
2546
+ status: "complete",
2539
2547
  progress: 100,
2540
- uploadedUrl: uploadResult?.url ?? presignedResult.fullPath
2548
+ uploadedUrl: uploadResult?.url ?? presignedResult.full_path
2541
2549
  };
2542
- setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? uploadedFile : f));
2550
+ setFilesState((prev) => prev.map((f) => f.id === fileWithStatus.id ? uploadedFile : f));
2543
2551
  upload.onUploadComplete?.(uploadedFile);
2544
2552
  return uploadedFile;
2545
2553
  } catch (error) {
@@ -2548,13 +2556,13 @@ const useFileUpload = (options = {}) => {
2548
2556
  status: "idle",
2549
2557
  progress: 0
2550
2558
  };
2551
- const errorMessage = error instanceof Error ? error.message : "Upload failed";
2559
+ const errorMessage = extractErrorMessage(error);
2552
2560
  const failedFile = {
2553
2561
  ...fileWithStatus,
2554
2562
  status: "error",
2555
2563
  error: errorMessage
2556
2564
  };
2557
- setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? failedFile : f));
2565
+ setFilesState((prev) => prev.map((f) => f.id === fileWithStatus.id ? failedFile : f));
2558
2566
  upload.onUploadError?.(failedFile, error);
2559
2567
  return failedFile;
2560
2568
  } finally {
@@ -2583,7 +2591,7 @@ const useFileUpload = (options = {}) => {
2583
2591
  const newFilesArray = Array.from(newFiles);
2584
2592
  const newErrors = [];
2585
2593
  setErrors([]);
2586
- if (!multiple) setFiles((prev) => {
2594
+ if (!multiple) setFilesState((prev) => {
2587
2595
  for (const file of prev) if (file.preview && file.file instanceof File) URL.revokeObjectURL(file.preview);
2588
2596
  return [];
2589
2597
  });
@@ -2612,7 +2620,7 @@ const useFileUpload = (options = {}) => {
2612
2620
  }
2613
2621
  if (validFiles.length > 0) {
2614
2622
  onFilesAdded?.(validFiles);
2615
- setFiles((prev) => {
2623
+ setFilesState((prev) => {
2616
2624
  const updatedFiles = !multiple ? validFiles : [...prev, ...validFiles];
2617
2625
  onFilesChange?.(updatedFiles);
2618
2626
  return updatedFiles;
@@ -2642,7 +2650,7 @@ const useFileUpload = (options = {}) => {
2642
2650
  controller.abort();
2643
2651
  abortControllersRef.current.delete(id);
2644
2652
  }
2645
- setFiles((prev) => {
2653
+ setFilesState((prev) => {
2646
2654
  const fileToRemove = prev.find((file) => file.id === id);
2647
2655
  if (fileToRemove?.preview && fileToRemove.file instanceof File) URL.revokeObjectURL(fileToRemove.preview);
2648
2656
  const newFiles = prev.filter((file) => file.id !== id);
@@ -2651,23 +2659,50 @@ const useFileUpload = (options = {}) => {
2651
2659
  });
2652
2660
  }, [onFilesChange]);
2653
2661
  const clearFiles = useCallback(() => {
2654
- for (const controller of abortControllersRef.current.values()) controller.abort();
2655
- abortControllersRef.current.clear();
2656
- setFiles((prev) => {
2662
+ cancelAllUploads();
2663
+ setFilesState((prev) => {
2657
2664
  for (const file of prev) if (file.preview && file.file instanceof File) URL.revokeObjectURL(file.preview);
2658
2665
  return [];
2659
2666
  });
2660
2667
  if (inputRef.current) inputRef.current.value = "";
2661
2668
  setErrors([]);
2662
2669
  onFilesChange?.([]);
2663
- }, [onFilesChange]);
2670
+ }, [cancelAllUploads, onFilesChange]);
2664
2671
  const clearErrors = useCallback(() => {
2665
2672
  setErrors([]);
2666
2673
  }, []);
2674
+ const reset = useCallback((newFiles) => {
2675
+ cancelAllUploads();
2676
+ for (const file of files) if (file.preview && file.file instanceof File) URL.revokeObjectURL(file.preview);
2677
+ if (inputRef.current) inputRef.current.value = "";
2678
+ setErrors([]);
2679
+ const initializedFiles = (newFiles ?? []).map((file) => ({
2680
+ file,
2681
+ id: file.id,
2682
+ preview: file.url,
2683
+ progress: 100,
2684
+ status: "complete",
2685
+ uploadedUrl: file.url
2686
+ }));
2687
+ setFilesState(initializedFiles);
2688
+ onFilesChange?.(initializedFiles);
2689
+ setInstanceKey((prev) => prev + 1);
2690
+ }, [
2691
+ cancelAllUploads,
2692
+ files,
2693
+ onFilesChange
2694
+ ]);
2695
+ const setFiles = useCallback((newFiles) => {
2696
+ setFilesState((prev) => {
2697
+ const nextFiles = typeof newFiles === "function" ? newFiles(prev) : newFiles;
2698
+ onFilesChange?.(nextFiles);
2699
+ return nextFiles;
2700
+ });
2701
+ }, [onFilesChange]);
2667
2702
  const retryUpload = useCallback(async (id) => {
2668
2703
  const file = files.find((f) => f.id === id);
2669
2704
  if (file && file.status === "error") {
2670
- setFiles((prev) => prev.map((f) => f.id === id ? {
2705
+ setFilesState((prev) => prev.map((f) => f.id === id ? {
2671
2706
  ...f,
2672
2707
  status: "idle",
2673
2708
  error: void 0
@@ -2685,7 +2720,7 @@ const useFileUpload = (options = {}) => {
2685
2720
  controller.abort();
2686
2721
  abortControllersRef.current.delete(id);
2687
2722
  }
2688
- setFiles((prev) => prev.map((f) => f.id === id ? {
2723
+ setFilesState((prev) => prev.map((f) => f.id === id ? {
2689
2724
  ...f,
2690
2725
  status: "idle",
2691
2726
  progress: 0
@@ -2717,61 +2752,573 @@ const useFileUpload = (options = {}) => {
2717
2752
  const handleFileChange = useCallback((e) => {
2718
2753
  if (e.target.files?.length) addFiles(e.target.files);
2719
2754
  }, [addFiles]);
2720
- const openFileDialog = useCallback(() => {
2721
- inputRef.current?.click();
2722
- }, []);
2723
- const getInputProps = useCallback((props = {}) => ({
2724
- ...props,
2725
- accept: props.accept || accept,
2726
- multiple: props.multiple !== void 0 ? props.multiple : multiple,
2727
- onChange: handleFileChange,
2728
- ref: inputRef,
2729
- type: "file"
2730
- }), [
2731
- accept,
2732
- multiple,
2733
- handleFileChange
2734
- ]);
2735
- return [{
2755
+ return {
2736
2756
  files,
2737
2757
  isDragging,
2758
+ isUploading,
2738
2759
  errors,
2739
- isUploading
2740
- }, {
2741
2760
  addFiles,
2742
2761
  removeFile,
2743
2762
  clearFiles,
2744
2763
  clearErrors,
2764
+ reset,
2765
+ setFiles,
2766
+ instanceKey,
2767
+ uploadFiles,
2768
+ retryUpload,
2769
+ cancelUpload,
2745
2770
  handleDragEnter,
2746
2771
  handleDragLeave,
2747
2772
  handleDragOver,
2748
2773
  handleDrop,
2749
2774
  handleFileChange,
2750
- openFileDialog,
2751
- getInputProps,
2752
- uploadFiles,
2753
- retryUpload,
2754
- cancelUpload
2755
- }];
2775
+ openFileDialog: useCallback(() => {
2776
+ inputRef.current?.click();
2777
+ }, []),
2778
+ getInputProps: useCallback((props = {}) => ({
2779
+ ...props,
2780
+ accept: props.accept || accept,
2781
+ multiple: props.multiple !== void 0 ? props.multiple : multiple,
2782
+ onChange: handleFileChange,
2783
+ ref: inputRef,
2784
+ type: "file"
2785
+ }), [
2786
+ accept,
2787
+ multiple,
2788
+ handleFileChange
2789
+ ])
2790
+ };
2756
2791
  };
2757
2792
 
2758
2793
  //#endregion
2759
- //#region src/icons/file-icon.tsx
2760
- function FileIcon(props) {
2794
+ //#region src/icons/pdf-icon.tsx
2795
+ function PdfIcon(props) {
2761
2796
  return /* @__PURE__ */ jsxs("svg", {
2762
2797
  xmlns: "http://www.w3.org/2000/svg",
2763
2798
  viewBox: "0 0 24 24",
2764
2799
  fill: "none",
2765
- stroke: "currentColor",
2766
- strokeWidth: 2,
2767
- strokeLinecap: "round",
2768
- strokeLinejoin: "round",
2769
2800
  ...props,
2770
2801
  className: cn("shrink-0", props.className),
2771
- children: [/* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), /* @__PURE__ */ jsx("polyline", { points: "14,2 14,8 20,8" })]
2802
+ children: [
2803
+ /* @__PURE__ */ jsx("path", {
2804
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
2805
+ fill: "#E53935"
2806
+ }),
2807
+ /* @__PURE__ */ jsx("path", {
2808
+ d: "M14 2v6h6",
2809
+ fill: "#FFCDD2"
2810
+ }),
2811
+ /* @__PURE__ */ jsx("path", {
2812
+ d: "M14 2v6h6",
2813
+ stroke: "#E53935",
2814
+ strokeWidth: 1.5,
2815
+ strokeLinecap: "round",
2816
+ strokeLinejoin: "round"
2817
+ }),
2818
+ /* @__PURE__ */ jsx("text", {
2819
+ x: "12",
2820
+ y: "16",
2821
+ textAnchor: "middle",
2822
+ fill: "white",
2823
+ fontSize: "5",
2824
+ fontWeight: "bold",
2825
+ fontFamily: "system-ui, sans-serif",
2826
+ children: "PDF"
2827
+ })
2828
+ ]
2829
+ });
2830
+ }
2831
+
2832
+ //#endregion
2833
+ //#region src/icons/word-icon.tsx
2834
+ function WordIcon(props) {
2835
+ return /* @__PURE__ */ jsxs("svg", {
2836
+ xmlns: "http://www.w3.org/2000/svg",
2837
+ viewBox: "0 0 24 24",
2838
+ fill: "none",
2839
+ ...props,
2840
+ className: cn("shrink-0", props.className),
2841
+ children: [
2842
+ /* @__PURE__ */ jsx("path", {
2843
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
2844
+ fill: "#1976D2"
2845
+ }),
2846
+ /* @__PURE__ */ jsx("path", {
2847
+ d: "M14 2v6h6",
2848
+ fill: "#BBDEFB"
2849
+ }),
2850
+ /* @__PURE__ */ jsx("path", {
2851
+ d: "M14 2v6h6",
2852
+ stroke: "#1976D2",
2853
+ strokeWidth: 1.5,
2854
+ strokeLinecap: "round",
2855
+ strokeLinejoin: "round"
2856
+ }),
2857
+ /* @__PURE__ */ jsx("text", {
2858
+ x: "12",
2859
+ y: "16",
2860
+ textAnchor: "middle",
2861
+ fill: "white",
2862
+ fontSize: "5",
2863
+ fontWeight: "bold",
2864
+ fontFamily: "system-ui, sans-serif",
2865
+ children: "DOC"
2866
+ })
2867
+ ]
2868
+ });
2869
+ }
2870
+
2871
+ //#endregion
2872
+ //#region src/icons/excel-icon.tsx
2873
+ function ExcelIcon(props) {
2874
+ return /* @__PURE__ */ jsxs("svg", {
2875
+ xmlns: "http://www.w3.org/2000/svg",
2876
+ viewBox: "0 0 24 24",
2877
+ fill: "none",
2878
+ ...props,
2879
+ className: cn("shrink-0", props.className),
2880
+ children: [
2881
+ /* @__PURE__ */ jsx("path", {
2882
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
2883
+ fill: "#388E3C"
2884
+ }),
2885
+ /* @__PURE__ */ jsx("path", {
2886
+ d: "M14 2v6h6",
2887
+ fill: "#C8E6C9"
2888
+ }),
2889
+ /* @__PURE__ */ jsx("path", {
2890
+ d: "M14 2v6h6",
2891
+ stroke: "#388E3C",
2892
+ strokeWidth: 1.5,
2893
+ strokeLinecap: "round",
2894
+ strokeLinejoin: "round"
2895
+ }),
2896
+ /* @__PURE__ */ jsx("text", {
2897
+ x: "12",
2898
+ y: "16",
2899
+ textAnchor: "middle",
2900
+ fill: "white",
2901
+ fontSize: "5",
2902
+ fontWeight: "bold",
2903
+ fontFamily: "system-ui, sans-serif",
2904
+ children: "XLS"
2905
+ })
2906
+ ]
2907
+ });
2908
+ }
2909
+
2910
+ //#endregion
2911
+ //#region src/icons/image-file-icon.tsx
2912
+ function ImageFileIcon(props) {
2913
+ return /* @__PURE__ */ jsxs("svg", {
2914
+ xmlns: "http://www.w3.org/2000/svg",
2915
+ viewBox: "0 0 24 24",
2916
+ fill: "none",
2917
+ ...props,
2918
+ className: cn("shrink-0", props.className),
2919
+ children: [
2920
+ /* @__PURE__ */ jsx("path", {
2921
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
2922
+ fill: "#7B1FA2"
2923
+ }),
2924
+ /* @__PURE__ */ jsx("path", {
2925
+ d: "M14 2v6h6",
2926
+ fill: "#E1BEE7"
2927
+ }),
2928
+ /* @__PURE__ */ jsx("path", {
2929
+ d: "M14 2v6h6",
2930
+ stroke: "#7B1FA2",
2931
+ strokeWidth: 1.5,
2932
+ strokeLinecap: "round",
2933
+ strokeLinejoin: "round"
2934
+ }),
2935
+ /* @__PURE__ */ jsx("circle", {
2936
+ cx: "9",
2937
+ cy: "13",
2938
+ r: "1.5",
2939
+ fill: "white"
2940
+ }),
2941
+ /* @__PURE__ */ jsx("path", {
2942
+ d: "M17 18H7l3-4 2 2 3-4 2 3",
2943
+ stroke: "white",
2944
+ strokeWidth: 1.5,
2945
+ strokeLinecap: "round",
2946
+ strokeLinejoin: "round",
2947
+ fill: "none"
2948
+ })
2949
+ ]
2772
2950
  });
2773
2951
  }
2774
2952
 
2953
+ //#endregion
2954
+ //#region src/icons/video-icon.tsx
2955
+ function VideoIcon(props) {
2956
+ return /* @__PURE__ */ jsxs("svg", {
2957
+ xmlns: "http://www.w3.org/2000/svg",
2958
+ viewBox: "0 0 24 24",
2959
+ fill: "none",
2960
+ ...props,
2961
+ className: cn("shrink-0", props.className),
2962
+ children: [
2963
+ /* @__PURE__ */ jsx("path", {
2964
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
2965
+ fill: "#D32F2F"
2966
+ }),
2967
+ /* @__PURE__ */ jsx("path", {
2968
+ d: "M14 2v6h6",
2969
+ fill: "#FFCDD2"
2970
+ }),
2971
+ /* @__PURE__ */ jsx("path", {
2972
+ d: "M14 2v6h6",
2973
+ stroke: "#D32F2F",
2974
+ strokeWidth: 1.5,
2975
+ strokeLinecap: "round",
2976
+ strokeLinejoin: "round"
2977
+ }),
2978
+ /* @__PURE__ */ jsx("path", {
2979
+ d: "M10 12v6l5-3-5-3Z",
2980
+ fill: "white"
2981
+ })
2982
+ ]
2983
+ });
2984
+ }
2985
+
2986
+ //#endregion
2987
+ //#region src/icons/audio-icon.tsx
2988
+ function AudioIcon(props) {
2989
+ return /* @__PURE__ */ jsxs("svg", {
2990
+ xmlns: "http://www.w3.org/2000/svg",
2991
+ viewBox: "0 0 24 24",
2992
+ fill: "none",
2993
+ ...props,
2994
+ className: cn("shrink-0", props.className),
2995
+ children: [
2996
+ /* @__PURE__ */ jsx("path", {
2997
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
2998
+ fill: "#F57C00"
2999
+ }),
3000
+ /* @__PURE__ */ jsx("path", {
3001
+ d: "M14 2v6h6",
3002
+ fill: "#FFE0B2"
3003
+ }),
3004
+ /* @__PURE__ */ jsx("path", {
3005
+ d: "M14 2v6h6",
3006
+ stroke: "#F57C00",
3007
+ strokeWidth: 1.5,
3008
+ strokeLinecap: "round",
3009
+ strokeLinejoin: "round"
3010
+ }),
3011
+ /* @__PURE__ */ jsx("path", {
3012
+ d: "M12 11v5.5a2 2 0 1 1-2-2h2",
3013
+ stroke: "white",
3014
+ strokeWidth: 1.5,
3015
+ strokeLinecap: "round",
3016
+ strokeLinejoin: "round",
3017
+ fill: "none"
3018
+ }),
3019
+ /* @__PURE__ */ jsx("path", {
3020
+ d: "M12 11l3-1v4",
3021
+ stroke: "white",
3022
+ strokeWidth: 1.5,
3023
+ strokeLinecap: "round",
3024
+ strokeLinejoin: "round",
3025
+ fill: "none"
3026
+ })
3027
+ ]
3028
+ });
3029
+ }
3030
+
3031
+ //#endregion
3032
+ //#region src/icons/archive-icon.tsx
3033
+ function ArchiveIcon(props) {
3034
+ return /* @__PURE__ */ jsxs("svg", {
3035
+ xmlns: "http://www.w3.org/2000/svg",
3036
+ viewBox: "0 0 24 24",
3037
+ fill: "none",
3038
+ ...props,
3039
+ className: cn("shrink-0", props.className),
3040
+ children: [
3041
+ /* @__PURE__ */ jsx("path", {
3042
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
3043
+ fill: "#795548"
3044
+ }),
3045
+ /* @__PURE__ */ jsx("path", {
3046
+ d: "M14 2v6h6",
3047
+ fill: "#D7CCC8"
3048
+ }),
3049
+ /* @__PURE__ */ jsx("path", {
3050
+ d: "M14 2v6h6",
3051
+ stroke: "#795548",
3052
+ strokeWidth: 1.5,
3053
+ strokeLinecap: "round",
3054
+ strokeLinejoin: "round"
3055
+ }),
3056
+ /* @__PURE__ */ jsx("rect", {
3057
+ x: "9",
3058
+ y: "11",
3059
+ width: "2",
3060
+ height: "2",
3061
+ fill: "white"
3062
+ }),
3063
+ /* @__PURE__ */ jsx("rect", {
3064
+ x: "11",
3065
+ y: "13",
3066
+ width: "2",
3067
+ height: "2",
3068
+ fill: "white"
3069
+ }),
3070
+ /* @__PURE__ */ jsx("rect", {
3071
+ x: "9",
3072
+ y: "15",
3073
+ width: "2",
3074
+ height: "2",
3075
+ fill: "white"
3076
+ }),
3077
+ /* @__PURE__ */ jsx("rect", {
3078
+ x: "11",
3079
+ y: "17",
3080
+ width: "2",
3081
+ height: "2",
3082
+ fill: "white"
3083
+ })
3084
+ ]
3085
+ });
3086
+ }
3087
+
3088
+ //#endregion
3089
+ //#region src/icons/code-file-icon.tsx
3090
+ function CodeFileIcon(props) {
3091
+ return /* @__PURE__ */ jsxs("svg", {
3092
+ xmlns: "http://www.w3.org/2000/svg",
3093
+ viewBox: "0 0 24 24",
3094
+ fill: "none",
3095
+ ...props,
3096
+ className: cn("shrink-0", props.className),
3097
+ children: [
3098
+ /* @__PURE__ */ jsx("path", {
3099
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
3100
+ fill: "#455A64"
3101
+ }),
3102
+ /* @__PURE__ */ jsx("path", {
3103
+ d: "M14 2v6h6",
3104
+ fill: "#CFD8DC"
3105
+ }),
3106
+ /* @__PURE__ */ jsx("path", {
3107
+ d: "M14 2v6h6",
3108
+ stroke: "#455A64",
3109
+ strokeWidth: 1.5,
3110
+ strokeLinecap: "round",
3111
+ strokeLinejoin: "round"
3112
+ }),
3113
+ /* @__PURE__ */ jsx("path", {
3114
+ d: "M9 12l-2 2.5L9 17",
3115
+ stroke: "white",
3116
+ strokeWidth: 1.5,
3117
+ strokeLinecap: "round",
3118
+ strokeLinejoin: "round"
3119
+ }),
3120
+ /* @__PURE__ */ jsx("path", {
3121
+ d: "M15 12l2 2.5-2 2.5",
3122
+ stroke: "white",
3123
+ strokeWidth: 1.5,
3124
+ strokeLinecap: "round",
3125
+ strokeLinejoin: "round"
3126
+ })
3127
+ ]
3128
+ });
3129
+ }
3130
+
3131
+ //#endregion
3132
+ //#region src/icons/text-file-icon.tsx
3133
+ function TextFileIcon(props) {
3134
+ return /* @__PURE__ */ jsxs("svg", {
3135
+ xmlns: "http://www.w3.org/2000/svg",
3136
+ viewBox: "0 0 24 24",
3137
+ fill: "none",
3138
+ ...props,
3139
+ className: cn("shrink-0", props.className),
3140
+ children: [
3141
+ /* @__PURE__ */ jsx("path", {
3142
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
3143
+ fill: "#607D8B"
3144
+ }),
3145
+ /* @__PURE__ */ jsx("path", {
3146
+ d: "M14 2v6h6",
3147
+ fill: "#CFD8DC"
3148
+ }),
3149
+ /* @__PURE__ */ jsx("path", {
3150
+ d: "M14 2v6h6",
3151
+ stroke: "#607D8B",
3152
+ strokeWidth: 1.5,
3153
+ strokeLinecap: "round",
3154
+ strokeLinejoin: "round"
3155
+ }),
3156
+ /* @__PURE__ */ jsx("path", {
3157
+ d: "M8 12h8M8 15h6M8 18h4",
3158
+ stroke: "white",
3159
+ strokeWidth: 1.5,
3160
+ strokeLinecap: "round"
3161
+ })
3162
+ ]
3163
+ });
3164
+ }
3165
+
3166
+ //#endregion
3167
+ //#region src/icons/generic-file-icon.tsx
3168
+ function GenericFileIcon(props) {
3169
+ return /* @__PURE__ */ jsxs("svg", {
3170
+ xmlns: "http://www.w3.org/2000/svg",
3171
+ viewBox: "0 0 24 24",
3172
+ fill: "none",
3173
+ ...props,
3174
+ className: cn("shrink-0", props.className),
3175
+ children: [
3176
+ /* @__PURE__ */ jsx("path", {
3177
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Z",
3178
+ fill: "#9E9E9E"
3179
+ }),
3180
+ /* @__PURE__ */ jsx("path", {
3181
+ d: "M14 2v6h6",
3182
+ fill: "#E0E0E0"
3183
+ }),
3184
+ /* @__PURE__ */ jsx("path", {
3185
+ d: "M14 2v6h6",
3186
+ stroke: "#9E9E9E",
3187
+ strokeWidth: 1.5,
3188
+ strokeLinecap: "round",
3189
+ strokeLinejoin: "round"
3190
+ })
3191
+ ]
3192
+ });
3193
+ }
3194
+
3195
+ //#endregion
3196
+ //#region src/icons/get-file-type-icon.ts
3197
+ const extensionMap = {
3198
+ pdf: PdfIcon,
3199
+ doc: WordIcon,
3200
+ docx: WordIcon,
3201
+ rtf: WordIcon,
3202
+ odt: WordIcon,
3203
+ xls: ExcelIcon,
3204
+ xlsx: ExcelIcon,
3205
+ csv: ExcelIcon,
3206
+ ods: ExcelIcon,
3207
+ png: ImageFileIcon,
3208
+ jpg: ImageFileIcon,
3209
+ jpeg: ImageFileIcon,
3210
+ gif: ImageFileIcon,
3211
+ webp: ImageFileIcon,
3212
+ svg: ImageFileIcon,
3213
+ bmp: ImageFileIcon,
3214
+ ico: ImageFileIcon,
3215
+ tiff: ImageFileIcon,
3216
+ tif: ImageFileIcon,
3217
+ mp4: VideoIcon,
3218
+ webm: VideoIcon,
3219
+ mov: VideoIcon,
3220
+ avi: VideoIcon,
3221
+ mkv: VideoIcon,
3222
+ wmv: VideoIcon,
3223
+ flv: VideoIcon,
3224
+ mp3: AudioIcon,
3225
+ wav: AudioIcon,
3226
+ ogg: AudioIcon,
3227
+ flac: AudioIcon,
3228
+ aac: AudioIcon,
3229
+ m4a: AudioIcon,
3230
+ wma: AudioIcon,
3231
+ zip: ArchiveIcon,
3232
+ rar: ArchiveIcon,
3233
+ "7z": ArchiveIcon,
3234
+ tar: ArchiveIcon,
3235
+ gz: ArchiveIcon,
3236
+ bz2: ArchiveIcon,
3237
+ js: CodeFileIcon,
3238
+ jsx: CodeFileIcon,
3239
+ ts: CodeFileIcon,
3240
+ tsx: CodeFileIcon,
3241
+ json: CodeFileIcon,
3242
+ html: CodeFileIcon,
3243
+ css: CodeFileIcon,
3244
+ scss: CodeFileIcon,
3245
+ less: CodeFileIcon,
3246
+ py: CodeFileIcon,
3247
+ rb: CodeFileIcon,
3248
+ java: CodeFileIcon,
3249
+ c: CodeFileIcon,
3250
+ cpp: CodeFileIcon,
3251
+ h: CodeFileIcon,
3252
+ go: CodeFileIcon,
3253
+ rs: CodeFileIcon,
3254
+ php: CodeFileIcon,
3255
+ sql: CodeFileIcon,
3256
+ sh: CodeFileIcon,
3257
+ bash: CodeFileIcon,
3258
+ yml: CodeFileIcon,
3259
+ yaml: CodeFileIcon,
3260
+ xml: CodeFileIcon,
3261
+ txt: TextFileIcon,
3262
+ md: TextFileIcon,
3263
+ markdown: TextFileIcon,
3264
+ log: TextFileIcon
3265
+ };
3266
+ const mimeTypeMap = {
3267
+ "application/pdf": PdfIcon,
3268
+ "application/msword": WordIcon,
3269
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": WordIcon,
3270
+ "application/rtf": WordIcon,
3271
+ "application/vnd.oasis.opendocument.text": WordIcon,
3272
+ "application/vnd.ms-excel": ExcelIcon,
3273
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ExcelIcon,
3274
+ "text/csv": ExcelIcon,
3275
+ "application/vnd.oasis.opendocument.spreadsheet": ExcelIcon,
3276
+ "application/zip": ArchiveIcon,
3277
+ "application/x-rar-compressed": ArchiveIcon,
3278
+ "application/x-7z-compressed": ArchiveIcon,
3279
+ "application/x-tar": ArchiveIcon,
3280
+ "application/gzip": ArchiveIcon,
3281
+ "application/javascript": CodeFileIcon,
3282
+ "application/typescript": CodeFileIcon,
3283
+ "application/json": CodeFileIcon,
3284
+ "text/html": CodeFileIcon,
3285
+ "text/css": CodeFileIcon,
3286
+ "application/xml": CodeFileIcon,
3287
+ "text/xml": CodeFileIcon,
3288
+ "text/plain": TextFileIcon,
3289
+ "text/markdown": TextFileIcon
3290
+ };
3291
+ /**
3292
+ * Get the appropriate file type icon component for a file.
3293
+ * Uses MIME type first, then falls back to file extension.
3294
+ *
3295
+ * @param file - Object with name and optional type (MIME type)
3296
+ * @returns React icon component for the file type
3297
+ *
3298
+ * @example
3299
+ * ```tsx
3300
+ * import { getFileTypeIcon } from "@px-ui/core";
3301
+ *
3302
+ * const Icon = getFileTypeIcon({ name: "document.pdf", type: "application/pdf" });
3303
+ * <Icon className="size-5" />
3304
+ * ```
3305
+ */
3306
+ function getFileTypeIcon(file) {
3307
+ if (file.type) {
3308
+ if (file.type.startsWith("image/")) return ImageFileIcon;
3309
+ if (file.type.startsWith("video/")) return VideoIcon;
3310
+ if (file.type.startsWith("audio/")) return AudioIcon;
3311
+ const mimeIcon = mimeTypeMap[file.type];
3312
+ if (mimeIcon) return mimeIcon;
3313
+ }
3314
+ const extension = file.name.split(".").pop()?.toLowerCase();
3315
+ if (extension) {
3316
+ const extIcon = extensionMap[extension];
3317
+ if (extIcon) return extIcon;
3318
+ }
3319
+ return GenericFileIcon;
3320
+ }
3321
+
2775
3322
  //#endregion
2776
3323
  //#region src/components/file-upload.tsx
2777
3324
  const FileUploadContext = React$1.createContext(null);
@@ -2780,24 +3327,12 @@ function useFileUploadContext() {
2780
3327
  if (!context) throw new Error("FileUpload components must be used within FileUpload.Root");
2781
3328
  return context;
2782
3329
  }
2783
- function Root({ children, files, addFiles, removeFile, clearFiles, retryUpload, openFileDialog, getInputProps, handleDragEnter, handleDragLeave, handleDragOver, handleDrop, isDragActive = false, isUploading = false, accept, multiple = false, disabled = false, className }) {
3330
+ function Root({ children, upload, accept, multiple = false, disabled = false, className }) {
2784
3331
  const contextValue = {
2785
- files,
2786
- addFiles,
2787
- removeFile,
2788
- clearFiles,
2789
- retryUpload,
3332
+ upload,
2790
3333
  accept,
2791
3334
  multiple,
2792
- disabled,
2793
- isDragActive,
2794
- isUploading,
2795
- openFileDialog,
2796
- getInputProps,
2797
- handleDragEnter,
2798
- handleDragLeave,
2799
- handleDragOver,
2800
- handleDrop
3335
+ disabled
2801
3336
  };
2802
3337
  return /* @__PURE__ */ jsx(FileUploadContext.Provider, {
2803
3338
  value: contextValue,
@@ -2825,8 +3360,9 @@ const dropzoneVariants = cva("flex flex-col items-center justify-center gap-4 ro
2825
3360
  isDragActive: false
2826
3361
  }
2827
3362
  });
2828
- function Dropzone({ className, size, children, dropzoneText = "Paste Or Drag & Drop Files Here", browseText = "Browse for files", hideDefaultContent = false, ...props }) {
2829
- const { accept, multiple, disabled, isDragActive, isUploading, openFileDialog, getInputProps, handleDragEnter, handleDragLeave, handleDragOver, handleDrop, addFiles } = useFileUploadContext();
3363
+ function Dropzone({ className, size, dropzoneText = "Paste Or Drag & Drop Files Here", browseText = "Browse for files", render, ...props }) {
3364
+ const { upload, accept, multiple, disabled } = useFileUploadContext();
3365
+ const { isDragging, isUploading, files, openFileDialog, getInputProps, handleDragEnter, handleDragLeave, handleDragOver, handleDrop, addFiles } = upload;
2830
3366
  const descriptionId = React$1.useId();
2831
3367
  const instructionsId = React$1.useId();
2832
3368
  const [announcement, setAnnouncement] = React$1.useState("");
@@ -2839,327 +3375,238 @@ function Dropzone({ className, size, children, dropzoneText = "Paste Or Drag & D
2839
3375
  }, [openFileDialog]);
2840
3376
  const handlePaste = React$1.useCallback((e) => {
2841
3377
  if (disabled) return;
2842
- const files = e.clipboardData.files;
2843
- if (files.length > 0) {
3378
+ const pastedFiles = e.clipboardData.files;
3379
+ if (pastedFiles.length > 0) {
2844
3380
  e.preventDefault();
2845
- const filesArray = Array.from(files);
3381
+ const filesArray = Array.from(pastedFiles);
2846
3382
  addFiles(filesArray);
2847
3383
  setAnnouncement(`${filesArray.length} file${filesArray.length > 1 ? "s" : ""} pasted`);
2848
3384
  }
2849
3385
  }, [disabled, addFiles]);
2850
- return /* @__PURE__ */ jsxs("div", {
2851
- "data-slot": "file-upload-dropzone",
2852
- className: cn(dropzoneVariants({
2853
- size,
2854
- isDragActive
2855
- }), disabled && "cursor-not-allowed opacity-60", className),
3386
+ const handleClick = React$1.useCallback(() => {
3387
+ if (disabled || isUploading) return;
3388
+ openFileDialog();
3389
+ }, [
3390
+ disabled,
3391
+ isUploading,
3392
+ openFileDialog
3393
+ ]);
3394
+ const state = {
3395
+ isDragging,
3396
+ isUploading,
3397
+ disabled,
3398
+ files
3399
+ };
3400
+ const renderProps = {
2856
3401
  onDragEnter: handleDragEnter,
2857
3402
  onDragLeave: handleDragLeave,
2858
3403
  onDragOver: handleDragOver,
2859
3404
  onDrop: handleDrop,
2860
3405
  onPaste: handlePaste,
2861
3406
  onKeyDown: handleKeyDown,
3407
+ onClick: handleClick,
2862
3408
  tabIndex: disabled ? -1 : 0,
2863
3409
  role: "button",
2864
3410
  "aria-disabled": disabled,
3411
+ "data-dragging": isDragging
3412
+ };
3413
+ const hiddenInput = /* @__PURE__ */ jsx("input", {
3414
+ ...inputProps,
3415
+ className: "sr-only",
3416
+ accept,
3417
+ multiple,
3418
+ disabled,
3419
+ tabIndex: -1,
3420
+ "aria-hidden": "true"
3421
+ });
3422
+ const srElements = /* @__PURE__ */ jsxs(Fragment, { children: [
3423
+ /* @__PURE__ */ jsx("div", {
3424
+ role: "status",
3425
+ "aria-live": "polite",
3426
+ "aria-atomic": "true",
3427
+ className: "sr-only",
3428
+ children: announcement
3429
+ }),
3430
+ /* @__PURE__ */ jsx("div", {
3431
+ id: descriptionId,
3432
+ className: "sr-only",
3433
+ children: dropzoneText
3434
+ }),
3435
+ /* @__PURE__ */ jsx("div", {
3436
+ id: instructionsId,
3437
+ className: "sr-only",
3438
+ children: "Press Enter or Space to browse files, or drag and drop files here."
3439
+ })
3440
+ ] });
3441
+ if (render) return /* @__PURE__ */ jsxs("div", {
3442
+ "data-slot": "file-upload-dropzone",
3443
+ children: [
3444
+ hiddenInput,
3445
+ srElements,
3446
+ render(renderProps, state)
3447
+ ]
3448
+ });
3449
+ return /* @__PURE__ */ jsxs("div", {
3450
+ "data-slot": "file-upload-dropzone",
3451
+ className: cn(dropzoneVariants({
3452
+ size,
3453
+ isDragActive: isDragging
3454
+ }), disabled && "cursor-not-allowed opacity-60", className),
3455
+ ...renderProps,
2865
3456
  "aria-describedby": `${descriptionId} ${instructionsId}`,
2866
3457
  "aria-label": "File upload dropzone",
2867
3458
  ...props,
2868
3459
  children: [
2869
- /* @__PURE__ */ jsx("div", {
2870
- role: "status",
2871
- "aria-live": "polite",
2872
- "aria-atomic": "true",
2873
- className: "sr-only",
2874
- children: announcement
2875
- }),
2876
- /* @__PURE__ */ jsx("div", {
2877
- id: descriptionId,
2878
- className: "sr-only",
2879
- children: dropzoneText
3460
+ srElements,
3461
+ hiddenInput,
3462
+ /* @__PURE__ */ jsxs("div", {
3463
+ className: "text-ppx-neutral-10 flex items-center gap-3",
3464
+ children: [/* @__PURE__ */ jsx(UploadCloudIcon, {
3465
+ size: 40,
3466
+ "aria-hidden": "true"
3467
+ }), /* @__PURE__ */ jsx("span", {
3468
+ className: "text-ppx-base text-ppx-neutral-13 font-medium",
3469
+ children: dropzoneText
3470
+ })]
2880
3471
  }),
2881
- /* @__PURE__ */ jsx("div", {
2882
- id: instructionsId,
2883
- className: "sr-only",
2884
- children: "Press Enter or Space to browse files, or drag and drop files here."
2885
- }),
2886
- /* @__PURE__ */ jsx("input", {
2887
- ...inputProps,
2888
- className: "sr-only",
2889
- accept,
2890
- multiple,
2891
- disabled,
2892
- tabIndex: -1,
2893
- "aria-hidden": "true"
3472
+ /* @__PURE__ */ jsxs("div", {
3473
+ className: "flex w-full items-center gap-3",
3474
+ "aria-hidden": "true",
3475
+ children: [
3476
+ /* @__PURE__ */ jsx("div", { className: "bg-ppx-neutral-5 h-px flex-1" }),
3477
+ /* @__PURE__ */ jsx("span", {
3478
+ className: "text-ppx-sm text-ppx-neutral-10 font-medium",
3479
+ children: "OR"
3480
+ }),
3481
+ /* @__PURE__ */ jsx("div", { className: "bg-ppx-neutral-5 h-px flex-1" })
3482
+ ]
2894
3483
  }),
2895
- children ? children : !hideDefaultContent ? /* @__PURE__ */ jsxs(Fragment, { children: [
2896
- /* @__PURE__ */ jsxs("div", {
2897
- className: "text-ppx-neutral-10 flex items-center gap-3",
2898
- children: [/* @__PURE__ */ jsx(UploadCloudIcon, {
2899
- size: 40,
2900
- "aria-hidden": "true"
2901
- }), /* @__PURE__ */ jsx("span", {
2902
- className: "text-ppx-base text-ppx-neutral-13 font-medium",
2903
- children: dropzoneText
2904
- })]
2905
- }),
2906
- /* @__PURE__ */ jsxs("div", {
2907
- className: "flex w-full items-center gap-3",
2908
- "aria-hidden": "true",
2909
- children: [
2910
- /* @__PURE__ */ jsx("div", { className: "bg-ppx-neutral-5 h-px flex-1" }),
2911
- /* @__PURE__ */ jsx("span", {
2912
- className: "text-ppx-sm text-ppx-neutral-10 font-medium",
2913
- children: "OR"
2914
- }),
2915
- /* @__PURE__ */ jsx("div", { className: "bg-ppx-neutral-5 h-px flex-1" })
2916
- ]
2917
- }),
2918
- /* @__PURE__ */ jsx(Button, {
2919
- type: "button",
2920
- variant: "default",
2921
- onClick: openFileDialog,
2922
- disabled: disabled || isUploading,
2923
- children: isUploading ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SpinnerIcon, { className: "size-4 animate-spin" }), "Uploading..."] }) : browseText
2924
- })
2925
- ] }) : null
3484
+ /* @__PURE__ */ jsx(Button, {
3485
+ type: "button",
3486
+ variant: "default",
3487
+ disabled: disabled || isUploading,
3488
+ children: isUploading ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SpinnerIcon, { className: "size-4 animate-spin" }), "Uploading..."] }) : browseText
3489
+ })
2926
3490
  ]
2927
3491
  });
2928
3492
  }
2929
- function Trigger({ children, uploadingText = "Uploading...", showUploadingState = true, hideDefaultContent = false, ...props }) {
2930
- const { openFileDialog, disabled, isUploading } = useFileUploadContext();
2931
- return /* @__PURE__ */ jsx(Button, {
2932
- type: "button",
2933
- onClick: openFileDialog,
2934
- disabled: disabled || showUploadingState && isUploading,
2935
- "data-slot": "file-upload-trigger",
2936
- className: cn(hideDefaultContent && "not-disabled:hover:bg-transparent h-auto border-none bg-transparent p-0 shadow-none hover:bg-transparent focus-visible:ring-0 active:bg-transparent", props.className),
3493
+ function HiddenInput({ className, ...props }) {
3494
+ const { upload, accept, multiple, disabled } = useFileUploadContext();
3495
+ return /* @__PURE__ */ jsx("input", {
3496
+ ...upload.getInputProps(),
2937
3497
  ...props,
2938
- children: showUploadingState && isUploading ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SpinnerIcon, { className: "size-4 animate-spin" }), uploadingText] }) : children ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(UploadIcon, { className: "size-4" }), "Select files"] })
3498
+ className: cn("sr-only", className),
3499
+ accept,
3500
+ multiple,
3501
+ disabled,
3502
+ tabIndex: -1,
3503
+ "aria-hidden": "true"
2939
3504
  });
2940
3505
  }
2941
- function ItemList({ className, children, ...props }) {
2942
- const { files } = useFileUploadContext();
3506
+ function List({ className, children, ...props }) {
3507
+ const { upload } = useFileUploadContext();
3508
+ const { files } = upload;
2943
3509
  if (files.length === 0) return null;
2944
3510
  return /* @__PURE__ */ jsx("div", {
2945
- "data-slot": "file-upload-item-list",
3511
+ "data-slot": "file-upload-list",
2946
3512
  className: cn("flex flex-col gap-2", className),
2947
3513
  ...props,
2948
3514
  children: typeof children === "function" ? children(files) : children
2949
3515
  });
2950
3516
  }
2951
- const ItemContext = React$1.createContext(null);
2952
- function useFileUploadItem() {
2953
- const context = React$1.useContext(ItemContext);
2954
- if (!context) throw new Error("FileUpload.Item* components must be used within FileUpload.Item");
2955
- return context;
2956
- }
2957
- function Item({ file, className, children, statusStyles = true, ...props }) {
2958
- return /* @__PURE__ */ jsx(ItemContext.Provider, {
2959
- value: file,
2960
- children: /* @__PURE__ */ jsx("div", {
2961
- "data-slot": "file-upload-item",
2962
- "data-status": file.status,
2963
- className: cn("rounded-ppx-s border-ppx-neutral-4 bg-ppx-neutral-1 flex items-center gap-3 border p-3", statusStyles && file.status === "error" && "border-ppx-red-4 bg-ppx-red-1", className),
2964
- ...props,
2965
- children
2966
- })
2967
- });
2968
- }
2969
- function ItemPreview({ className, fallback, ...props }) {
2970
- const file = useFileUploadItem();
2971
- return /* @__PURE__ */ jsx("div", {
2972
- "data-slot": "file-upload-item-preview",
2973
- className: cn("rounded-ppx-xs bg-ppx-neutral-3 flex size-10 shrink-0 items-center justify-center overflow-hidden", className),
2974
- ...props,
2975
- children: file.preview ? /* @__PURE__ */ jsx("img", {
2976
- src: file.preview,
2977
- alt: file.file.name,
2978
- className: "size-full object-cover"
2979
- }) : fallback ?? /* @__PURE__ */ jsx(FileIcon, { className: "text-ppx-neutral-10 size-5" })
2980
- });
2981
- }
2982
- function ItemName({ className, ...props }) {
2983
- const file = useFileUploadItem();
2984
- return /* @__PURE__ */ jsx("span", {
2985
- "data-slot": "file-upload-item-name",
2986
- className: cn("text-ppx-sm text-ppx-neutral-14 truncate font-medium", className),
2987
- ...props,
2988
- children: file.file.name
2989
- });
2990
- }
2991
- function ItemSize({ className, ...props }) {
2992
- const file = useFileUploadItem();
2993
- return /* @__PURE__ */ jsx("span", {
2994
- "data-slot": "file-upload-item-size",
2995
- className: cn("text-ppx-xs text-ppx-neutral-10", className),
2996
- ...props,
2997
- children: formatBytes(file.file.size)
2998
- });
2999
- }
3000
- function ItemRemove({ className, children, ...props }) {
3001
- const { removeFile } = useFileUploadContext();
3002
- const file = useFileUploadItem();
3003
- return /* @__PURE__ */ jsx(Button, {
3004
- type: "button",
3005
- variant: "ghost",
3006
- size: "icon-sm",
3007
- onClick: () => removeFile(file.id),
3008
- "data-slot": "file-upload-item-remove",
3009
- "aria-label": `Remove ${file.file.name}`,
3010
- className: cn("ml-auto shrink-0", className),
3011
- ...props,
3012
- children: children ?? /* @__PURE__ */ jsx(CloseIcon, { className: "size-4" })
3013
- });
3014
- }
3015
- function ItemProgress({ className, ...props }) {
3016
- const file = useFileUploadItem();
3017
- if (file.progress === void 0) return null;
3018
- return /* @__PURE__ */ jsx("div", {
3019
- "data-slot": "file-upload-item-progress",
3020
- className: cn("bg-ppx-neutral-3 h-1.5 w-full overflow-hidden rounded-full", className),
3021
- ...props,
3022
- children: /* @__PURE__ */ jsx("div", {
3023
- className: "bg-ppx-primary-5 h-full transition-all duration-300",
3024
- style: { width: `${file.progress}%` }
3025
- })
3026
- });
3027
- }
3028
- function ItemStatus({ className, successIcon, uploadingContent, errorContent, ...props }) {
3029
- const file = useFileUploadItem();
3030
- if (file.status === "uploading") return /* @__PURE__ */ jsx("span", {
3031
- "data-slot": "file-upload-item-status",
3032
- className: cn("text-ppx-xs text-ppx-neutral-10 shrink-0", className),
3033
- ...props,
3034
- children: uploadingContent ?? `${file.progress ?? 0}%`
3517
+ function ListItem({ file, className, showIcon = true, showProgress = true, showError = true, showRemove = true, showRetry = true, icon, ...props }) {
3518
+ const { upload, disabled } = useFileUploadContext();
3519
+ const { removeFile, retryUpload } = upload;
3520
+ const isUploading = file.status === "uploading";
3521
+ const isError = file.status === "error";
3522
+ const FileTypeIcon = getFileTypeIcon({
3523
+ name: file.file.name,
3524
+ type: file.file.type
3035
3525
  });
3036
- if (file.status === "success") return /* @__PURE__ */ jsx("span", {
3037
- "data-slot": "file-upload-item-status",
3038
- className: cn("text-ppx-green-5 shrink-0", className),
3039
- ...props,
3040
- children: successIcon ?? /* @__PURE__ */ jsx(CheckIcon, { className: "size-4" })
3041
- });
3042
- if (file.status === "error") return /* @__PURE__ */ jsx("span", {
3043
- "data-slot": "file-upload-item-status",
3044
- className: cn("text-ppx-xs text-ppx-red-5 shrink-0", className),
3045
- ...props,
3046
- children: errorContent ?? "Failed"
3047
- });
3048
- return null;
3049
- }
3050
- function ItemError({ className, ...props }) {
3051
- const file = useFileUploadItem();
3052
- if (!file.error) return null;
3053
- return /* @__PURE__ */ jsx("span", {
3054
- "data-slot": "file-upload-item-error",
3055
- className: cn("text-ppx-xs text-ppx-red-5", className),
3056
- ...props,
3057
- children: file.error
3058
- });
3059
- }
3060
- function ItemRetry({ className, children, ...props }) {
3061
- const { retryUpload } = useFileUploadContext();
3062
- const file = useFileUploadItem();
3063
- if (file.status !== "error" || !retryUpload) return null;
3064
- return /* @__PURE__ */ jsx(Button, {
3065
- type: "button",
3066
- variant: "ghost",
3067
- size: "icon-sm",
3068
- onClick: () => retryUpload(file.id),
3069
- "data-slot": "file-upload-item-retry",
3070
- "aria-label": `Retry uploading ${file.file.name}`,
3071
- className: cn("shrink-0", className),
3072
- ...props,
3073
- children: children ?? /* @__PURE__ */ jsx(RetryIcon, { className: "size-4" })
3074
- });
3075
- }
3076
- function ClearButton({ children, ...props }) {
3077
- const { clearFiles, files } = useFileUploadContext();
3078
- if (files.length === 0) return null;
3079
- return /* @__PURE__ */ jsx(Button, {
3080
- type: "button",
3081
- variant: "ghost",
3082
- onClick: clearFiles,
3083
- "data-slot": "file-upload-clear",
3084
- ...props,
3085
- children: children ?? "Remove all files"
3086
- });
3087
- }
3088
- function ImageGrid({ className, children, ...props }) {
3089
- const { files } = useFileUploadContext();
3090
- if (files.length === 0) return null;
3091
- return /* @__PURE__ */ jsx("div", {
3092
- "data-slot": "file-upload-image-grid",
3093
- className: cn("grid grid-cols-4 gap-2", className),
3094
- ...props,
3095
- children: typeof children === "function" ? children(files) : children
3096
- });
3097
- }
3098
- function ImageGridItem({ file, className, showStatusOverlay = true, ...props }) {
3099
- const { removeFile, retryUpload } = useFileUploadContext();
3100
3526
  return /* @__PURE__ */ jsxs("div", {
3101
- "data-slot": "file-upload-image-grid-item",
3527
+ "data-slot": "file-upload-list-item",
3102
3528
  "data-status": file.status,
3103
- className: cn("rounded-ppx-s group relative aspect-square overflow-hidden", file.status === "error" && "ring-ppx-red-5 ring-2", className),
3529
+ className: cn("rounded-ppx-s border-ppx-neutral-4 bg-ppx-neutral-1 flex items-center gap-3 border p-3", isError && "border-ppx-red-4 bg-ppx-red-1", className),
3104
3530
  ...props,
3105
3531
  children: [
3106
- file.preview ? /* @__PURE__ */ jsx("img", {
3107
- src: file.preview,
3108
- alt: file.file.name,
3109
- className: "size-full object-cover"
3110
- }) : /* @__PURE__ */ jsx("div", {
3111
- className: "bg-ppx-neutral-3 flex size-full items-center justify-center",
3112
- children: /* @__PURE__ */ jsx(FileIcon, { className: "text-ppx-neutral-10 size-8" })
3532
+ showIcon && /* @__PURE__ */ jsx("div", {
3533
+ className: "rounded-ppx-xs bg-ppx-neutral-3 flex size-10 shrink-0 items-center justify-center overflow-hidden",
3534
+ children: file.preview ? /* @__PURE__ */ jsx("img", {
3535
+ src: file.preview,
3536
+ alt: file.file.name,
3537
+ className: "size-full object-cover"
3538
+ }) : icon ? icon : /* @__PURE__ */ jsx(FileTypeIcon, { className: "size-5" })
3113
3539
  }),
3114
- showStatusOverlay && file.status === "uploading" && /* @__PURE__ */ jsx("div", {
3115
- className: "absolute inset-0 flex items-center justify-center bg-black/40",
3116
- children: /* @__PURE__ */ jsxs("div", {
3117
- className: "text-sm font-medium text-white",
3118
- children: [file.progress, "%"]
3119
- })
3540
+ /* @__PURE__ */ jsxs("div", {
3541
+ className: "flex min-w-0 flex-1 flex-col gap-1",
3542
+ children: [
3543
+ /* @__PURE__ */ jsx("span", {
3544
+ className: "text-ppx-sm text-ppx-neutral-14 truncate font-medium",
3545
+ children: file.file.name
3546
+ }),
3547
+ /* @__PURE__ */ jsxs("div", {
3548
+ className: "flex items-center gap-2",
3549
+ children: [showProgress && isUploading && /* @__PURE__ */ jsx("div", {
3550
+ className: "bg-ppx-neutral-3 h-1.5 flex-1 overflow-hidden rounded-full",
3551
+ children: /* @__PURE__ */ jsx("div", {
3552
+ className: "bg-ppx-primary-5 h-full transition-all duration-300",
3553
+ style: { width: `${file.progress}%` }
3554
+ })
3555
+ }), isUploading && /* @__PURE__ */ jsxs("span", {
3556
+ className: "text-ppx-xs text-ppx-neutral-10 shrink-0",
3557
+ children: [file.progress, "%"]
3558
+ })]
3559
+ }),
3560
+ showError && isError && file.error && /* @__PURE__ */ jsx("span", {
3561
+ className: "text-ppx-xs text-ppx-red-5",
3562
+ children: file.error
3563
+ })
3564
+ ]
3120
3565
  }),
3121
- showStatusOverlay && file.status === "error" && retryUpload && /* @__PURE__ */ jsx("div", {
3122
- className: "absolute inset-0 flex items-center justify-center bg-black/40",
3123
- children: /* @__PURE__ */ jsx(Button, {
3566
+ /* @__PURE__ */ jsxs("div", {
3567
+ className: "flex shrink-0 items-center gap-1",
3568
+ children: [showRetry && isError && /* @__PURE__ */ jsx(Button, {
3124
3569
  type: "button",
3125
3570
  variant: "ghost",
3126
3571
  size: "icon-sm",
3127
3572
  onClick: () => retryUpload(file.id),
3128
- className: "text-white hover:text-white",
3129
- children: /* @__PURE__ */ jsx(RetryIcon, { className: "size-5" })
3130
- })
3131
- }),
3132
- showStatusOverlay && file.status === "success" && /* @__PURE__ */ jsx("div", {
3133
- className: "bg-ppx-green-5 absolute bottom-1 right-1 rounded-full p-0.5",
3134
- children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-3 text-white" })
3135
- }),
3136
- /* @__PURE__ */ jsx("button", {
3137
- type: "button",
3138
- onClick: () => removeFile(file.id),
3139
- className: "absolute right-1 top-1 flex size-6 items-center justify-center rounded-full bg-black/60 text-white opacity-0 transition-opacity group-hover:opacity-100",
3140
- "aria-label": `Remove ${file.file.name}`,
3141
- children: /* @__PURE__ */ jsx(CloseIcon, { className: "size-3" })
3573
+ disabled,
3574
+ "aria-label": `Retry uploading ${file.file.name}`,
3575
+ children: /* @__PURE__ */ jsx(RetryIcon, { className: "size-4" })
3576
+ }), showRemove && /* @__PURE__ */ jsx(Button, {
3577
+ type: "button",
3578
+ variant: "ghost",
3579
+ size: "icon-sm",
3580
+ onClick: () => removeFile(file.id),
3581
+ disabled,
3582
+ "aria-label": `Remove ${file.file.name}`,
3583
+ children: /* @__PURE__ */ jsx(CloseIcon, { className: "size-4" })
3584
+ })]
3142
3585
  })
3143
3586
  ]
3144
3587
  });
3145
3588
  }
3589
+ function ClearAll({ children, ...props }) {
3590
+ const { upload, disabled } = useFileUploadContext();
3591
+ const { clearFiles, files } = upload;
3592
+ if (files.length === 0) return null;
3593
+ return /* @__PURE__ */ jsx(Button, {
3594
+ type: "button",
3595
+ variant: "ghost",
3596
+ onClick: clearFiles,
3597
+ disabled,
3598
+ "data-slot": "file-upload-clear-all",
3599
+ ...props,
3600
+ children: children ?? "Remove all files"
3601
+ });
3602
+ }
3146
3603
  const FileUpload = {
3147
3604
  Root,
3148
3605
  Dropzone,
3149
- Trigger,
3150
- ItemList,
3151
- Item,
3152
- ItemPreview,
3153
- ItemName,
3154
- ItemSize,
3155
- ItemRemove,
3156
- ItemProgress,
3157
- ItemStatus,
3158
- ItemError,
3159
- ItemRetry,
3160
- ClearButton,
3161
- ImageGrid,
3162
- ImageGridItem
3606
+ HiddenInput,
3607
+ List,
3608
+ ListItem,
3609
+ ClearAll
3163
3610
  };
3164
3611
 
3165
3612
  //#endregion
@@ -3236,6 +3683,86 @@ function OtpInput({ length = 6, separatorAfter = [], className, containerClassNa
3236
3683
  });
3237
3684
  }
3238
3685
 
3686
+ //#endregion
3687
+ //#region src/icons/file-icon.tsx
3688
+ function FileIcon(props) {
3689
+ return /* @__PURE__ */ jsxs("svg", {
3690
+ xmlns: "http://www.w3.org/2000/svg",
3691
+ viewBox: "0 0 24 24",
3692
+ fill: "none",
3693
+ stroke: "currentColor",
3694
+ strokeWidth: 2,
3695
+ strokeLinecap: "round",
3696
+ strokeLinejoin: "round",
3697
+ ...props,
3698
+ className: cn("shrink-0", props.className),
3699
+ children: [/* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), /* @__PURE__ */ jsx("polyline", { points: "14,2 14,8 20,8" })]
3700
+ });
3701
+ }
3702
+
3703
+ //#endregion
3704
+ //#region src/icons/upload-icon.tsx
3705
+ function UploadIcon(props) {
3706
+ return /* @__PURE__ */ jsxs("svg", {
3707
+ xmlns: "http://www.w3.org/2000/svg",
3708
+ viewBox: "0 0 24 24",
3709
+ fill: "none",
3710
+ stroke: "currentColor",
3711
+ strokeWidth: 2,
3712
+ strokeLinecap: "round",
3713
+ strokeLinejoin: "round",
3714
+ ...props,
3715
+ className: cn("shrink-0", props.className),
3716
+ children: [
3717
+ /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
3718
+ /* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
3719
+ /* @__PURE__ */ jsx("line", {
3720
+ x1: "12",
3721
+ y1: "3",
3722
+ x2: "12",
3723
+ y2: "15"
3724
+ })
3725
+ ]
3726
+ });
3727
+ }
3728
+
3729
+ //#endregion
3730
+ //#region src/icons/send-icon.tsx
3731
+ function SendIcon(props) {
3732
+ return /* @__PURE__ */ jsx("svg", {
3733
+ xmlns: "http://www.w3.org/2000/svg",
3734
+ viewBox: "0 0 16 16",
3735
+ fill: "none",
3736
+ ...props,
3737
+ className: cn("shrink-0", props.className),
3738
+ children: /* @__PURE__ */ jsx("path", {
3739
+ fill: "currentColor",
3740
+ fillRule: "evenodd",
3741
+ clipRule: "evenodd",
3742
+ d: "M8.75 15V3.56l3.72 3.72 1.06-1.06-5-5a.75.75 0 0 0-1.06 0l-5 5 1.06 1.06 3.72-3.72V15z"
3743
+ })
3744
+ });
3745
+ }
3746
+
3747
+ //#endregion
3748
+ //#region src/icons/stop-icon.tsx
3749
+ function StopIcon(props) {
3750
+ return /* @__PURE__ */ jsx("svg", {
3751
+ xmlns: "http://www.w3.org/2000/svg",
3752
+ viewBox: "0 0 24 24",
3753
+ fill: "currentColor",
3754
+ ...props,
3755
+ className: cn("shrink-0", props.className),
3756
+ children: /* @__PURE__ */ jsx("rect", {
3757
+ x: "6",
3758
+ y: "6",
3759
+ width: "12",
3760
+ height: "12",
3761
+ rx: "2"
3762
+ })
3763
+ });
3764
+ }
3765
+
3239
3766
  //#endregion
3240
3767
  //#region src/hooks/use-mobile.ts
3241
3768
  const MOBILE_BREAKPOINT = 768;
@@ -3254,5 +3781,5 @@ function useIsMobile() {
3254
3781
  }
3255
3782
 
3256
3783
  //#endregion
3257
- export { Avatar, AvatarGroup, AvatarImpl, block_checkbox_group_exports as BlockCheckboxGroup, block_radio_group_exports as BlockRadioGroup, breadcrumbs_exports as Breadcrumbs, Button, Calendar, Checkbox, ChevronDownIcon, collapsible_exports as Collapsible, combobox_exports as Combobox, DatePicker, dialog_exports as Dialog, FileIcon, FileUpload, Input, input_group_exports as InputGroup, Label, menu_exports as Menu, OtpInput, PXUIProvider, popover_exports as Popover, progress_exports as Progress, radio_group_exports as RadioGroup, segmented_control_exports as SegmentedControl, select_exports as Select, Separator, Spinner, Switch, tabs_exports as Tabs, Textarea, tooltip_exports as Tooltip, UploadIcon, anchoredToast, buttonVariants, cn, defineLoadOptions, formatBytes, toast, useAsyncOptions, useFileUpload, useIntersectionObserver, useIsMobile };
3784
+ export { ArchiveIcon, AudioIcon, Avatar, AvatarGroup, AvatarImpl, block_checkbox_group_exports as BlockCheckboxGroup, block_radio_group_exports as BlockRadioGroup, breadcrumbs_exports as Breadcrumbs, Button, Calendar, Checkbox, ChevronDownIcon, CodeFileIcon, collapsible_exports as Collapsible, combobox_exports as Combobox, DatePicker, dialog_exports as Dialog, ExcelIcon, FileIcon, FileUpload, GenericFileIcon, ImageFileIcon, InfoIcon, Input, input_group_exports as InputGroup, Label, menu_exports as Menu, OtpInput, PXUIProvider, PdfIcon, popover_exports as Popover, progress_exports as Progress, radio_group_exports as RadioGroup, segmented_control_exports as SegmentedControl, select_exports as Select, SendIcon, Separator, Spinner, StopIcon, Switch, tabs_exports as Tabs, TextFileIcon, Textarea, tooltip_exports as Tooltip, UploadIcon, VideoIcon, WordIcon, anchoredToast, buttonVariants, cn, defineLoadOptions, formatBytes, getFileTypeIcon, toast, useAsyncOptions, useFileUpload, useIntersectionObserver, useIsMobile };
3258
3785
  //# sourceMappingURL=index.js.map