@oprt/react 0.0.0-stage → 0.2.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 +129 -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 +123 -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 +17831 -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,261 @@
1
+ "use client";
2
+
3
+ // src/InlineEdit/InlineEdit.tsx
4
+ import { forwardRef, useEffect, useRef, useState } from "react";
5
+ import { cva } from "class-variance-authority";
6
+ import clsx from "clsx";
7
+ import { Button } from "../Button/index.js";
8
+ import { Input } from "../Input/index.js";
9
+ import { Textarea } from "../Textarea/index.js";
10
+ import { joinIds, usePartIds } from "../_internal/fieldIds.js";
11
+ import { useIsMounted } from "../_internal/useIsMounted.js";
12
+ import { useMergedRefs } from "../_internal/mergeRefs.js";
13
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
14
+ var rootStyles = cva(
15
+ "flex min-w-0 flex-col gap-1u font-sans text-oprt-base normal-case tracking-normal text-oprt-text"
16
+ );
17
+ function matchesAttempt(attempt, value, label) {
18
+ const acceptedReplacement = value === attempt.submitted && value !== attempt.session.baseline;
19
+ return (label === attempt.session.label || acceptedReplacement) && (value === attempt.session.baseline || value === attempt.submitted);
20
+ }
21
+ var InlineEdit = forwardRef(
22
+ ({ label, value, onSave, disabled = false, readOnly = false, validate, className, ...props }, ref) => {
23
+ const [editing, setEditing] = useState(false);
24
+ const [draft, setDraft] = useState(value);
25
+ const [error, setError] = useState(null);
26
+ const [pending, setPending] = useState(false);
27
+ const [multiline, setMultiline] = useState(false);
28
+ const [returnFocus, setReturnFocus] = useState(null);
29
+ const [changedTo, setChangedTo] = useState(null);
30
+ const rootRef = useRef(null);
31
+ const mergedRef = useMergedRefs(rootRef, ref);
32
+ const inputRef = useRef(null);
33
+ const editRef = useRef(null);
34
+ const refocusInput = useRef(false);
35
+ const session = useRef(null);
36
+ const request = useRef(null);
37
+ const composing = useRef(false);
38
+ const isMounted = useIsMounted();
39
+ const latest = useRef({ label, value, disabled, readOnly });
40
+ latest.current = { label, value, disabled, readOnly };
41
+ const ids = usePartIds(["error", "changed"]);
42
+ useEffect(
43
+ () => () => {
44
+ session.current = null;
45
+ request.current = null;
46
+ },
47
+ []
48
+ );
49
+ useEffect(() => {
50
+ const current = session.current;
51
+ if (!current) return;
52
+ const attempt = request.current;
53
+ if (disabled || readOnly || attempt && !matchesAttempt(attempt, value, label)) {
54
+ session.current = null;
55
+ request.current = null;
56
+ setEditing(false);
57
+ setPending(false);
58
+ setError(null);
59
+ setReturnFocus(null);
60
+ setChangedTo(null);
61
+ return;
62
+ }
63
+ if (attempt || current.label === label && current.baseline === value) return;
64
+ session.current = { baseline: value, label };
65
+ if (current.baseline !== value) setChangedTo(value);
66
+ }, [value, label, disabled, readOnly]);
67
+ useEffect(() => {
68
+ if (editing) inputRef.current?.focus();
69
+ }, [editing]);
70
+ useEffect(() => {
71
+ if (pending || !refocusInput.current) return;
72
+ refocusInput.current = false;
73
+ const active = document.activeElement;
74
+ if (active === null || active === document.body || rootRef.current?.contains(active))
75
+ inputRef.current?.focus();
76
+ }, [pending]);
77
+ useEffect(() => {
78
+ if (!returnFocus || editing) return;
79
+ if (!disabled && !readOnly && matchesAttempt(returnFocus, value, label))
80
+ editRef.current?.focus();
81
+ setReturnFocus(null);
82
+ }, [returnFocus, editing, disabled, readOnly, label, value]);
83
+ function start() {
84
+ if (disabled || readOnly) return;
85
+ session.current = { baseline: value, label };
86
+ composing.current = false;
87
+ setMultiline(/[\r\n]/.test(value));
88
+ setDraft(value);
89
+ setError(null);
90
+ setChangedTo(null);
91
+ setEditing(true);
92
+ }
93
+ function cancel() {
94
+ if (request.current || !session.current) return;
95
+ setReturnFocus({ session: session.current, submitted: value });
96
+ session.current = null;
97
+ setEditing(false);
98
+ setError(null);
99
+ setChangedTo(null);
100
+ }
101
+ function isCurrent(attempt) {
102
+ const current = latest.current;
103
+ return isMounted() && request.current === attempt && session.current === attempt.session && !current.disabled && !current.readOnly && matchesAttempt(attempt, current.value, current.label);
104
+ }
105
+ async function save() {
106
+ if (request.current || !session.current || disabled || readOnly || composing.current) return;
107
+ const validationError = validate?.(draft);
108
+ if (validationError) {
109
+ setError(validationError);
110
+ inputRef.current?.focus();
111
+ return;
112
+ }
113
+ const attempt = { session: session.current, submitted: draft };
114
+ request.current = attempt;
115
+ setPending(true);
116
+ setError(null);
117
+ try {
118
+ await onSave(draft);
119
+ if (!isCurrent(attempt)) return;
120
+ request.current = null;
121
+ session.current = null;
122
+ setPending(false);
123
+ setEditing(false);
124
+ setChangedTo(null);
125
+ setReturnFocus(attempt);
126
+ } catch (reason) {
127
+ if (!isCurrent(attempt)) return;
128
+ request.current = null;
129
+ refocusInput.current = true;
130
+ setPending(false);
131
+ setError(
132
+ reason instanceof Error && reason.message ? reason.message : "Could not save. Try again."
133
+ );
134
+ }
135
+ }
136
+ const Control = multiline ? Textarea : Input;
137
+ return /* @__PURE__ */ jsx(
138
+ "div",
139
+ {
140
+ ...props,
141
+ ref: mergedRef,
142
+ className: clsx(rootStyles(), className),
143
+ "aria-busy": pending || void 0,
144
+ children: editing ? /* @__PURE__ */ jsxs(Fragment, { children: [
145
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-1u", children: [
146
+ /* @__PURE__ */ jsx(
147
+ Control,
148
+ {
149
+ ref: (node) => {
150
+ inputRef.current = node;
151
+ },
152
+ "aria-label": label,
153
+ value: draft,
154
+ disabled: pending || disabled || readOnly,
155
+ "aria-invalid": Boolean(error),
156
+ "aria-describedby": joinIds(changedTo !== null && ids.changed, error && ids.error),
157
+ className: "min-w-0 flex-1",
158
+ onChange: (event) => {
159
+ setDraft(event.target.value);
160
+ setError(null);
161
+ },
162
+ onCompositionStart: () => {
163
+ composing.current = true;
164
+ },
165
+ onCompositionEnd: () => {
166
+ composing.current = false;
167
+ },
168
+ onKeyDown: (event) => {
169
+ if (composing.current || event.nativeEvent.isComposing || event.keyCode === 229)
170
+ return;
171
+ if (event.key === "Enter" && !multiline) {
172
+ event.preventDefault();
173
+ void save();
174
+ } else if (event.key === "Escape" && !pending) {
175
+ event.preventDefault();
176
+ event.stopPropagation();
177
+ cancel();
178
+ }
179
+ }
180
+ }
181
+ ),
182
+ /* @__PURE__ */ jsx(
183
+ Button,
184
+ {
185
+ size: "sm",
186
+ "aria-label": `Save ${label}`,
187
+ disabled: pending || disabled || readOnly,
188
+ onClick: () => {
189
+ void save();
190
+ },
191
+ children: "Save"
192
+ }
193
+ ),
194
+ /* @__PURE__ */ jsx(
195
+ Button,
196
+ {
197
+ size: "sm",
198
+ variant: "secondary",
199
+ "aria-label": `Cancel ${label}`,
200
+ disabled: pending,
201
+ onClick: cancel,
202
+ children: "Cancel"
203
+ }
204
+ )
205
+ ] }),
206
+ /* @__PURE__ */ jsx(
207
+ "p",
208
+ {
209
+ id: ids.changed,
210
+ className: clsx(
211
+ "m-0 oprt-wrap-anywhere text-oprt-base text-oprt-text-dim",
212
+ changedTo === null && "sr-only"
213
+ ),
214
+ role: "status",
215
+ children: changedTo !== null && /* @__PURE__ */ jsxs(Fragment, { children: [
216
+ "Changed to \u201C",
217
+ changedTo || "\u2014",
218
+ "\u201D while you were editing."
219
+ ] })
220
+ }
221
+ ),
222
+ /* @__PURE__ */ jsx(
223
+ "p",
224
+ {
225
+ className: clsx("m-0 text-oprt-base text-oprt-text-dim", !pending && "sr-only"),
226
+ role: "status",
227
+ children: pending && "Saving\u2026"
228
+ }
229
+ ),
230
+ error && /* @__PURE__ */ jsx(
231
+ "p",
232
+ {
233
+ id: ids.error,
234
+ className: "m-0 oprt-wrap-anywhere text-oprt-base text-oprt-error",
235
+ role: "alert",
236
+ children: error
237
+ }
238
+ )
239
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2u", children: [
240
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 whitespace-break-spaces oprt-wrap-anywhere", children: value || "\u2014" }),
241
+ !readOnly && /* @__PURE__ */ jsx(
242
+ Button,
243
+ {
244
+ ref: editRef,
245
+ size: "sm",
246
+ variant: "ghost",
247
+ "aria-label": `Edit ${label}`,
248
+ disabled,
249
+ onClick: start,
250
+ children: "Edit"
251
+ }
252
+ )
253
+ ] })
254
+ }
255
+ );
256
+ }
257
+ );
258
+ InlineEdit.displayName = "InlineEdit";
259
+ export {
260
+ InlineEdit
261
+ };
@@ -0,0 +1,40 @@
1
+ // src/InlineEdit/InlineEdit.manifest.ts
2
+ var InlineEditManifest = {
3
+ InlineEdit: {
4
+ description: "Controlled inline text editing with explicit save, cancel and recoverable validation or save errors.",
5
+ props: {
6
+ label: {
7
+ type: "string",
8
+ required: true,
9
+ description: "Names the editor and its Edit, Save and Cancel actions."
10
+ },
11
+ value: {
12
+ type: "string",
13
+ required: true,
14
+ description: "Authoritative displayed value. Case is preserved. A change while the operator is typing keeps the draft and shows a status line naming the new value."
15
+ },
16
+ onSave: {
17
+ type: "function",
18
+ required: true,
19
+ description: "Receives the exact draft; return a promise for asynchronous acceptance and reject to retain the draft with an error."
20
+ },
21
+ validate: {
22
+ type: "function",
23
+ description: "Returns an error message or undefined before saving."
24
+ },
25
+ disabled: { type: "boolean", default: false },
26
+ readOnly: {
27
+ type: "boolean",
28
+ default: false,
29
+ description: "Displays the value without an Edit action."
30
+ },
31
+ className: { type: "string" }
32
+ },
33
+ composable_with: ["ContextMenu", "DataGrid", "FormSection"],
34
+ never_inside: ["Button"],
35
+ example: '<InlineEdit label="Equipment name" value={name} onSave={saveName} validate={(value) => value.trim() ? undefined : "Enter a name."} />'
36
+ }
37
+ };
38
+ export {
39
+ InlineEditManifest
40
+ };
@@ -0,0 +1,7 @@
1
+ // src/InlineEdit/index.ts
2
+ import { InlineEdit } from "./InlineEdit.js";
3
+ import { InlineEditManifest } from "./InlineEdit.manifest.js";
4
+ export {
5
+ InlineEdit,
6
+ InlineEditManifest
7
+ };
@@ -0,0 +1,126 @@
1
+ "use client";
2
+
3
+ // src/Input/Input.tsx
4
+ import { cva } from "class-variance-authority";
5
+ import { forwardRef } from "react";
6
+ import clsx from "clsx";
7
+ import { InputManifest } from "./Input.manifest.js";
8
+ import { devValidate } from "../_internal/devValidate.js";
9
+ import { useFieldWiring } from "../_internal/fieldIds.js";
10
+ import { FORCED_FOCUS_WITHIN, FORCED_NO_RESTING_OUTLINE } from "../_internal/controlStyles.js";
11
+ import { Calendar, Clock } from "@oprt/icons";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ var wrapperStyles = cva(
14
+ // Disabled looks like DC-9's disabled buttons (coordinator ruling on DC-B04-2): dim text, the
15
+ // control outline and a muted fill, with no fade of the whole field, which took an affix to
16
+ // 2.14:1 (Input-B2M-5); the outline also replaces an invalid field's red, as for danger buttons.
17
+ "inline-flex min-w-0 max-w-full items-center gap-1u border bg-oprt-surface-2 normal-case transition-colors duration-oprt-fast focus-within:shadow-oprt-focus has-[input:disabled]:cursor-not-allowed has-[input:disabled]:bg-oprt-surface-3 has-[input:disabled]:border-oprt-border-control",
18
+ {
19
+ variants: {
20
+ invalid: {
21
+ true: "border-oprt-error focus-within:border-oprt-error",
22
+ // The control outline (design call DC-3); focus in the focus token, as the siblings do.
23
+ false: "border-oprt-border-control focus-within:border-oprt-border-focus"
24
+ },
25
+ // The height is a minimum: a long prefix or suffix wraps in its own column and the field
26
+ // grows taller (coordinator ruling on DC-B04-3, Input-B2M-1..3), while a one-line field keeps
27
+ // exactly its token height, as DC-8 rules for buttons. The value's 24px line fits md and lg;
28
+ // sm caps it inside its 2px of border, as the fixed height did. A capped input cannot stretch
29
+ // to a field that grew taller, and a stretched item that hits its cap sits at the top, so sm
30
+ // centers it with auto margins instead (Stage 1 final review, I-2).
31
+ size: {
32
+ sm: "min-h-oprt-sm px-2u [&_input]:my-auto [&_input]:max-h-[calc(var(--oprt-height-sm)-2px)]",
33
+ md: "min-h-oprt-md px-2u",
34
+ lg: "min-h-oprt-lg px-3u"
35
+ }
36
+ },
37
+ defaultVariants: { invalid: false, size: "md" }
38
+ }
39
+ );
40
+ var inputStyles = cva(
41
+ // The value keeps about ten characters beside a long affix, and less only in a container
42
+ // narrower than that (Input-B2M-1..3); the field around it can shrink in a narrow host (Input-W0-1).
43
+ // It stretches to the field's height, so the whole field is the click and measured target and
44
+ // not the one line of text inside it (operations-map-R4); a text input centers its text itself.
45
+ "peer min-w-[min(10ch,100%)] flex-1 self-stretch bg-transparent border-0 outline-hidden font-sans font-medium text-oprt-md text-oprt-text placeholder:text-oprt-text-placeholder disabled:placeholder:text-oprt-text-dim disabled:cursor-not-allowed disabled:text-oprt-text-dim"
46
+ );
47
+ var Input = forwardRef((allProps, ref) => {
48
+ const {
49
+ className,
50
+ size,
51
+ prefix,
52
+ suffix,
53
+ promptSymbol,
54
+ type = "text",
55
+ id,
56
+ invalid: invalidProp,
57
+ required: requiredProp,
58
+ "aria-describedby": ariaDescribedBy,
59
+ "aria-invalid": ariaInvalid,
60
+ ...props
61
+ } = allProps;
62
+ const {
63
+ id: finalId,
64
+ describedBy,
65
+ invalid,
66
+ ariaInvalid: finalAriaInvalid,
67
+ required
68
+ } = useFieldWiring(
69
+ {
70
+ id,
71
+ "aria-describedby": ariaDescribedBy,
72
+ "aria-invalid": ariaInvalid,
73
+ invalid: invalidProp,
74
+ required: requiredProp
75
+ },
76
+ { label: "for" }
77
+ );
78
+ if (process.env.NODE_ENV !== "production") {
79
+ devValidate("Input", InputManifest.Input.props, { ...allProps });
80
+ }
81
+ const temporal = type === "date" || type === "time" || type === "datetime-local";
82
+ const PickerIcon = type === "time" ? Clock : Calendar;
83
+ const control = /* @__PURE__ */ jsx(
84
+ "input",
85
+ {
86
+ ref,
87
+ id: finalId,
88
+ type,
89
+ "aria-invalid": finalAriaInvalid,
90
+ "aria-describedby": describedBy,
91
+ required,
92
+ className: clsx(
93
+ inputStyles(),
94
+ // Forced colors paint outline-hidden's transparent outline; the field draws focus instead.
95
+ FORCED_NO_RESTING_OUTLINE,
96
+ temporal && "h-full w-full pr-3u [color-scheme:dark] [&::-webkit-calendar-picker-indicator]:absolute [&::-webkit-calendar-picker-indicator]:right-0 [&::-webkit-calendar-picker-indicator]:top-1/2 [&::-webkit-calendar-picker-indicator]:-translate-y-1/2 [&::-webkit-calendar-picker-indicator]:m-0 [&::-webkit-calendar-picker-indicator]:h-oprt-sm [&::-webkit-calendar-picker-indicator]:w-oprt-sm [&::-webkit-calendar-picker-indicator]:p-0 [&::-webkit-calendar-picker-indicator]:opacity-0 [&::-webkit-calendar-picker-indicator]:cursor-pointer"
97
+ ),
98
+ ...props
99
+ }
100
+ );
101
+ return (
102
+ // In forced colors, which drop the focus shadow and flatten the border, focus anywhere in the
103
+ // field is a 2px CanvasText outline around it, as for ComboBox (Input-B5-1).
104
+ /* @__PURE__ */ jsxs("div", { className: clsx(wrapperStyles({ invalid, size }), FORCED_FOCUS_WITHIN, className), children: [
105
+ promptSymbol && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-oprt-accent font-mono text-oprt-md", children: ">" }),
106
+ prefix && /* @__PURE__ */ jsx("span", { className: "min-w-0 oprt-wrap-anywhere text-oprt-text-dim", children: prefix }),
107
+ temporal ? /* @__PURE__ */ jsxs("div", { className: "relative flex min-w-0 flex-1 items-center self-stretch", children: [
108
+ control,
109
+ /* @__PURE__ */ jsx(
110
+ "span",
111
+ {
112
+ "data-oprt-picker-icon": "",
113
+ "aria-hidden": "true",
114
+ className: "pointer-events-none absolute inset-y-0 right-0 flex w-3u items-center justify-center bg-oprt-surface-2 text-oprt-text-dim peer-disabled:bg-oprt-surface-3",
115
+ children: /* @__PURE__ */ jsx(PickerIcon, { size: 16 })
116
+ }
117
+ )
118
+ ] }) : control,
119
+ suffix && /* @__PURE__ */ jsx("span", { className: "min-w-0 oprt-wrap-anywhere text-oprt-text-dim", children: suffix })
120
+ ] })
121
+ );
122
+ });
123
+ Input.displayName = "Input";
124
+ export {
125
+ Input
126
+ };
@@ -0,0 +1,49 @@
1
+ // src/Input/Input.manifest.ts
2
+ var InputManifest = {
3
+ Input: {
4
+ description: "Single-line input with optional prefix/suffix slots and prompt-symbol variant. Date and time fields preserve native editing and picker interaction with decorative OPERATOR Calendar/Clock icons and a dark native color scheme.",
5
+ props: {
6
+ type: {
7
+ type: "enum",
8
+ values: [
9
+ "text",
10
+ "number",
11
+ "password",
12
+ "search",
13
+ "email",
14
+ "tel",
15
+ "url",
16
+ "date",
17
+ "time",
18
+ "datetime-local",
19
+ "month",
20
+ "week"
21
+ ],
22
+ default: "text",
23
+ description: "The text-like and date-like input types. TypeScript accepts any HTML input type, but one that is not a text field (checkbox, radio, file, range, color, hidden, button, submit, reset, image) breaks the field's look and is reported in development; use Checkbox, RadioGroup, Slider or FileUpload instead."
24
+ },
25
+ size: { type: "enum", values: ["sm", "md", "lg"], default: "md" },
26
+ placeholder: { type: "string" },
27
+ disabled: { type: "boolean", default: false },
28
+ invalid: {
29
+ type: "boolean",
30
+ description: "Marks the field invalid: an error border and aria-invalid. Wins over aria-invalid, which wins over a surrounding Field's error, as on Textarea."
31
+ },
32
+ promptSymbol: { type: "boolean", default: false },
33
+ prefix: {
34
+ type: "node",
35
+ description: "ReactNode rendered before the input (icon, currency symbol, etc.)."
36
+ },
37
+ suffix: {
38
+ type: "node",
39
+ description: "ReactNode rendered after the input (icon, clear button, unit, etc.). For interactive elements use an accessible Button or icon-button."
40
+ }
41
+ },
42
+ composable_with: ["Field"],
43
+ never_inside: ["Button", "Badge"],
44
+ example: '<Field label="ENDPOINT">\n <Input placeholder="api.system.io" />\n</Field>'
45
+ }
46
+ };
47
+ export {
48
+ InputManifest
49
+ };
@@ -0,0 +1,7 @@
1
+ // src/Input/index.ts
2
+ import { Input } from "./Input.js";
3
+ import { InputManifest } from "./Input.manifest.js";
4
+ export {
5
+ Input,
6
+ InputManifest
7
+ };
@@ -0,0 +1,63 @@
1
+ "use client";
2
+
3
+ // src/Inspector/Inspector.tsx
4
+ import { forwardRef, useRef } from "react";
5
+ import { cva } from "class-variance-authority";
6
+ import clsx from "clsx";
7
+ import { Button } from "../Button/Button.js";
8
+ import { joinIds, usePartIds } from "../_internal/fieldIds.js";
9
+ import { useMergedRefs } from "../_internal/mergeRefs.js";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ var inspectorStyles = cva(
12
+ "flex min-w-0 flex-col gap-2u break-words border border-oprt-border bg-oprt-surface-1 p-2u font-sans text-oprt-base normal-case text-oprt-text"
13
+ );
14
+ var Inspector = forwardRef(
15
+ ({
16
+ open = true,
17
+ title,
18
+ description,
19
+ onClose,
20
+ children,
21
+ className,
22
+ "aria-labelledby": labelledBy,
23
+ "aria-describedby": describedBy,
24
+ ...props
25
+ }, ref) => {
26
+ const root = useRef(null);
27
+ const setRef = useMergedRefs(root, ref);
28
+ const ids = usePartIds(["title", "description"], {
29
+ readRendered: () => root.current?.getAttribute("data-oprt-ids")
30
+ });
31
+ if (!open) return null;
32
+ return /* @__PURE__ */ jsxs(
33
+ "aside",
34
+ {
35
+ ...props,
36
+ ref: setRef,
37
+ "data-oprt-ids": ids.base,
38
+ "aria-labelledby": joinIds(ids.title, labelledBy),
39
+ "aria-describedby": joinIds(description ? ids.description : void 0, describedBy),
40
+ className: clsx(inspectorStyles(), className),
41
+ children: [
42
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-1u", children: [
43
+ /* @__PURE__ */ jsx(
44
+ "h3",
45
+ {
46
+ id: ids.title,
47
+ className: "m-0 min-w-0 text-oprt-md font-medium normal-case oprt-wrap-anywhere",
48
+ children: title
49
+ }
50
+ ),
51
+ onClose && /* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "sm", onClick: onClose, "aria-label": `Close ${title}`, children: "Close" })
52
+ ] }),
53
+ description && /* @__PURE__ */ jsx("p", { id: ids.description, className: "m-0 min-w-0 text-oprt-text-dim oprt-wrap-anywhere", children: description }),
54
+ children
55
+ ]
56
+ }
57
+ );
58
+ }
59
+ );
60
+ Inspector.displayName = "Inspector";
61
+ export {
62
+ Inspector
63
+ };
@@ -0,0 +1,35 @@
1
+ // src/Inspector/Inspector.manifest.ts
2
+ var InspectorManifest = {
3
+ Inspector: {
4
+ description: "Modeless named details aside that leaves background content and focus navigation available.",
5
+ props: {
6
+ open: {
7
+ type: "boolean",
8
+ default: true
9
+ },
10
+ title: {
11
+ type: "string",
12
+ required: true,
13
+ description: "Accessible title; entity names preserve supplied casing."
14
+ },
15
+ description: {
16
+ type: "string"
17
+ },
18
+ onClose: {
19
+ type: "function",
20
+ description: "Shows Close when supplied. The caller manages closing state and return focus."
21
+ }
22
+ },
23
+ slots: {
24
+ children: {
25
+ type: "ReactNode"
26
+ }
27
+ },
28
+ composable_with: ["AppShell", "SplitPane", "OperationalStatus", "ActionStatus"],
29
+ never_inside: ["Button"],
30
+ example: "<Inspector open={open} title={asset.name} onClose={closeAndRestoreFocus}><OperationalStatus state={asset.status} source={source} updatedAt={asset.updatedAt} /></Inspector>"
31
+ }
32
+ };
33
+ export {
34
+ InspectorManifest
35
+ };
@@ -0,0 +1,7 @@
1
+ // src/Inspector/index.ts
2
+ import { Inspector } from "./Inspector.js";
3
+ import { InspectorManifest } from "./Inspector.manifest.js";
4
+ export {
5
+ Inspector,
6
+ InspectorManifest
7
+ };