@px-ui/core 2.0.0 → 2.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
@@ -1,6 +1,6 @@
1
1
  import { n as __reExport, t as __export } from "./chunk-CYeTv9WL.js";
2
2
  import * as React$1 from "react";
3
- import React, { useEffect, useEffectEvent, useMemo, useRef, useState } from "react";
3
+ import React, { useCallback, useEffect, useEffectEvent, useMemo, useRef, useState } from "react";
4
4
  import { Dialog } from "@base-ui-components/react";
5
5
  import classnames from "classnames";
6
6
  import { extendTailwindMerge } from "tailwind-merge";
@@ -133,11 +133,11 @@ var dialog_exports = /* @__PURE__ */ __export({
133
133
  HeaderIcon: () => HeaderIcon,
134
134
  Overlay: () => Overlay,
135
135
  Portal: () => Portal$1,
136
- Root: () => Root$9,
136
+ Root: () => Root$10,
137
137
  Title: () => Title$3,
138
- Trigger: () => Trigger$6
138
+ Trigger: () => Trigger$7
139
139
  });
140
- function Root$9({ ...props }) {
140
+ function Root$10({ ...props }) {
141
141
  return /* @__PURE__ */ jsx(Dialog.Root, {
142
142
  "data-slot": "dialog",
143
143
  ...props
@@ -149,7 +149,7 @@ function Portal$1({ ...props }) {
149
149
  ...props
150
150
  });
151
151
  }
152
- function Trigger$6({ ...props }) {
152
+ function Trigger$7({ ...props }) {
153
153
  return /* @__PURE__ */ jsx(Dialog.Trigger, {
154
154
  "data-slot": "dialog-trigger",
155
155
  ...props
@@ -242,11 +242,11 @@ var popover_exports = /* @__PURE__ */ __export({
242
242
  Description: () => Description$2,
243
243
  Footer: () => Footer,
244
244
  Header: () => Header$2,
245
- Root: () => Root$8,
245
+ Root: () => Root$9,
246
246
  Title: () => Title$2,
247
- Trigger: () => Trigger$5
247
+ Trigger: () => Trigger$6
248
248
  });
249
- function Root$8(props) {
249
+ function Root$9(props) {
250
250
  return /* @__PURE__ */ jsx(Popover.Root, {
251
251
  "data-slot": "popover",
252
252
  ...props
@@ -258,7 +258,7 @@ function Portal(props) {
258
258
  ...props
259
259
  });
260
260
  }
261
- function Trigger$5(props) {
261
+ function Trigger$6(props) {
262
262
  return /* @__PURE__ */ jsx(Popover.Trigger, {
263
263
  "data-slot": "popover-trigger",
264
264
  ...props
@@ -531,7 +531,7 @@ var input_group_exports = /* @__PURE__ */ __export({
531
531
  Addon: () => Addon,
532
532
  Button: () => Button$1,
533
533
  Input: () => Input$1,
534
- Root: () => Root$7,
534
+ Root: () => Root$8,
535
535
  Text: () => Text
536
536
  });
537
537
  const inputGroupVariants = cva("group/input-group relative flex items-center border border-ppx-neutral-5 bg-ppx-neutral-1 outline-transparent has-[[data-slot=input-group-control]:focus-visible]:outline-2 has-[[data-slot=input-group-control]:focus-visible]:-outline-offset-1 has-[[data-slot=input-group-control]:focus-visible]:bg-ppx-background has-[[data-slot=input-group-control]:focus-visible]:outline-ppx-primary-focus has-[[data-slot][aria-invalid=true]]:outline-ppx-red-4 has-[[data-slot][aria-invalid=true]]:outline has-[[data-slot][aria-invalid=true]]:-outline-offset-1 has-[[data-slot][aria-invalid=true]]:bg-ppx-red-1 has-[[data-slot=input-group-control]:disabled]:*:cursor-not-allowed has-[[data-slot=input-group-control]:disabled]:border-ppx-neutral-3 has-[[data-slot=input-group-control]:disabled]:bg-ppx-neutral-3 has-[[data-slot=input-group-control]:disabled]:text-ppx-neutral-11 has-[>[data-align=inline-start]]:[&>input]:pl-input has-[>[data-align=inline-end]]:[&>input]:pr-input", {
@@ -551,7 +551,7 @@ const inputGroupVariants = cva("group/input-group relative flex items-center bor
551
551
  widthVariant: "full"
552
552
  }
553
553
  });
554
- function Root$7({ className, size, disabled, widthVariant, ...props }) {
554
+ function Root$8({ className, size, disabled, widthVariant, ...props }) {
555
555
  return /* @__PURE__ */ jsx("div", {
556
556
  "data-slot": "input-group",
557
557
  role: "group",
@@ -688,22 +688,22 @@ var combobox_exports = /* @__PURE__ */ __export({
688
688
  Chip: () => Chip,
689
689
  ChipsTrigger: () => ChipsTrigger,
690
690
  Content: () => Content$4,
691
- Item: () => Item$6,
691
+ Item: () => Item$7,
692
692
  List: () => List$2,
693
693
  LoadingIndicator: () => LoadingIndicator,
694
694
  MultiItem: () => MultiItem$1,
695
- Root: () => Root$6,
695
+ Root: () => Root$7,
696
696
  Search: () => Search,
697
697
  SearchableTrigger: () => SearchableTrigger,
698
698
  SearchableTriggerDropdownAddon: () => SearchableTriggerDropdownAddon,
699
- Trigger: () => Trigger$4,
699
+ Trigger: () => Trigger$5,
700
700
  Value: () => Value$2,
701
701
  useComboboxContext: () => useComboboxContext
702
702
  });
703
703
  const SINGLE_TEXT_CONTENT_CN = "px-4 py-2 text-ppx-sm min-h-11 flex items-center justify-center text-ppx-muted-foreground";
704
704
  const List$2 = Combobox.List;
705
705
  const ComboboxContext = React$1.createContext({});
706
- function Root$6({ children, ...props }) {
706
+ function Root$7({ children, ...props }) {
707
707
  const chipsTriggerRef = React$1.useRef(null);
708
708
  const searchableTriggerRef = React$1.useRef(null);
709
709
  const [isOpen, setIsOpen] = React$1.useState(false);
@@ -783,7 +783,7 @@ function Content$4({ empty = "No options", portalProps, positionerProps, popupPr
783
783
  })
784
784
  });
785
785
  }
786
- function Item$6({ className, ...props }) {
786
+ function Item$7({ className, ...props }) {
787
787
  return /* @__PURE__ */ jsx(Combobox.Item, {
788
788
  className: cn(DROPDOWN_ITEM_CN, className),
789
789
  ...props,
@@ -821,7 +821,7 @@ function LoadingIndicator(props) {
821
821
  }
822
822
  function SearchableTrigger(props) {
823
823
  const { invalid, disabled, searchableTriggerRef } = useComboboxContext();
824
- return /* @__PURE__ */ jsxs(Root$7, {
824
+ return /* @__PURE__ */ jsxs(Root$8, {
825
825
  ...props,
826
826
  disabled,
827
827
  ref: searchableTriggerRef,
@@ -860,7 +860,7 @@ function SearchableTriggerDropdownAddon() {
860
860
  ]
861
861
  });
862
862
  }
863
- function Trigger$4({ size, widthVariant, children, className, ...props }) {
863
+ function Trigger$5({ size, widthVariant, children, className, ...props }) {
864
864
  const { isLoading, invalid } = useComboboxContext();
865
865
  return /* @__PURE__ */ jsxs(Combobox.Trigger, {
866
866
  "aria-label": "Open popup",
@@ -966,19 +966,19 @@ const BaseCombobox = Combobox;
966
966
  var select_exports = /* @__PURE__ */ __export({
967
967
  BaseSelect: () => BaseSelect,
968
968
  Content: () => Content$3,
969
- Item: () => Item$5,
969
+ Item: () => Item$6,
970
970
  List: () => List$1,
971
971
  MultiItem: () => MultiItem,
972
972
  MultiSelectedValue: () => MultiSelectedValue,
973
- Root: () => Root$5,
974
- Trigger: () => Trigger$3,
973
+ Root: () => Root$6,
974
+ Trigger: () => Trigger$4,
975
975
  Value: () => Value$1
976
976
  });
977
977
  const SelectContext = React$1.createContext({});
978
978
  function useSelectContext() {
979
979
  return React$1.useContext(SelectContext);
980
980
  }
981
- function Root$5({ children, invalid, ...props }) {
981
+ function Root$6({ children, invalid, ...props }) {
982
982
  const value = React$1.useMemo(() => ({ invalid }), [invalid]);
983
983
  return /* @__PURE__ */ jsx(SelectContext.Provider, {
984
984
  value,
@@ -1005,7 +1005,7 @@ function Content$3({ portalProps, positionerProps, popupProps, children, widthVa
1005
1005
  });
1006
1006
  }
1007
1007
  const List$1 = Select.List;
1008
- function Item$5({ className, ...props }) {
1008
+ function Item$6({ className, ...props }) {
1009
1009
  return /* @__PURE__ */ jsx(Select.Item, {
1010
1010
  className: cn(DROPDOWN_ITEM_CN, className),
1011
1011
  ...props,
@@ -1028,7 +1028,7 @@ function ItemIndicator(props) {
1028
1028
  children: /* @__PURE__ */ jsx(Select.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, {}) })
1029
1029
  });
1030
1030
  }
1031
- function Trigger$3({ size, widthVariant, ...props }) {
1031
+ function Trigger$4({ size, widthVariant, ...props }) {
1032
1032
  const { invalid } = useSelectContext();
1033
1033
  return /* @__PURE__ */ jsxs(Select.Trigger, {
1034
1034
  "aria-label": "Open popup",
@@ -1083,15 +1083,15 @@ var menu_exports = /* @__PURE__ */ __export({
1083
1083
  DropdownIndicator: () => DropdownIndicator,
1084
1084
  Group: () => Group$3,
1085
1085
  GroupLabel: () => GroupLabel,
1086
- Item: () => Item$4,
1086
+ Item: () => Item$5,
1087
1087
  RadioGroup: () => RadioGroup$1,
1088
1088
  RadioItem: () => RadioItem,
1089
- Root: () => Root$4,
1089
+ Root: () => Root$5,
1090
1090
  Separator: () => Separator$1,
1091
- Trigger: () => Trigger$2
1091
+ Trigger: () => Trigger$3
1092
1092
  });
1093
- const Root$4 = Menu.Root;
1094
- function Trigger$2({ className, children, size, widthVariant = "fit", ...props }) {
1093
+ const Root$5 = Menu.Root;
1094
+ function Trigger$3({ className, children, size, widthVariant = "fit", ...props }) {
1095
1095
  return /* @__PURE__ */ jsxs(Menu.Trigger, {
1096
1096
  className: cn(triggerVariants({
1097
1097
  size,
@@ -1120,7 +1120,7 @@ function Content$2({ portalProps, positionerProps, popupProps, children, widthVa
1120
1120
  function DropdownIndicator() {
1121
1121
  return /* @__PURE__ */ jsx(ChevronDownIcon, { className: "data-popup-open:rotate-180" });
1122
1122
  }
1123
- function Item$4({ className, children, ...props }) {
1123
+ function Item$5({ className, children, ...props }) {
1124
1124
  return /* @__PURE__ */ jsx(Menu.Item, {
1125
1125
  className: cn(DROPDOWN_ITEM_CN, className),
1126
1126
  ...props,
@@ -1157,7 +1157,7 @@ var progress_exports = /* @__PURE__ */ __export({
1157
1157
  BaseProgress: () => BaseProgress,
1158
1158
  Indicator: () => Indicator$1,
1159
1159
  Label: () => Label$1,
1160
- Root: () => Root$3,
1160
+ Root: () => Root$4,
1161
1161
  Track: () => Track,
1162
1162
  Value: () => Value
1163
1163
  });
@@ -1169,7 +1169,7 @@ const progressTrackVariants = cva("relative h-2 w-full overflow-hidden rounded-f
1169
1169
  } },
1170
1170
  defaultVariants: { size: "default" }
1171
1171
  });
1172
- const Root$3 = Progress.Root;
1172
+ const Root$4 = Progress.Root;
1173
1173
  function Track({ className, size, children, ...props }) {
1174
1174
  return /* @__PURE__ */ jsx(Progress.Track, {
1175
1175
  className: cn(progressTrackVariants({ size }), className),
@@ -1200,8 +1200,8 @@ const BaseProgress = Progress;
1200
1200
  //#endregion
1201
1201
  //#region src/components/segmented-control.tsx
1202
1202
  var segmented_control_exports = /* @__PURE__ */ __export({
1203
- Item: () => Item$3,
1204
- Root: () => Root$2
1203
+ Item: () => Item$4,
1204
+ Root: () => Root$3
1205
1205
  });
1206
1206
  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 disabled:cursor-not-allowed disabled:opacity-50", {
1207
1207
  variants: {
@@ -1217,14 +1217,14 @@ const segmentedControlItemVariants = cva("relative flex items-center justify-cen
1217
1217
  size: "default"
1218
1218
  }
1219
1219
  });
1220
- function Root$2({ className, ...props }) {
1220
+ function Root$3({ className, ...props }) {
1221
1221
  return /* @__PURE__ */ jsx(RadioGroup, {
1222
1222
  "data-slot": "segmented-control",
1223
1223
  className: cn("p-1 inline-flex items-center rounded-full bg-ppx-neutral-3", className),
1224
1224
  ...props
1225
1225
  });
1226
1226
  }
1227
- function Item$3({ children, className, variant, size, ...props }) {
1227
+ function Item$4({ children, className, variant, size, ...props }) {
1228
1228
  return /* @__PURE__ */ jsx(Radio.Root, {
1229
1229
  "data-slot": "segmented-control-item",
1230
1230
  className: cn(segmentedControlItemVariants({
@@ -1242,8 +1242,8 @@ function Item$3({ children, className, variant, size, ...props }) {
1242
1242
  var tabs_exports = /* @__PURE__ */ __export({
1243
1243
  Content: () => Content$1,
1244
1244
  List: () => List,
1245
- Root: () => Root$1,
1246
- Trigger: () => Trigger$1
1245
+ Root: () => Root$2,
1246
+ Trigger: () => Trigger$2
1247
1247
  });
1248
1248
  const TabsContext = React$1.createContext(null);
1249
1249
  const useTabs = () => {
@@ -1251,7 +1251,7 @@ const useTabs = () => {
1251
1251
  if (!context) throw new Error("useTabs must be used within a Tabs");
1252
1252
  return context;
1253
1253
  };
1254
- function Root$1({ variant = "underline", className, ...props }) {
1254
+ function Root$2({ variant = "underline", className, ...props }) {
1255
1255
  return /* @__PURE__ */ jsx(TabsContext.Provider, {
1256
1256
  value: { variant },
1257
1257
  children: /* @__PURE__ */ jsx(Tabs.Root, {
@@ -1273,7 +1273,7 @@ function List({ className, children, ...props }) {
1273
1273
  ]
1274
1274
  });
1275
1275
  }
1276
- function Trigger$1({ className, ...props }) {
1276
+ function Trigger$2({ className, ...props }) {
1277
1277
  return /* @__PURE__ */ jsx(Tabs.Tab, {
1278
1278
  "data-slot": "tabs-trigger",
1279
1279
  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),
@@ -1302,8 +1302,8 @@ var tooltip_exports = /* @__PURE__ */ __export({
1302
1302
  BaseProvider: () => BaseProvider,
1303
1303
  BaseRoot: () => BaseRoot,
1304
1304
  Content: () => Content,
1305
- Root: () => Root,
1306
- Trigger: () => Trigger
1305
+ Root: () => Root$1,
1306
+ Trigger: () => Trigger$1
1307
1307
  });
1308
1308
  function TooltipProvider(props) {
1309
1309
  return /* @__PURE__ */ jsx(Tooltip.Provider, {
@@ -1329,7 +1329,7 @@ function TooltipArrow({ ...props }) {
1329
1329
  ...props
1330
1330
  });
1331
1331
  }
1332
- function Root({ ...props }) {
1332
+ function Root$1({ ...props }) {
1333
1333
  return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(Tooltip.Root, {
1334
1334
  "data-slot": "tooltip",
1335
1335
  ...props
@@ -1337,7 +1337,7 @@ function Root({ ...props }) {
1337
1337
  }
1338
1338
  const BaseRoot = Tooltip.Root;
1339
1339
  const BaseProvider = Tooltip.Provider;
1340
- function Trigger({ ...props }) {
1340
+ function Trigger$1({ ...props }) {
1341
1341
  return /* @__PURE__ */ jsx(Tooltip.Trigger, {
1342
1342
  "data-slot": "tooltip-trigger",
1343
1343
  ...props
@@ -1434,7 +1434,7 @@ var block_checkbox_group_exports = /* @__PURE__ */ __export({
1434
1434
  Description: () => Description$1,
1435
1435
  Group: () => Group$2,
1436
1436
  Header: () => Header$1,
1437
- Item: () => Item$2,
1437
+ Item: () => Item$3,
1438
1438
  Title: () => Title$1
1439
1439
  });
1440
1440
  function Group$2({ className, ...props }) {
@@ -1443,7 +1443,7 @@ function Group$2({ className, ...props }) {
1443
1443
  ...props
1444
1444
  });
1445
1445
  }
1446
- function Item$2({ className, invalid, children, ...rest }) {
1446
+ function Item$3({ className, invalid, children, ...rest }) {
1447
1447
  return /* @__PURE__ */ jsxs("label", {
1448
1448
  className: cn("gap-2 p-5 flex min-h-[155px] justify-between rounded-ppx-s border-2 border-ppx-neutral-3 shadow-[0px_0px_12px_#0000001F] transition-colors duration-300 has-not-disabled:hover:border-ppx-neutral-6 has-disabled:cursor-not-allowed has-disabled:opacity-60 has-disabled:hover:border-ppx-neutral-3 has-aria-invalid:shadow-ppx-red-2 has-data-checked:border-ppx-primary-5!", className),
1449
1449
  children: [/* @__PURE__ */ jsx("div", {
@@ -1480,7 +1480,7 @@ function Description$1(props) {
1480
1480
  //#region src/components/radio-group.tsx
1481
1481
  var radio_group_exports = /* @__PURE__ */ __export({
1482
1482
  Group: () => Group$1,
1483
- Item: () => Item
1483
+ Item: () => Item$1
1484
1484
  });
1485
1485
  function Group$1({ className, ...props }) {
1486
1486
  return /* @__PURE__ */ jsx(RadioGroup, {
@@ -1503,7 +1503,7 @@ const radioVariants = cva("bg-white aria-invalid:border-ppx-red-5 aspect-square
1503
1503
  size: "default"
1504
1504
  }
1505
1505
  });
1506
- function Item({ className, variant, size, ...props }) {
1506
+ function Item$1({ className, variant, size, ...props }) {
1507
1507
  return /* @__PURE__ */ jsx(Radio.Root, {
1508
1508
  "data-slot": "radio-group-item",
1509
1509
  className: cn(radioVariants({
@@ -1542,7 +1542,7 @@ var block_radio_group_exports = /* @__PURE__ */ __export({
1542
1542
  Description: () => Description,
1543
1543
  Group: () => Group,
1544
1544
  Header: () => Header,
1545
- Item: () => Item$1,
1545
+ Item: () => Item$2,
1546
1546
  Title: () => Title
1547
1547
  });
1548
1548
  function Group({ className, ...props }) {
@@ -1552,13 +1552,13 @@ function Group({ className, ...props }) {
1552
1552
  ...props
1553
1553
  });
1554
1554
  }
1555
- function Item$1({ className, invalid, children, ...rest }) {
1555
+ function Item$2({ className, invalid, children, ...rest }) {
1556
1556
  return /* @__PURE__ */ jsxs("label", {
1557
1557
  className: cn("rounded-ppx-s border-ppx-neutral-3 has-not-disabled:hover:border-ppx-neutral-6 has-disabled:cursor-not-allowed has-disabled:opacity-60 has-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),
1558
1558
  children: [/* @__PURE__ */ jsx("div", {
1559
1559
  className: "flex-1",
1560
1560
  children
1561
- }), /* @__PURE__ */ jsx(Item, {
1561
+ }), /* @__PURE__ */ jsx(Item$1, {
1562
1562
  ...rest,
1563
1563
  className: "ml-auto shrink-0 self-start",
1564
1564
  size: "lg",
@@ -1869,9 +1869,9 @@ const replaceSizeInUrl = (url, size) => {
1869
1869
  return url.replace("/SIZE/", `/${newSize}/`);
1870
1870
  };
1871
1871
  function Avatar(props) {
1872
- return /* @__PURE__ */ jsxs(Root, {
1872
+ return /* @__PURE__ */ jsxs(Root$1, {
1873
1873
  disabled: props.hideTooltip,
1874
- children: [/* @__PURE__ */ jsx(Trigger, { render: (tooltipProps) => /* @__PURE__ */ jsx(AvatarImpl, {
1874
+ children: [/* @__PURE__ */ jsx(Trigger$1, { render: (tooltipProps) => /* @__PURE__ */ jsx(AvatarImpl, {
1875
1875
  ...props,
1876
1876
  avatarRootProps: tooltipProps
1877
1877
  }) }), /* @__PURE__ */ jsx(Content, { children: props.name })]
@@ -1916,7 +1916,7 @@ function AvatarGroup({ max = 4, avatars, className }) {
1916
1916
  return /* @__PURE__ */ jsx(BaseProvider, { children: /* @__PURE__ */ jsxs("div", {
1917
1917
  className: cn("flex items-center", className),
1918
1918
  "data-slot": "avatar-group",
1919
- children: [avatars.map((avatar, index) => /* @__PURE__ */ jsx(React.Fragment, { children: /* @__PURE__ */ jsxs(BaseRoot, { children: [/* @__PURE__ */ jsx(Trigger, { render: (tooltipProps) => /* @__PURE__ */ jsx("div", {
1919
+ children: [avatars.map((avatar, index) => /* @__PURE__ */ jsx(React.Fragment, { children: /* @__PURE__ */ jsxs(BaseRoot, { children: [/* @__PURE__ */ jsx(Trigger$1, { render: (tooltipProps) => /* @__PURE__ */ jsx("div", {
1920
1920
  className: "relative",
1921
1921
  style: {
1922
1922
  marginLeft: index > 0 ? `-${parseInt(avatar.size ?? "100px") * .25}px` : "0",
@@ -1933,9 +1933,9 @@ function AvatarGroup({ max = 4, avatars, className }) {
1933
1933
  marginLeft: `-${parseInt(avatars[0].size ?? "100px") * .25}px`,
1934
1934
  zIndex: 0
1935
1935
  },
1936
- children: /* @__PURE__ */ jsxs(Root$8, {
1936
+ children: /* @__PURE__ */ jsxs(Root$9, {
1937
1937
  openOnHover: true,
1938
- children: [/* @__PURE__ */ jsx(Trigger$5, { children: /* @__PURE__ */ jsxs("div", {
1938
+ children: [/* @__PURE__ */ jsx(Trigger$6, { children: /* @__PURE__ */ jsxs("div", {
1939
1939
  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"),
1940
1940
  style: {
1941
1941
  width: avatars[0].size ?? "100px",
@@ -2023,11 +2023,11 @@ function DatePicker({ triggerProps, placeholder = "Pick a date", format: format$
2023
2023
  calendarProps.onSelect(...args);
2024
2024
  !calendarProps.mode || calendarProps.mode === "single" && setOpen(false);
2025
2025
  };
2026
- return /* @__PURE__ */ jsxs(Root$8, {
2026
+ return /* @__PURE__ */ jsxs(Root$9, {
2027
2027
  open,
2028
2028
  onOpenChange: setOpen,
2029
2029
  ...popoverRootProps,
2030
- children: [/* @__PURE__ */ jsxs(Trigger$5, {
2030
+ children: [/* @__PURE__ */ jsxs(Trigger$6, {
2031
2031
  disabled: triggerProps?.disabled,
2032
2032
  className: cn(triggerVariants({
2033
2033
  size: triggerProps?.size,
@@ -2057,6 +2057,812 @@ function renderFormattedDate(calendarProps, format$1) {
2057
2057
  return "";
2058
2058
  }
2059
2059
 
2060
+ //#endregion
2061
+ //#region src/icons/upload-cloud-icon.tsx
2062
+ function UploadCloudIcon({ size = 24, ...props }) {
2063
+ return /* @__PURE__ */ jsx("svg", {
2064
+ xmlns: "http://www.w3.org/2000/svg",
2065
+ width: size,
2066
+ height: size,
2067
+ viewBox: "0 0 24 24",
2068
+ fill: "currentColor",
2069
+ ...props,
2070
+ children: /* @__PURE__ */ jsx("path", { d: "M19.35 10.04C18.67 6.59 15.64 4 12 4C9.11 4 6.6 5.64 5.35 8.04C2.34 8.36 0 10.91 0 14C0 17.31 2.69 20 6 20H19C21.76 20 24 17.76 24 15C24 12.36 21.95 10.22 19.35 10.04ZM19 18H6C3.79 18 2 16.21 2 14C2 11.95 3.53 10.24 5.56 10.03L6.63 9.92L7.13 8.97C8.08 7.14 9.94 6 12 6C14.62 6 16.88 7.86 17.39 10.43L17.69 11.93L19.22 12.04C20.78 12.14 22 13.45 22 15C22 16.65 20.65 18 19 18ZM8 13H10.55V16H13.45V13H16L12 9L8 13Z" })
2071
+ });
2072
+ }
2073
+
2074
+ //#endregion
2075
+ //#region src/icons/retry-icon.tsx
2076
+ function RetryIcon(props) {
2077
+ return /* @__PURE__ */ jsxs("svg", {
2078
+ xmlns: "http://www.w3.org/2000/svg",
2079
+ viewBox: "0 0 24 24",
2080
+ fill: "none",
2081
+ stroke: "currentColor",
2082
+ strokeWidth: 2,
2083
+ strokeLinecap: "round",
2084
+ strokeLinejoin: "round",
2085
+ ...props,
2086
+ className: cn("shrink-0", props.className),
2087
+ children: [
2088
+ /* @__PURE__ */ jsx("path", { d: "M21 2v6h-6" }),
2089
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 1 15-6.7L21 8" }),
2090
+ /* @__PURE__ */ jsx("path", { d: "M3 22v-6h6" }),
2091
+ /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 1-15 6.7L3 16" })
2092
+ ]
2093
+ });
2094
+ }
2095
+
2096
+ //#endregion
2097
+ //#region src/icons/spinner-icon.tsx
2098
+ function SpinnerIcon(props) {
2099
+ return /* @__PURE__ */ jsx("svg", {
2100
+ xmlns: "http://www.w3.org/2000/svg",
2101
+ viewBox: "0 0 24 24",
2102
+ fill: "none",
2103
+ stroke: "currentColor",
2104
+ strokeWidth: 2,
2105
+ strokeLinecap: "round",
2106
+ strokeLinejoin: "round",
2107
+ ...props,
2108
+ className: cn("shrink-0", props.className),
2109
+ children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
2110
+ });
2111
+ }
2112
+
2113
+ //#endregion
2114
+ //#region src/icons/upload-icon.tsx
2115
+ function UploadIcon(props) {
2116
+ return /* @__PURE__ */ jsxs("svg", {
2117
+ xmlns: "http://www.w3.org/2000/svg",
2118
+ viewBox: "0 0 24 24",
2119
+ fill: "none",
2120
+ stroke: "currentColor",
2121
+ strokeWidth: 2,
2122
+ strokeLinecap: "round",
2123
+ strokeLinejoin: "round",
2124
+ ...props,
2125
+ className: cn("shrink-0", props.className),
2126
+ children: [
2127
+ /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
2128
+ /* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
2129
+ /* @__PURE__ */ jsx("line", {
2130
+ x1: "12",
2131
+ y1: "3",
2132
+ x2: "12",
2133
+ y2: "15"
2134
+ })
2135
+ ]
2136
+ });
2137
+ }
2138
+
2139
+ //#endregion
2140
+ //#region src/hooks/use-file-upload.ts
2141
+ const formatBytes = (bytes, decimals = 2) => {
2142
+ if (bytes === 0) return "0 Bytes";
2143
+ const k = 1024;
2144
+ const dm = decimals < 0 ? 0 : decimals;
2145
+ const sizes = [
2146
+ "Bytes",
2147
+ "KB",
2148
+ "MB",
2149
+ "GB",
2150
+ "TB",
2151
+ "PB",
2152
+ "EB",
2153
+ "ZB",
2154
+ "YB"
2155
+ ];
2156
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
2157
+ return Number.parseFloat((bytes / k ** i).toFixed(dm)) + sizes[i];
2158
+ };
2159
+ const useFileUpload = (options = {}) => {
2160
+ const { upload, ...baseOptions } = options;
2161
+ const autoUpload = upload?.autoUpload ?? true;
2162
+ const [files, setFiles] = useState((baseOptions.initialFiles ?? []).map((file) => ({
2163
+ file,
2164
+ id: file.id,
2165
+ preview: file.url,
2166
+ progress: 100,
2167
+ status: "success",
2168
+ uploadedUrl: file.url
2169
+ })));
2170
+ const [isUploading, setIsUploading] = useState(false);
2171
+ const [isDragging, setIsDragging] = useState(false);
2172
+ const [errors, setErrors] = useState([]);
2173
+ const inputRef = useRef(null);
2174
+ const abortControllersRef = useRef(/* @__PURE__ */ new Map());
2175
+ const { maxFiles = Number.POSITIVE_INFINITY, maxSize = Number.POSITIVE_INFINITY, accept = "*", multiple = false, onFilesChange, onFilesAdded } = baseOptions;
2176
+ const validateFile = useCallback((file) => {
2177
+ if (file.size > maxSize) return `File "${file.name}" exceeds the maximum size of ${formatBytes(maxSize)}.`;
2178
+ if (accept !== "*") {
2179
+ const acceptedTypes = accept.split(",").map((type) => type.trim());
2180
+ const fileType = file.type || "";
2181
+ const fileExtension = `.${file.name.split(".").pop()}`;
2182
+ if (!acceptedTypes.some((type) => {
2183
+ if (type.startsWith(".")) return fileExtension.toLowerCase() === type.toLowerCase();
2184
+ if (type.endsWith("/*")) {
2185
+ const baseType = type.split("/")[0];
2186
+ return fileType.startsWith(`${baseType}/`);
2187
+ }
2188
+ return fileType === type;
2189
+ })) return `File "${file.name}" is not an accepted file type.`;
2190
+ }
2191
+ return null;
2192
+ }, [accept, maxSize]);
2193
+ const createPreview = useCallback((file) => {
2194
+ if (file.type.startsWith("image/")) return URL.createObjectURL(file);
2195
+ }, []);
2196
+ const generateUniqueId = useCallback((file) => {
2197
+ return `${file.name}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
2198
+ }, []);
2199
+ const uploadSingleFile = useCallback(async (fileWithStatus) => {
2200
+ if (!upload) return {
2201
+ ...fileWithStatus,
2202
+ status: "error",
2203
+ error: "No upload config provided"
2204
+ };
2205
+ const file = fileWithStatus.file;
2206
+ if (!(file instanceof File)) return {
2207
+ ...fileWithStatus,
2208
+ status: "success",
2209
+ progress: 100
2210
+ };
2211
+ const abortController = new AbortController();
2212
+ abortControllersRef.current.set(fileWithStatus.id, abortController);
2213
+ try {
2214
+ setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2215
+ ...f,
2216
+ status: "uploading",
2217
+ progress: 0
2218
+ } : f));
2219
+ const { result: presignedResult, error: presignedError } = await upload.getPresignedUrl({
2220
+ filename: file.name,
2221
+ contentType: file.type,
2222
+ size: file.size,
2223
+ signal: abortController.signal
2224
+ });
2225
+ if (presignedError || !presignedResult) throw presignedError || /* @__PURE__ */ new Error("Failed to get presigned URL");
2226
+ setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2227
+ ...f,
2228
+ progress: 10
2229
+ } : f));
2230
+ const { result: uploadResult, error: uploadError } = await upload.uploadFile(presignedResult.url, file, presignedResult, (progress) => {
2231
+ const scaledProgress = 10 + progress * .9;
2232
+ setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? {
2233
+ ...f,
2234
+ progress: Math.round(scaledProgress)
2235
+ } : f));
2236
+ }, abortController.signal);
2237
+ if (uploadError) throw uploadError;
2238
+ const uploadedFile = {
2239
+ ...fileWithStatus,
2240
+ status: "success",
2241
+ progress: 100,
2242
+ uploadedUrl: uploadResult?.url ?? presignedResult.fullPath
2243
+ };
2244
+ setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? uploadedFile : f));
2245
+ upload.onUploadComplete?.(uploadedFile);
2246
+ return uploadedFile;
2247
+ } catch (error) {
2248
+ if (error instanceof Error && (error.name === "AbortError" || abortController.signal.aborted)) return {
2249
+ ...fileWithStatus,
2250
+ status: "idle",
2251
+ progress: 0
2252
+ };
2253
+ const errorMessage = error instanceof Error ? error.message : "Upload failed";
2254
+ const failedFile = {
2255
+ ...fileWithStatus,
2256
+ status: "error",
2257
+ error: errorMessage
2258
+ };
2259
+ setFiles((prev) => prev.map((f) => f.id === fileWithStatus.id ? failedFile : f));
2260
+ upload.onUploadError?.(failedFile, error);
2261
+ return failedFile;
2262
+ } finally {
2263
+ abortControllersRef.current.delete(fileWithStatus.id);
2264
+ }
2265
+ }, [upload]);
2266
+ const uploadFiles = useCallback(async (filesToUpload) => {
2267
+ const targetFiles = filesToUpload ?? files.filter((f) => f.status === "idle");
2268
+ if (targetFiles.length === 0) return [];
2269
+ setIsUploading(true);
2270
+ const results = [];
2271
+ for (const file of targetFiles) {
2272
+ const result = await uploadSingleFile(file);
2273
+ results.push(result);
2274
+ }
2275
+ setIsUploading(false);
2276
+ upload?.onAllUploadsComplete?.(results);
2277
+ return results;
2278
+ }, [
2279
+ files,
2280
+ uploadSingleFile,
2281
+ upload
2282
+ ]);
2283
+ const addFiles = useCallback((newFiles) => {
2284
+ if (!newFiles || newFiles.length === 0) return;
2285
+ const newFilesArray = Array.from(newFiles);
2286
+ const newErrors = [];
2287
+ setErrors([]);
2288
+ if (!multiple) setFiles((prev) => {
2289
+ for (const file of prev) if (file.preview && file.file instanceof File) URL.revokeObjectURL(file.preview);
2290
+ return [];
2291
+ });
2292
+ if (multiple && maxFiles !== Number.POSITIVE_INFINITY && files.length + newFilesArray.length > maxFiles) {
2293
+ newErrors.push(`You can only upload a maximum of ${maxFiles} files.`);
2294
+ setErrors(newErrors);
2295
+ return;
2296
+ }
2297
+ const validFiles = [];
2298
+ for (const file of newFilesArray) {
2299
+ if (multiple) {
2300
+ if (files.some((existingFile) => existingFile.file.name === file.name && existingFile.file.size === file.size)) continue;
2301
+ }
2302
+ const error = validateFile(file);
2303
+ if (error) {
2304
+ newErrors.push(error);
2305
+ continue;
2306
+ }
2307
+ validFiles.push({
2308
+ file,
2309
+ id: generateUniqueId(file),
2310
+ preview: createPreview(file),
2311
+ progress: 0,
2312
+ status: "idle"
2313
+ });
2314
+ }
2315
+ if (validFiles.length > 0) {
2316
+ onFilesAdded?.(validFiles);
2317
+ setFiles((prev) => {
2318
+ const updatedFiles = !multiple ? validFiles : [...prev, ...validFiles];
2319
+ onFilesChange?.(updatedFiles);
2320
+ return updatedFiles;
2321
+ });
2322
+ if (autoUpload && upload) setTimeout(() => {
2323
+ uploadFiles(validFiles);
2324
+ }, 0);
2325
+ }
2326
+ if (newErrors.length > 0) setErrors(newErrors);
2327
+ if (inputRef.current) inputRef.current.value = "";
2328
+ }, [
2329
+ files,
2330
+ maxFiles,
2331
+ multiple,
2332
+ validateFile,
2333
+ createPreview,
2334
+ generateUniqueId,
2335
+ onFilesChange,
2336
+ onFilesAdded,
2337
+ autoUpload,
2338
+ upload,
2339
+ uploadFiles
2340
+ ]);
2341
+ const removeFile = useCallback((id) => {
2342
+ const controller = abortControllersRef.current.get(id);
2343
+ if (controller) {
2344
+ controller.abort();
2345
+ abortControllersRef.current.delete(id);
2346
+ }
2347
+ setFiles((prev) => {
2348
+ const fileToRemove = prev.find((file) => file.id === id);
2349
+ if (fileToRemove?.preview && fileToRemove.file instanceof File) URL.revokeObjectURL(fileToRemove.preview);
2350
+ const newFiles = prev.filter((file) => file.id !== id);
2351
+ onFilesChange?.(newFiles);
2352
+ return newFiles;
2353
+ });
2354
+ }, [onFilesChange]);
2355
+ const clearFiles = useCallback(() => {
2356
+ for (const controller of abortControllersRef.current.values()) controller.abort();
2357
+ abortControllersRef.current.clear();
2358
+ setFiles((prev) => {
2359
+ for (const file of prev) if (file.preview && file.file instanceof File) URL.revokeObjectURL(file.preview);
2360
+ return [];
2361
+ });
2362
+ if (inputRef.current) inputRef.current.value = "";
2363
+ setErrors([]);
2364
+ onFilesChange?.([]);
2365
+ }, [onFilesChange]);
2366
+ const clearErrors = useCallback(() => {
2367
+ setErrors([]);
2368
+ }, []);
2369
+ const retryUpload = useCallback(async (id) => {
2370
+ const file = files.find((f) => f.id === id);
2371
+ if (file && file.status === "error") {
2372
+ setFiles((prev) => prev.map((f) => f.id === id ? {
2373
+ ...f,
2374
+ status: "idle",
2375
+ error: void 0
2376
+ } : f));
2377
+ await uploadSingleFile({
2378
+ ...file,
2379
+ status: "idle",
2380
+ error: void 0
2381
+ });
2382
+ }
2383
+ }, [files, uploadSingleFile]);
2384
+ const cancelUpload = useCallback((id) => {
2385
+ const controller = abortControllersRef.current.get(id);
2386
+ if (controller) {
2387
+ controller.abort();
2388
+ abortControllersRef.current.delete(id);
2389
+ }
2390
+ setFiles((prev) => prev.map((f) => f.id === id ? {
2391
+ ...f,
2392
+ status: "idle",
2393
+ progress: 0
2394
+ } : f));
2395
+ }, []);
2396
+ const handleDragEnter = useCallback((e) => {
2397
+ e.preventDefault();
2398
+ e.stopPropagation();
2399
+ setIsDragging(true);
2400
+ }, []);
2401
+ const handleDragLeave = useCallback((e) => {
2402
+ e.preventDefault();
2403
+ e.stopPropagation();
2404
+ if (e.currentTarget.contains(e.relatedTarget)) return;
2405
+ setIsDragging(false);
2406
+ }, []);
2407
+ const handleDragOver = useCallback((e) => {
2408
+ e.preventDefault();
2409
+ e.stopPropagation();
2410
+ }, []);
2411
+ const handleDrop = useCallback((e) => {
2412
+ e.preventDefault();
2413
+ e.stopPropagation();
2414
+ setIsDragging(false);
2415
+ if (inputRef.current?.disabled) return;
2416
+ if (e.dataTransfer.files?.length > 0) if (!multiple) addFiles([e.dataTransfer.files[0]]);
2417
+ else addFiles(e.dataTransfer.files);
2418
+ }, [addFiles, multiple]);
2419
+ const handleFileChange = useCallback((e) => {
2420
+ if (e.target.files?.length) addFiles(e.target.files);
2421
+ }, [addFiles]);
2422
+ const openFileDialog = useCallback(() => {
2423
+ inputRef.current?.click();
2424
+ }, []);
2425
+ const getInputProps = useCallback((props = {}) => ({
2426
+ ...props,
2427
+ accept: props.accept || accept,
2428
+ multiple: props.multiple !== void 0 ? props.multiple : multiple,
2429
+ onChange: handleFileChange,
2430
+ ref: inputRef,
2431
+ type: "file"
2432
+ }), [
2433
+ accept,
2434
+ multiple,
2435
+ handleFileChange
2436
+ ]);
2437
+ return [{
2438
+ files,
2439
+ isDragging,
2440
+ errors,
2441
+ isUploading
2442
+ }, {
2443
+ addFiles,
2444
+ removeFile,
2445
+ clearFiles,
2446
+ clearErrors,
2447
+ handleDragEnter,
2448
+ handleDragLeave,
2449
+ handleDragOver,
2450
+ handleDrop,
2451
+ handleFileChange,
2452
+ openFileDialog,
2453
+ getInputProps,
2454
+ uploadFiles,
2455
+ retryUpload,
2456
+ cancelUpload
2457
+ }];
2458
+ };
2459
+
2460
+ //#endregion
2461
+ //#region src/icons/file-icon.tsx
2462
+ function FileIcon(props) {
2463
+ return /* @__PURE__ */ jsxs("svg", {
2464
+ xmlns: "http://www.w3.org/2000/svg",
2465
+ viewBox: "0 0 24 24",
2466
+ fill: "none",
2467
+ stroke: "currentColor",
2468
+ strokeWidth: 2,
2469
+ strokeLinecap: "round",
2470
+ strokeLinejoin: "round",
2471
+ ...props,
2472
+ className: cn("shrink-0", props.className),
2473
+ 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" })]
2474
+ });
2475
+ }
2476
+
2477
+ //#endregion
2478
+ //#region src/components/file-upload.tsx
2479
+ const FileUploadContext = React$1.createContext(null);
2480
+ function useFileUploadContext() {
2481
+ const context = React$1.useContext(FileUploadContext);
2482
+ if (!context) throw new Error("FileUpload components must be used within FileUpload.Root");
2483
+ return context;
2484
+ }
2485
+ function Root({ children, files, addFiles, removeFile, clearFiles, retryUpload, openFileDialog, getInputProps, handleDragEnter, handleDragLeave, handleDragOver, handleDrop, isDragActive = false, isUploading = false, accept, multiple = false, disabled = false, className }) {
2486
+ const contextValue = {
2487
+ files,
2488
+ addFiles,
2489
+ removeFile,
2490
+ clearFiles,
2491
+ retryUpload,
2492
+ accept,
2493
+ multiple,
2494
+ disabled,
2495
+ isDragActive,
2496
+ isUploading,
2497
+ openFileDialog,
2498
+ getInputProps,
2499
+ handleDragEnter,
2500
+ handleDragLeave,
2501
+ handleDragOver,
2502
+ handleDrop
2503
+ };
2504
+ return /* @__PURE__ */ jsx(FileUploadContext.Provider, {
2505
+ value: contextValue,
2506
+ children: /* @__PURE__ */ jsx("div", {
2507
+ "data-slot": "file-upload",
2508
+ className: cn("flex flex-col gap-4", className),
2509
+ children
2510
+ })
2511
+ });
2512
+ }
2513
+ const dropzoneVariants = cva("flex flex-col items-center justify-center gap-4 rounded-ppx-m bg-ppx-neutral-2 transition-colors outline-none focus-visible:ring-3 focus-visible:ring-ppx-neutral-17/30", {
2514
+ variants: {
2515
+ size: {
2516
+ default: "p-8 min-h-[200px]",
2517
+ sm: "p-6 min-h-[160px]",
2518
+ lg: "p-10 min-h-[260px]"
2519
+ },
2520
+ isDragActive: {
2521
+ true: "border-2 border-dashed border-ppx-primary-5 bg-ppx-primary-1",
2522
+ false: ""
2523
+ }
2524
+ },
2525
+ defaultVariants: {
2526
+ size: "default",
2527
+ isDragActive: false
2528
+ }
2529
+ });
2530
+ function Dropzone({ className, size, children, dropzoneText = "Paste Or Drag & Drop Files Here", browseText = "Browse for files", hideDefaultContent = false, ...props }) {
2531
+ const { accept, multiple, disabled, isDragActive, isUploading, openFileDialog, getInputProps, handleDragEnter, handleDragLeave, handleDragOver, handleDrop, addFiles } = useFileUploadContext();
2532
+ const descriptionId = React$1.useId();
2533
+ const instructionsId = React$1.useId();
2534
+ const [announcement, setAnnouncement] = React$1.useState("");
2535
+ const inputProps = getInputProps();
2536
+ const handleKeyDown = React$1.useCallback((e) => {
2537
+ if (e.key === "Enter" || e.key === " ") {
2538
+ e.preventDefault();
2539
+ openFileDialog();
2540
+ }
2541
+ }, [openFileDialog]);
2542
+ const handlePaste = React$1.useCallback((e) => {
2543
+ if (disabled) return;
2544
+ const files = e.clipboardData.files;
2545
+ if (files.length > 0) {
2546
+ e.preventDefault();
2547
+ const filesArray = Array.from(files);
2548
+ addFiles(filesArray);
2549
+ setAnnouncement(`${filesArray.length} file${filesArray.length > 1 ? "s" : ""} pasted`);
2550
+ }
2551
+ }, [disabled, addFiles]);
2552
+ return /* @__PURE__ */ jsxs("div", {
2553
+ "data-slot": "file-upload-dropzone",
2554
+ className: cn(dropzoneVariants({
2555
+ size,
2556
+ isDragActive
2557
+ }), disabled && "cursor-not-allowed opacity-60", className),
2558
+ onDragEnter: handleDragEnter,
2559
+ onDragLeave: handleDragLeave,
2560
+ onDragOver: handleDragOver,
2561
+ onDrop: handleDrop,
2562
+ onPaste: handlePaste,
2563
+ onKeyDown: handleKeyDown,
2564
+ tabIndex: disabled ? -1 : 0,
2565
+ role: "button",
2566
+ "aria-disabled": disabled,
2567
+ "aria-describedby": `${descriptionId} ${instructionsId}`,
2568
+ "aria-label": "File upload dropzone",
2569
+ ...props,
2570
+ children: [
2571
+ /* @__PURE__ */ jsx("div", {
2572
+ role: "status",
2573
+ "aria-live": "polite",
2574
+ "aria-atomic": "true",
2575
+ className: "sr-only",
2576
+ children: announcement
2577
+ }),
2578
+ /* @__PURE__ */ jsx("div", {
2579
+ id: descriptionId,
2580
+ className: "sr-only",
2581
+ children: dropzoneText
2582
+ }),
2583
+ /* @__PURE__ */ jsx("div", {
2584
+ id: instructionsId,
2585
+ className: "sr-only",
2586
+ children: "Press Enter or Space to browse files, or drag and drop files here."
2587
+ }),
2588
+ /* @__PURE__ */ jsx("input", {
2589
+ ...inputProps,
2590
+ className: "sr-only",
2591
+ accept,
2592
+ multiple,
2593
+ disabled,
2594
+ tabIndex: -1,
2595
+ "aria-hidden": "true"
2596
+ }),
2597
+ children ? children : !hideDefaultContent ? /* @__PURE__ */ jsxs(Fragment, { children: [
2598
+ /* @__PURE__ */ jsxs("div", {
2599
+ className: "text-ppx-neutral-10 flex items-center gap-3",
2600
+ children: [/* @__PURE__ */ jsx(UploadCloudIcon, {
2601
+ size: 40,
2602
+ "aria-hidden": "true"
2603
+ }), /* @__PURE__ */ jsx("span", {
2604
+ className: "text-ppx-base text-ppx-neutral-13 font-medium",
2605
+ children: dropzoneText
2606
+ })]
2607
+ }),
2608
+ /* @__PURE__ */ jsxs("div", {
2609
+ className: "flex w-full items-center gap-3",
2610
+ "aria-hidden": "true",
2611
+ children: [
2612
+ /* @__PURE__ */ jsx("div", { className: "bg-ppx-neutral-5 h-px flex-1" }),
2613
+ /* @__PURE__ */ jsx("span", {
2614
+ className: "text-ppx-sm text-ppx-neutral-10 font-medium",
2615
+ children: "OR"
2616
+ }),
2617
+ /* @__PURE__ */ jsx("div", { className: "bg-ppx-neutral-5 h-px flex-1" })
2618
+ ]
2619
+ }),
2620
+ /* @__PURE__ */ jsx(Button, {
2621
+ type: "button",
2622
+ variant: "default",
2623
+ onClick: openFileDialog,
2624
+ disabled: disabled || isUploading,
2625
+ children: isUploading ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SpinnerIcon, { className: "size-4 animate-spin" }), "Uploading..."] }) : browseText
2626
+ })
2627
+ ] }) : null
2628
+ ]
2629
+ });
2630
+ }
2631
+ function Trigger({ children, uploadingText = "Uploading...", showUploadingState = true, ...props }) {
2632
+ const { openFileDialog, disabled, isUploading } = useFileUploadContext();
2633
+ return /* @__PURE__ */ jsx(Button, {
2634
+ type: "button",
2635
+ onClick: openFileDialog,
2636
+ disabled: disabled || showUploadingState && isUploading,
2637
+ "data-slot": "file-upload-trigger",
2638
+ ...props,
2639
+ 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"] })
2640
+ });
2641
+ }
2642
+ function ItemList({ className, children, ...props }) {
2643
+ const { files } = useFileUploadContext();
2644
+ if (files.length === 0) return null;
2645
+ return /* @__PURE__ */ jsx("div", {
2646
+ "data-slot": "file-upload-item-list",
2647
+ className: cn("flex flex-col gap-2", className),
2648
+ ...props,
2649
+ children: typeof children === "function" ? children(files) : children
2650
+ });
2651
+ }
2652
+ const ItemContext = React$1.createContext(null);
2653
+ function useFileUploadItem() {
2654
+ const context = React$1.useContext(ItemContext);
2655
+ if (!context) throw new Error("FileUpload.Item* components must be used within FileUpload.Item");
2656
+ return context;
2657
+ }
2658
+ function Item({ file, className, children, statusStyles = true, ...props }) {
2659
+ return /* @__PURE__ */ jsx(ItemContext.Provider, {
2660
+ value: file,
2661
+ children: /* @__PURE__ */ jsx("div", {
2662
+ "data-slot": "file-upload-item",
2663
+ "data-status": file.status,
2664
+ 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),
2665
+ ...props,
2666
+ children
2667
+ })
2668
+ });
2669
+ }
2670
+ function ItemPreview({ className, fallback, ...props }) {
2671
+ const file = useFileUploadItem();
2672
+ return /* @__PURE__ */ jsx("div", {
2673
+ "data-slot": "file-upload-item-preview",
2674
+ className: cn("rounded-ppx-xs bg-ppx-neutral-3 flex size-10 shrink-0 items-center justify-center overflow-hidden", className),
2675
+ ...props,
2676
+ children: file.preview ? /* @__PURE__ */ jsx("img", {
2677
+ src: file.preview,
2678
+ alt: file.file.name,
2679
+ className: "size-full object-cover"
2680
+ }) : fallback ?? /* @__PURE__ */ jsx(FileIcon, { className: "text-ppx-neutral-10 size-5" })
2681
+ });
2682
+ }
2683
+ function ItemName({ className, ...props }) {
2684
+ const file = useFileUploadItem();
2685
+ return /* @__PURE__ */ jsx("span", {
2686
+ "data-slot": "file-upload-item-name",
2687
+ className: cn("text-ppx-sm text-ppx-neutral-14 truncate font-medium", className),
2688
+ ...props,
2689
+ children: file.file.name
2690
+ });
2691
+ }
2692
+ function ItemSize({ className, ...props }) {
2693
+ const file = useFileUploadItem();
2694
+ return /* @__PURE__ */ jsx("span", {
2695
+ "data-slot": "file-upload-item-size",
2696
+ className: cn("text-ppx-xs text-ppx-neutral-10", className),
2697
+ ...props,
2698
+ children: formatBytes(file.file.size)
2699
+ });
2700
+ }
2701
+ function ItemRemove({ className, children, ...props }) {
2702
+ const { removeFile } = useFileUploadContext();
2703
+ const file = useFileUploadItem();
2704
+ return /* @__PURE__ */ jsx(Button, {
2705
+ type: "button",
2706
+ variant: "ghost",
2707
+ size: "icon-sm",
2708
+ onClick: () => removeFile(file.id),
2709
+ "data-slot": "file-upload-item-remove",
2710
+ "aria-label": `Remove ${file.file.name}`,
2711
+ className: cn("ml-auto shrink-0", className),
2712
+ ...props,
2713
+ children: children ?? /* @__PURE__ */ jsx(CloseIcon, { className: "size-4" })
2714
+ });
2715
+ }
2716
+ function ItemProgress({ className, ...props }) {
2717
+ const file = useFileUploadItem();
2718
+ if (file.progress === void 0) return null;
2719
+ return /* @__PURE__ */ jsx("div", {
2720
+ "data-slot": "file-upload-item-progress",
2721
+ className: cn("bg-ppx-neutral-3 h-1.5 w-full overflow-hidden rounded-full", className),
2722
+ ...props,
2723
+ children: /* @__PURE__ */ jsx("div", {
2724
+ className: "bg-ppx-primary-5 h-full transition-all duration-300",
2725
+ style: { width: `${file.progress}%` }
2726
+ })
2727
+ });
2728
+ }
2729
+ function ItemStatus({ className, successIcon, uploadingContent, errorContent, ...props }) {
2730
+ const file = useFileUploadItem();
2731
+ if (file.status === "uploading") return /* @__PURE__ */ jsx("span", {
2732
+ "data-slot": "file-upload-item-status",
2733
+ className: cn("text-ppx-xs text-ppx-neutral-10 shrink-0", className),
2734
+ ...props,
2735
+ children: uploadingContent ?? `${file.progress ?? 0}%`
2736
+ });
2737
+ if (file.status === "success") return /* @__PURE__ */ jsx("span", {
2738
+ "data-slot": "file-upload-item-status",
2739
+ className: cn("text-ppx-green-5 shrink-0", className),
2740
+ ...props,
2741
+ children: successIcon ?? /* @__PURE__ */ jsx(CheckIcon, { className: "size-4" })
2742
+ });
2743
+ if (file.status === "error") return /* @__PURE__ */ jsx("span", {
2744
+ "data-slot": "file-upload-item-status",
2745
+ className: cn("text-ppx-xs text-ppx-red-5 shrink-0", className),
2746
+ ...props,
2747
+ children: errorContent ?? "Failed"
2748
+ });
2749
+ return null;
2750
+ }
2751
+ function ItemError({ className, ...props }) {
2752
+ const file = useFileUploadItem();
2753
+ if (!file.error) return null;
2754
+ return /* @__PURE__ */ jsx("span", {
2755
+ "data-slot": "file-upload-item-error",
2756
+ className: cn("text-ppx-xs text-ppx-red-5", className),
2757
+ ...props,
2758
+ children: file.error
2759
+ });
2760
+ }
2761
+ function ItemRetry({ className, children, ...props }) {
2762
+ const { retryUpload } = useFileUploadContext();
2763
+ const file = useFileUploadItem();
2764
+ if (file.status !== "error" || !retryUpload) return null;
2765
+ return /* @__PURE__ */ jsx(Button, {
2766
+ type: "button",
2767
+ variant: "ghost",
2768
+ size: "icon-sm",
2769
+ onClick: () => retryUpload(file.id),
2770
+ "data-slot": "file-upload-item-retry",
2771
+ "aria-label": `Retry uploading ${file.file.name}`,
2772
+ className: cn("shrink-0", className),
2773
+ ...props,
2774
+ children: children ?? /* @__PURE__ */ jsx(RetryIcon, { className: "size-4" })
2775
+ });
2776
+ }
2777
+ function ClearButton({ children, ...props }) {
2778
+ const { clearFiles, files } = useFileUploadContext();
2779
+ if (files.length === 0) return null;
2780
+ return /* @__PURE__ */ jsx(Button, {
2781
+ type: "button",
2782
+ variant: "ghost",
2783
+ onClick: clearFiles,
2784
+ "data-slot": "file-upload-clear",
2785
+ ...props,
2786
+ children: children ?? "Remove all files"
2787
+ });
2788
+ }
2789
+ function ImageGrid({ className, children, ...props }) {
2790
+ const { files } = useFileUploadContext();
2791
+ if (files.length === 0) return null;
2792
+ return /* @__PURE__ */ jsx("div", {
2793
+ "data-slot": "file-upload-image-grid",
2794
+ className: cn("grid grid-cols-4 gap-2", className),
2795
+ ...props,
2796
+ children: typeof children === "function" ? children(files) : children
2797
+ });
2798
+ }
2799
+ function ImageGridItem({ file, className, showStatusOverlay = true, ...props }) {
2800
+ const { removeFile, retryUpload } = useFileUploadContext();
2801
+ return /* @__PURE__ */ jsxs("div", {
2802
+ "data-slot": "file-upload-image-grid-item",
2803
+ "data-status": file.status,
2804
+ className: cn("rounded-ppx-s group relative aspect-square overflow-hidden", file.status === "error" && "ring-ppx-red-5 ring-2", className),
2805
+ ...props,
2806
+ children: [
2807
+ file.preview ? /* @__PURE__ */ jsx("img", {
2808
+ src: file.preview,
2809
+ alt: file.file.name,
2810
+ className: "size-full object-cover"
2811
+ }) : /* @__PURE__ */ jsx("div", {
2812
+ className: "bg-ppx-neutral-3 flex size-full items-center justify-center",
2813
+ children: /* @__PURE__ */ jsx(FileIcon, { className: "text-ppx-neutral-10 size-8" })
2814
+ }),
2815
+ showStatusOverlay && file.status === "uploading" && /* @__PURE__ */ jsx("div", {
2816
+ className: "absolute inset-0 flex items-center justify-center bg-black/40",
2817
+ children: /* @__PURE__ */ jsxs("div", {
2818
+ className: "text-sm font-medium text-white",
2819
+ children: [file.progress, "%"]
2820
+ })
2821
+ }),
2822
+ showStatusOverlay && file.status === "error" && retryUpload && /* @__PURE__ */ jsx("div", {
2823
+ className: "absolute inset-0 flex items-center justify-center bg-black/40",
2824
+ children: /* @__PURE__ */ jsx(Button, {
2825
+ type: "button",
2826
+ variant: "ghost",
2827
+ size: "icon-sm",
2828
+ onClick: () => retryUpload(file.id),
2829
+ className: "text-white hover:text-white",
2830
+ children: /* @__PURE__ */ jsx(RetryIcon, { className: "size-5" })
2831
+ })
2832
+ }),
2833
+ showStatusOverlay && file.status === "success" && /* @__PURE__ */ jsx("div", {
2834
+ className: "bg-ppx-green-5 absolute bottom-1 right-1 rounded-full p-0.5",
2835
+ children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-3 text-white" })
2836
+ }),
2837
+ /* @__PURE__ */ jsx("button", {
2838
+ type: "button",
2839
+ onClick: () => removeFile(file.id),
2840
+ 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",
2841
+ "aria-label": `Remove ${file.file.name}`,
2842
+ children: /* @__PURE__ */ jsx(CloseIcon, { className: "size-3" })
2843
+ })
2844
+ ]
2845
+ });
2846
+ }
2847
+ const FileUpload = {
2848
+ Root,
2849
+ Dropzone,
2850
+ Trigger,
2851
+ ItemList,
2852
+ Item,
2853
+ ItemPreview,
2854
+ ItemName,
2855
+ ItemSize,
2856
+ ItemRemove,
2857
+ ItemProgress,
2858
+ ItemStatus,
2859
+ ItemError,
2860
+ ItemRetry,
2861
+ ClearButton,
2862
+ ImageGrid,
2863
+ ImageGridItem
2864
+ };
2865
+
2060
2866
  //#endregion
2061
2867
  //#region src/index.ts
2062
2868
  var src_exports = /* @__PURE__ */ __export({
@@ -2072,6 +2878,8 @@ var src_exports = /* @__PURE__ */ __export({
2072
2878
  Combobox: () => combobox_exports,
2073
2879
  DatePicker: () => DatePicker,
2074
2880
  Dialog: () => dialog_exports,
2881
+ FileIcon: () => FileIcon,
2882
+ FileUpload: () => FileUpload,
2075
2883
  Input: () => Input,
2076
2884
  InputGroup: () => input_group_exports,
2077
2885
  Label: () => Label,
@@ -2087,13 +2895,16 @@ var src_exports = /* @__PURE__ */ __export({
2087
2895
  Tabs: () => tabs_exports,
2088
2896
  Textarea: () => Textarea,
2089
2897
  Tooltip: () => tooltip_exports,
2898
+ UploadIcon: () => UploadIcon,
2090
2899
  buttonVariants: () => buttonVariants,
2091
2900
  cn: () => cn,
2092
2901
  defineLoadOptions: () => defineLoadOptions,
2902
+ formatBytes: () => formatBytes,
2093
2903
  useAsyncOptions: () => useAsyncOptions,
2904
+ useFileUpload: () => useFileUpload,
2094
2905
  useIntersectionObserver: () => useIntersectionObserver
2095
2906
  });
2096
2907
 
2097
2908
  //#endregion
2098
- export { Avatar, AvatarGroup, AvatarImpl, block_checkbox_group_exports as BlockCheckboxGroup, block_radio_group_exports as BlockRadioGroup, breadcrumbs_exports as Breadcrumbs, Button, Calendar, Checkbox, combobox_exports as Combobox, DatePicker, dialog_exports as Dialog, Input, input_group_exports as InputGroup, Label, menu_exports as Menu, 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, buttonVariants, cn, defineLoadOptions, useAsyncOptions, useIntersectionObserver };
2909
+ export { Avatar, AvatarGroup, AvatarImpl, block_checkbox_group_exports as BlockCheckboxGroup, block_radio_group_exports as BlockRadioGroup, breadcrumbs_exports as Breadcrumbs, Button, Calendar, Checkbox, combobox_exports as Combobox, DatePicker, dialog_exports as Dialog, FileIcon, FileUpload, Input, input_group_exports as InputGroup, Label, menu_exports as Menu, 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, buttonVariants, cn, defineLoadOptions, formatBytes, useAsyncOptions, useFileUpload, useIntersectionObserver };
2099
2910
  //# sourceMappingURL=index.js.map