@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.
Files changed (266) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +105 -2
  3. package/dist/ActionStatus/ActionStatus.js +104 -0
  4. package/dist/ActionStatus/ActionStatus.manifest.js +64 -0
  5. package/dist/ActionStatus/index.js +7 -0
  6. package/dist/Alert/Alert.js +86 -0
  7. package/dist/Alert/Alert.manifest.js +36 -0
  8. package/dist/Alert/index.js +7 -0
  9. package/dist/AppShell/AppShell.js +103 -0
  10. package/dist/AppShell/AppShell.manifest.js +66 -0
  11. package/dist/AppShell/index.js +9 -0
  12. package/dist/AttachmentPreview/AttachmentPreview.js +145 -0
  13. package/dist/AttachmentPreview/AttachmentPreview.manifest.js +42 -0
  14. package/dist/AttachmentPreview/index.js +9 -0
  15. package/dist/Avatar/Avatar.js +87 -0
  16. package/dist/Avatar/Avatar.manifest.js +25 -0
  17. package/dist/Avatar/index.js +7 -0
  18. package/dist/Badge/Badge.js +124 -0
  19. package/dist/Badge/Badge.manifest.js +41 -0
  20. package/dist/Badge/index.js +7 -0
  21. package/dist/Breadcrumb/Breadcrumb.js +64 -0
  22. package/dist/Breadcrumb/Breadcrumb.manifest.js +28 -0
  23. package/dist/Breadcrumb/index.js +7 -0
  24. package/dist/BulkActionBar/BulkActionBar.js +145 -0
  25. package/dist/BulkActionBar/BulkActionBar.manifest.js +46 -0
  26. package/dist/BulkActionBar/index.js +9 -0
  27. package/dist/BulkActionBar/selection.js +44 -0
  28. package/dist/BulkResults/BulkResults.js +269 -0
  29. package/dist/BulkResults/BulkResults.manifest.js +45 -0
  30. package/dist/BulkResults/index.js +7 -0
  31. package/dist/Button/Button.js +170 -0
  32. package/dist/Button/Button.manifest.js +36 -0
  33. package/dist/Button/index.js +7 -0
  34. package/dist/ButtonGroup/ButtonGroup.js +60 -0
  35. package/dist/ButtonGroup/ButtonGroup.manifest.js +22 -0
  36. package/dist/ButtonGroup/index.js +7 -0
  37. package/dist/Calendar/Calendar.js +106 -0
  38. package/dist/Calendar/Calendar.manifest.js +32 -0
  39. package/dist/Calendar/index.js +7 -0
  40. package/dist/Card/Card.js +70 -0
  41. package/dist/Card/Card.manifest.js +57 -0
  42. package/dist/Card/index.js +16 -0
  43. package/dist/Chart/Chart.js +1200 -0
  44. package/dist/Chart/Chart.manifest.js +110 -0
  45. package/dist/Chart/ChartControls.js +190 -0
  46. package/dist/Chart/geometry.js +217 -0
  47. package/dist/Chart/index.js +9 -0
  48. package/dist/Checkbox/Checkbox.js +166 -0
  49. package/dist/Checkbox/Checkbox.manifest.js +38 -0
  50. package/dist/Checkbox/index.js +7 -0
  51. package/dist/Collapsible/Collapsible.js +177 -0
  52. package/dist/Collapsible/Collapsible.manifest.js +54 -0
  53. package/dist/Collapsible/index.js +12 -0
  54. package/dist/CollectionState/CollectionState.js +68 -0
  55. package/dist/CollectionState/CollectionState.manifest.js +44 -0
  56. package/dist/CollectionState/index.js +7 -0
  57. package/dist/ComboBox/ComboBox.js +221 -0
  58. package/dist/ComboBox/ComboBox.manifest.js +87 -0
  59. package/dist/ComboBox/index.js +7 -0
  60. package/dist/CommandPalette/CommandPalette.js +276 -0
  61. package/dist/CommandPalette/CommandPalette.manifest.js +24 -0
  62. package/dist/CommandPalette/index.js +7 -0
  63. package/dist/ConfirmDialog/ConfirmDialog.js +84 -0
  64. package/dist/ConfirmDialog/ConfirmDialog.manifest.js +32 -0
  65. package/dist/ConfirmDialog/index.js +7 -0
  66. package/dist/ContextMenu/ContextMenu.js +192 -0
  67. package/dist/ContextMenu/ContextMenu.manifest.js +41 -0
  68. package/dist/ContextMenu/index.js +7 -0
  69. package/dist/CoordinateInput/CoordinateInput.js +141 -0
  70. package/dist/CoordinateInput/CoordinateInput.manifest.js +36 -0
  71. package/dist/CoordinateInput/index.js +9 -0
  72. package/dist/CopyButton/CopyButton.js +110 -0
  73. package/dist/CopyButton/CopyButton.manifest.js +35 -0
  74. package/dist/CopyButton/index.js +7 -0
  75. package/dist/DataGrid/DataGrid.js +459 -0
  76. package/dist/DataGrid/DataGrid.manifest.js +135 -0
  77. package/dist/DataGrid/PageControls.js +41 -0
  78. package/dist/DataGrid/index.js +9 -0
  79. package/dist/DataTable/DataTable.js +375 -0
  80. package/dist/DataTable/DataTable.manifest.js +86 -0
  81. package/dist/DataTable/index.js +9 -0
  82. package/dist/DataTable/sort.js +45 -0
  83. package/dist/DataTable/useScrollsSideways.js +61 -0
  84. package/dist/DataTable/useTableWindow.js +185 -0
  85. package/dist/DatePicker/DatePicker.js +187 -0
  86. package/dist/DatePicker/DatePicker.manifest.js +40 -0
  87. package/dist/DatePicker/index.js +7 -0
  88. package/dist/DateRangePicker/DateRangePicker.js +156 -0
  89. package/dist/DateRangePicker/DateRangePicker.manifest.js +41 -0
  90. package/dist/DateRangePicker/index.js +7 -0
  91. package/dist/DateTimePicker/DateTimePicker.js +213 -0
  92. package/dist/DateTimePicker/DateTimePicker.manifest.js +44 -0
  93. package/dist/DateTimePicker/index.js +7 -0
  94. package/dist/DescriptionList/DescriptionList.js +93 -0
  95. package/dist/DescriptionList/DescriptionList.manifest.js +40 -0
  96. package/dist/DescriptionList/index.js +9 -0
  97. package/dist/Dialog/Dialog.js +214 -0
  98. package/dist/Dialog/Dialog.manifest.js +31 -0
  99. package/dist/Dialog/index.js +7 -0
  100. package/dist/Divider/Divider.js +64 -0
  101. package/dist/Divider/Divider.manifest.js +21 -0
  102. package/dist/Divider/index.js +7 -0
  103. package/dist/DropdownMenu/DropdownMenu.js +170 -0
  104. package/dist/DropdownMenu/DropdownMenu.manifest.js +82 -0
  105. package/dist/DropdownMenu/index.js +16 -0
  106. package/dist/EntityPreview/EntityPreview.js +82 -0
  107. package/dist/EntityPreview/EntityPreview.manifest.js +43 -0
  108. package/dist/EntityPreview/index.js +7 -0
  109. package/dist/EventTimeline/EventTimeline.js +249 -0
  110. package/dist/EventTimeline/EventTimeline.manifest.js +57 -0
  111. package/dist/EventTimeline/index.js +7 -0
  112. package/dist/Field/Field.js +81 -0
  113. package/dist/Field/Field.manifest.js +32 -0
  114. package/dist/Field/index.js +9 -0
  115. package/dist/FileUpload/FileUpload.js +215 -0
  116. package/dist/FileUpload/FileUpload.manifest.js +48 -0
  117. package/dist/FileUpload/index.js +7 -0
  118. package/dist/FilterBar/FilterBar.js +173 -0
  119. package/dist/FilterBar/FilterBar.manifest.js +49 -0
  120. package/dist/FilterBar/index.js +7 -0
  121. package/dist/FormErrorSummary/FormErrorSummary.js +70 -0
  122. package/dist/FormErrorSummary/FormErrorSummary.manifest.js +29 -0
  123. package/dist/FormErrorSummary/index.js +9 -0
  124. package/dist/FormSection/FormSection.js +51 -0
  125. package/dist/FormSection/FormSection.manifest.js +30 -0
  126. package/dist/FormSection/index.js +7 -0
  127. package/dist/InlineEdit/InlineEdit.js +261 -0
  128. package/dist/InlineEdit/InlineEdit.manifest.js +40 -0
  129. package/dist/InlineEdit/index.js +7 -0
  130. package/dist/Input/Input.js +126 -0
  131. package/dist/Input/Input.manifest.js +49 -0
  132. package/dist/Input/index.js +7 -0
  133. package/dist/Inspector/Inspector.js +63 -0
  134. package/dist/Inspector/Inspector.manifest.js +35 -0
  135. package/dist/Inspector/index.js +7 -0
  136. package/dist/JobStatus/JobStatus.js +118 -0
  137. package/dist/JobStatus/JobStatus.manifest.js +53 -0
  138. package/dist/JobStatus/index.js +7 -0
  139. package/dist/LayerControl/LayerControl.js +199 -0
  140. package/dist/LayerControl/LayerControl.manifest.js +34 -0
  141. package/dist/LayerControl/index.js +7 -0
  142. package/dist/Link/Link.js +83 -0
  143. package/dist/Link/Link.manifest.js +37 -0
  144. package/dist/Link/index.js +7 -0
  145. package/dist/MapControls/MapControls.js +122 -0
  146. package/dist/MapControls/MapControls.manifest.js +31 -0
  147. package/dist/MapControls/index.js +7 -0
  148. package/dist/MapLegend/MapLegend.js +89 -0
  149. package/dist/MapLegend/MapLegend.manifest.js +29 -0
  150. package/dist/MapLegend/index.js +7 -0
  151. package/dist/MapScale/MapScale.js +96 -0
  152. package/dist/MapScale/MapScale.manifest.js +31 -0
  153. package/dist/MapScale/index.js +7 -0
  154. package/dist/MediaFrame/MediaFrame.js +113 -0
  155. package/dist/MediaFrame/MediaFrame.manifest.js +57 -0
  156. package/dist/MediaFrame/index.js +7 -0
  157. package/dist/MultiSelect/MultiSelect.js +113 -0
  158. package/dist/MultiSelect/MultiSelect.manifest.js +51 -0
  159. package/dist/MultiSelect/index.js +7 -0
  160. package/dist/NumberInput/NumberInput.js +210 -0
  161. package/dist/NumberInput/NumberInput.manifest.js +56 -0
  162. package/dist/NumberInput/index.js +7 -0
  163. package/dist/OperationalStatus/OperationalStatus.js +89 -0
  164. package/dist/OperationalStatus/OperationalStatus.manifest.js +39 -0
  165. package/dist/OperationalStatus/index.js +9 -0
  166. package/dist/PlaybackControls/PlaybackControls.js +289 -0
  167. package/dist/PlaybackControls/PlaybackControls.manifest.js +85 -0
  168. package/dist/PlaybackControls/index.js +7 -0
  169. package/dist/Popover/Popover.js +302 -0
  170. package/dist/Popover/Popover.manifest.js +50 -0
  171. package/dist/Popover/index.js +7 -0
  172. package/dist/Progress/Progress.js +132 -0
  173. package/dist/Progress/Progress.manifest.js +30 -0
  174. package/dist/Progress/index.js +7 -0
  175. package/dist/PropertyFilter/PropertyFilter.js +306 -0
  176. package/dist/PropertyFilter/PropertyFilter.manifest.js +32 -0
  177. package/dist/PropertyFilter/index.js +11 -0
  178. package/dist/PropertyFilter/tokenError.js +17 -0
  179. package/dist/RadioGroup/RadioGroup.js +143 -0
  180. package/dist/RadioGroup/RadioGroup.manifest.js +44 -0
  181. package/dist/RadioGroup/index.js +9 -0
  182. package/dist/Select/Select.js +219 -0
  183. package/dist/Select/Select.manifest.js +77 -0
  184. package/dist/Select/index.js +9 -0
  185. package/dist/Sidebar/Sidebar.js +146 -0
  186. package/dist/Sidebar/Sidebar.manifest.js +72 -0
  187. package/dist/Sidebar/index.js +18 -0
  188. package/dist/Skeleton/Skeleton.js +76 -0
  189. package/dist/Skeleton/Skeleton.manifest.js +30 -0
  190. package/dist/Skeleton/index.js +7 -0
  191. package/dist/Slider/Slider.js +246 -0
  192. package/dist/Slider/Slider.manifest.js +56 -0
  193. package/dist/Slider/index.js +7 -0
  194. package/dist/Sparkline/Sparkline.js +135 -0
  195. package/dist/Sparkline/Sparkline.manifest.js +37 -0
  196. package/dist/Sparkline/index.js +7 -0
  197. package/dist/SplitPane/SplitPane.js +316 -0
  198. package/dist/SplitPane/SplitPane.manifest.js +79 -0
  199. package/dist/SplitPane/index.js +7 -0
  200. package/dist/StatCard/StatCard.js +163 -0
  201. package/dist/StatCard/StatCard.manifest.js +45 -0
  202. package/dist/StatCard/index.js +7 -0
  203. package/dist/Tabs/Tabs.js +181 -0
  204. package/dist/Tabs/Tabs.manifest.js +72 -0
  205. package/dist/Tabs/index.js +16 -0
  206. package/dist/Tabs/useTabsIndicator.js +71 -0
  207. package/dist/Tabs/useTabsScroll.js +123 -0
  208. package/dist/TagGroup/TagGroup.js +142 -0
  209. package/dist/TagGroup/TagGroup.manifest.js +35 -0
  210. package/dist/TagGroup/index.js +7 -0
  211. package/dist/Textarea/Textarea.js +68 -0
  212. package/dist/Textarea/Textarea.manifest.js +25 -0
  213. package/dist/Textarea/index.js +7 -0
  214. package/dist/TimeField/TimeField.js +118 -0
  215. package/dist/TimeField/TimeField.manifest.js +42 -0
  216. package/dist/TimeField/index.js +7 -0
  217. package/dist/TimeRange/TimeRange.js +184 -0
  218. package/dist/TimeRange/TimeRange.manifest.js +48 -0
  219. package/dist/TimeRange/index.js +9 -0
  220. package/dist/Toast/Toast.js +188 -0
  221. package/dist/Toast/Toast.manifest.js +77 -0
  222. package/dist/Toast/index.js +9 -0
  223. package/dist/Toggle/Toggle.js +154 -0
  224. package/dist/Toggle/Toggle.manifest.js +54 -0
  225. package/dist/Toggle/index.js +7 -0
  226. package/dist/Toolbar/Toolbar.js +86 -0
  227. package/dist/Toolbar/Toolbar.manifest.js +70 -0
  228. package/dist/Toolbar/index.js +12 -0
  229. package/dist/Tooltip/Tooltip.js +122 -0
  230. package/dist/Tooltip/Tooltip.manifest.js +27 -0
  231. package/dist/Tooltip/index.js +7 -0
  232. package/dist/TreeView/TreeView.js +129 -0
  233. package/dist/TreeView/TreeView.manifest.js +56 -0
  234. package/dist/TreeView/index.js +7 -0
  235. package/dist/UploadQueue/UploadQueue.js +296 -0
  236. package/dist/UploadQueue/UploadQueue.manifest.js +34 -0
  237. package/dist/UploadQueue/index.js +7 -0
  238. package/dist/_internal/MotionPopover.js +113 -0
  239. package/dist/_internal/aria.js +40 -0
  240. package/dist/_internal/bytes.js +18 -0
  241. package/dist/_internal/controlStyles.js +26 -0
  242. package/dist/_internal/date.js +179 -0
  243. package/dist/_internal/devValidate.js +51 -0
  244. package/dist/_internal/fieldIds.js +50 -0
  245. package/dist/_internal/hydration.js +74 -0
  246. package/dist/_internal/manifest-entry.js +0 -0
  247. package/dist/_internal/mergeRefs.js +68 -0
  248. package/dist/_internal/motion.js +138 -0
  249. package/dist/_internal/navigationLandmark.js +13 -0
  250. package/dist/_internal/numberText.js +176 -0
  251. package/dist/_internal/overlay.js +53 -0
  252. package/dist/_internal/segmentField.js +125 -0
  253. package/dist/_internal/suggestions.js +20 -0
  254. package/dist/_internal/timestamp.js +25 -0
  255. package/dist/_internal/unavailable.js +13 -0
  256. package/dist/_internal/useActionFocus.js +27 -0
  257. package/dist/_internal/useElementWidth.js +37 -0
  258. package/dist/_internal/useIsMounted.js +18 -0
  259. package/dist/_internal/useIsomorphicLayoutEffect.js +8 -0
  260. package/dist/_internal/useRestoreFocusOnRemoval.js +57 -0
  261. package/dist/index.cjs +17811 -0
  262. package/dist/index.d.cts +2330 -0
  263. package/dist/index.d.ts +2330 -0
  264. package/dist/index.js +407 -0
  265. package/dist/version.js +8 -0
  266. package/package.json +80 -3
