@oprt/react 0.0.0-stage → 0.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 +105 -2
- package/dist/ActionStatus/ActionStatus.js +104 -0
- package/dist/ActionStatus/ActionStatus.manifest.js +64 -0
- package/dist/ActionStatus/index.js +7 -0
- package/dist/Alert/Alert.js +86 -0
- package/dist/Alert/Alert.manifest.js +36 -0
- package/dist/Alert/index.js +7 -0
- package/dist/AppShell/AppShell.js +103 -0
- package/dist/AppShell/AppShell.manifest.js +66 -0
- package/dist/AppShell/index.js +9 -0
- package/dist/AttachmentPreview/AttachmentPreview.js +145 -0
- package/dist/AttachmentPreview/AttachmentPreview.manifest.js +42 -0
- package/dist/AttachmentPreview/index.js +9 -0
- package/dist/Avatar/Avatar.js +87 -0
- package/dist/Avatar/Avatar.manifest.js +25 -0
- package/dist/Avatar/index.js +7 -0
- package/dist/Badge/Badge.js +124 -0
- package/dist/Badge/Badge.manifest.js +41 -0
- package/dist/Badge/index.js +7 -0
- package/dist/Breadcrumb/Breadcrumb.js +64 -0
- package/dist/Breadcrumb/Breadcrumb.manifest.js +28 -0
- package/dist/Breadcrumb/index.js +7 -0
- package/dist/BulkActionBar/BulkActionBar.js +145 -0
- package/dist/BulkActionBar/BulkActionBar.manifest.js +46 -0
- package/dist/BulkActionBar/index.js +9 -0
- package/dist/BulkActionBar/selection.js +44 -0
- package/dist/BulkResults/BulkResults.js +269 -0
- package/dist/BulkResults/BulkResults.manifest.js +45 -0
- package/dist/BulkResults/index.js +7 -0
- package/dist/Button/Button.js +170 -0
- package/dist/Button/Button.manifest.js +36 -0
- package/dist/Button/index.js +7 -0
- package/dist/ButtonGroup/ButtonGroup.js +60 -0
- package/dist/ButtonGroup/ButtonGroup.manifest.js +22 -0
- package/dist/ButtonGroup/index.js +7 -0
- package/dist/Calendar/Calendar.js +106 -0
- package/dist/Calendar/Calendar.manifest.js +32 -0
- package/dist/Calendar/index.js +7 -0
- package/dist/Card/Card.js +70 -0
- package/dist/Card/Card.manifest.js +57 -0
- package/dist/Card/index.js +16 -0
- package/dist/Chart/Chart.js +1200 -0
- package/dist/Chart/Chart.manifest.js +110 -0
- package/dist/Chart/ChartControls.js +190 -0
- package/dist/Chart/geometry.js +217 -0
- package/dist/Chart/index.js +9 -0
- package/dist/Checkbox/Checkbox.js +166 -0
- package/dist/Checkbox/Checkbox.manifest.js +38 -0
- package/dist/Checkbox/index.js +7 -0
- package/dist/Collapsible/Collapsible.js +177 -0
- package/dist/Collapsible/Collapsible.manifest.js +54 -0
- package/dist/Collapsible/index.js +12 -0
- package/dist/CollectionState/CollectionState.js +68 -0
- package/dist/CollectionState/CollectionState.manifest.js +44 -0
- package/dist/CollectionState/index.js +7 -0
- package/dist/ComboBox/ComboBox.js +221 -0
- package/dist/ComboBox/ComboBox.manifest.js +87 -0
- package/dist/ComboBox/index.js +7 -0
- package/dist/CommandPalette/CommandPalette.js +276 -0
- package/dist/CommandPalette/CommandPalette.manifest.js +24 -0
- package/dist/CommandPalette/index.js +7 -0
- package/dist/ConfirmDialog/ConfirmDialog.js +84 -0
- package/dist/ConfirmDialog/ConfirmDialog.manifest.js +32 -0
- package/dist/ConfirmDialog/index.js +7 -0
- package/dist/ContextMenu/ContextMenu.js +192 -0
- package/dist/ContextMenu/ContextMenu.manifest.js +41 -0
- package/dist/ContextMenu/index.js +7 -0
- package/dist/CoordinateInput/CoordinateInput.js +141 -0
- package/dist/CoordinateInput/CoordinateInput.manifest.js +36 -0
- package/dist/CoordinateInput/index.js +9 -0
- package/dist/CopyButton/CopyButton.js +110 -0
- package/dist/CopyButton/CopyButton.manifest.js +35 -0
- package/dist/CopyButton/index.js +7 -0
- package/dist/DataGrid/DataGrid.js +459 -0
- package/dist/DataGrid/DataGrid.manifest.js +135 -0
- package/dist/DataGrid/PageControls.js +41 -0
- package/dist/DataGrid/index.js +9 -0
- package/dist/DataTable/DataTable.js +375 -0
- package/dist/DataTable/DataTable.manifest.js +86 -0
- package/dist/DataTable/index.js +9 -0
- package/dist/DataTable/sort.js +45 -0
- package/dist/DataTable/useScrollsSideways.js +61 -0
- package/dist/DataTable/useTableWindow.js +185 -0
- package/dist/DatePicker/DatePicker.js +187 -0
- package/dist/DatePicker/DatePicker.manifest.js +40 -0
- package/dist/DatePicker/index.js +7 -0
- package/dist/DateRangePicker/DateRangePicker.js +156 -0
- package/dist/DateRangePicker/DateRangePicker.manifest.js +41 -0
- package/dist/DateRangePicker/index.js +7 -0
- package/dist/DateTimePicker/DateTimePicker.js +213 -0
- package/dist/DateTimePicker/DateTimePicker.manifest.js +44 -0
- package/dist/DateTimePicker/index.js +7 -0
- package/dist/DescriptionList/DescriptionList.js +93 -0
- package/dist/DescriptionList/DescriptionList.manifest.js +40 -0
- package/dist/DescriptionList/index.js +9 -0
- package/dist/Dialog/Dialog.js +214 -0
- package/dist/Dialog/Dialog.manifest.js +31 -0
- package/dist/Dialog/index.js +7 -0
- package/dist/Divider/Divider.js +64 -0
- package/dist/Divider/Divider.manifest.js +21 -0
- package/dist/Divider/index.js +7 -0
- package/dist/DropdownMenu/DropdownMenu.js +170 -0
- package/dist/DropdownMenu/DropdownMenu.manifest.js +82 -0
- package/dist/DropdownMenu/index.js +16 -0
- package/dist/EntityPreview/EntityPreview.js +82 -0
- package/dist/EntityPreview/EntityPreview.manifest.js +43 -0
- package/dist/EntityPreview/index.js +7 -0
- package/dist/EventTimeline/EventTimeline.js +249 -0
- package/dist/EventTimeline/EventTimeline.manifest.js +57 -0
- package/dist/EventTimeline/index.js +7 -0
- package/dist/Field/Field.js +81 -0
- package/dist/Field/Field.manifest.js +32 -0
- package/dist/Field/index.js +9 -0
- package/dist/FileUpload/FileUpload.js +215 -0
- package/dist/FileUpload/FileUpload.manifest.js +48 -0
- package/dist/FileUpload/index.js +7 -0
- package/dist/FilterBar/FilterBar.js +173 -0
- package/dist/FilterBar/FilterBar.manifest.js +49 -0
- package/dist/FilterBar/index.js +7 -0
- package/dist/FormErrorSummary/FormErrorSummary.js +70 -0
- package/dist/FormErrorSummary/FormErrorSummary.manifest.js +29 -0
- package/dist/FormErrorSummary/index.js +9 -0
- package/dist/FormSection/FormSection.js +51 -0
- package/dist/FormSection/FormSection.manifest.js +30 -0
- package/dist/FormSection/index.js +7 -0
- package/dist/InlineEdit/InlineEdit.js +261 -0
- package/dist/InlineEdit/InlineEdit.manifest.js +40 -0
- package/dist/InlineEdit/index.js +7 -0
- package/dist/Input/Input.js +126 -0
- package/dist/Input/Input.manifest.js +49 -0
- package/dist/Input/index.js +7 -0
- package/dist/Inspector/Inspector.js +63 -0
- package/dist/Inspector/Inspector.manifest.js +35 -0
- package/dist/Inspector/index.js +7 -0
- package/dist/JobStatus/JobStatus.js +118 -0
- package/dist/JobStatus/JobStatus.manifest.js +53 -0
- package/dist/JobStatus/index.js +7 -0
- package/dist/LayerControl/LayerControl.js +199 -0
- package/dist/LayerControl/LayerControl.manifest.js +34 -0
- package/dist/LayerControl/index.js +7 -0
- package/dist/Link/Link.js +83 -0
- package/dist/Link/Link.manifest.js +37 -0
- package/dist/Link/index.js +7 -0
- package/dist/MapControls/MapControls.js +122 -0
- package/dist/MapControls/MapControls.manifest.js +31 -0
- package/dist/MapControls/index.js +7 -0
- package/dist/MapLegend/MapLegend.js +89 -0
- package/dist/MapLegend/MapLegend.manifest.js +29 -0
- package/dist/MapLegend/index.js +7 -0
- package/dist/MapScale/MapScale.js +96 -0
- package/dist/MapScale/MapScale.manifest.js +31 -0
- package/dist/MapScale/index.js +7 -0
- package/dist/MediaFrame/MediaFrame.js +113 -0
- package/dist/MediaFrame/MediaFrame.manifest.js +57 -0
- package/dist/MediaFrame/index.js +7 -0
- package/dist/MultiSelect/MultiSelect.js +113 -0
- package/dist/MultiSelect/MultiSelect.manifest.js +51 -0
- package/dist/MultiSelect/index.js +7 -0
- package/dist/NumberInput/NumberInput.js +210 -0
- package/dist/NumberInput/NumberInput.manifest.js +56 -0
- package/dist/NumberInput/index.js +7 -0
- package/dist/OperationalStatus/OperationalStatus.js +89 -0
- package/dist/OperationalStatus/OperationalStatus.manifest.js +39 -0
- package/dist/OperationalStatus/index.js +9 -0
- package/dist/PlaybackControls/PlaybackControls.js +289 -0
- package/dist/PlaybackControls/PlaybackControls.manifest.js +85 -0
- package/dist/PlaybackControls/index.js +7 -0
- package/dist/Popover/Popover.js +302 -0
- package/dist/Popover/Popover.manifest.js +50 -0
- package/dist/Popover/index.js +7 -0
- package/dist/Progress/Progress.js +132 -0
- package/dist/Progress/Progress.manifest.js +30 -0
- package/dist/Progress/index.js +7 -0
- package/dist/PropertyFilter/PropertyFilter.js +306 -0
- package/dist/PropertyFilter/PropertyFilter.manifest.js +32 -0
- package/dist/PropertyFilter/index.js +11 -0
- package/dist/PropertyFilter/tokenError.js +17 -0
- package/dist/RadioGroup/RadioGroup.js +143 -0
- package/dist/RadioGroup/RadioGroup.manifest.js +44 -0
- package/dist/RadioGroup/index.js +9 -0
- package/dist/Select/Select.js +219 -0
- package/dist/Select/Select.manifest.js +77 -0
- package/dist/Select/index.js +9 -0
- package/dist/Sidebar/Sidebar.js +146 -0
- package/dist/Sidebar/Sidebar.manifest.js +72 -0
- package/dist/Sidebar/index.js +18 -0
- package/dist/Skeleton/Skeleton.js +76 -0
- package/dist/Skeleton/Skeleton.manifest.js +30 -0
- package/dist/Skeleton/index.js +7 -0
- package/dist/Slider/Slider.js +246 -0
- package/dist/Slider/Slider.manifest.js +56 -0
- package/dist/Slider/index.js +7 -0
- package/dist/Sparkline/Sparkline.js +135 -0
- package/dist/Sparkline/Sparkline.manifest.js +37 -0
- package/dist/Sparkline/index.js +7 -0
- package/dist/SplitPane/SplitPane.js +316 -0
- package/dist/SplitPane/SplitPane.manifest.js +79 -0
- package/dist/SplitPane/index.js +7 -0
- package/dist/StatCard/StatCard.js +163 -0
- package/dist/StatCard/StatCard.manifest.js +45 -0
- package/dist/StatCard/index.js +7 -0
- package/dist/Tabs/Tabs.js +181 -0
- package/dist/Tabs/Tabs.manifest.js +72 -0
- package/dist/Tabs/index.js +16 -0
- package/dist/Tabs/useTabsIndicator.js +71 -0
- package/dist/Tabs/useTabsScroll.js +123 -0
- package/dist/TagGroup/TagGroup.js +142 -0
- package/dist/TagGroup/TagGroup.manifest.js +35 -0
- package/dist/TagGroup/index.js +7 -0
- package/dist/Textarea/Textarea.js +68 -0
- package/dist/Textarea/Textarea.manifest.js +25 -0
- package/dist/Textarea/index.js +7 -0
- package/dist/TimeField/TimeField.js +118 -0
- package/dist/TimeField/TimeField.manifest.js +42 -0
- package/dist/TimeField/index.js +7 -0
- package/dist/TimeRange/TimeRange.js +184 -0
- package/dist/TimeRange/TimeRange.manifest.js +48 -0
- package/dist/TimeRange/index.js +9 -0
- package/dist/Toast/Toast.js +188 -0
- package/dist/Toast/Toast.manifest.js +77 -0
- package/dist/Toast/index.js +9 -0
- package/dist/Toggle/Toggle.js +154 -0
- package/dist/Toggle/Toggle.manifest.js +54 -0
- package/dist/Toggle/index.js +7 -0
- package/dist/Toolbar/Toolbar.js +86 -0
- package/dist/Toolbar/Toolbar.manifest.js +70 -0
- package/dist/Toolbar/index.js +12 -0
- package/dist/Tooltip/Tooltip.js +122 -0
- package/dist/Tooltip/Tooltip.manifest.js +27 -0
- package/dist/Tooltip/index.js +7 -0
- package/dist/TreeView/TreeView.js +129 -0
- package/dist/TreeView/TreeView.manifest.js +56 -0
- package/dist/TreeView/index.js +7 -0
- package/dist/UploadQueue/UploadQueue.js +296 -0
- package/dist/UploadQueue/UploadQueue.manifest.js +34 -0
- package/dist/UploadQueue/index.js +7 -0
- package/dist/_internal/MotionPopover.js +113 -0
- package/dist/_internal/aria.js +40 -0
- package/dist/_internal/bytes.js +18 -0
- package/dist/_internal/controlStyles.js +26 -0
- package/dist/_internal/date.js +179 -0
- package/dist/_internal/devValidate.js +51 -0
- package/dist/_internal/fieldIds.js +50 -0
- package/dist/_internal/hydration.js +74 -0
- package/dist/_internal/manifest-entry.js +0 -0
- package/dist/_internal/mergeRefs.js +68 -0
- package/dist/_internal/motion.js +138 -0
- package/dist/_internal/navigationLandmark.js +13 -0
- package/dist/_internal/numberText.js +176 -0
- package/dist/_internal/overlay.js +53 -0
- package/dist/_internal/segmentField.js +125 -0
- package/dist/_internal/suggestions.js +20 -0
- package/dist/_internal/timestamp.js +25 -0
- package/dist/_internal/unavailable.js +13 -0
- package/dist/_internal/useActionFocus.js +27 -0
- package/dist/_internal/useElementWidth.js +37 -0
- package/dist/_internal/useIsMounted.js +18 -0
- package/dist/_internal/useIsomorphicLayoutEffect.js +8 -0
- package/dist/_internal/useRestoreFocusOnRemoval.js +57 -0
- package/dist/index.cjs +17811 -0
- package/dist/index.d.cts +2330 -0
- package/dist/index.d.ts +2330 -0
- package/dist/index.js +407 -0
- package/dist/version.js +8 -0
- package/package.json +80 -3
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/Tooltip/Tooltip.tsx
|
|
4
|
+
import {
|
|
5
|
+
TooltipTrigger,
|
|
6
|
+
Tooltip as AriaTooltip,
|
|
7
|
+
OverlayArrow,
|
|
8
|
+
Focusable
|
|
9
|
+
} from "react-aria-components";
|
|
10
|
+
import {
|
|
11
|
+
cloneElement,
|
|
12
|
+
forwardRef,
|
|
13
|
+
useCallback,
|
|
14
|
+
useEffect,
|
|
15
|
+
useRef,
|
|
16
|
+
useState
|
|
17
|
+
} from "react";
|
|
18
|
+
import clsx from "clsx";
|
|
19
|
+
import { TooltipManifest } from "./Tooltip.manifest.js";
|
|
20
|
+
import { devValidate } from "../_internal/devValidate.js";
|
|
21
|
+
import { definedOnly } from "../_internal/aria.js";
|
|
22
|
+
import { isSingleElement, SCREEN_MARGIN, toPlacement, TOOLTIP_WIDTH } from "../_internal/overlay.js";
|
|
23
|
+
import { FocusableWhenUnavailableProvider } from "../_internal/unavailable.js";
|
|
24
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
25
|
+
var PLAIN_TRIGGER = "inline-flex min-h-3u items-center border-0 bg-transparent p-0 [color:inherit] [font:inherit] [letter-spacing:inherit] underline decoration-dotted underline-offset-2 cursor-help outline-hidden focus-visible:shadow-oprt-focus";
|
|
26
|
+
var Tooltip = forwardRef(
|
|
27
|
+
({
|
|
28
|
+
content,
|
|
29
|
+
children,
|
|
30
|
+
side = "top",
|
|
31
|
+
align = "center",
|
|
32
|
+
delayDuration = 200,
|
|
33
|
+
open,
|
|
34
|
+
defaultOpen,
|
|
35
|
+
onOpenChange,
|
|
36
|
+
className,
|
|
37
|
+
...contentProps
|
|
38
|
+
}, ref) => {
|
|
39
|
+
const [localOpen, setLocalOpen] = useState(defaultOpen ?? false);
|
|
40
|
+
const isOpen = open ?? localOpen;
|
|
41
|
+
const tapped = useRef(null);
|
|
42
|
+
const [tapOpen, setTapOpen] = useState(false);
|
|
43
|
+
const setOpen = useCallback(
|
|
44
|
+
(next) => {
|
|
45
|
+
if (!next) setTapOpen(false);
|
|
46
|
+
if (open === void 0) setLocalOpen(next);
|
|
47
|
+
onOpenChange?.(next);
|
|
48
|
+
},
|
|
49
|
+
[open, onOpenChange]
|
|
50
|
+
);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!tapOpen || !isOpen) return;
|
|
53
|
+
const dismiss = (event) => {
|
|
54
|
+
if (!tapped.current?.contains(event.target)) setOpen(false);
|
|
55
|
+
};
|
|
56
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
57
|
+
return () => document.removeEventListener("pointerdown", dismiss, true);
|
|
58
|
+
}, [tapOpen, isOpen, setOpen]);
|
|
59
|
+
if (process.env.NODE_ENV !== "production") {
|
|
60
|
+
devValidate("Tooltip", TooltipManifest.Tooltip.props, { ...contentProps, side, align });
|
|
61
|
+
}
|
|
62
|
+
if (children === null || children === void 0 || typeof children === "boolean") return null;
|
|
63
|
+
const element = isSingleElement(children) ? children : null;
|
|
64
|
+
const unavailable = element !== null && (element.props.disabled === true || element.props.isDisabled === true);
|
|
65
|
+
const trigger = !element ? /* @__PURE__ */ jsx("button", { type: "button", className: PLAIN_TRIGGER, children }) : unavailable ? cloneElement(element, {
|
|
66
|
+
onPointerUp: (event) => {
|
|
67
|
+
element.props.onPointerUp?.(event);
|
|
68
|
+
if (event.pointerType === "mouse") return;
|
|
69
|
+
tapped.current = event.currentTarget;
|
|
70
|
+
setTapOpen(true);
|
|
71
|
+
setOpen(true);
|
|
72
|
+
}
|
|
73
|
+
}) : element;
|
|
74
|
+
const focusable = /* @__PURE__ */ jsx(Focusable, { children: trigger });
|
|
75
|
+
return /* @__PURE__ */ jsxs(
|
|
76
|
+
TooltipTrigger,
|
|
77
|
+
{
|
|
78
|
+
isOpen,
|
|
79
|
+
onOpenChange: setOpen,
|
|
80
|
+
delay: delayDuration,
|
|
81
|
+
closeDelay: 0,
|
|
82
|
+
shouldCloseOnPress: !unavailable,
|
|
83
|
+
children: [
|
|
84
|
+
unavailable ? /* @__PURE__ */ jsx(FocusableWhenUnavailableProvider, { value: true, children: focusable }) : focusable,
|
|
85
|
+
/* @__PURE__ */ jsxs(
|
|
86
|
+
AriaTooltip,
|
|
87
|
+
{
|
|
88
|
+
ref,
|
|
89
|
+
placement: toPlacement(side, align),
|
|
90
|
+
offset: 4,
|
|
91
|
+
containerPadding: SCREEN_MARGIN,
|
|
92
|
+
className: clsx(
|
|
93
|
+
"z-50 bg-oprt-surface-2 border border-oprt-border px-2u py-1u text-oprt-base normal-case text-oprt-text font-sans oprt-wrap-anywhere",
|
|
94
|
+
TOOLTIP_WIDTH,
|
|
95
|
+
className
|
|
96
|
+
),
|
|
97
|
+
...definedOnly(contentProps),
|
|
98
|
+
children: [
|
|
99
|
+
content,
|
|
100
|
+
/* @__PURE__ */ jsx(OverlayArrow, { className: "group", children: /* @__PURE__ */ jsx(
|
|
101
|
+
"svg",
|
|
102
|
+
{
|
|
103
|
+
width: 10,
|
|
104
|
+
height: 5,
|
|
105
|
+
viewBox: "0 0 10 5",
|
|
106
|
+
"aria-hidden": "true",
|
|
107
|
+
className: "fill-oprt-border group-data-[placement=bottom]:rotate-180 group-data-[placement=left]:-rotate-90 group-data-[placement=right]:rotate-90",
|
|
108
|
+
children: /* @__PURE__ */ jsx("path", { d: "M0 0 L5 5 L10 0 Z" })
|
|
109
|
+
}
|
|
110
|
+
) })
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
Tooltip.displayName = "Tooltip";
|
|
120
|
+
export {
|
|
121
|
+
Tooltip
|
|
122
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/Tooltip/Tooltip.manifest.ts
|
|
2
|
+
var TooltipManifest = {
|
|
3
|
+
Tooltip: {
|
|
4
|
+
description: "Supplementary text on hover or keyboard focus of a trigger, wrapping at about 20rem. A disabled Button trigger stays focusable and announced unavailable, so focus or a tap shows the explanation. Built on React Aria Components (TooltipTrigger + Tooltip), portal'd, with a bordered surface.",
|
|
5
|
+
props: {
|
|
6
|
+
side: { type: "enum", values: ["top", "right", "bottom", "left"], default: "top" },
|
|
7
|
+
align: { type: "enum", values: ["start", "center", "end"], default: "center" },
|
|
8
|
+
delayDuration: { type: "number", default: 200 },
|
|
9
|
+
open: { type: "boolean" },
|
|
10
|
+
defaultOpen: { type: "boolean" },
|
|
11
|
+
onOpenChange: { type: "function" }
|
|
12
|
+
},
|
|
13
|
+
slots: {
|
|
14
|
+
content: { type: "text | node", required: true },
|
|
15
|
+
children: {
|
|
16
|
+
type: "focusable trigger element | text (text renders a text button)",
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
composable_with: ["Button", "Badge", "Toolbar"],
|
|
21
|
+
never_inside: ["Tooltip"],
|
|
22
|
+
example: '<Tooltip content="GRID 38S MC"><Button>COORD</Button></Tooltip>'
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
export {
|
|
26
|
+
TooltipManifest
|
|
27
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/TreeView/TreeView.tsx
|
|
4
|
+
import { forwardRef, useEffect, useRef, useState } from "react";
|
|
5
|
+
import {
|
|
6
|
+
Tree,
|
|
7
|
+
TreeItem,
|
|
8
|
+
TreeItemContent,
|
|
9
|
+
Button as AriaButton
|
|
10
|
+
} from "react-aria-components";
|
|
11
|
+
import { ChevronDown, ChevronRight } from "@oprt/icons";
|
|
12
|
+
import { cva } from "class-variance-authority";
|
|
13
|
+
import clsx from "clsx";
|
|
14
|
+
import { useMergedRefs } from "../_internal/mergeRefs.js";
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
var forcedFocus = "forced-colors:outline-0 forced-colors:data-[focus-visible]:outline-solid forced-colors:data-[focus-visible]:outline-2 forced-colors:data-[focus-visible]:-outline-offset-2 forced-colors:data-[focus-visible]:outline-[CanvasText]";
|
|
17
|
+
var treeStyles = cva(
|
|
18
|
+
`grid min-w-0 grid-cols-[minmax(min-content,1fr)] overflow-x-auto p-px border border-transparent font-sans text-oprt-base font-medium normal-case text-oprt-text outline-hidden data-[focus-visible]:border-oprt-border-focus data-[focus-visible]:shadow-oprt-focus ${forcedFocus}`
|
|
19
|
+
);
|
|
20
|
+
var itemStyles = cva(
|
|
21
|
+
`min-h-3u border border-transparent outline-hidden data-[focus-visible]:border-oprt-border-focus data-[focus-visible]:shadow-oprt-focus data-[selected]:bg-oprt-surface-selected data-[selected]:border-oprt-accent forced-colors:data-[selected]:border-[Highlight] data-[disabled]:opacity-50 ${forcedFocus}`
|
|
22
|
+
);
|
|
23
|
+
function aimAtLabel(tree, row) {
|
|
24
|
+
const label = row.querySelector("[data-oprt-tree-label]");
|
|
25
|
+
if (!label) return;
|
|
26
|
+
const start = (label.previousElementSibling ?? label).getBoundingClientRect();
|
|
27
|
+
const text = label.getBoundingClientRect();
|
|
28
|
+
const box = row.getBoundingClientRect();
|
|
29
|
+
let left = Math.min(start.left, text.left);
|
|
30
|
+
let right = Math.max(start.right, text.right);
|
|
31
|
+
const room = tree.clientWidth;
|
|
32
|
+
if (room > 0 && right - left > room) {
|
|
33
|
+
if (getComputedStyle(row).direction === "rtl") left = right - room;
|
|
34
|
+
else right = left + room;
|
|
35
|
+
}
|
|
36
|
+
row.style.scrollMarginLeft = `${Math.min(0, box.left - left)}px`;
|
|
37
|
+
row.style.scrollMarginRight = `${Math.min(0, right - box.right)}px`;
|
|
38
|
+
}
|
|
39
|
+
var TreeView = forwardRef(
|
|
40
|
+
({
|
|
41
|
+
items,
|
|
42
|
+
label = "Navigation",
|
|
43
|
+
selectedId,
|
|
44
|
+
onSelectionChange,
|
|
45
|
+
expandedIds,
|
|
46
|
+
defaultExpandedIds = [],
|
|
47
|
+
onExpandedChange,
|
|
48
|
+
disabled = false,
|
|
49
|
+
emptyMessage = "No items.",
|
|
50
|
+
className,
|
|
51
|
+
...attributes
|
|
52
|
+
}, ref) => {
|
|
53
|
+
const [localSelection, setLocalSelection] = useState(null);
|
|
54
|
+
const [localExpanded, setLocalExpanded] = useState(defaultExpandedIds);
|
|
55
|
+
const selection = selectedId === void 0 ? localSelection : selectedId;
|
|
56
|
+
const treeRef = useRef(null);
|
|
57
|
+
const setRef = useMergedRefs(treeRef, ref);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
const tree = treeRef.current;
|
|
60
|
+
if (!tree) return;
|
|
61
|
+
const aim = (event) => {
|
|
62
|
+
const row = event.target?.closest?.('[role="row"]');
|
|
63
|
+
if (row instanceof HTMLElement && tree.contains(row)) aimAtLabel(tree, row);
|
|
64
|
+
};
|
|
65
|
+
tree.addEventListener("focusin", aim);
|
|
66
|
+
return () => tree.removeEventListener("focusin", aim);
|
|
67
|
+
}, []);
|
|
68
|
+
const renderItems = (nodes, depth = 0) => nodes.map((item) => /* @__PURE__ */ jsxs(
|
|
69
|
+
TreeItem,
|
|
70
|
+
{
|
|
71
|
+
id: item.id,
|
|
72
|
+
textValue: item.label,
|
|
73
|
+
isDisabled: disabled || item.disabled === true,
|
|
74
|
+
className: itemStyles(),
|
|
75
|
+
children: [
|
|
76
|
+
/* @__PURE__ */ jsx(TreeItemContent, { children: ({ isExpanded, hasChildItems }) => /* @__PURE__ */ jsxs("div", { className: "flex min-h-3u items-center gap-1u p-1u", children: [
|
|
77
|
+
Array.from({ length: depth }, (_, index) => /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "w-1u shrink-0" }, index)),
|
|
78
|
+
hasChildItems ? /* @__PURE__ */ jsx(
|
|
79
|
+
AriaButton,
|
|
80
|
+
{
|
|
81
|
+
slot: "chevron",
|
|
82
|
+
"aria-label": isExpanded ? "Collapse" : "Expand",
|
|
83
|
+
isDisabled: disabled || item.disabled === true,
|
|
84
|
+
className: `flex h-oprt-sm w-3u shrink-0 items-center justify-center border border-transparent text-oprt-base font-medium outline-hidden data-[focus-visible]:border-oprt-border-focus data-[focus-visible]:shadow-oprt-focus ${forcedFocus}`,
|
|
85
|
+
children: isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { size: 16, "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRight, { size: 16, "aria-hidden": "true" })
|
|
86
|
+
}
|
|
87
|
+
) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "w-3u shrink-0" }),
|
|
88
|
+
/* @__PURE__ */ jsx("span", { "data-oprt-tree-label": "", className: "min-w-8u oprt-wrap-anywhere", children: item.label })
|
|
89
|
+
] }) }),
|
|
90
|
+
item.children && renderItems(item.children, depth + 1)
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
item.id
|
|
94
|
+
));
|
|
95
|
+
return /* @__PURE__ */ jsx(
|
|
96
|
+
Tree,
|
|
97
|
+
{
|
|
98
|
+
...attributes,
|
|
99
|
+
ref: setRef,
|
|
100
|
+
"aria-label": label,
|
|
101
|
+
selectionMode: "single",
|
|
102
|
+
disallowEmptySelection: true,
|
|
103
|
+
selectionBehavior: "replace",
|
|
104
|
+
selectedKeys: selection ? [selection] : [],
|
|
105
|
+
expandedKeys: expandedIds ?? localExpanded,
|
|
106
|
+
className: clsx(treeStyles(), className),
|
|
107
|
+
onSelectionChange: (keys) => {
|
|
108
|
+
if (disabled || keys === "all") return;
|
|
109
|
+
const next = [...keys][0];
|
|
110
|
+
const id = next === void 0 ? null : String(next);
|
|
111
|
+
if (selectedId === void 0) setLocalSelection(id);
|
|
112
|
+
onSelectionChange?.(id);
|
|
113
|
+
},
|
|
114
|
+
onExpandedChange: (keys) => {
|
|
115
|
+
if (disabled) return;
|
|
116
|
+
const next = [...keys].map(String);
|
|
117
|
+
if (expandedIds === void 0) setLocalExpanded(next);
|
|
118
|
+
onExpandedChange?.(next);
|
|
119
|
+
},
|
|
120
|
+
renderEmptyState: () => /* @__PURE__ */ jsx("p", { className: "m-0 p-2u text-oprt-text-dim", children: emptyMessage }),
|
|
121
|
+
children: renderItems(items)
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
TreeView.displayName = "TreeView";
|
|
127
|
+
export {
|
|
128
|
+
TreeView
|
|
129
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// src/TreeView/TreeView.manifest.ts
|
|
2
|
+
var TreeViewManifest = {
|
|
3
|
+
TreeView: {
|
|
4
|
+
description: "React Aria hierarchical treegrid with stable string IDs, single selection, expansion, arrow-key navigation, and typeahead. Labels wrap and keep a readable width; a hierarchy deeper than the tree is wide scrolls sideways inside the tree, and keyboard focus brings the focused row's label into view. Accepts id, style, aria-labelledby, aria-describedby and data attributes.",
|
|
5
|
+
props: {
|
|
6
|
+
items: {
|
|
7
|
+
type: "array",
|
|
8
|
+
required: true,
|
|
9
|
+
items: {
|
|
10
|
+
id: "unique string",
|
|
11
|
+
label: "string",
|
|
12
|
+
children: "optional recursive TreeViewItem[]",
|
|
13
|
+
disabled: "optional boolean"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
label: {
|
|
17
|
+
type: "string",
|
|
18
|
+
default: "Navigation"
|
|
19
|
+
},
|
|
20
|
+
selectedId: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Controlled selected string ID; null clears the selection."
|
|
23
|
+
},
|
|
24
|
+
onSelectionChange: {
|
|
25
|
+
type: "function",
|
|
26
|
+
description: "(id: string | null) => void. Navigation may select as focus moves."
|
|
27
|
+
},
|
|
28
|
+
expandedIds: {
|
|
29
|
+
type: "array",
|
|
30
|
+
description: "Controlled expanded string IDs."
|
|
31
|
+
},
|
|
32
|
+
defaultExpandedIds: {
|
|
33
|
+
type: "array",
|
|
34
|
+
description: "Initial expanded IDs for local state."
|
|
35
|
+
},
|
|
36
|
+
onExpandedChange: {
|
|
37
|
+
type: "function",
|
|
38
|
+
description: "(ids: string[]) => void."
|
|
39
|
+
},
|
|
40
|
+
disabled: {
|
|
41
|
+
type: "boolean",
|
|
42
|
+
default: false
|
|
43
|
+
},
|
|
44
|
+
emptyMessage: {
|
|
45
|
+
type: "string",
|
|
46
|
+
default: "No items."
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
composable_with: ["AppShell", "Inspector"],
|
|
50
|
+
never_inside: ["Button"],
|
|
51
|
+
example: '<TreeView label="Assets" items={groups} selectedId={selectedId} onSelectionChange={setSelectedId} />'
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
export {
|
|
55
|
+
TreeViewManifest
|
|
56
|
+
};
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/UploadQueue/UploadQueue.tsx
|
|
4
|
+
import {
|
|
5
|
+
forwardRef,
|
|
6
|
+
useEffect,
|
|
7
|
+
useImperativeHandle,
|
|
8
|
+
useRef,
|
|
9
|
+
useState
|
|
10
|
+
} from "react";
|
|
11
|
+
import { cva } from "class-variance-authority";
|
|
12
|
+
import clsx from "clsx";
|
|
13
|
+
import { Badge } from "../Badge/Badge.js";
|
|
14
|
+
import { Button } from "../Button/Button.js";
|
|
15
|
+
import { Progress } from "../Progress/Progress.js";
|
|
16
|
+
import { ByteCountLabel, NUMBER_UNIT_SPACE } from "../_internal/bytes.js";
|
|
17
|
+
import { joinIds, usePartIds } from "../_internal/fieldIds.js";
|
|
18
|
+
import { useRestoreFocusOnRemoval } from "../_internal/useRestoreFocusOnRemoval.js";
|
|
19
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
var queueStyles = cva(
|
|
21
|
+
"flex min-w-0 flex-col gap-2u font-sans text-oprt-base normal-case text-oprt-text outline-hidden focus-visible:shadow-oprt-focus"
|
|
22
|
+
);
|
|
23
|
+
var labels = {
|
|
24
|
+
ready: "Ready locally",
|
|
25
|
+
queued: "Queued",
|
|
26
|
+
uploading: "Uploading",
|
|
27
|
+
"cancel-requested": "Cancel requested",
|
|
28
|
+
uploaded: "Uploaded",
|
|
29
|
+
failed: "Failed",
|
|
30
|
+
canceled: "Canceled"
|
|
31
|
+
};
|
|
32
|
+
var variants = {
|
|
33
|
+
ready: "neutral",
|
|
34
|
+
queued: "neutral",
|
|
35
|
+
uploading: "info",
|
|
36
|
+
"cancel-requested": "warning",
|
|
37
|
+
uploaded: "success",
|
|
38
|
+
failed: "error",
|
|
39
|
+
canceled: "neutral"
|
|
40
|
+
};
|
|
41
|
+
var KNOWN_STATES = Object.keys(labels);
|
|
42
|
+
var isKnownState = (state) => typeof state === "string" && Object.prototype.hasOwnProperty.call(labels, state);
|
|
43
|
+
var UNKNOWN_STATE = "Unknown state";
|
|
44
|
+
var stateLabel = (state) => isKnownState(state) ? labels[state] : UNKNOWN_STATE;
|
|
45
|
+
var count = (value) => Number.isSafeInteger(value) && value >= 0;
|
|
46
|
+
var reportedStates = /* @__PURE__ */ new Set();
|
|
47
|
+
function reportUnknownState(state) {
|
|
48
|
+
const received = String(state);
|
|
49
|
+
if (process.env.NODE_ENV === "production" || reportedStates.has(received)) return;
|
|
50
|
+
reportedStates.add(received);
|
|
51
|
+
console.error(
|
|
52
|
+
JSON.stringify(
|
|
53
|
+
{
|
|
54
|
+
component: "UploadQueue",
|
|
55
|
+
error: "INVALID_PROP_VALUE",
|
|
56
|
+
prop: "items[].state",
|
|
57
|
+
received,
|
|
58
|
+
valid_values: KNOWN_STATES,
|
|
59
|
+
suggestion: `Valid values for \`items[].state\`: ${KNOWN_STATES.join(", ")}. The row shows "${UNKNOWN_STATE}" until the state is one of them.`
|
|
60
|
+
},
|
|
61
|
+
null,
|
|
62
|
+
2
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
function hasInvalidIdentity(items) {
|
|
67
|
+
const seen = /* @__PURE__ */ new Set();
|
|
68
|
+
for (const item of items) {
|
|
69
|
+
if (!item.id.trim() || seen.has(item.id)) return true;
|
|
70
|
+
seen.add(item.id);
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
var rowsOf = (items) => items.map((item) => [item.id, item.name, String(item.state), item.message ?? ""]);
|
|
75
|
+
var NAMED_CHANGES = 3;
|
|
76
|
+
function describeChanges(before, after) {
|
|
77
|
+
const previous = new Map(before.map((row) => [row[0], row]));
|
|
78
|
+
const current = new Set(after.map((row) => row[0]));
|
|
79
|
+
const changes = [];
|
|
80
|
+
for (const [id, name, state, message] of after) {
|
|
81
|
+
const was = previous.get(id);
|
|
82
|
+
if (was && was[1] === name && was[2] === state && was[3] === message) continue;
|
|
83
|
+
const label = stateLabel(state);
|
|
84
|
+
changes.push({ label, sentence: `${name}: ${label}.${message ? ` ${message}` : ""}` });
|
|
85
|
+
}
|
|
86
|
+
for (const [id, name] of before)
|
|
87
|
+
if (!current.has(id)) changes.push({ label: "Removed", sentence: `${name}: Removed.` });
|
|
88
|
+
const parts = changes.length <= NAMED_CHANGES ? changes.map((change) => change.sentence) : Array.from(
|
|
89
|
+
changes.reduce(
|
|
90
|
+
(counts, { label }) => counts.set(label, (counts.get(label) ?? 0) + 1),
|
|
91
|
+
/* @__PURE__ */ new Map()
|
|
92
|
+
),
|
|
93
|
+
([label, total]) => `${label}: ${total} ${total === 1 ? "file" : "files"}.`
|
|
94
|
+
);
|
|
95
|
+
if (after.length === 0 && before.length > 0) parts.push("No files selected.");
|
|
96
|
+
return parts.join(" ");
|
|
97
|
+
}
|
|
98
|
+
var UploadQueue = forwardRef(
|
|
99
|
+
({
|
|
100
|
+
label,
|
|
101
|
+
items,
|
|
102
|
+
onCancel,
|
|
103
|
+
onRetry,
|
|
104
|
+
onRemove,
|
|
105
|
+
disabled = false,
|
|
106
|
+
className,
|
|
107
|
+
onFocusCapture,
|
|
108
|
+
onBlurCapture,
|
|
109
|
+
"aria-labelledby": labelledBy,
|
|
110
|
+
...props
|
|
111
|
+
}, ref) => {
|
|
112
|
+
const root = useRef(null);
|
|
113
|
+
const ids = usePartIds(["label"], {
|
|
114
|
+
id: props.id,
|
|
115
|
+
readRendered: () => root.current?.getAttribute("data-oprt-ids")
|
|
116
|
+
});
|
|
117
|
+
const rows = useRef(/* @__PURE__ */ new Map());
|
|
118
|
+
useImperativeHandle(ref, () => root.current, []);
|
|
119
|
+
const invalidIdentity = hasInvalidIdentity(items);
|
|
120
|
+
const restoreFocus = useRestoreFocusOnRemoval(root, {
|
|
121
|
+
track: (element) => {
|
|
122
|
+
const index = items.findIndex((item) => rows.current.get(item.id)?.contains(element));
|
|
123
|
+
return index >= 0 ? { index } : null;
|
|
124
|
+
},
|
|
125
|
+
// The next row's first enabled action, else the row itself, else the queue.
|
|
126
|
+
findTarget: ({ index }) => {
|
|
127
|
+
const next = items[Math.min(index, items.length - 1)];
|
|
128
|
+
const row = next ? rows.current.get(next.id) : null;
|
|
129
|
+
return row?.querySelector("button:not(:disabled)") ?? row ?? root.current;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
const signature = JSON.stringify(rowsOf(items));
|
|
133
|
+
const announced = useRef(null);
|
|
134
|
+
const [announcement, setAnnouncement] = useState("");
|
|
135
|
+
const lastAnnouncement = useRef("");
|
|
136
|
+
const repeatFrame = useRef(null);
|
|
137
|
+
useEffect(
|
|
138
|
+
() => () => {
|
|
139
|
+
if (repeatFrame.current !== null) cancelAnimationFrame(repeatFrame.current);
|
|
140
|
+
},
|
|
141
|
+
[]
|
|
142
|
+
);
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
const after = JSON.parse(signature);
|
|
145
|
+
const before = announced.current;
|
|
146
|
+
announced.current = after;
|
|
147
|
+
if (before === null) return;
|
|
148
|
+
const text = describeChanges(before, after);
|
|
149
|
+
if (!text) return;
|
|
150
|
+
if (repeatFrame.current !== null) {
|
|
151
|
+
cancelAnimationFrame(repeatFrame.current);
|
|
152
|
+
repeatFrame.current = null;
|
|
153
|
+
}
|
|
154
|
+
if (text !== lastAnnouncement.current) {
|
|
155
|
+
lastAnnouncement.current = text;
|
|
156
|
+
setAnnouncement(text);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
setAnnouncement("");
|
|
160
|
+
repeatFrame.current = requestAnimationFrame(() => {
|
|
161
|
+
repeatFrame.current = null;
|
|
162
|
+
setAnnouncement(text);
|
|
163
|
+
});
|
|
164
|
+
}, [signature]);
|
|
165
|
+
const unknownStates = items.filter((item) => !isKnownState(item.state)).map((item) => item.state);
|
|
166
|
+
const unknownKey = JSON.stringify(unknownStates);
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
if (process.env.NODE_ENV === "production") return;
|
|
169
|
+
for (const state of JSON.parse(unknownKey)) reportUnknownState(state);
|
|
170
|
+
}, [unknownKey]);
|
|
171
|
+
return /* @__PURE__ */ jsxs(
|
|
172
|
+
"div",
|
|
173
|
+
{
|
|
174
|
+
...props,
|
|
175
|
+
ref: root,
|
|
176
|
+
role: "region",
|
|
177
|
+
tabIndex: -1,
|
|
178
|
+
"data-oprt-ids": ids.base,
|
|
179
|
+
"aria-labelledby": joinIds(ids.label, labelledBy),
|
|
180
|
+
className: clsx(queueStyles(), className),
|
|
181
|
+
onFocusCapture: (event) => {
|
|
182
|
+
onFocusCapture?.(event);
|
|
183
|
+
restoreFocus.onFocusCapture(event);
|
|
184
|
+
},
|
|
185
|
+
onBlurCapture: (event) => {
|
|
186
|
+
onBlurCapture?.(event);
|
|
187
|
+
restoreFocus.onBlurCapture(event);
|
|
188
|
+
},
|
|
189
|
+
children: [
|
|
190
|
+
/* @__PURE__ */ jsx(
|
|
191
|
+
"h3",
|
|
192
|
+
{
|
|
193
|
+
id: ids.label,
|
|
194
|
+
className: "m-0 oprt-wrap-anywhere font-medium uppercase tracking-oprt-sm",
|
|
195
|
+
children: label
|
|
196
|
+
}
|
|
197
|
+
),
|
|
198
|
+
/* @__PURE__ */ jsx("p", { role: "status", "aria-atomic": "true", className: "sr-only", children: announcement }),
|
|
199
|
+
invalidIdentity && /* @__PURE__ */ jsx("p", { role: "alert", className: "m-0 text-oprt-error", children: "Queue item IDs must be unique and nonempty. Actions are unavailable." }),
|
|
200
|
+
!items.length ? /* @__PURE__ */ jsx("p", { className: "m-0 text-oprt-text-dim", children: "No files selected." }) : /* @__PURE__ */ jsx("ul", { className: "m-0 flex min-w-0 list-none flex-col gap-2u p-0", children: items.map((item, index) => {
|
|
201
|
+
const transferring = item.state === "uploading" || item.state === "cancel-requested";
|
|
202
|
+
const invalidProgress = item.loadedBytes !== void 0 && !count(item.loadedBytes) || item.totalBytes !== void 0 && !count(item.totalBytes) || item.loadedBytes !== void 0 && item.totalBytes !== void 0 && item.loadedBytes > item.totalBytes;
|
|
203
|
+
const validLoaded = item.loadedBytes !== void 0 && count(item.loadedBytes);
|
|
204
|
+
const blocked = disabled || invalidIdentity;
|
|
205
|
+
return /* @__PURE__ */ jsxs(
|
|
206
|
+
"li",
|
|
207
|
+
{
|
|
208
|
+
ref: (node) => {
|
|
209
|
+
if (node) rows.current.set(item.id, node);
|
|
210
|
+
else rows.current.delete(item.id);
|
|
211
|
+
},
|
|
212
|
+
tabIndex: -1,
|
|
213
|
+
className: "flex min-w-0 flex-col gap-1u border border-oprt-border p-2u outline-hidden focus-visible:shadow-oprt-focus",
|
|
214
|
+
children: [
|
|
215
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-wrap items-start justify-between gap-1u", children: [
|
|
216
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 oprt-wrap-anywhere", children: item.name }),
|
|
217
|
+
/* @__PURE__ */ jsx(
|
|
218
|
+
Badge,
|
|
219
|
+
{
|
|
220
|
+
appearance: "text",
|
|
221
|
+
variant: isKnownState(item.state) ? variants[item.state] : "neutral",
|
|
222
|
+
children: stateLabel(item.state)
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
] }),
|
|
226
|
+
/* @__PURE__ */ jsx("p", { className: "m-0 text-oprt-text-dim", children: /* @__PURE__ */ jsx(ByteCountLabel, { value: item.sizeBytes }) }),
|
|
227
|
+
item.message && /* @__PURE__ */ jsx("p", { className: "m-0 oprt-wrap-anywhere", children: item.message }),
|
|
228
|
+
transferring && (invalidProgress ? /* @__PURE__ */ jsx("p", { className: "m-0 text-oprt-error", children: "Invalid progress counts." }) : item.totalBytes === 0 ? /* @__PURE__ */ jsx("p", { className: "m-0 text-oprt-text-dim", children: `0${NUMBER_UNIT_SPACE}bytes total; no percentage available.` }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
229
|
+
/* @__PURE__ */ jsx(
|
|
230
|
+
Progress,
|
|
231
|
+
{
|
|
232
|
+
"aria-label": `Upload progress for ${item.name}`,
|
|
233
|
+
...item.totalBytes !== void 0 && validLoaded ? { value: item.loadedBytes, max: item.totalBytes } : {}
|
|
234
|
+
}
|
|
235
|
+
),
|
|
236
|
+
/* @__PURE__ */ jsxs("p", { className: "m-0 font-mono tabular-nums text-oprt-text-dim", children: [
|
|
237
|
+
validLoaded ? `${item.loadedBytes}${NUMBER_UNIT_SPACE}bytes transferred` : "Transferred byte count unavailable",
|
|
238
|
+
item.totalBytes !== void 0 ? ` of ${item.totalBytes}${NUMBER_UNIT_SPACE}bytes` : "; total unknown",
|
|
239
|
+
"."
|
|
240
|
+
] })
|
|
241
|
+
] })),
|
|
242
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1u", children: [
|
|
243
|
+
item.cancelable && onCancel && (item.state === "queued" || item.state === "uploading") && /* @__PURE__ */ jsx(
|
|
244
|
+
Button,
|
|
245
|
+
{
|
|
246
|
+
size: "sm",
|
|
247
|
+
variant: "tertiary",
|
|
248
|
+
disabled: blocked,
|
|
249
|
+
"aria-label": `Cancel ${item.name}`,
|
|
250
|
+
onClick: () => {
|
|
251
|
+
if (!blocked) onCancel(item.id);
|
|
252
|
+
},
|
|
253
|
+
children: "Cancel"
|
|
254
|
+
}
|
|
255
|
+
),
|
|
256
|
+
item.retryable && onRetry && item.state === "failed" && /* @__PURE__ */ jsx(
|
|
257
|
+
Button,
|
|
258
|
+
{
|
|
259
|
+
size: "sm",
|
|
260
|
+
variant: "secondary",
|
|
261
|
+
disabled: blocked,
|
|
262
|
+
"aria-label": `Retry ${item.name}`,
|
|
263
|
+
onClick: () => {
|
|
264
|
+
if (!blocked) onRetry(item.id);
|
|
265
|
+
},
|
|
266
|
+
children: "Retry"
|
|
267
|
+
}
|
|
268
|
+
),
|
|
269
|
+
item.removable && onRemove && /* @__PURE__ */ jsx(
|
|
270
|
+
Button,
|
|
271
|
+
{
|
|
272
|
+
size: "sm",
|
|
273
|
+
variant: "tertiary",
|
|
274
|
+
disabled: blocked,
|
|
275
|
+
"aria-label": `Remove ${item.name}`,
|
|
276
|
+
onClick: () => {
|
|
277
|
+
if (!blocked) onRemove(item.id);
|
|
278
|
+
},
|
|
279
|
+
children: "Remove"
|
|
280
|
+
}
|
|
281
|
+
)
|
|
282
|
+
] })
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
invalidIdentity ? index : item.id
|
|
286
|
+
);
|
|
287
|
+
}) })
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
UploadQueue.displayName = "UploadQueue";
|
|
294
|
+
export {
|
|
295
|
+
UploadQueue
|
|
296
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// src/UploadQueue/UploadQueue.manifest.ts
|
|
2
|
+
var UploadQueueManifest = {
|
|
3
|
+
UploadQueue: {
|
|
4
|
+
description: "Controlled file queue with supplied transfer states, byte progress and explicit recovery actions.",
|
|
5
|
+
props: {
|
|
6
|
+
label: { type: "string", required: true },
|
|
7
|
+
items: {
|
|
8
|
+
type: "array",
|
|
9
|
+
required: true,
|
|
10
|
+
description: "Readonly UploadQueueItem[] with unique id, name, sizeBytes, state (ready/queued/uploading/cancel-requested/uploaded/failed/canceled), optional loadedBytes/totalBytes/message and explicit cancelable/retryable/removable capabilities. Ready means local selection; uploaded requires a supplied transport outcome. Any other state shows as Unknown state."
|
|
11
|
+
},
|
|
12
|
+
disabled: { type: "boolean", default: false },
|
|
13
|
+
onCancel: {
|
|
14
|
+
type: "function",
|
|
15
|
+
description: "Requests cancellation by stable ID only for explicitly cancelable queued/uploading items. Does not change supplied state."
|
|
16
|
+
},
|
|
17
|
+
onRetry: {
|
|
18
|
+
type: "function",
|
|
19
|
+
description: "Requests retry by stable ID only for explicitly retryable failed items."
|
|
20
|
+
},
|
|
21
|
+
onRemove: {
|
|
22
|
+
type: "function",
|
|
23
|
+
description: "Requests removal by stable ID only for explicitly removable items. The row remains until items changes; focus moves only when its focused element is removed."
|
|
24
|
+
},
|
|
25
|
+
className: { type: "string" }
|
|
26
|
+
},
|
|
27
|
+
composable_with: ["FileUpload", "AttachmentPreview", "JobStatus"],
|
|
28
|
+
never_inside: ["Button"],
|
|
29
|
+
example: '<UploadQueue label="Import files" items={files} onCancel={requestCancel} onRetry={requestRetry} onRemove={requestRemove} />'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
export {
|
|
33
|
+
UploadQueueManifest
|
|
34
|
+
};
|