@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,213 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/DateTimePicker/DateTimePicker.tsx
|
|
4
|
+
import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { cva } from "class-variance-authority";
|
|
6
|
+
import clsx from "clsx";
|
|
7
|
+
import { DatePicker } from "../DatePicker/DatePicker.js";
|
|
8
|
+
import { TimeField } from "../TimeField/TimeField.js";
|
|
9
|
+
import { Button } from "../Button/Button.js";
|
|
10
|
+
import { RadioGroup, Radio } from "../RadioGroup/RadioGroup.js";
|
|
11
|
+
import { instantWallTime, resolveWallTime, validInstant, validTimeZone } from "../_internal/date.js";
|
|
12
|
+
import { joinIds, usePartIds } from "../_internal/fieldIds.js";
|
|
13
|
+
import {
|
|
14
|
+
FIELD_COLUMNS,
|
|
15
|
+
FIELD_LABEL_STYLES,
|
|
16
|
+
SegmentGroupContext,
|
|
17
|
+
firstSegmentFocus
|
|
18
|
+
} from "../_internal/segmentField.js";
|
|
19
|
+
import { useMergedRefs } from "../_internal/mergeRefs.js";
|
|
20
|
+
import { formatUtcTimestamp } from "../_internal/timestamp.js";
|
|
21
|
+
import { useRestoreFocusOnRemoval } from "../_internal/useRestoreFocusOnRemoval.js";
|
|
22
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
23
|
+
var pickerStyles = cva(
|
|
24
|
+
"flex min-w-0 flex-col gap-2u font-sans text-oprt-base text-oprt-text focus-visible:outline-hidden focus-visible:shadow-oprt-focus"
|
|
25
|
+
);
|
|
26
|
+
var DateTimePicker = forwardRef(
|
|
27
|
+
({
|
|
28
|
+
label,
|
|
29
|
+
value,
|
|
30
|
+
onValueChange,
|
|
31
|
+
onDraftValidityChange,
|
|
32
|
+
timeZone,
|
|
33
|
+
min,
|
|
34
|
+
max,
|
|
35
|
+
disabled = false,
|
|
36
|
+
readOnly = false,
|
|
37
|
+
required = false,
|
|
38
|
+
id,
|
|
39
|
+
className
|
|
40
|
+
}, ref) => {
|
|
41
|
+
const root = useRef(null);
|
|
42
|
+
const setRoot = useMergedRefs(root, ref);
|
|
43
|
+
const ids = usePartIds(["label", "zone", "error", "status"], {
|
|
44
|
+
id,
|
|
45
|
+
readRendered: () => root.current?.id
|
|
46
|
+
});
|
|
47
|
+
const zoneName = typeof timeZone === "string" ? timeZone : "invalid";
|
|
48
|
+
const base = `${String(value)}|${String(timeZone)}`;
|
|
49
|
+
const wall = useMemo(() => instantWallTime(value, timeZone), [value, timeZone]);
|
|
50
|
+
const initial = {
|
|
51
|
+
base,
|
|
52
|
+
date: wall.date,
|
|
53
|
+
time: wall.time,
|
|
54
|
+
occurrence: wall.occurrence,
|
|
55
|
+
dateValid: true,
|
|
56
|
+
timeValid: true,
|
|
57
|
+
dirty: false
|
|
58
|
+
};
|
|
59
|
+
const [draft, setDraft] = useState(initial);
|
|
60
|
+
const current = draft.base === base ? draft : initial;
|
|
61
|
+
const zoneValid = validTimeZone(timeZone);
|
|
62
|
+
const boundsValid = (min === void 0 || validInstant(min)) && (max === void 0 || validInstant(max)) && !(min !== void 0 && max !== void 0 && min > max);
|
|
63
|
+
const resolution = current.date && current.time ? resolveWallTime(current.date, current.time, timeZone) : null;
|
|
64
|
+
const ambiguous = resolution?.status === "valid" && resolution.earlier !== resolution.later;
|
|
65
|
+
const candidate = resolution?.status === "valid" ? current.occurrence === "later" ? resolution.later : resolution.earlier : null;
|
|
66
|
+
const empty = current.date === null && current.time === null;
|
|
67
|
+
const checkedInstant = current.dirty ? candidate : value;
|
|
68
|
+
const error = !zoneValid ? "Invalid time zone. Supply an IANA time zone." : !boundsValid ? "Invalid instant bounds. Supply finite epoch milliseconds in ascending order." : !current.dirty && wall.error ? wall.error : !current.dateValid || !current.timeValid ? "Complete the date and time before applying this change." : empty ? required ? "A date and time are required." : null : !current.date || !current.time ? "Enter both a date and a time." : resolution?.status === "invalid" ? resolution.error : ambiguous && current.occurrence === null ? "Choose the earlier or later occurrence of this repeated time." : checkedInstant !== null && min !== void 0 && checkedInstant < min ? `Choose an instant at or after ${formatUtcTimestamp(min)}.` : checkedInstant !== null && max !== void 0 && checkedInstant > max ? `Choose an instant at or before ${formatUtcTimestamp(max)}.` : null;
|
|
69
|
+
const group = useMemo(() => {
|
|
70
|
+
const dayOf = (bound) => bound !== void 0 && zoneValid && boundsValid ? instantWallTime(bound, timeZone).date ?? void 0 : void 0;
|
|
71
|
+
return { required, calendar: { min: dayOf(min), max: dayOf(max) } };
|
|
72
|
+
}, [required, min, max, timeZone, zoneValid, boundsValid]);
|
|
73
|
+
const restoring = useRef(false);
|
|
74
|
+
const restore = useRestoreFocusOnRemoval(root, {
|
|
75
|
+
findTarget: () => {
|
|
76
|
+
restoring.current = true;
|
|
77
|
+
queueMicrotask(() => {
|
|
78
|
+
restoring.current = false;
|
|
79
|
+
});
|
|
80
|
+
return root.current;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
const keepFocus = (event) => {
|
|
84
|
+
if (restoring.current) {
|
|
85
|
+
restoring.current = false;
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
const from = event.relatedTarget;
|
|
89
|
+
return from instanceof Node && event.currentTarget.contains(from);
|
|
90
|
+
};
|
|
91
|
+
const callback = useRef(onDraftValidityChange);
|
|
92
|
+
callback.current = onDraftValidityChange;
|
|
93
|
+
useEffect(
|
|
94
|
+
() => callback.current?.(!error && !current.dirty, { pending: current.dirty }),
|
|
95
|
+
[error, current.dirty]
|
|
96
|
+
);
|
|
97
|
+
const edit = (part, next) => {
|
|
98
|
+
if (disabled || readOnly) return;
|
|
99
|
+
setDraft({ ...current, [part]: next, dirty: true, occurrence: null });
|
|
100
|
+
};
|
|
101
|
+
const reportValidity = (part, valid) => setDraft((previous) => {
|
|
102
|
+
const active = previous.base === base ? previous : initial;
|
|
103
|
+
if (active[part] === valid) return previous;
|
|
104
|
+
return { ...active, [part]: valid, dirty: active.dirty || !valid };
|
|
105
|
+
});
|
|
106
|
+
return /* @__PURE__ */ jsxs(
|
|
107
|
+
"div",
|
|
108
|
+
{
|
|
109
|
+
ref: setRoot,
|
|
110
|
+
id: ids.base,
|
|
111
|
+
role: "group",
|
|
112
|
+
"aria-labelledby": ids.label,
|
|
113
|
+
"aria-describedby": joinIds(
|
|
114
|
+
ids.zone,
|
|
115
|
+
error && ids.error,
|
|
116
|
+
!error && current.dirty && ids.status
|
|
117
|
+
),
|
|
118
|
+
"aria-invalid": !!error || void 0,
|
|
119
|
+
className: clsx(pickerStyles(), className),
|
|
120
|
+
onFocusCapture: restore.onFocusCapture,
|
|
121
|
+
onBlurCapture: restore.onBlurCapture,
|
|
122
|
+
...firstSegmentFocus(disabled, keepFocus),
|
|
123
|
+
children: [
|
|
124
|
+
/* @__PURE__ */ jsxs("p", { id: ids.label, className: FIELD_LABEL_STYLES, children: [
|
|
125
|
+
label,
|
|
126
|
+
required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " *" })
|
|
127
|
+
] }),
|
|
128
|
+
/* @__PURE__ */ jsxs("p", { id: ids.zone, className: "m-0 text-oprt-text-dim oprt-wrap-anywhere", children: [
|
|
129
|
+
"Time zone: ",
|
|
130
|
+
/* @__PURE__ */ jsx("span", { children: zoneName })
|
|
131
|
+
] }),
|
|
132
|
+
/* @__PURE__ */ jsx(SegmentGroupContext.Provider, { value: group, children: /* @__PURE__ */ jsxs("div", { className: FIELD_COLUMNS, children: [
|
|
133
|
+
/* @__PURE__ */ jsx(
|
|
134
|
+
DatePicker,
|
|
135
|
+
{
|
|
136
|
+
label: `${label} date`,
|
|
137
|
+
value: current.date,
|
|
138
|
+
onValueChange: (next) => edit("date", next),
|
|
139
|
+
onDraftValidityChange: (valid) => reportValidity("dateValid", valid),
|
|
140
|
+
disabled: disabled || !zoneValid || !boundsValid,
|
|
141
|
+
readOnly,
|
|
142
|
+
className: "min-w-0 flex-1"
|
|
143
|
+
}
|
|
144
|
+
),
|
|
145
|
+
/* @__PURE__ */ jsx(
|
|
146
|
+
TimeField,
|
|
147
|
+
{
|
|
148
|
+
label: `${label} time`,
|
|
149
|
+
value: current.time,
|
|
150
|
+
onValueChange: (next) => edit("time", next),
|
|
151
|
+
onDraftValidityChange: (valid) => reportValidity("timeValid", valid),
|
|
152
|
+
disabled: disabled || !zoneValid || !boundsValid,
|
|
153
|
+
readOnly,
|
|
154
|
+
className: "min-w-0 flex-1"
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
] }, base) }),
|
|
158
|
+
ambiguous && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1u", children: [
|
|
159
|
+
/* @__PURE__ */ jsxs("p", { className: "m-0 text-oprt-text-dim oprt-wrap-anywhere", children: [
|
|
160
|
+
"This wall time occurs twice in ",
|
|
161
|
+
zoneName,
|
|
162
|
+
"."
|
|
163
|
+
] }),
|
|
164
|
+
/* @__PURE__ */ jsxs(
|
|
165
|
+
RadioGroup,
|
|
166
|
+
{
|
|
167
|
+
"aria-label": "Repeated time occurrence",
|
|
168
|
+
value: current.occurrence ?? "",
|
|
169
|
+
disabled: disabled || readOnly,
|
|
170
|
+
onValueChange: (occurrence) => {
|
|
171
|
+
if (!disabled && !readOnly && (occurrence === "earlier" || occurrence === "later"))
|
|
172
|
+
setDraft({ ...current, occurrence, dirty: true });
|
|
173
|
+
},
|
|
174
|
+
children: [
|
|
175
|
+
/* @__PURE__ */ jsxs(Radio, { value: "earlier", children: [
|
|
176
|
+
"Earlier occurrence (",
|
|
177
|
+
formatUtcTimestamp(resolution.status === "valid" ? resolution.earlier : 0),
|
|
178
|
+
")"
|
|
179
|
+
] }),
|
|
180
|
+
/* @__PURE__ */ jsxs(Radio, { value: "later", children: [
|
|
181
|
+
"Later occurrence (",
|
|
182
|
+
formatUtcTimestamp(resolution.status === "valid" ? resolution.later : 0),
|
|
183
|
+
")"
|
|
184
|
+
] })
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
] }),
|
|
189
|
+
error && /* @__PURE__ */ jsx("p", { id: ids.error, className: "m-0 text-oprt-error", children: error }),
|
|
190
|
+
!error && current.dirty && /* @__PURE__ */ jsx("p", { id: ids.status, className: "m-0 text-oprt-text-dim", children: "Apply this change before continuing." }),
|
|
191
|
+
/* @__PURE__ */ jsx(
|
|
192
|
+
Button,
|
|
193
|
+
{
|
|
194
|
+
className: "self-start",
|
|
195
|
+
disabled: disabled || readOnly || !current.dirty || !!error,
|
|
196
|
+
onClick: () => {
|
|
197
|
+
if (disabled || readOnly || error || !current.dirty) return;
|
|
198
|
+
const next = empty ? null : candidate;
|
|
199
|
+
if (next === value) setDraft({ ...current, dirty: false });
|
|
200
|
+
onValueChange(next);
|
|
201
|
+
},
|
|
202
|
+
children: "Apply"
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
DateTimePicker.displayName = "DateTimePicker";
|
|
211
|
+
export {
|
|
212
|
+
DateTimePicker
|
|
213
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/DateTimePicker/DateTimePicker.manifest.ts
|
|
2
|
+
var DateTimePickerManifest = {
|
|
3
|
+
DateTimePicker: {
|
|
4
|
+
description: "Controlled instant editor with an explicit IANA time zone, minute-level date/time drafts, Apply, and explicit daylight-saving overlap choices.",
|
|
5
|
+
props: {
|
|
6
|
+
label: { type: "string", required: true },
|
|
7
|
+
value: {
|
|
8
|
+
type: "number",
|
|
9
|
+
required: true,
|
|
10
|
+
description: "Integer epoch milliseconds, or null. Untouched values retain their supplied seconds and milliseconds."
|
|
11
|
+
},
|
|
12
|
+
timeZone: {
|
|
13
|
+
type: "string",
|
|
14
|
+
required: true,
|
|
15
|
+
description: "IANA time zone used to display and resolve the wall-time draft. Visible beside the fields."
|
|
16
|
+
},
|
|
17
|
+
onValueChange: {
|
|
18
|
+
type: "function",
|
|
19
|
+
required: true,
|
|
20
|
+
description: "Requests an instant or null only after Apply. Minute-level edits commit with zero seconds and milliseconds."
|
|
21
|
+
},
|
|
22
|
+
onDraftValidityChange: {
|
|
23
|
+
type: "function",
|
|
24
|
+
description: "Callback (valid, { pending }). Pending identifies uncommitted local edits; pristine required-empty or malformed supplied values are invalid but not pending. False for invalid, incomplete, or unapplied edits. Returns true when the host accepts Apply or supplies another valid value. Block Review/Save while false."
|
|
25
|
+
},
|
|
26
|
+
min: { type: "number", description: "Inclusive epoch-millisecond lower bound." },
|
|
27
|
+
max: { type: "number", description: "Inclusive epoch-millisecond upper bound." },
|
|
28
|
+
disabled: { type: "boolean", default: false },
|
|
29
|
+
readOnly: { type: "boolean", default: false },
|
|
30
|
+
required: { type: "boolean", default: false },
|
|
31
|
+
id: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "ID of the focusable group. Focusing it or its forwarded HTMLDivElement ref enters the first date segment."
|
|
34
|
+
},
|
|
35
|
+
className: { type: "string" }
|
|
36
|
+
},
|
|
37
|
+
composable_with: ["FormSection", "FormErrorSummary", "DatePicker", "TimeField"],
|
|
38
|
+
never_inside: ["Button"],
|
|
39
|
+
example: '<DateTimePicker id="window-start" label="Window start" value={instant} timeZone="America/Los_Angeles" onValueChange={setInstant} onDraftValidityChange={setInstantValid} required />'
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
export {
|
|
43
|
+
DateTimePickerManifest
|
|
44
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/DescriptionList/DescriptionList.tsx
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import clsx from "clsx";
|
|
6
|
+
import { forwardRef, useEffect, useRef } from "react";
|
|
7
|
+
import { DescriptionListManifest } from "./DescriptionList.manifest.js";
|
|
8
|
+
import { devValidate } from "../_internal/devValidate.js";
|
|
9
|
+
import { NumberText, isNumberText } from "../_internal/numberText.js";
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
var listStyles = cva("m-0 min-w-0 font-sans text-oprt-base text-oprt-text", {
|
|
12
|
+
variants: {
|
|
13
|
+
layout: {
|
|
14
|
+
stacked: "flex flex-col gap-2u",
|
|
15
|
+
aligned: "flex flex-col gap-2u",
|
|
16
|
+
details: "flex flex-col gap-1u"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: { layout: "stacked" }
|
|
20
|
+
});
|
|
21
|
+
var itemStyles = cva("grid min-w-0", {
|
|
22
|
+
variants: {
|
|
23
|
+
layout: {
|
|
24
|
+
stacked: "grid-cols-1 gap-1u",
|
|
25
|
+
aligned: "grid-cols-[repeat(auto-fit,minmax(min(100%,8rem),1fr))] gap-y-1u gap-x-3u",
|
|
26
|
+
details: "grid-cols-[minmax(0,2fr)_minmax(0,3fr)] items-baseline gap-y-1u gap-x-2u"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: { layout: "stacked" }
|
|
30
|
+
});
|
|
31
|
+
var labelStyles = cva(
|
|
32
|
+
"m-0 min-w-0 oprt-wrap-anywhere text-oprt-text-dim uppercase tracking-oprt-sm",
|
|
33
|
+
{
|
|
34
|
+
variants: {
|
|
35
|
+
layout: { stacked: "", aligned: "", details: "text-oprt-sm font-medium" }
|
|
36
|
+
},
|
|
37
|
+
defaultVariants: { layout: "stacked" }
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
var valueStyles = cva(
|
|
41
|
+
"m-0 min-w-0 oprt-wrap-anywhere normal-case tracking-normal [&>[data-oprt-badge]]:align-baseline",
|
|
42
|
+
{
|
|
43
|
+
variants: {
|
|
44
|
+
layout: { stacked: "", aligned: "", details: "text-right" }
|
|
45
|
+
},
|
|
46
|
+
defaultVariants: { layout: "stacked" }
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
var isMissing = (value) => value === null || value === void 0 || value === "";
|
|
50
|
+
var DescriptionList = forwardRef(
|
|
51
|
+
({ items, layout = "stacked", className, ...props }, ref) => {
|
|
52
|
+
if (process.env.NODE_ENV !== "production") {
|
|
53
|
+
devValidate("DescriptionList", DescriptionListManifest.DescriptionList.props, { layout });
|
|
54
|
+
}
|
|
55
|
+
const reported = useRef(/* @__PURE__ */ new Set());
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (process.env.NODE_ENV === "production") return;
|
|
58
|
+
const fresh = items.filter(({ id, value }) => isMissing(value) && !reported.current.has(id)).map(({ id }) => id);
|
|
59
|
+
if (fresh.length === 0) return;
|
|
60
|
+
for (const id of fresh) reported.current.add(id);
|
|
61
|
+
console.warn(
|
|
62
|
+
JSON.stringify(
|
|
63
|
+
{
|
|
64
|
+
component: "DescriptionList",
|
|
65
|
+
warning: "MISSING_VALUE",
|
|
66
|
+
prop: "items",
|
|
67
|
+
received: `value of ${fresh.map((id) => JSON.stringify(id)).join(", ")}`,
|
|
68
|
+
suggestion: "Supply explicit text for a missing value, such as Not supplied: an empty value leaves its term standing alone, on screen and for a screen reader. Zero and false are shown as they are."
|
|
69
|
+
},
|
|
70
|
+
null,
|
|
71
|
+
2
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
}, [items]);
|
|
75
|
+
return /* @__PURE__ */ jsx(
|
|
76
|
+
"dl",
|
|
77
|
+
{
|
|
78
|
+
ref,
|
|
79
|
+
className: clsx(listStyles({ layout }), className),
|
|
80
|
+
"data-layout": layout,
|
|
81
|
+
...props,
|
|
82
|
+
children: items.map(({ id, label, value, mono }) => /* @__PURE__ */ jsxs("div", { className: itemStyles({ layout }), children: [
|
|
83
|
+
/* @__PURE__ */ jsx("dt", { className: labelStyles({ layout }), children: label }),
|
|
84
|
+
/* @__PURE__ */ jsx("dd", { className: clsx(valueStyles({ layout }), mono && "font-mono"), children: typeof value === "boolean" ? String(value) : isNumberText(value) ? /* @__PURE__ */ jsx(NumberText, { value }) : value })
|
|
85
|
+
] }, id))
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
DescriptionList.displayName = "DescriptionList";
|
|
91
|
+
export {
|
|
92
|
+
DescriptionList
|
|
93
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// src/DescriptionList/DescriptionList.manifest.ts
|
|
2
|
+
var DescriptionListManifest = {
|
|
3
|
+
DescriptionList: {
|
|
4
|
+
description: "Semantic label/value facts with wrapping, exact values, and stacked, responsive aligned, or compact detail layouts.",
|
|
5
|
+
props: {
|
|
6
|
+
items: {
|
|
7
|
+
type: "array",
|
|
8
|
+
required: true,
|
|
9
|
+
description: "Readonly DescriptionListItem array. IDs are stable unique keys within this list, never DOM IDs. Direct booleans render as true/false; zero and other ReactNode values are preserved. Supply explicit text for missing values (development warns for null, undefined or empty text) and include units in the value. A value that is a number, optionally followed by its unit, wraps only between digit groups and keeps the unit with its last group; a word after it that is not a unit wraps as text, and more than 15 ungrouped digits are an identifier that wraps anywhere.",
|
|
10
|
+
items: {
|
|
11
|
+
id: "string (required, unique)",
|
|
12
|
+
label: "ReactNode (required)",
|
|
13
|
+
value: "ReactNode (required)",
|
|
14
|
+
mono: "boolean (optional)"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
layout: {
|
|
18
|
+
type: "enum",
|
|
19
|
+
values: ["stacked", "aligned", "details"],
|
|
20
|
+
default: "stacked",
|
|
21
|
+
description: "Stacked places each value below its label. Aligned uses columns when space permits and stacks in narrow containers. Details keeps 40/60 columns with 9px medium uppercase muted labels, 11px right-aligned values, baseline alignment, 8px row spacing and a 16px column gap. Long content wraps in either column."
|
|
22
|
+
},
|
|
23
|
+
className: { type: "string" }
|
|
24
|
+
},
|
|
25
|
+
composable_with: [
|
|
26
|
+
"EntityPreview",
|
|
27
|
+
"OperationalStatus",
|
|
28
|
+
"Inspector",
|
|
29
|
+
"Popover",
|
|
30
|
+
"Card",
|
|
31
|
+
"Link",
|
|
32
|
+
"CopyButton"
|
|
33
|
+
],
|
|
34
|
+
never_inside: ["Button", "Badge", "Link"],
|
|
35
|
+
example: '<DescriptionList layout="aligned" items={[{ id: "pressure", label: "Pressure", value: "0 kPa", mono: true }, { id: "enabled", label: "Enabled", value: false }]} />'
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
export {
|
|
39
|
+
DescriptionListManifest
|
|
40
|
+
};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/Dialog/Dialog.tsx
|
|
4
|
+
import { X } from "@oprt/icons";
|
|
5
|
+
import {
|
|
6
|
+
DialogTrigger,
|
|
7
|
+
Dialog as AriaDialog,
|
|
8
|
+
ModalOverlay,
|
|
9
|
+
Modal,
|
|
10
|
+
Heading,
|
|
11
|
+
Text,
|
|
12
|
+
Button as AriaButton,
|
|
13
|
+
Pressable
|
|
14
|
+
} from "react-aria-components";
|
|
15
|
+
import { mergeProps } from "react-aria";
|
|
16
|
+
import { cva } from "class-variance-authority";
|
|
17
|
+
import {
|
|
18
|
+
forwardRef,
|
|
19
|
+
cloneElement,
|
|
20
|
+
useEffect,
|
|
21
|
+
useId,
|
|
22
|
+
useRef,
|
|
23
|
+
useState,
|
|
24
|
+
useLayoutEffect
|
|
25
|
+
} from "react";
|
|
26
|
+
import clsx from "clsx";
|
|
27
|
+
import { Button } from "../Button/Button.js";
|
|
28
|
+
import { DialogManifest } from "./Dialog.manifest.js";
|
|
29
|
+
import { devValidate } from "../_internal/devValidate.js";
|
|
30
|
+
import { definedOnly } from "../_internal/aria.js";
|
|
31
|
+
import { useMergedRefs } from "../_internal/mergeRefs.js";
|
|
32
|
+
import {
|
|
33
|
+
useMotion,
|
|
34
|
+
composeMotionHandlers,
|
|
35
|
+
MotionContext
|
|
36
|
+
} from "../_internal/motion.js";
|
|
37
|
+
import { isSingleElement } from "../_internal/overlay.js";
|
|
38
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
39
|
+
var surfaceStyles = cva("oprt-motion-surface relative z-50 flex max-h-full w-full flex-col", {
|
|
40
|
+
variants: {
|
|
41
|
+
size: {
|
|
42
|
+
sm: "max-w-sm",
|
|
43
|
+
md: "max-w-md",
|
|
44
|
+
lg: "max-w-lg"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
defaultVariants: { size: "md" }
|
|
48
|
+
});
|
|
49
|
+
function DialogReentryFocus({
|
|
50
|
+
open,
|
|
51
|
+
dialog,
|
|
52
|
+
children
|
|
53
|
+
}) {
|
|
54
|
+
const wasOpen = useRef(open);
|
|
55
|
+
useLayoutEffect(() => {
|
|
56
|
+
if (open && !wasOpen.current && !dialog.current?.contains(document.activeElement)) {
|
|
57
|
+
dialog.current?.focus({ preventScroll: true });
|
|
58
|
+
}
|
|
59
|
+
wasOpen.current = open;
|
|
60
|
+
}, [open, dialog]);
|
|
61
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
62
|
+
}
|
|
63
|
+
function useScrolls(element, content) {
|
|
64
|
+
const [scrolls, setScrolls] = useState(false);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const box = element.current;
|
|
67
|
+
if (!box || typeof ResizeObserver === "undefined") return;
|
|
68
|
+
const measure = () => setScrolls(box.scrollHeight > box.clientHeight + 1);
|
|
69
|
+
const observer = new ResizeObserver(measure);
|
|
70
|
+
observer.observe(box);
|
|
71
|
+
if (content.current) observer.observe(content.current);
|
|
72
|
+
measure();
|
|
73
|
+
return () => observer.disconnect();
|
|
74
|
+
}, [element, content]);
|
|
75
|
+
return scrolls;
|
|
76
|
+
}
|
|
77
|
+
function DialogBody({ title, children }) {
|
|
78
|
+
const body = useRef(null);
|
|
79
|
+
const content = useRef(null);
|
|
80
|
+
const scrolls = useScrolls(body, content);
|
|
81
|
+
return /* @__PURE__ */ jsx(
|
|
82
|
+
"div",
|
|
83
|
+
{
|
|
84
|
+
ref: body,
|
|
85
|
+
"data-oprt-dialog-body": "",
|
|
86
|
+
className: "-m-0.5u min-h-0 flex-1 overflow-y-auto overscroll-contain p-0.5u outline-hidden focus-visible:shadow-oprt-focus forced-colors:focus-visible:outline-solid forced-colors:focus-visible:outline-2 forced-colors:focus-visible:-outline-offset-2 forced-colors:focus-visible:outline-[CanvasText]",
|
|
87
|
+
...scrolls ? { tabIndex: 0, role: "region", "aria-label": `${title} content` } : {},
|
|
88
|
+
children: /* @__PURE__ */ jsx("div", { ref: content, className: "flex flex-col gap-3u", children })
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
function withDroppedProps(rendered, accepted) {
|
|
93
|
+
const dropped = {};
|
|
94
|
+
for (const [key, value] of Object.entries(accepted)) {
|
|
95
|
+
if (value === void 0) continue;
|
|
96
|
+
if (!(key in rendered) || rendered[key] === void 0) dropped[key] = value;
|
|
97
|
+
else if (typeof value === "function" && rendered[key] !== value) dropped[key] = value;
|
|
98
|
+
}
|
|
99
|
+
return mergeProps(rendered, dropped);
|
|
100
|
+
}
|
|
101
|
+
var Dialog = forwardRef(
|
|
102
|
+
({
|
|
103
|
+
title,
|
|
104
|
+
motion = "auto",
|
|
105
|
+
description,
|
|
106
|
+
trigger,
|
|
107
|
+
footer,
|
|
108
|
+
open,
|
|
109
|
+
defaultOpen,
|
|
110
|
+
onOpenChange,
|
|
111
|
+
size = "md",
|
|
112
|
+
className,
|
|
113
|
+
children,
|
|
114
|
+
...props
|
|
115
|
+
}, ref) => {
|
|
116
|
+
const motionState = useMotion(motion);
|
|
117
|
+
const dialogRef = useRef(null);
|
|
118
|
+
const setDialogRef = useMergedRefs(dialogRef, ref);
|
|
119
|
+
const rootProps = definedOnly({
|
|
120
|
+
isOpen: open,
|
|
121
|
+
defaultOpen,
|
|
122
|
+
onOpenChange
|
|
123
|
+
});
|
|
124
|
+
if (process.env.NODE_ENV !== "production") {
|
|
125
|
+
devValidate("Dialog", DialogManifest.Dialog.props, { ...props, size });
|
|
126
|
+
}
|
|
127
|
+
const generatedId = useId();
|
|
128
|
+
const describedBy = description ? `${generatedId}description` : void 0;
|
|
129
|
+
const naming = definedOnly({
|
|
130
|
+
id: props.id,
|
|
131
|
+
role: props.role === "alertdialog" ? "alertdialog" : void 0,
|
|
132
|
+
"aria-label": props["aria-label"],
|
|
133
|
+
"aria-labelledby": props["aria-labelledby"],
|
|
134
|
+
"aria-describedby": props["aria-describedby"] ?? describedBy
|
|
135
|
+
});
|
|
136
|
+
const overlay = (
|
|
137
|
+
// With a trigger the open state is owned by DialogTrigger and read from
|
|
138
|
+
// context; standalone the ModalOverlay owns it. `isDismissable` restores
|
|
139
|
+
// the Radix behavior of closing on an outside click (React Aria opts out
|
|
140
|
+
// by default). Escape is handled by React Aria unless explicitly disabled.
|
|
141
|
+
// The overlay is as tall as the visible viewport React Aria measures, so the dialog also
|
|
142
|
+
// fits above an on-screen keyboard.
|
|
143
|
+
/* @__PURE__ */ jsx(
|
|
144
|
+
ModalOverlay,
|
|
145
|
+
{
|
|
146
|
+
...trigger ? {} : rootProps,
|
|
147
|
+
isDismissable: true,
|
|
148
|
+
className: "oprt-motion oprt-motion-overlay fixed inset-x-0 top-0 z-40 flex h-[var(--visual-viewport-height,100dvh)] items-center justify-center p-2u bg-oprt-bg/80",
|
|
149
|
+
...motionState.props,
|
|
150
|
+
render: (domProps) => /* @__PURE__ */ jsx("div", { ...domProps, ...motionState.props }),
|
|
151
|
+
children: /* @__PURE__ */ jsx(Modal, { className: surfaceStyles({ size }), children: ({ state }) => /* @__PURE__ */ jsx(DialogReentryFocus, { open: state.isOpen, dialog: dialogRef, children: /* @__PURE__ */ jsxs(
|
|
152
|
+
AriaDialog,
|
|
153
|
+
{
|
|
154
|
+
ref: setDialogRef,
|
|
155
|
+
className: clsx(
|
|
156
|
+
"flex min-h-0 w-full flex-col gap-3u bg-oprt-surface-1 border border-oprt-border p-4u font-sans focus-visible:border-oprt-border-focus focus-visible:shadow-oprt-focus focus-visible:outline-hidden forced-colors:focus-visible:outline-solid forced-colors:focus-visible:outline-2 forced-colors:focus-visible:-outline-offset-2 forced-colors:focus-visible:outline-[CanvasText]",
|
|
157
|
+
className
|
|
158
|
+
),
|
|
159
|
+
...naming,
|
|
160
|
+
render: (domProps) => /* @__PURE__ */ jsx("section", { ...withDroppedProps(domProps, props) }),
|
|
161
|
+
children: [
|
|
162
|
+
/* @__PURE__ */ jsx(
|
|
163
|
+
Heading,
|
|
164
|
+
{
|
|
165
|
+
slot: "title",
|
|
166
|
+
className: "m-0 min-w-0 shrink-0 pr-2u text-oprt-lg uppercase tracking-oprt-lg text-oprt-text oprt-wrap-anywhere",
|
|
167
|
+
children: title
|
|
168
|
+
}
|
|
169
|
+
),
|
|
170
|
+
/* @__PURE__ */ jsx(
|
|
171
|
+
AriaButton,
|
|
172
|
+
{
|
|
173
|
+
slot: "close",
|
|
174
|
+
"aria-label": "Close",
|
|
175
|
+
className: "absolute right-2u top-2u inline-flex items-center justify-center w-3u h-oprt-sm border border-transparent text-oprt-text-dim hover:text-oprt-text outline-hidden data-[focus-visible]:border-oprt-border-focus data-[focus-visible]:shadow-oprt-focus",
|
|
176
|
+
children: /* @__PURE__ */ jsx(X, { size: 12 })
|
|
177
|
+
}
|
|
178
|
+
),
|
|
179
|
+
/* @__PURE__ */ jsxs(DialogBody, { title, children: [
|
|
180
|
+
description && /* @__PURE__ */ jsx(
|
|
181
|
+
Text,
|
|
182
|
+
{
|
|
183
|
+
slot: "description",
|
|
184
|
+
elementType: "p",
|
|
185
|
+
id: describedBy,
|
|
186
|
+
className: "m-0 min-w-0 text-oprt-base normal-case text-oprt-text-dim oprt-wrap-anywhere",
|
|
187
|
+
children: description
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
children
|
|
191
|
+
] }),
|
|
192
|
+
footer && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 flex-wrap justify-end gap-2u", children: footer })
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
) }) })
|
|
196
|
+
}
|
|
197
|
+
)
|
|
198
|
+
);
|
|
199
|
+
if (!trigger)
|
|
200
|
+
return /* @__PURE__ */ jsx(MotionContext.Provider, { value: motionState.mode, children: overlay });
|
|
201
|
+
const triggerElement = isSingleElement(trigger) ? trigger : /* @__PURE__ */ jsx(Button, { children: trigger });
|
|
202
|
+
return /* @__PURE__ */ jsx(MotionContext.Provider, { value: motionState.mode, children: /* @__PURE__ */ jsxs(DialogTrigger, { ...rootProps, children: [
|
|
203
|
+
/* @__PURE__ */ jsx(Pressable, { ...{ "aria-haspopup": "dialog" }, children: cloneElement(
|
|
204
|
+
triggerElement,
|
|
205
|
+
composeMotionHandlers(motionState.props, triggerElement.props)
|
|
206
|
+
) }),
|
|
207
|
+
overlay
|
|
208
|
+
] }) });
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
Dialog.displayName = "Dialog";
|
|
212
|
+
export {
|
|
213
|
+
Dialog
|
|
214
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/Dialog/Dialog.manifest.ts
|
|
2
|
+
var DialogManifest = {
|
|
3
|
+
Dialog: {
|
|
4
|
+
description: "Modal dialog with a flat API: pass title, optional description, trigger, footer, and body children. Portal'd overlay + content built on React Aria Components (ModalOverlay + Modal + Dialog).",
|
|
5
|
+
props: {
|
|
6
|
+
motion: {
|
|
7
|
+
type: "enum",
|
|
8
|
+
values: ["auto", "none"],
|
|
9
|
+
default: "auto",
|
|
10
|
+
description: "Tactile pointer/touch feedback. None disables motion; keyboard and system reduced motion are always immediate."
|
|
11
|
+
},
|
|
12
|
+
title: { type: "string", required: true },
|
|
13
|
+
description: { type: "string" },
|
|
14
|
+
size: { type: "enum", values: ["sm", "md", "lg"], default: "md" },
|
|
15
|
+
open: { type: "boolean" },
|
|
16
|
+
defaultOpen: { type: "boolean" },
|
|
17
|
+
onOpenChange: { type: "function" }
|
|
18
|
+
},
|
|
19
|
+
slots: {
|
|
20
|
+
trigger: { type: "focusable element | text (text renders a Button)" },
|
|
21
|
+
children: { type: "any", required: true },
|
|
22
|
+
footer: { type: "Button | ButtonGroup" }
|
|
23
|
+
},
|
|
24
|
+
composable_with: ["Button", "ButtonGroup"],
|
|
25
|
+
never_inside: ["Button", "Badge"],
|
|
26
|
+
example: '<Dialog\n title="DEPLOY UNIT"\n description="Confirm deployment to the selected theater."\n trigger={<Button variant="primary">DEPLOY</Button>}\n footer={\n <>\n <Button variant="secondary">CANCEL</Button>\n <Button variant="primary">CONFIRM</Button>\n </>\n }\n>\n <p>This action cannot be undone.</p>\n</Dialog>'
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export {
|
|
30
|
+
DialogManifest
|
|
31
|
+
};
|