@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,210 @@
1
+ "use client";
2
+
3
+ // src/NumberInput/NumberInput.tsx
4
+ import { forwardRef, useEffect, useRef, useState } from "react";
5
+ import { cva } from "class-variance-authority";
6
+ import clsx from "clsx";
7
+ import { useMergedRefs } from "../_internal/mergeRefs.js";
8
+ import { joinIds, usePartIds } from "../_internal/fieldIds.js";
9
+ import { FORCED_FOCUS_WITHIN, FORCED_NO_RESTING_OUTLINE } from "../_internal/controlStyles.js";
10
+ import { devValidate } from "../_internal/devValidate.js";
11
+ import { NumberInputManifest } from "./NumberInput.manifest.js";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ var styles = cva(
14
+ // Disabled looks like DC-9's disabled buttons (coordinator ruling on DC-B04-2, NumberInput-R1):
15
+ // dim text, the control outline and a muted fill; CoordinateInput's axes inherit it.
16
+ "flex min-w-0 items-center gap-1u border bg-oprt-surface-2 px-2u 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",
17
+ {
18
+ variants: {
19
+ invalid: {
20
+ true: "border-oprt-error",
21
+ // The control outline (design call DC-3).
22
+ false: "border-oprt-border-control focus-within:border-oprt-border-focus"
23
+ },
24
+ // The height is a minimum: a long unit wraps in its own column beside the number and the
25
+ // field grows taller (coordinator ruling on DC-B04-3, NumberInput-R3), while a one-line field
26
+ // keeps exactly its token height; sm caps the number's 24px line inside its 2px of border.
27
+ size: {
28
+ // Capped at sm, so centered with auto margins rather than stretched (see Input).
29
+ sm: "min-h-oprt-sm [&_input]:my-auto [&_input]:max-h-[calc(var(--oprt-height-sm)-2px)]",
30
+ md: "min-h-oprt-md",
31
+ lg: "min-h-oprt-lg"
32
+ }
33
+ },
34
+ defaultVariants: { invalid: false, size: "md" }
35
+ }
36
+ );
37
+ function validate(text, unit, min, max, step, required) {
38
+ if (!unit.trim()) return "A unit is required.";
39
+ if (min !== void 0 && !Number.isFinite(min) || max !== void 0 && !Number.isFinite(max) || min !== void 0 && max !== void 0 && min > max)
40
+ return "Invalid numeric range.";
41
+ if (step !== "any" && (!Number.isFinite(step) || step <= 0))
42
+ return "Step must be a positive finite number.";
43
+ if (text.trim() === "") return required ? "A value is required." : null;
44
+ if (!/^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i.test(text.trim()) || !Number.isFinite(Number(text)))
45
+ return "Enter a finite number.";
46
+ const number = Number(text);
47
+ if (min !== void 0 && number < min) return `Enter a value of at least ${min} ${unit}.`;
48
+ if (max !== void 0 && number > max) return `Enter a value of at most ${max} ${unit}.`;
49
+ if (step !== "any") {
50
+ const steps = (number - (min ?? 0)) / step;
51
+ if (Math.abs(steps - Math.round(steps)) > 1e-7)
52
+ return `Use increments of ${step} ${unit} from ${min ?? 0}.`;
53
+ }
54
+ return null;
55
+ }
56
+ function plainDecimal(value) {
57
+ return value.toLocaleString("en-US", { useGrouping: false, maximumFractionDigits: 20 });
58
+ }
59
+ var NumberInput = forwardRef((allProps, ref) => {
60
+ const {
61
+ label,
62
+ unit,
63
+ value,
64
+ defaultValue = null,
65
+ onValueChange,
66
+ onValidationChange,
67
+ min,
68
+ max,
69
+ step = "any",
70
+ size = "md",
71
+ description,
72
+ error,
73
+ required = false,
74
+ disabled = false,
75
+ readOnly = false,
76
+ className,
77
+ id,
78
+ onBlur,
79
+ onKeyDown,
80
+ "aria-describedby": describedBy,
81
+ ...props
82
+ } = allProps;
83
+ if (process.env.NODE_ENV !== "production") {
84
+ devValidate("NumberInput", NumberInputManifest.NumberInput.props, { ...allProps });
85
+ }
86
+ const labelRef = useRef(null);
87
+ const ids = usePartIds(["unit", "description", "error", "unknown"], {
88
+ id,
89
+ readRendered: () => labelRef.current?.htmlFor
90
+ });
91
+ const inputId = ids.base;
92
+ const inputRef = useRef(null);
93
+ const mergedRef = useMergedRefs(inputRef, ref);
94
+ const [local, setLocal] = useState(defaultValue);
95
+ const numeric = value === void 0 ? local : value;
96
+ const [draft, setDraft] = useState(null);
97
+ const text = draft && Object.is(draft.base, numeric) ? draft.text : numeric === null ? "" : String(numeric);
98
+ const validation = error || validate(text, unit, min, max, step, required);
99
+ const validationRef = useRef(onValidationChange);
100
+ validationRef.current = onValidationChange;
101
+ useEffect(() => {
102
+ inputRef.current?.setCustomValidity(validation ?? "");
103
+ validationRef.current?.(validation ?? null);
104
+ }, [validation]);
105
+ const commit = (next) => {
106
+ if (value === void 0) setLocal(next);
107
+ onValueChange?.(next);
108
+ };
109
+ const descriptions = joinIds(
110
+ describedBy,
111
+ ids.unit,
112
+ description && ids.description,
113
+ validation ? ids.error : text === "" && ids.unknown
114
+ );
115
+ return /* @__PURE__ */ jsxs(
116
+ "div",
117
+ {
118
+ className: clsx(
119
+ "flex min-w-0 flex-col gap-1u font-sans text-oprt-base normal-case text-oprt-text",
120
+ className
121
+ ),
122
+ children: [
123
+ /* @__PURE__ */ jsx(
124
+ "label",
125
+ {
126
+ ref: labelRef,
127
+ htmlFor: inputId,
128
+ className: "m-0 min-w-0 oprt-wrap-anywhere text-oprt-base font-medium text-oprt-text",
129
+ children: label
130
+ }
131
+ ),
132
+ /* @__PURE__ */ jsxs("div", { className: clsx(styles({ size, invalid: Boolean(validation) }), FORCED_FOCUS_WITHIN), children: [
133
+ /* @__PURE__ */ jsx(
134
+ "input",
135
+ {
136
+ ...props,
137
+ ref: mergedRef,
138
+ id: inputId,
139
+ type: "text",
140
+ role: "spinbutton",
141
+ inputMode: "decimal",
142
+ value: text,
143
+ disabled,
144
+ readOnly,
145
+ required,
146
+ "aria-valuemin": min,
147
+ "aria-valuemax": max,
148
+ "aria-valuenow": text !== "" && !validation ? plainDecimal(Number(text)) : void 0,
149
+ "aria-valuetext": validation ? `Invalid: ${text}` : text === "" ? "Unknown" : `${text} ${unit}`,
150
+ "aria-invalid": Boolean(validation) || void 0,
151
+ "aria-describedby": descriptions,
152
+ className: clsx(
153
+ "min-w-[min(calc(10ch_+_10_*_var(--oprt-tracking-md)_+_2px),100%)] flex-1 self-stretch border-0 bg-transparent font-mono text-oprt-md font-medium tabular-nums text-oprt-text outline-hidden disabled:cursor-not-allowed disabled:text-oprt-text-dim",
154
+ FORCED_NO_RESTING_OUTLINE
155
+ ),
156
+ onChange: (event) => {
157
+ if (disabled || readOnly) return;
158
+ const nextText = event.target.value;
159
+ const invalid = validate(nextText, unit, min, max, step, required);
160
+ const next = nextText.trim() === "" ? null : Number(nextText);
161
+ setDraft({ text: nextText, base: value === void 0 && !invalid ? next : numeric });
162
+ if (!invalid) commit(next);
163
+ },
164
+ onBlur: (event) => {
165
+ if (!validation) setDraft(null);
166
+ onBlur?.(event);
167
+ },
168
+ onKeyDown: (event) => {
169
+ onKeyDown?.(event);
170
+ if (event.defaultPrevented || disabled || readOnly) return;
171
+ let next;
172
+ if (event.key === "ArrowUp" || event.key === "ArrowDown") {
173
+ const delta = step === "any" ? 1 : step;
174
+ const base = text.trim() !== "" && Number.isFinite(Number(text)) ? Number(text) : min ?? 0;
175
+ next = Number((base + (event.key === "ArrowUp" ? delta : -delta)).toPrecision(14));
176
+ } else if (event.key === "Home" && min !== void 0) next = min;
177
+ else if (event.key === "End" && max !== void 0) next = max;
178
+ if (next === void 0) return;
179
+ event.preventDefault();
180
+ next = Math.min(max ?? Infinity, Math.max(min ?? -Infinity, next));
181
+ if (validate(String(next), unit, min, max, step, required)) return;
182
+ setDraft(null);
183
+ commit(next);
184
+ }
185
+ }
186
+ ),
187
+ /* @__PURE__ */ jsx("span", { id: ids.unit, className: "min-w-0 oprt-wrap-anywhere font-mono text-oprt-text-dim", children: unit || "Unit missing" })
188
+ ] }),
189
+ description && /* @__PURE__ */ jsx("p", { id: ids.description, className: "m-0 min-w-0 oprt-wrap-anywhere text-oprt-text-dim", children: description }),
190
+ validation ? (
191
+ // A caller's error is an alert, as in a Field (MultiSelect-R2); the field's own
192
+ // as-you-type message stays a description, so typing raises no alert per keystroke.
193
+ /* @__PURE__ */ jsx(
194
+ "p",
195
+ {
196
+ id: ids.error,
197
+ ...error ? { role: "alert" } : {},
198
+ className: "m-0 min-w-0 oprt-wrap-anywhere text-oprt-error",
199
+ children: validation
200
+ }
201
+ )
202
+ ) : text === "" && /* @__PURE__ */ jsx("p", { id: ids.unknown, className: "m-0 text-oprt-text-dim", children: "Unknown" })
203
+ ]
204
+ }
205
+ );
206
+ });
207
+ NumberInput.displayName = "NumberInput";
208
+ export {
209
+ NumberInput
210
+ };
@@ -0,0 +1,56 @@
1
+ // src/NumberInput/NumberInput.manifest.ts
2
+ var NumberInputManifest = {
3
+ NumberInput: {
4
+ description: "Numeric entry with an explicit unit, keyboard stepping, range and step validation, and unknown-value state.",
5
+ props: {
6
+ label: { type: "string", required: true },
7
+ unit: {
8
+ type: "string",
9
+ required: true,
10
+ description: "Visible and described unit such as m, kn or \xB0. Empty units are invalid; no conversion is performed."
11
+ },
12
+ value: {
13
+ type: "number",
14
+ description: "Controlled number or null for unknown. Invalid drafts stay visible and never emit NaN or out-of-range values."
15
+ },
16
+ defaultValue: {
17
+ type: "number",
18
+ description: "Initial uncontrolled number, or null (the default)."
19
+ },
20
+ onValueChange: {
21
+ type: "function",
22
+ description: "(value: number | null) => void. Emits valid numeric edits or null when cleared. Does not emit invalid drafts."
23
+ },
24
+ onValidationChange: {
25
+ type: "function",
26
+ description: "(error: string | null) => void. Reports draft and supplied-value validation; use this to block application submission while a draft is invalid."
27
+ },
28
+ min: { type: "number" },
29
+ max: { type: "number" },
30
+ step: {
31
+ type: "string",
32
+ default: "any",
33
+ description: "Positive number or 'any'. Numeric steps validate from min (or zero); Arrow keys use 1 for 'any'."
34
+ },
35
+ size: { type: "enum", values: ["sm", "md", "lg"], default: "md" },
36
+ disabled: { type: "boolean", default: false },
37
+ readOnly: { type: "boolean", default: false },
38
+ required: { type: "boolean", default: false },
39
+ description: { type: "string" },
40
+ error: {
41
+ type: "string",
42
+ description: "Caller-supplied validation error, displayed before built-in validation."
43
+ },
44
+ name: {
45
+ type: "string",
46
+ description: "Native form field name. Constraint validation blocks invalid numeric drafts."
47
+ }
48
+ },
49
+ composable_with: ["Card", "CoordinateInput"],
50
+ never_inside: ["Button"],
51
+ example: '<NumberInput label="Altitude" unit="m" value={altitude} onValueChange={setAltitude} min={0} max={20000} step={10} />'
52
+ }
53
+ };
54
+ export {
55
+ NumberInputManifest
56
+ };
@@ -0,0 +1,7 @@
1
+ // src/NumberInput/index.ts
2
+ import { NumberInput } from "./NumberInput.js";
3
+ import { NumberInputManifest } from "./NumberInput.manifest.js";
4
+ export {
5
+ NumberInput,
6
+ NumberInputManifest
7
+ };
@@ -0,0 +1,89 @@
1
+ "use client";
2
+
3
+ // src/OperationalStatus/OperationalStatus.tsx
4
+ import { forwardRef, useId } from "react";
5
+ import { cva } from "class-variance-authority";
6
+ import clsx from "clsx";
7
+ import { Badge } from "../Badge/Badge.js";
8
+ import { DescriptionList } from "../DescriptionList/DescriptionList.js";
9
+ import { devValidate } from "../_internal/devValidate.js";
10
+ import { formatUtcTimestamp, isValidTimestamp } from "../_internal/timestamp.js";
11
+ import { OperationalStatusManifest } from "./OperationalStatus.manifest.js";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ var statusStyles = cva(
14
+ "flex min-w-0 flex-col gap-1u font-sans text-oprt-base normal-case tracking-normal text-oprt-text"
15
+ );
16
+ var variants = {
17
+ current: "success",
18
+ stale: "warning",
19
+ partial: "warning",
20
+ unavailable: "error",
21
+ unknown: "neutral"
22
+ };
23
+ var OperationalStatus = forwardRef(
24
+ (allProps, ref) => {
25
+ const { state = "unknown", source, updatedAt, detail, className, ...props } = allProps;
26
+ const qualityId = `${useId()}-quality`;
27
+ if (process.env.NODE_ENV !== "production") {
28
+ devValidate("OperationalStatus", OperationalStatusManifest.OperationalStatus.props, {
29
+ ...allProps
30
+ });
31
+ }
32
+ const shown = isValidTimestamp(updatedAt) ? formatUtcTimestamp(updatedAt) : null;
33
+ const isoTime = isValidTimestamp(updatedAt) ? new Date(updatedAt).toISOString() : null;
34
+ const split = shown?.indexOf(" ") ?? -1;
35
+ return /* @__PURE__ */ jsxs(
36
+ "div",
37
+ {
38
+ role: "group",
39
+ "aria-labelledby": qualityId,
40
+ ...props,
41
+ ref,
42
+ className: clsx(statusStyles(), className),
43
+ children: [
44
+ /* @__PURE__ */ jsx(
45
+ DescriptionList,
46
+ {
47
+ layout: "details",
48
+ items: [
49
+ {
50
+ id: "quality",
51
+ label: /* @__PURE__ */ jsx("span", { id: qualityId, children: "Data quality" }),
52
+ value: /* @__PURE__ */ jsx(
53
+ Badge,
54
+ {
55
+ appearance: "text",
56
+ size: "md",
57
+ variant: variants[state],
58
+ className: "ml-auto tracking-oprt-sm",
59
+ children: state
60
+ }
61
+ )
62
+ },
63
+ { id: "source", label: "Source", value: source || "Unknown" },
64
+ {
65
+ id: "updated",
66
+ label: "Updated",
67
+ value: isoTime && shown ? (
68
+ // The date and the time wrap apart; neither breaks inside, so "UTC" stays with
69
+ // the time.
70
+ /* @__PURE__ */ jsxs("time", { dateTime: isoTime, className: "font-mono", children: [
71
+ /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: shown.slice(0, split) }),
72
+ " ",
73
+ /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: shown.slice(split + 1) })
74
+ ] })
75
+ ) : "Time unknown"
76
+ }
77
+ ]
78
+ }
79
+ ),
80
+ detail && /* @__PURE__ */ jsx("p", { className: "m-0 mt-1u oprt-wrap-anywhere text-oprt-text-dim", children: detail })
81
+ ]
82
+ }
83
+ );
84
+ }
85
+ );
86
+ OperationalStatus.displayName = "OperationalStatus";
87
+ export {
88
+ OperationalStatus
89
+ };
@@ -0,0 +1,39 @@
1
+ // src/OperationalStatus/OperationalStatus.manifest.ts
2
+ var OperationalStatusManifest = {
3
+ OperationalStatus: {
4
+ description: "Application-asserted data quality, source, and UTC update time in shared label/value detail rows.",
5
+ props: {
6
+ state: {
7
+ type: "enum",
8
+ values: ["current", "stale", "partial", "unavailable", "unknown"],
9
+ default: "unknown",
10
+ description: "Application assertion rendered as a text-only badge; never inferred from connection or the wall clock."
11
+ },
12
+ source: {
13
+ type: "string",
14
+ description: "Provenance label; defaults to Unknown."
15
+ },
16
+ updatedAt: {
17
+ type: "number",
18
+ description: "Epoch milliseconds, including zero. Shown as UTC to the second, 'YYYY-MM-DD HH:MM:SS UTC', with the date and the time wrapping separately; the machine-readable time element keeps the exact instant. Null, missing, or invalid renders Time unknown in the Updated row."
19
+ },
20
+ detail: {
21
+ type: "string",
22
+ description: "Missing coverage, stale threshold, quality, or last-known context."
23
+ }
24
+ },
25
+ composable_with: [
26
+ "AppShell",
27
+ "Inspector",
28
+ "DataGrid",
29
+ "EntityPreview",
30
+ "DescriptionList",
31
+ "Badge"
32
+ ],
33
+ never_inside: ["Button"],
34
+ example: '<OperationalStatus state="partial" source="Supplied report" updatedAt={lastReport} detail="One source has not reported." />'
35
+ }
36
+ };
37
+ export {
38
+ OperationalStatusManifest
39
+ };
@@ -0,0 +1,9 @@
1
+ // src/OperationalStatus/index.ts
2
+ import {
3
+ OperationalStatus
4
+ } from "./OperationalStatus.js";
5
+ import { OperationalStatusManifest } from "./OperationalStatus.manifest.js";
6
+ export {
7
+ OperationalStatus,
8
+ OperationalStatusManifest
9
+ };