@px-ui/core 1.29.7 → 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/LICENSE +21 -0
- package/README.md +16 -0
- package/dist/assets/Lato-Bold.ttf +0 -0
- package/dist/assets/Lato-Light.ttf +0 -0
- package/dist/index.d.ts +508 -157
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +877 -63
- package/dist/index.js.map +1 -1
- package/package.json +14 -17
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$
|
|
136
|
+
Root: () => Root$10,
|
|
137
137
|
Title: () => Title$3,
|
|
138
|
-
Trigger: () => Trigger$
|
|
138
|
+
Trigger: () => Trigger$7
|
|
139
139
|
});
|
|
140
|
-
function Root$
|
|
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$
|
|
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$
|
|
245
|
+
Root: () => Root$9,
|
|
246
246
|
Title: () => Title$2,
|
|
247
|
-
Trigger: () => Trigger$
|
|
247
|
+
Trigger: () => Trigger$6
|
|
248
248
|
});
|
|
249
|
-
function Root$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
691
|
+
Item: () => Item$7,
|
|
692
692
|
List: () => List$2,
|
|
693
693
|
LoadingIndicator: () => LoadingIndicator,
|
|
694
694
|
MultiItem: () => MultiItem$1,
|
|
695
|
-
Root: () => Root$
|
|
695
|
+
Root: () => Root$7,
|
|
696
696
|
Search: () => Search,
|
|
697
697
|
SearchableTrigger: () => SearchableTrigger,
|
|
698
698
|
SearchableTriggerDropdownAddon: () => SearchableTriggerDropdownAddon,
|
|
699
|
-
Trigger: () => Trigger$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
969
|
+
Item: () => Item$6,
|
|
970
970
|
List: () => List$1,
|
|
971
971
|
MultiItem: () => MultiItem,
|
|
972
972
|
MultiSelectedValue: () => MultiSelectedValue,
|
|
973
|
-
Root: () => Root$
|
|
974
|
-
Trigger: () => Trigger$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
1086
|
+
Item: () => Item$5,
|
|
1087
1087
|
RadioGroup: () => RadioGroup$1,
|
|
1088
1088
|
RadioItem: () => RadioItem,
|
|
1089
|
-
Root: () => Root$
|
|
1089
|
+
Root: () => Root$5,
|
|
1090
1090
|
Separator: () => Separator$1,
|
|
1091
|
-
Trigger: () => Trigger$
|
|
1091
|
+
Trigger: () => Trigger$3
|
|
1092
1092
|
});
|
|
1093
|
-
const Root$
|
|
1094
|
-
function Trigger$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
1204
|
-
Root: () => Root$
|
|
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$
|
|
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$
|
|
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$
|
|
1246
|
-
Trigger: () => Trigger$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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", {
|
|
@@ -1478,7 +1478,11 @@ function Description$1(props) {
|
|
|
1478
1478
|
|
|
1479
1479
|
//#endregion
|
|
1480
1480
|
//#region src/components/radio-group.tsx
|
|
1481
|
-
|
|
1481
|
+
var radio_group_exports = /* @__PURE__ */ __export({
|
|
1482
|
+
Group: () => Group$1,
|
|
1483
|
+
Item: () => Item$1
|
|
1484
|
+
});
|
|
1485
|
+
function Group$1({ className, ...props }) {
|
|
1482
1486
|
return /* @__PURE__ */ jsx(RadioGroup, {
|
|
1483
1487
|
"data-slot": "radio-group",
|
|
1484
1488
|
className: cn("flex flex-col gap-3", className),
|
|
@@ -1499,7 +1503,7 @@ const radioVariants = cva("bg-white aria-invalid:border-ppx-red-5 aspect-square
|
|
|
1499
1503
|
size: "default"
|
|
1500
1504
|
}
|
|
1501
1505
|
});
|
|
1502
|
-
function Item({ className, variant, size, ...props }) {
|
|
1506
|
+
function Item$1({ className, variant, size, ...props }) {
|
|
1503
1507
|
return /* @__PURE__ */ jsx(Radio.Root, {
|
|
1504
1508
|
"data-slot": "radio-group-item",
|
|
1505
1509
|
className: cn(radioVariants({
|
|
@@ -1536,25 +1540,25 @@ function Item({ className, variant, size, ...props }) {
|
|
|
1536
1540
|
//#region src/components/block-radio-group.tsx
|
|
1537
1541
|
var block_radio_group_exports = /* @__PURE__ */ __export({
|
|
1538
1542
|
Description: () => Description,
|
|
1539
|
-
Group: () => Group
|
|
1543
|
+
Group: () => Group,
|
|
1540
1544
|
Header: () => Header,
|
|
1541
|
-
Item: () => Item$
|
|
1545
|
+
Item: () => Item$2,
|
|
1542
1546
|
Title: () => Title
|
|
1543
1547
|
});
|
|
1544
|
-
function Group
|
|
1548
|
+
function Group({ className, ...props }) {
|
|
1545
1549
|
return /* @__PURE__ */ jsx(RadioGroup, {
|
|
1546
1550
|
"data-slot": "radio-group",
|
|
1547
1551
|
className: cn("flex gap-4", className),
|
|
1548
1552
|
...props
|
|
1549
1553
|
});
|
|
1550
1554
|
}
|
|
1551
|
-
function Item$
|
|
1555
|
+
function Item$2({ className, invalid, children, ...rest }) {
|
|
1552
1556
|
return /* @__PURE__ */ jsxs("label", {
|
|
1553
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),
|
|
1554
1558
|
children: [/* @__PURE__ */ jsx("div", {
|
|
1555
1559
|
className: "flex-1",
|
|
1556
1560
|
children
|
|
1557
|
-
}), /* @__PURE__ */ jsx(Item, {
|
|
1561
|
+
}), /* @__PURE__ */ jsx(Item$1, {
|
|
1558
1562
|
...rest,
|
|
1559
1563
|
className: "ml-auto shrink-0 self-start",
|
|
1560
1564
|
size: "lg",
|
|
@@ -1865,9 +1869,9 @@ const replaceSizeInUrl = (url, size) => {
|
|
|
1865
1869
|
return url.replace("/SIZE/", `/${newSize}/`);
|
|
1866
1870
|
};
|
|
1867
1871
|
function Avatar(props) {
|
|
1868
|
-
return /* @__PURE__ */ jsxs(Root, {
|
|
1872
|
+
return /* @__PURE__ */ jsxs(Root$1, {
|
|
1869
1873
|
disabled: props.hideTooltip,
|
|
1870
|
-
children: [/* @__PURE__ */ jsx(Trigger, { render: (tooltipProps) => /* @__PURE__ */ jsx(AvatarImpl, {
|
|
1874
|
+
children: [/* @__PURE__ */ jsx(Trigger$1, { render: (tooltipProps) => /* @__PURE__ */ jsx(AvatarImpl, {
|
|
1871
1875
|
...props,
|
|
1872
1876
|
avatarRootProps: tooltipProps
|
|
1873
1877
|
}) }), /* @__PURE__ */ jsx(Content, { children: props.name })]
|
|
@@ -1912,7 +1916,7 @@ function AvatarGroup({ max = 4, avatars, className }) {
|
|
|
1912
1916
|
return /* @__PURE__ */ jsx(BaseProvider, { children: /* @__PURE__ */ jsxs("div", {
|
|
1913
1917
|
className: cn("flex items-center", className),
|
|
1914
1918
|
"data-slot": "avatar-group",
|
|
1915
|
-
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", {
|
|
1916
1920
|
className: "relative",
|
|
1917
1921
|
style: {
|
|
1918
1922
|
marginLeft: index > 0 ? `-${parseInt(avatar.size ?? "100px") * .25}px` : "0",
|
|
@@ -1929,9 +1933,9 @@ function AvatarGroup({ max = 4, avatars, className }) {
|
|
|
1929
1933
|
marginLeft: `-${parseInt(avatars[0].size ?? "100px") * .25}px`,
|
|
1930
1934
|
zIndex: 0
|
|
1931
1935
|
},
|
|
1932
|
-
children: /* @__PURE__ */ jsxs(Root$
|
|
1936
|
+
children: /* @__PURE__ */ jsxs(Root$9, {
|
|
1933
1937
|
openOnHover: true,
|
|
1934
|
-
children: [/* @__PURE__ */ jsx(Trigger$
|
|
1938
|
+
children: [/* @__PURE__ */ jsx(Trigger$6, { children: /* @__PURE__ */ jsxs("div", {
|
|
1935
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"),
|
|
1936
1940
|
style: {
|
|
1937
1941
|
width: avatars[0].size ?? "100px",
|
|
@@ -2019,11 +2023,11 @@ function DatePicker({ triggerProps, placeholder = "Pick a date", format: format$
|
|
|
2019
2023
|
calendarProps.onSelect(...args);
|
|
2020
2024
|
!calendarProps.mode || calendarProps.mode === "single" && setOpen(false);
|
|
2021
2025
|
};
|
|
2022
|
-
return /* @__PURE__ */ jsxs(Root$
|
|
2026
|
+
return /* @__PURE__ */ jsxs(Root$9, {
|
|
2023
2027
|
open,
|
|
2024
2028
|
onOpenChange: setOpen,
|
|
2025
2029
|
...popoverRootProps,
|
|
2026
|
-
children: [/* @__PURE__ */ jsxs(Trigger$
|
|
2030
|
+
children: [/* @__PURE__ */ jsxs(Trigger$6, {
|
|
2027
2031
|
disabled: triggerProps?.disabled,
|
|
2028
2032
|
className: cn(triggerVariants({
|
|
2029
2033
|
size: triggerProps?.size,
|
|
@@ -2053,6 +2057,812 @@ function renderFormattedDate(calendarProps, format$1) {
|
|
|
2053
2057
|
return "";
|
|
2054
2058
|
}
|
|
2055
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
|
+
|
|
2056
2866
|
//#endregion
|
|
2057
2867
|
//#region src/index.ts
|
|
2058
2868
|
var src_exports = /* @__PURE__ */ __export({
|
|
@@ -2068,14 +2878,15 @@ var src_exports = /* @__PURE__ */ __export({
|
|
|
2068
2878
|
Combobox: () => combobox_exports,
|
|
2069
2879
|
DatePicker: () => DatePicker,
|
|
2070
2880
|
Dialog: () => dialog_exports,
|
|
2071
|
-
|
|
2881
|
+
FileIcon: () => FileIcon,
|
|
2882
|
+
FileUpload: () => FileUpload,
|
|
2072
2883
|
Input: () => Input,
|
|
2073
2884
|
InputGroup: () => input_group_exports,
|
|
2074
|
-
Item: () => Item,
|
|
2075
2885
|
Label: () => Label,
|
|
2076
2886
|
Menu: () => menu_exports,
|
|
2077
2887
|
Popover: () => popover_exports,
|
|
2078
2888
|
Progress: () => progress_exports,
|
|
2889
|
+
RadioGroup: () => radio_group_exports,
|
|
2079
2890
|
SegmentedControl: () => segmented_control_exports,
|
|
2080
2891
|
Select: () => select_exports,
|
|
2081
2892
|
Separator: () => Separator,
|
|
@@ -2084,13 +2895,16 @@ var src_exports = /* @__PURE__ */ __export({
|
|
|
2084
2895
|
Tabs: () => tabs_exports,
|
|
2085
2896
|
Textarea: () => Textarea,
|
|
2086
2897
|
Tooltip: () => tooltip_exports,
|
|
2898
|
+
UploadIcon: () => UploadIcon,
|
|
2087
2899
|
buttonVariants: () => buttonVariants,
|
|
2088
2900
|
cn: () => cn,
|
|
2089
2901
|
defineLoadOptions: () => defineLoadOptions,
|
|
2902
|
+
formatBytes: () => formatBytes,
|
|
2090
2903
|
useAsyncOptions: () => useAsyncOptions,
|
|
2904
|
+
useFileUpload: () => useFileUpload,
|
|
2091
2905
|
useIntersectionObserver: () => useIntersectionObserver
|
|
2092
2906
|
});
|
|
2093
2907
|
|
|
2094
2908
|
//#endregion
|
|
2095
|
-
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,
|
|
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 };
|
|
2096
2910
|
//# sourceMappingURL=index.js.map
|