@@ -0,0 +1,192 @@
1
+ "use client";
2
+
3
+ // src/ContextMenu/ContextMenu.tsx
4
+ import {
5
+ forwardRef,
6
+ useEffect,
7
+ useRef,
8
+ useState
9
+ } from "react";
10
+ import { Keyboard, Menu, MenuItem, MenuTrigger, Pressable, Text } from "react-aria-components";
11
+ import { usePress } from "react-aria";
12
+ import { cva } from "class-variance-authority";
13
+ import clsx from "clsx";
14
+ import { Button } from "../Button/Button.js";
15
+ import { useHydrationRoot } from "../_internal/hydration.js";
16
+ import { composeMotionHandlers, MotionContext, useMotion } from "../_internal/motion.js";
17
+ import { MotionPopover } from "../_internal/MotionPopover.js";
18
+ import {
19
+ DESTRUCTIVE_ACTION,
20
+ MENU_EMPTY,
21
+ MENU_ITEM_DESCRIPTION,
22
+ MENU_ITEM_LABEL,
23
+ MENU_ITEM_SHORTCUT,
24
+ MENU_ITEM_TEXT,
25
+ MENU_OFFSET,
26
+ MENU_SURFACE,
27
+ menuItemStyles,
28
+ SCREEN_MARGIN
29
+ } from "../_internal/overlay.js";
30
+ import { jsx, jsxs } from "react/jsx-runtime";
31
+ var surfaceStyles = cva(
32
+ "min-h-3u min-w-0 border border-transparent outline-hidden focus-visible:border-oprt-border-focus focus-visible:shadow-oprt-focus"
33
+ );
34
+ function isMac() {
35
+ if (typeof navigator === "undefined") return false;
36
+ const platform = navigator.userAgentData?.platform || navigator.platform;
37
+ return /^mac/i.test(platform) && !(navigator.maxTouchPoints > 1);
38
+ }
39
+ function ContextSurface({
40
+ label,
41
+ disabled,
42
+ children
43
+ }) {
44
+ const surfaceRef = useRef(null);
45
+ const { pressProps } = usePress({ ref: surfaceRef, isDisabled: disabled });
46
+ return /* @__PURE__ */ jsx(
47
+ "div",
48
+ {
49
+ ref: surfaceRef,
50
+ id: pressProps.id,
51
+ role: "group",
52
+ "aria-label": label,
53
+ tabIndex: disabled ? -1 : 0,
54
+ className: surfaceStyles(),
55
+ onContextMenu: disabled ? void 0 : (event) => {
56
+ event.currentTarget.focus({ preventScroll: true });
57
+ pressProps.onContextMenu?.(event);
58
+ },
59
+ onKeyDown: (event) => {
60
+ if (disabled || event.target !== event.currentTarget || event.defaultPrevented) return;
61
+ const contextKey = event.key === "ContextMenu" || event.shiftKey && event.key === "F10";
62
+ const macShortcut = event.ctrlKey && !event.metaKey && !event.altKey && event.key === "Enter" && isMac();
63
+ if (!contextKey && !macShortcut) return;
64
+ event.preventDefault();
65
+ const target = event.currentTarget;
66
+ const rect = target.getBoundingClientRect();
67
+ target.dispatchEvent(
68
+ new MouseEvent("contextmenu", {
69
+ bubbles: true,
70
+ cancelable: true,
71
+ button: 2,
72
+ clientX: rect.left,
73
+ clientY: rect.bottom
74
+ })
75
+ );
76
+ },
77
+ children
78
+ }
79
+ );
80
+ }
81
+ var ContextMenu = forwardRef(
82
+ ({
83
+ label,
84
+ items,
85
+ onAction,
86
+ disabled = false,
87
+ emptyMessage = "No actions available",
88
+ children,
89
+ className,
90
+ ...props
91
+ }, ref) => {
92
+ const [open, setOpen] = useState(null);
93
+ const hydration = useHydrationRoot();
94
+ const motionState = useMotion("auto", "ContextMenu");
95
+ useEffect(() => {
96
+ if (disabled) setOpen(null);
97
+ }, [disabled]);
98
+ const menu = () => /* @__PURE__ */ jsx(
99
+ MotionPopover,
100
+ {
101
+ motionState,
102
+ offset: MENU_OFFSET,
103
+ containerPadding: SCREEN_MARGIN,
104
+ placement: "bottom start",
105
+ className: MENU_SURFACE,
106
+ children: /* @__PURE__ */ jsx(
107
+ Menu,
108
+ {
109
+ "aria-label": `${label} actions`,
110
+ "aria-labelledby": "",
111
+ className: "outline-hidden",
112
+ items,
113
+ renderEmptyState: () => /* @__PURE__ */ jsx("div", { className: MENU_EMPTY, children: emptyMessage }),
114
+ onAction: (key) => {
115
+ const item = items.find((candidate) => candidate.id === key);
116
+ if (!disabled && item && !item.disabled) onAction(item.id);
117
+ },
118
+ children: (item) => /* @__PURE__ */ jsxs(
119
+ MenuItem,
120
+ {
121
+ id: item.id,
122
+ textValue: item.label,
123
+ isDisabled: item.disabled ?? false,
124
+ className: menuItemStyles({ danger: item.danger ?? false }),
125
+ children: [
126
+ /* @__PURE__ */ jsxs("span", { className: MENU_ITEM_TEXT, children: [
127
+ /* @__PURE__ */ jsx(Text, { slot: "label", className: MENU_ITEM_LABEL, children: item.label }),
128
+ item.danger && /* @__PURE__ */ jsx(Text, { slot: "description", className: MENU_ITEM_DESCRIPTION, children: DESTRUCTIVE_ACTION })
129
+ ] }),
130
+ item.shortcut && /* @__PURE__ */ jsx(Keyboard, { className: MENU_ITEM_SHORTCUT, children: item.shortcut })
131
+ ]
132
+ }
133
+ )
134
+ }
135
+ )
136
+ }
137
+ );
138
+ return /* @__PURE__ */ jsx(MotionContext.Provider, { value: motionState.mode, children: /* @__PURE__ */ jsxs(
139
+ "div",
140
+ {
141
+ ...props,
142
+ ...composeMotionHandlers(motionState.props, props),
143
+ ...hydration.probeProps,
144
+ ref,
145
+ className: clsx(
146
+ "flex min-w-0 flex-wrap items-center gap-1u font-sans text-oprt-base normal-case tracking-normal text-oprt-text",
147
+ className
148
+ ),
149
+ children: [
150
+ /* @__PURE__ */ jsxs(
151
+ MenuTrigger,
152
+ {
153
+ trigger: "contextMenu",
154
+ isOpen: !disabled && open === "surface",
155
+ onOpenChange: (next) => setOpen(next && !disabled ? "surface" : null),
156
+ children: [
157
+ /* @__PURE__ */ jsx(ContextSurface, { label, disabled, children }),
158
+ menu()
159
+ ]
160
+ },
161
+ `${hydration.key}-surface`
162
+ ),
163
+ /* @__PURE__ */ jsxs(
164
+ MenuTrigger,
165
+ {
166
+ isOpen: !disabled && open === "button",
167
+ onOpenChange: (next) => setOpen(next && !disabled ? "button" : null),
168
+ children: [
169
+ /* @__PURE__ */ jsx(Pressable, { isDisabled: disabled, children: /* @__PURE__ */ jsx(
170
+ Button,
171
+ {
172
+ variant: "secondary",
173
+ size: "sm",
174
+ disabled,
175
+ "aria-label": `${label} actions`,
176
+ children: "Actions"
177
+ }
178
+ ) }),
179
+ menu()
180
+ ]
181
+ },
182
+ `${hydration.key}-button`
183
+ )
184
+ ]
185
+ }
186
+ ) });
187
+ }
188
+ );
189
+ ContextMenu.displayName = "ContextMenu";
190
+ export {
191
+ ContextMenu
192
+ };
@@ -0,0 +1,41 @@
1
+ // src/ContextMenu/ContextMenu.manifest.ts
2
+ var ContextMenuManifest = {
3
+ ContextMenu: {
4
+ description: "Context actions with a focusable surface and an equivalent visible menu button.",
5
+ props: {
6
+ label: {
7
+ type: "string",
8
+ required: true,
9
+ description: "Names the surface; the visible button is named `${label} actions`."
10
+ },
11
+ items: {
12
+ type: "array",
13
+ required: true,
14
+ description: "Stable unique id and readable label, with optional shortcut text, disabled and danger flags."
15
+ },
16
+ onAction: {
17
+ type: "function",
18
+ required: true,
19
+ description: "Receives the selected item ID. Both activation paths use the same supplied actions."
20
+ },
21
+ disabled: {
22
+ type: "boolean",
23
+ default: false,
24
+ description: "Disables both menu activation paths without disabling supplied child content."
25
+ },
26
+ emptyMessage: {
27
+ type: "string",
28
+ default: "No actions available",
29
+ description: "Non-interactive row the menu shows when items is empty."
30
+ },
31
+ className: { type: "string" }
32
+ },
33
+ slots: { children: { type: "ReactNode", required: true } },
34
+ composable_with: ["InlineEdit", "DataGrid"],
35
+ never_inside: ["Button"],
36
+ example: '<ContextMenu label="Alpha relay" items={[{id: "inspect", label: "Inspect"}]} onAction={handleAction}>EQ-01</ContextMenu>'
37
+ }
38
+ };
39
+ export {
40
+ ContextMenuManifest
41
+ };
@@ -0,0 +1,7 @@
1
+ // src/ContextMenu/index.ts
2
+ import { ContextMenu } from "./ContextMenu.js";
3
+ import { ContextMenuManifest } from "./ContextMenu.manifest.js";
4
+ export {
5
+ ContextMenu,
6
+ ContextMenuManifest
7
+ };
@@ -0,0 +1,141 @@
1
+ "use client";
2
+
3
+ // src/CoordinateInput/CoordinateInput.tsx
4
+ import { forwardRef, useEffect, useRef, useState } from "react";
5
+ import clsx from "clsx";
6
+ import { NumberInput } from "../NumberInput/NumberInput.js";
7
+ import { joinIds, usePartIds } from "../_internal/fieldIds.js";
8
+ import { useMergedRefs } from "../_internal/mergeRefs.js";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ var unknown = { latitude: null, longitude: null };
11
+ var CoordinateInput = forwardRef(
12
+ ({
13
+ label = "Coordinates",
14
+ value,
15
+ defaultValue = unknown,
16
+ onValueChange,
17
+ onValidationChange,
18
+ description,
19
+ error,
20
+ latitudeName,
21
+ longitudeName,
22
+ disabled = false,
23
+ className,
24
+ "aria-describedby": describedBy,
25
+ ...props
26
+ }, ref) => {
27
+ const fieldset = useRef(null);
28
+ const fieldsetRef = useMergedRefs(fieldset, ref);
29
+ const ids = usePartIds(["status", "description", "error"], {
30
+ readRendered: () => fieldset.current?.getAttribute("data-oprt-ids")
31
+ });
32
+ const [local, setLocal] = useState(defaultValue);
33
+ const [invalidAxes, setInvalidAxes] = useState({ latitude: false, longitude: false });
34
+ const position = value ?? local;
35
+ const invalid = Boolean(error) || invalidAxes.latitude || invalidAxes.longitude || position.latitude !== null && (!Number.isFinite(position.latitude) || Math.abs(position.latitude) > 90) || position.longitude !== null && (!Number.isFinite(position.longitude) || Math.abs(position.longitude) > 180);
36
+ const validationRef = useRef(onValidationChange);
37
+ validationRef.current = onValidationChange;
38
+ useEffect(() => {
39
+ validationRef.current?.(invalid);
40
+ }, [invalid]);
41
+ const status = invalid ? "Position invalid" : position.latitude === null || position.longitude === null ? "Position unknown" : "Decimal degrees";
42
+ const change = (axis, next) => {
43
+ if (disabled) return;
44
+ const nextPosition = { ...position, [axis]: next };
45
+ if (value === void 0) setLocal(nextPosition);
46
+ onValueChange?.(nextPosition);
47
+ };
48
+ return /* @__PURE__ */ jsxs(
49
+ "fieldset",
50
+ {
51
+ ...props,
52
+ ref: fieldsetRef,
53
+ "data-oprt-ids": ids.base,
54
+ disabled,
55
+ "aria-invalid": invalid || void 0,
56
+ "aria-describedby": joinIds(
57
+ describedBy,
58
+ ids.status,
59
+ description && ids.description,
60
+ error && ids.error
61
+ ),
62
+ className: clsx(
63
+ "m-0 min-w-0 border p-2u font-sans text-oprt-base normal-case text-oprt-text",
64
+ invalid ? "border-oprt-error" : "border-oprt-border",
65
+ className
66
+ ),
67
+ children: [
68
+ /* @__PURE__ */ jsx("legend", { className: "min-w-0 px-1u oprt-wrap-anywhere text-oprt-base font-medium text-oprt-text", children: label }),
69
+ description && /* @__PURE__ */ jsx(
70
+ "p",
71
+ {
72
+ id: ids.description,
73
+ className: "m-0 mb-1u min-w-0 oprt-wrap-anywhere text-oprt-text-dim",
74
+ children: description
75
+ }
76
+ ),
77
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[repeat(auto-fit,minmax(min(100%,12rem),1fr))] gap-2u", children: [
78
+ /* @__PURE__ */ jsx(
79
+ NumberInput,
80
+ {
81
+ label: "Latitude",
82
+ unit: "\xB0",
83
+ value: position.latitude,
84
+ onValueChange: (next) => change("latitude", next),
85
+ onValidationChange: (validation) => setInvalidAxes(
86
+ (axes) => axes.latitude === Boolean(validation) ? axes : { ...axes, latitude: Boolean(validation) }
87
+ ),
88
+ min: -90,
89
+ max: 90,
90
+ disabled,
91
+ ...latitudeName !== void 0 ? { name: latitudeName } : {}
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsx(
95
+ NumberInput,
96
+ {
97
+ label: "Longitude",
98
+ unit: "\xB0",
99
+ value: position.longitude,
100
+ onValueChange: (next) => change("longitude", next),
101
+ onValidationChange: (validation) => setInvalidAxes(
102
+ (axes) => axes.longitude === Boolean(validation) ? axes : { ...axes, longitude: Boolean(validation) }
103
+ ),
104
+ min: -180,
105
+ max: 180,
106
+ disabled,
107
+ ...longitudeName !== void 0 ? { name: longitudeName } : {}
108
+ }
109
+ )
110
+ ] }),
111
+ /* @__PURE__ */ jsx(
112
+ "p",
113
+ {
114
+ id: ids.status,
115
+ role: "status",
116
+ className: clsx(
117
+ "m-0 mt-1u min-w-0 oprt-wrap-anywhere",
118
+ invalid ? "text-oprt-error" : "text-oprt-text-dim"
119
+ ),
120
+ children: status
121
+ }
122
+ ),
123
+ error && // A caller's error is an alert, as in a Field (MultiSelect-R2).
124
+ /* @__PURE__ */ jsx(
125
+ "p",
126
+ {
127
+ id: ids.error,
128
+ role: "alert",
129
+ className: "m-0 mt-1u min-w-0 oprt-wrap-anywhere text-oprt-error",
130
+ children: error
131
+ }
132
+ )
133
+ ]
134
+ }
135
+ );
136
+ }
137
+ );
138
+ CoordinateInput.displayName = "CoordinateInput";
139
+ export {
140
+ CoordinateInput
141
+ };
@@ -0,0 +1,36 @@
1
+ // src/CoordinateInput/CoordinateInput.manifest.ts
2
+ var CoordinateInputManifest = {
3
+ CoordinateInput: {
4
+ description: "Decimal-degree latitude and longitude fields with bounded validation and explicit unknown or invalid position states.",
5
+ props: {
6
+ label: { type: "string", default: "Coordinates" },
7
+ value: {
8
+ type: "node",
9
+ description: "Controlled { latitude: number | null, longitude: number | null }. Latitude is -90\u202690; longitude is -180\u2026180, inclusive. Null axes are unknown."
10
+ },
11
+ defaultValue: {
12
+ type: "node",
13
+ description: "Initial uncontrolled coordinates. Defaults to both axes null."
14
+ },
15
+ onValueChange: {
16
+ type: "function",
17
+ description: "(position: CoordinateValue) => void. Only valid axis edits or a cleared null axis are emitted; the other axis is preserved. Does not normalize or wrap out-of-range input."
18
+ },
19
+ onValidationChange: {
20
+ type: "function",
21
+ description: "(invalid: boolean) => void. Reports aggregate invalid state initially and on change, including local typed drafts, supplied values and error. Missing/null axes are unknown rather than invalid; callers separately require both axes before Go-to or submission."
22
+ },
23
+ disabled: { type: "boolean", default: false },
24
+ description: { type: "string" },
25
+ error: { type: "string" },
26
+ latitudeName: { type: "string", description: "Native form field name for latitude." },
27
+ longitudeName: { type: "string", description: "Native form field name for longitude." }
28
+ },
29
+ composable_with: ["Card", "NumberInput"],
30
+ never_inside: ["Button"],
31
+ example: '<CoordinateInput label="Observation position" value={position} onValueChange={setPosition} />'
32
+ }
33
+ };
34
+ export {
35
+ CoordinateInputManifest
36
+ };
@@ -0,0 +1,9 @@
1
+ // src/CoordinateInput/index.ts
2
+ import {
3
+ CoordinateInput
4
+ } from "./CoordinateInput.js";
5
+ import { CoordinateInputManifest } from "./CoordinateInput.manifest.js";
6
+ export {
7
+ CoordinateInput,
8
+ CoordinateInputManifest
9
+ };
@@ -0,0 +1,110 @@
1
+ "use client";
2
+
3
+ // src/CopyButton/CopyButton.tsx
4
+ import { forwardRef, useRef, useState } from "react";
5
+ import { cva } from "class-variance-authority";
6
+ import { Copy } from "@oprt/icons";
7
+ import { Button } from "../Button/Button.js";
8
+ import { CopyButtonManifest } from "./CopyButton.manifest.js";
9
+ import { devValidate } from "../_internal/devValidate.js";
10
+ import { useIsMounted } from "../_internal/useIsMounted.js";
11
+ import { useIsomorphicLayoutEffect } from "../_internal/useIsomorphicLayoutEffect.js";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ var copyStyles = cva("inline-flex min-w-0 flex-wrap items-center gap-1u");
14
+ var iconSize = { sm: 12, md: 16, lg: 20 };
15
+ var feedbackStyles = cva("min-w-0 break-words font-sans text-oprt-base normal-case", {
16
+ variants: {
17
+ state: {
18
+ pending: "text-oprt-text-dim",
19
+ success: "text-oprt-success",
20
+ error: "text-oprt-error"
21
+ }
22
+ }
23
+ });
24
+ var CopyButton = forwardRef((allProps, ref) => {
25
+ const { value, label, onCopy, onCopyError, disabled = false, size = "md", className } = allProps;
26
+ const [pending, setPending] = useState(false);
27
+ const [feedback, setFeedback] = useState(null);
28
+ const pendingRef = useRef(false);
29
+ const isMounted = useIsMounted();
30
+ const context = useRef({ value, label, revision: 0 });
31
+ if (process.env.NODE_ENV !== "production") {
32
+ devValidate("CopyButton", CopyButtonManifest.CopyButton.props, { ...allProps });
33
+ }
34
+ useIsomorphicLayoutEffect(() => {
35
+ if (context.current.value !== value || context.current.label !== label) {
36
+ context.current = { value, label, revision: context.current.revision + 1 };
37
+ setFeedback(null);
38
+ }
39
+ }, [value, label]);
40
+ async function copy() {
41
+ if (disabled || pendingRef.current) return;
42
+ pendingRef.current = true;
43
+ setPending(true);
44
+ const request = { value, label, revision: context.current.revision };
45
+ setFeedback({ value, label, state: "pending" });
46
+ let outcome;
47
+ try {
48
+ const clipboard = navigator.clipboard;
49
+ if (typeof clipboard?.writeText !== "function") {
50
+ throw new Error("Clipboard writing is unavailable.");
51
+ }
52
+ await clipboard.writeText(request.value);
53
+ outcome = { state: "success" };
54
+ } catch (error) {
55
+ outcome = { state: "error", error };
56
+ }
57
+ pendingRef.current = false;
58
+ if (!isMounted()) return;
59
+ setPending(false);
60
+ if (context.current.revision !== request.revision || context.current.value !== request.value || context.current.label !== request.label)
61
+ return;
62
+ setFeedback({ value: request.value, label: request.label, state: outcome.state });
63
+ try {
64
+ if (outcome.state === "success") onCopy?.({ value: request.value });
65
+ else onCopyError?.({ value: request.value, error: outcome.error });
66
+ } catch {
67
+ }
68
+ }
69
+ const visibleFeedback = feedback?.value === value && feedback.label === label ? feedback : null;
70
+ return /* @__PURE__ */ jsxs("span", { className: copyStyles(), children: [
71
+ /* @__PURE__ */ jsxs(
72
+ Button,
73
+ {
74
+ ref,
75
+ variant: "tertiary",
76
+ size,
77
+ className,
78
+ "aria-label": label,
79
+ "aria-disabled": disabled || pending,
80
+ "aria-busy": pending,
81
+ disabled,
82
+ onClick: () => {
83
+ void copy();
84
+ },
85
+ children: [
86
+ /* @__PURE__ */ jsx(Copy, { "aria-hidden": "true", size: iconSize[size ?? "md"] }),
87
+ "Copy"
88
+ ]
89
+ }
90
+ ),
91
+ /* @__PURE__ */ jsxs(
92
+ "span",
93
+ {
94
+ role: "status",
95
+ "aria-live": "polite",
96
+ "aria-atomic": "true",
97
+ className: feedbackStyles({ state: visibleFeedback?.state }),
98
+ children: [
99
+ visibleFeedback?.state === "pending" && `${visibleFeedback.label}: copying\u2026`,
100
+ visibleFeedback?.state === "success" && `${visibleFeedback.label}: copied`,
101
+ visibleFeedback?.state === "error" && `${visibleFeedback.label}: failed. Select the value and copy it manually.`
102
+ ]
103
+ }
104
+ )
105
+ ] });
106
+ });
107
+ CopyButton.displayName = "CopyButton";
108
+ export {
109
+ CopyButton
110
+ };
@@ -0,0 +1,35 @@
1
+ // src/CopyButton/CopyButton.manifest.ts
2
+ var CopyButtonManifest = {
3
+ CopyButton: {
4
+ description: "Copies a supplied exact string with visible pending, success and failure feedback.",
5
+ props: {
6
+ value: {
7
+ type: "string",
8
+ required: true,
9
+ description: "Exact string to copy; whitespace and precision are preserved."
10
+ },
11
+ label: {
12
+ type: "string",
13
+ required: true,
14
+ description: 'Accessible action name identifying the value. Feedback reads this label, then the outcome: "Copy equipment ID: copied".'
15
+ },
16
+ size: { type: "enum", values: ["sm", "md", "lg"], default: "md" },
17
+ disabled: { type: "boolean", default: false },
18
+ className: { type: "string", description: "Classes applied to the native action button." },
19
+ onCopy: {
20
+ type: "function",
21
+ description: "Receives { value } after the requested write resolves. Suppressed after context changes or unmount."
22
+ },
23
+ onCopyError: {
24
+ type: "function",
25
+ description: "Receives { value, error } if writing fails or is unavailable. Suppressed after context changes or unmount."
26
+ }
27
+ },
28
+ composable_with: ["DescriptionList", "EntityPreview", "Popover", "Inspector", "Toolbar"],
29
+ never_inside: ["Button", "Link"],
30
+ example: '<CopyButton value={equipment.id} label="Copy equipment ID" size="sm" />'
31
+ }
32
+ };
33
+ export {
34
+ CopyButtonManifest
35
+ };
@@ -0,0 +1,7 @@
1
+ // src/CopyButton/index.ts
2
+ import { CopyButton } from "./CopyButton.js";
3
+ import { CopyButtonManifest } from "./CopyButton.manifest.js";
4
+ export {
5
+ CopyButton,
6
+ CopyButtonManifest
7
+ };