@aglyn/shared-ui-jsx 1.0.0-beta.143

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 (261) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +63 -0
  4. package/src/index.d.ts +48 -0
  5. package/src/index.js +179 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/aglyn-text.d.ts +86 -0
  8. package/src/lib/components/aglyn-text.js +44 -0
  9. package/src/lib/components/aglyn-text.js.map +1 -0
  10. package/src/lib/components/app-link.d.ts +74 -0
  11. package/src/lib/components/app-link.js +139 -0
  12. package/src/lib/components/app-link.js.map +1 -0
  13. package/src/lib/components/aspect-ratio.d.ts +59 -0
  14. package/src/lib/components/aspect-ratio.js +153 -0
  15. package/src/lib/components/aspect-ratio.js.map +1 -0
  16. package/src/lib/components/background-image.component.d.ts +30 -0
  17. package/src/lib/components/background-image.component.js +42 -0
  18. package/src/lib/components/background-image.component.js.map +1 -0
  19. package/src/lib/components/card-columns.d.ts +86 -0
  20. package/src/lib/components/card-columns.js +148 -0
  21. package/src/lib/components/card-columns.js.map +1 -0
  22. package/src/lib/components/card-display.d.ts +36 -0
  23. package/src/lib/components/card-display.js +158 -0
  24. package/src/lib/components/card-display.js.map +1 -0
  25. package/src/lib/components/card-list-item.d.ts +35 -0
  26. package/src/lib/components/card-list-item.js +137 -0
  27. package/src/lib/components/card-list-item.js.map +1 -0
  28. package/src/lib/components/children-function-prop.d.ts +25 -0
  29. package/src/lib/components/children-function-prop.js +29 -0
  30. package/src/lib/components/children-function-prop.js.map +1 -0
  31. package/src/lib/components/confirmation-provider.component.d.ts +19 -0
  32. package/src/lib/components/confirmation-provider.component.js +83 -0
  33. package/src/lib/components/confirmation-provider.component.js.map +1 -0
  34. package/src/lib/components/container.d.ts +25 -0
  35. package/src/lib/components/container.js +62 -0
  36. package/src/lib/components/container.js.map +1 -0
  37. package/src/lib/components/data-table.component.d.ts +54 -0
  38. package/src/lib/components/data-table.component.js +211 -0
  39. package/src/lib/components/data-table.component.js.map +1 -0
  40. package/src/lib/components/dialog-confirm.d.ts +36 -0
  41. package/src/lib/components/dialog-confirm.js +74 -0
  42. package/src/lib/components/dialog-confirm.js.map +1 -0
  43. package/src/lib/components/ellipsis-pulse.component.d.ts +22 -0
  44. package/src/lib/components/ellipsis-pulse.component.js +51 -0
  45. package/src/lib/components/ellipsis-pulse.component.js.map +1 -0
  46. package/src/lib/components/emotion-cache-provider.d.ts +31 -0
  47. package/src/lib/components/emotion-cache-provider.js +40 -0
  48. package/src/lib/components/emotion-cache-provider.js.map +1 -0
  49. package/src/lib/components/empty-state.component.d.ts +63 -0
  50. package/src/lib/components/empty-state.component.js +214 -0
  51. package/src/lib/components/empty-state.component.js.map +1 -0
  52. package/src/lib/components/error-boundary.component.d.ts +28 -0
  53. package/src/lib/components/error-boundary.component.js +86 -0
  54. package/src/lib/components/error-boundary.component.js.map +1 -0
  55. package/src/lib/components/grid-buttons.d.ts +26 -0
  56. package/src/lib/components/grid-buttons.js +45 -0
  57. package/src/lib/components/grid-buttons.js.map +1 -0
  58. package/src/lib/components/grid-items.d.ts +103 -0
  59. package/src/lib/components/grid-items.js +336 -0
  60. package/src/lib/components/grid-items.js.map +1 -0
  61. package/src/lib/components/grid-list.d.ts +37 -0
  62. package/src/lib/components/grid-list.js +156 -0
  63. package/src/lib/components/grid-list.js.map +1 -0
  64. package/src/lib/components/help-tip.component.d.ts +30 -0
  65. package/src/lib/components/help-tip.component.js +139 -0
  66. package/src/lib/components/help-tip.component.js.map +1 -0
  67. package/src/lib/components/link-navigation-reporter.d.ts +24 -0
  68. package/src/lib/components/link-navigation-reporter.js +64 -0
  69. package/src/lib/components/link-navigation-reporter.js.map +1 -0
  70. package/src/lib/components/list-pagination.component.d.ts +57 -0
  71. package/src/lib/components/list-pagination.component.js +90 -0
  72. package/src/lib/components/list-pagination.component.js.map +1 -0
  73. package/src/lib/components/list-table.component.d.ts +155 -0
  74. package/src/lib/components/list-table.component.js +369 -0
  75. package/src/lib/components/list-table.component.js.map +1 -0
  76. package/src/lib/components/loading-layout-app.component.d.ts +35 -0
  77. package/src/lib/components/loading-layout-app.component.js +42 -0
  78. package/src/lib/components/loading-layout-app.component.js.map +1 -0
  79. package/src/lib/components/loading-modal-overlay.d.ts +30 -0
  80. package/src/lib/components/loading-modal-overlay.js +156 -0
  81. package/src/lib/components/loading-modal-overlay.js.map +1 -0
  82. package/src/lib/components/loading-modal.d.ts +19 -0
  83. package/src/lib/components/loading-modal.js +113 -0
  84. package/src/lib/components/loading-modal.js.map +1 -0
  85. package/src/lib/components/loading-text.component.d.ts +21 -0
  86. package/src/lib/components/loading-text.component.js +40 -0
  87. package/src/lib/components/loading-text.component.js.map +1 -0
  88. package/src/lib/components/mdi-icon/index.d.ts +2 -0
  89. package/src/lib/components/mdi-icon/index.js +4 -0
  90. package/src/lib/components/mdi-icon/index.js.map +1 -0
  91. package/src/lib/components/mdi-icon/md-icon-stack.d.ts +31 -0
  92. package/src/lib/components/mdi-icon/md-icon-stack.js +101 -0
  93. package/src/lib/components/mdi-icon/md-icon-stack.js.map +1 -0
  94. package/src/lib/components/mdi-icon/md-icon.d.ts +32 -0
  95. package/src/lib/components/mdi-icon/md-icon.js +147 -0
  96. package/src/lib/components/mdi-icon/md-icon.js.map +1 -0
  97. package/src/lib/components/mdi-icon/mdi-icon-from-id.d.ts +23 -0
  98. package/src/lib/components/mdi-icon/mdi-icon-from-id.js +35 -0
  99. package/src/lib/components/mdi-icon/mdi-icon-from-id.js.map +1 -0
  100. package/src/lib/components/mdi-icon/mdi-icon.d.ts +24 -0
  101. package/src/lib/components/mdi-icon/mdi-icon.js +46 -0
  102. package/src/lib/components/mdi-icon/mdi-icon.js.map +1 -0
  103. package/src/lib/components/measured-figures.component.d.ts +64 -0
  104. package/src/lib/components/measured-figures.component.js +161 -0
  105. package/src/lib/components/measured-figures.component.js.map +1 -0
  106. package/src/lib/components/menu.d.ts +45 -0
  107. package/src/lib/components/menu.js +229 -0
  108. package/src/lib/components/menu.js.map +1 -0
  109. package/src/lib/components/mui-shadow-dom.d.ts +38 -0
  110. package/src/lib/components/mui-shadow-dom.js +161 -0
  111. package/src/lib/components/mui-shadow-dom.js.map +1 -0
  112. package/src/lib/components/navigation-drawer.component.d.ts +31 -0
  113. package/src/lib/components/navigation-drawer.component.js +76 -0
  114. package/src/lib/components/navigation-drawer.component.js.map +1 -0
  115. package/src/lib/components/navigation-intent.d.ts +18 -0
  116. package/src/lib/components/navigation-intent.js +56 -0
  117. package/src/lib/components/navigation-intent.js.map +1 -0
  118. package/src/lib/components/navigation-view/index.d.ts +18 -0
  119. package/src/lib/components/navigation-view/index.js +19 -0
  120. package/src/lib/components/navigation-view/index.js.map +1 -0
  121. package/src/lib/components/navigation-view/navigation-view.d.ts +35 -0
  122. package/src/lib/components/navigation-view/navigation-view.js +175 -0
  123. package/src/lib/components/navigation-view/navigation-view.js.map +1 -0
  124. package/src/lib/components/next-link.d.ts +27 -0
  125. package/src/lib/components/next-link.js +88 -0
  126. package/src/lib/components/next-link.js.map +1 -0
  127. package/src/lib/components/popper-styled.component.d.ts +25 -0
  128. package/src/lib/components/popper-styled.component.js +129 -0
  129. package/src/lib/components/popper-styled.component.js.map +1 -0
  130. package/src/lib/components/quota-readout.component.d.ts +69 -0
  131. package/src/lib/components/quota-readout.component.js +52 -0
  132. package/src/lib/components/quota-readout.component.js.map +1 -0
  133. package/src/lib/components/resizeable-stack.d.ts +4 -0
  134. package/src/lib/components/resizeable-stack.js +23 -0
  135. package/src/lib/components/resizeable-stack.js.map +1 -0
  136. package/src/lib/components/row-actions-menu.component.d.ts +53 -0
  137. package/src/lib/components/row-actions-menu.component.js +132 -0
  138. package/src/lib/components/row-actions-menu.component.js.map +1 -0
  139. package/src/lib/components/ruler-guides.component.d.ts +35 -0
  140. package/src/lib/components/ruler-guides.component.js +166 -0
  141. package/src/lib/components/ruler-guides.component.js.map +1 -0
  142. package/src/lib/components/sandbox-frame.d.ts +42 -0
  143. package/src/lib/components/sandbox-frame.js +122 -0
  144. package/src/lib/components/sandbox-frame.js.map +1 -0
  145. package/src/lib/components/scroll-reaction.d.ts +59 -0
  146. package/src/lib/components/scroll-reaction.js +43 -0
  147. package/src/lib/components/scroll-reaction.js.map +1 -0
  148. package/src/lib/components/scroll-table.component.d.ts +124 -0
  149. package/src/lib/components/scroll-table.component.js +103 -0
  150. package/src/lib/components/scroll-table.component.js.map +1 -0
  151. package/src/lib/components/shadow-dom/index.d.ts +18 -0
  152. package/src/lib/components/shadow-dom/index.js +19 -0
  153. package/src/lib/components/shadow-dom/index.js.map +1 -0
  154. package/src/lib/components/shadow-dom/shadow-dom.d.ts +42 -0
  155. package/src/lib/components/shadow-dom/shadow-dom.js +123 -0
  156. package/src/lib/components/shadow-dom/shadow-dom.js.map +1 -0
  157. package/src/lib/components/splash-screen.d.ts +33 -0
  158. package/src/lib/components/splash-screen.js +105 -0
  159. package/src/lib/components/splash-screen.js.map +1 -0
  160. package/src/lib/components/sr-only.d.ts +20 -0
  161. package/src/lib/components/sr-only.js +25 -0
  162. package/src/lib/components/sr-only.js.map +1 -0
  163. package/src/lib/components/status-screen-plain.component.d.ts +27 -0
  164. package/src/lib/components/status-screen-plain.component.js +178 -0
  165. package/src/lib/components/status-screen-plain.component.js.map +1 -0
  166. package/src/lib/components/usage-meter.component.d.ts +30 -0
  167. package/src/lib/components/usage-meter.component.js +92 -0
  168. package/src/lib/components/usage-meter.component.js.map +1 -0
  169. package/src/lib/components/variable-text-field.component.d.ts +50 -0
  170. package/src/lib/components/variable-text-field.component.js +188 -0
  171. package/src/lib/components/variable-text-field.component.js.map +1 -0
  172. package/src/lib/components/zoomable-panning-component/index.d.ts +1 -0
  173. package/src/lib/components/zoomable-panning-component/index.js +3 -0
  174. package/src/lib/components/zoomable-panning-component/index.js.map +1 -0
  175. package/src/lib/components/zoomable-panning-component/util.d.ts +58 -0
  176. package/src/lib/components/zoomable-panning-component/util.js +114 -0
  177. package/src/lib/components/zoomable-panning-component/util.js.map +1 -0
  178. package/src/lib/components/zoomable-panning-component/zoomable-panning-component.d.ts +132 -0
  179. package/src/lib/components/zoomable-panning-component/zoomable-panning-component.js +728 -0
  180. package/src/lib/components/zoomable-panning-component/zoomable-panning-component.js.map +1 -0
  181. package/src/lib/const/aglyn-besigner-logo-full.d.ts +39 -0
  182. package/src/lib/const/aglyn-besigner-logo-full.js +146 -0
  183. package/src/lib/const/aglyn-besigner-logo-full.js.map +1 -0
  184. package/src/lib/const/aglyn-console-logo-full.d.ts +34 -0
  185. package/src/lib/const/aglyn-console-logo-full.js +142 -0
  186. package/src/lib/const/aglyn-console-logo-full.js.map +1 -0
  187. package/src/lib/const/aglyn-logo-class-keys.d.ts +30 -0
  188. package/src/lib/const/aglyn-logo-class-keys.js +32 -0
  189. package/src/lib/const/aglyn-logo-class-keys.js.map +1 -0
  190. package/src/lib/const/aglyn-logo-full.d.ts +29 -0
  191. package/src/lib/const/aglyn-logo-full.js +111 -0
  192. package/src/lib/const/aglyn-logo-full.js.map +1 -0
  193. package/src/lib/const/list-filter.d.ts +260 -0
  194. package/src/lib/const/list-filter.js +409 -0
  195. package/src/lib/const/list-filter.js.map +1 -0
  196. package/src/lib/const/prebuilt-components.d.ts +17 -0
  197. package/src/lib/const/prebuilt-components.js +22 -0
  198. package/src/lib/const/prebuilt-components.js.map +1 -0
  199. package/src/lib/const/svg-icons.d.ts +75 -0
  200. package/src/lib/const/svg-icons.js +313 -0
  201. package/src/lib/const/svg-icons.js.map +1 -0
  202. package/src/lib/const/table-pagination.d.ts +106 -0
  203. package/src/lib/const/table-pagination.js +106 -0
  204. package/src/lib/const/table-pagination.js.map +1 -0
  205. package/src/lib/contexts/confirmation.context.d.ts +996 -0
  206. package/src/lib/contexts/confirmation.context.js +49 -0
  207. package/src/lib/contexts/confirmation.context.js.map +1 -0
  208. package/src/lib/contexts/loading.context.d.ts +93 -0
  209. package/src/lib/contexts/loading.context.js +126 -0
  210. package/src/lib/contexts/loading.context.js.map +1 -0
  211. package/src/lib/hocs/create-hoc-with-context-consumer.d.ts +36 -0
  212. package/src/lib/hocs/create-hoc-with-context-consumer.js +44 -0
  213. package/src/lib/hocs/create-hoc-with-context-consumer.js.map +1 -0
  214. package/src/lib/hocs/with-hoc.d.ts +32 -0
  215. package/src/lib/hocs/with-hoc.js +37 -0
  216. package/src/lib/hocs/with-hoc.js.map +1 -0
  217. package/src/lib/hooks/mdi-icon/use-mdi-icon.d.ts +20 -0
  218. package/src/lib/hooks/mdi-icon/use-mdi-icon.js +48 -0
  219. package/src/lib/hooks/mdi-icon/use-mdi-icon.js.map +1 -0
  220. package/src/lib/hooks/mdi-icon/use-mdi-icons-fuzzy.d.ts +26 -0
  221. package/src/lib/hooks/mdi-icon/use-mdi-icons-fuzzy.js +73 -0
  222. package/src/lib/hooks/mdi-icon/use-mdi-icons-fuzzy.js.map +1 -0
  223. package/src/lib/hooks/mdi-icon/use-mdi-icons.d.ts +19 -0
  224. package/src/lib/hooks/mdi-icon/use-mdi-icons.js +49 -0
  225. package/src/lib/hooks/mdi-icon/use-mdi-icons.js.map +1 -0
  226. package/src/lib/hooks/router-events.d.ts +56 -0
  227. package/src/lib/hooks/router-events.js +88 -0
  228. package/src/lib/hooks/router-events.js.map +1 -0
  229. package/src/lib/hooks/use-async-effect.d.ts +24 -0
  230. package/src/lib/hooks/use-async-effect.js +44 -0
  231. package/src/lib/hooks/use-async-effect.js.map +1 -0
  232. package/src/lib/hooks/use-callback-param-ref.d.ts +19 -0
  233. package/src/lib/hooks/use-callback-param-ref.js +29 -0
  234. package/src/lib/hooks/use-callback-param-ref.js.map +1 -0
  235. package/src/lib/hooks/use-id.d.ts +21 -0
  236. package/src/lib/hooks/use-id.js +28 -0
  237. package/src/lib/hooks/use-id.js.map +1 -0
  238. package/src/lib/hooks/use-isomorphic-layout-effect.d.ts +19 -0
  239. package/src/lib/hooks/use-isomorphic-layout-effect.js +20 -0
  240. package/src/lib/hooks/use-isomorphic-layout-effect.js.map +1 -0
  241. package/src/lib/hooks/use-merge-refs.d.ts +38 -0
  242. package/src/lib/hooks/use-merge-refs.js +52 -0
  243. package/src/lib/hooks/use-merge-refs.js.map +1 -0
  244. package/src/lib/hooks/use-subscribable.d.ts +29 -0
  245. package/src/lib/hooks/use-subscribable.js +50 -0
  246. package/src/lib/hooks/use-subscribable.js.map +1 -0
  247. package/src/lib/types.d.ts +18 -0
  248. package/src/lib/types.js +18 -0
  249. package/src/lib/types.js.map +1 -0
  250. package/src/lib/utils/make-link-elements.d.ts +24 -0
  251. package/src/lib/utils/make-link-elements.js +32 -0
  252. package/src/lib/utils/make-link-elements.js.map +1 -0
  253. package/src/lib/utils/make-meta-elements.d.ts +24 -0
  254. package/src/lib/utils/make-meta-elements.js +32 -0
  255. package/src/lib/utils/make-meta-elements.js.map +1 -0
  256. package/src/lib/utils/scroll-overflow.d.ts +120 -0
  257. package/src/lib/utils/scroll-overflow.js +115 -0
  258. package/src/lib/utils/scroll-overflow.js.map +1 -0
  259. package/src/lib/utils/vendor.d.ts +17 -0
  260. package/src/lib/utils/vendor.js +18 -0
  261. package/src/lib/utils/vendor.js.map +1 -0
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ /**
19
+ * THE THREE WAYS A MEASURED NUMBER IS ALLOWED TO REACH A SCREEN.
20
+ *
21
+ * Every reporting surface in this product renders the same three things — a
22
+ * titled block, a count, and a rate — and each carries a rule that is easy to
23
+ * state and easy to lose:
24
+ *
25
+ * - **A count that is `null` draws a dash, never a zero.** "We have no
26
+ * record of this" and "this happened zero times" lead a reader to opposite
27
+ * conclusions, and a zero renders the first as the second.
28
+ * - **A rate prints its denominator on the same line as its percentage.**
29
+ * An open rate over `sent` and one over `delivered` are different numbers
30
+ * sharing a label; a reader comparing two rates must be able to see they
31
+ * are over different populations without hovering anything. The same
32
+ * ambiguity exists wherever a rate is quoted — a form's lead rate over
33
+ * submissions and over submissions that carried an address differ by
34
+ * however many people declined to give one.
35
+ * - **A rate that cannot be divided draws a dash and no number.** There is
36
+ * no branch here that substitutes a denominator to get something
37
+ * printable.
38
+ *
39
+ * They live in one module because a second copy is a second chance to render
40
+ * a percentage without its denominator — and the copy would be written by
41
+ * whoever adds the next card, in a file nobody tests for it. The email
42
+ * plugin's `report-figures` re-exports these rather than keeping its own,
43
+ * which is what stopped the console's forms surface from becoming that copy.
44
+ */ import { Stack, Typography } from "@mui/material";
45
+ /**
46
+ * A rate, or `null` when one cannot honestly be taken.
47
+ *
48
+ * `null` on a zero or unrecorded denominator. Those are not the same as 0%:
49
+ * a rate over nothing is undefined, and printing it as zero states a measured
50
+ * failure where there was no measurement.
51
+ */ export function measuredRate(numerator, denominator, denominatorLabel) {
52
+ if (numerator == null || denominator == null) return null;
53
+ const top = Number(numerator);
54
+ const bottom = Number(denominator);
55
+ if (!Number.isFinite(top) || !Number.isFinite(bottom) || bottom <= 0) {
56
+ return null;
57
+ }
58
+ return {
59
+ value: top / bottom,
60
+ numerator: top,
61
+ denominator: bottom,
62
+ denominatorLabel
63
+ };
64
+ }
65
+ /** A titled block. */ export function Section(props) {
66
+ return /*#__PURE__*/ _jsxs(Stack, {
67
+ spacing: 1,
68
+ children: [
69
+ /*#__PURE__*/ _jsx(Typography, {
70
+ variant: "overline",
71
+ color: "text.secondary",
72
+ children: props.title
73
+ }),
74
+ props.children
75
+ ]
76
+ });
77
+ }
78
+ Section.displayName = 'Section';
79
+ /**
80
+ * One count, with the population it describes named underneath.
81
+ *
82
+ * `null` renders as an em dash and NOT as zero, which is the whole reason
83
+ * this takes `number | null` rather than defaulting.
84
+ */ export function Figure(props) {
85
+ return /*#__PURE__*/ _jsxs(Stack, {
86
+ sx: {
87
+ minWidth: 140
88
+ },
89
+ children: [
90
+ /*#__PURE__*/ _jsx(Typography, {
91
+ variant: "h6",
92
+ children: props.value === null ? '—' : props.value.toLocaleString()
93
+ }),
94
+ /*#__PURE__*/ _jsx(Typography, {
95
+ variant: "body2",
96
+ children: props.label
97
+ }),
98
+ /*#__PURE__*/ _jsx(Typography, {
99
+ variant: "caption",
100
+ color: "text.secondary",
101
+ children: props.value === null ? 'not recorded' : props.note
102
+ })
103
+ ]
104
+ });
105
+ }
106
+ Figure.displayName = 'Figure';
107
+ /** A percentage to one decimal place. */ export function percent(value) {
108
+ return `${(value * 100).toFixed(1)}%`;
109
+ }
110
+ /**
111
+ * One rate, with its denominator spelled out on the same line.
112
+ *
113
+ * The denominator is rendered as `12 of 480 delivered` rather than as a
114
+ * tooltip or a footnote, because a reader comparing two rates has to be able
115
+ * to see they are over different populations without hovering anything. A
116
+ * `null` rate draws the dash and no number at all.
117
+ */ export function RateRow(props) {
118
+ const { label, rate } = props;
119
+ return /*#__PURE__*/ _jsxs(Stack, {
120
+ direction: "row",
121
+ spacing: 2,
122
+ sx: {
123
+ justifyContent: 'space-between',
124
+ alignItems: 'baseline'
125
+ },
126
+ children: [
127
+ /*#__PURE__*/ _jsx(Typography, {
128
+ variant: "body2",
129
+ children: label
130
+ }),
131
+ rate ? /*#__PURE__*/ _jsxs(Stack, {
132
+ direction: "row",
133
+ spacing: 1,
134
+ sx: {
135
+ alignItems: 'baseline'
136
+ },
137
+ children: [
138
+ /*#__PURE__*/ _jsx(Typography, {
139
+ variant: "body2",
140
+ sx: {
141
+ fontWeight: 'bold'
142
+ },
143
+ children: percent(rate.value)
144
+ }),
145
+ /*#__PURE__*/ _jsx(Typography, {
146
+ variant: "caption",
147
+ color: "text.secondary",
148
+ children: `${rate.numerator.toLocaleString()} of ${rate.denominator.toLocaleString()} ${rate.denominatorLabel}`
149
+ })
150
+ ]
151
+ }) : /*#__PURE__*/ _jsx(Typography, {
152
+ variant: "caption",
153
+ color: "text.secondary",
154
+ children: '— not enough recorded to compute'
155
+ })
156
+ ]
157
+ });
158
+ }
159
+ RateRow.displayName = 'RateRow';
160
+
161
+ //# sourceMappingURL=measured-figures.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx/src/lib/components/measured-figures.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\n/**\n * THE THREE WAYS A MEASURED NUMBER IS ALLOWED TO REACH A SCREEN.\n *\n * Every reporting surface in this product renders the same three things — a\n * titled block, a count, and a rate — and each carries a rule that is easy to\n * state and easy to lose:\n *\n * - **A count that is `null` draws a dash, never a zero.** \"We have no\n * record of this\" and \"this happened zero times\" lead a reader to opposite\n * conclusions, and a zero renders the first as the second.\n * - **A rate prints its denominator on the same line as its percentage.**\n * An open rate over `sent` and one over `delivered` are different numbers\n * sharing a label; a reader comparing two rates must be able to see they\n * are over different populations without hovering anything. The same\n * ambiguity exists wherever a rate is quoted — a form's lead rate over\n * submissions and over submissions that carried an address differ by\n * however many people declined to give one.\n * - **A rate that cannot be divided draws a dash and no number.** There is\n * no branch here that substitutes a denominator to get something\n * printable.\n *\n * They live in one module because a second copy is a second chance to render\n * a percentage without its denominator — and the copy would be written by\n * whoever adds the next card, in a file nobody tests for it. The email\n * plugin's `report-figures` re-exports these rather than keeping its own,\n * which is what stopped the console's forms surface from becoming that copy.\n */\n\nimport { Stack, Typography } from '@mui/material'\nimport type { ReactNode } from 'react'\n\n/**\n * A rate, together with everything needed to say what it is a rate OF.\n *\n * The producer decides whether a rate can honestly be taken; a `null` in\n * place of one of these is how it says no. Nothing here formats — `value` is\n * 0–1 and the display multiplies — so a model can be tested on the number\n * without a renderer, and this file cannot invent a denominator.\n */\nexport interface MeasuredRate {\n /** 0–1. Multiply for display; a producer never formats. */\n value: number\n numerator: number\n denominator: number\n /** Reader-facing name of the denominator, e.g. `'delivered'`. */\n denominatorLabel: string\n}\n\n/**\n * A rate, or `null` when one cannot honestly be taken.\n *\n * `null` on a zero or unrecorded denominator. Those are not the same as 0%:\n * a rate over nothing is undefined, and printing it as zero states a measured\n * failure where there was no measurement.\n */\nexport function measuredRate(\n numerator: number | null | undefined,\n denominator: number | null | undefined,\n denominatorLabel: string,\n): MeasuredRate | null {\n if (numerator == null || denominator == null) return null\n const top = Number(numerator)\n const bottom = Number(denominator)\n if (!Number.isFinite(top) || !Number.isFinite(bottom) || bottom <= 0) {\n return null\n }\n return { value: top / bottom, numerator: top, denominator: bottom, denominatorLabel }\n}\n\n/** A titled block. */\nexport function Section(props: { title: string; children: ReactNode }) {\n return (\n <Stack spacing={1}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {props.title}\n </Typography>\n {props.children}\n </Stack>\n )\n}\nSection.displayName = 'Section'\n\n/**\n * One count, with the population it describes named underneath.\n *\n * `null` renders as an em dash and NOT as zero, which is the whole reason\n * this takes `number | null` rather than defaulting.\n */\nexport function Figure(props: {\n label: string\n value: number | null\n note: string\n}) {\n return (\n <Stack sx={{ minWidth: 140 }}>\n <Typography variant=\"h6\">\n {props.value === null ? '—' : props.value.toLocaleString()}\n </Typography>\n <Typography variant=\"body2\">{props.label}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {props.value === null ? 'not recorded' : props.note}\n </Typography>\n </Stack>\n )\n}\nFigure.displayName = 'Figure'\n\n/** A percentage to one decimal place. */\nexport function percent(value: number): string {\n return `${(value * 100).toFixed(1)}%`\n}\n\n/**\n * One rate, with its denominator spelled out on the same line.\n *\n * The denominator is rendered as `12 of 480 delivered` rather than as a\n * tooltip or a footnote, because a reader comparing two rates has to be able\n * to see they are over different populations without hovering anything. A\n * `null` rate draws the dash and no number at all.\n */\nexport function RateRow(props: { label: string; rate: MeasuredRate | null }) {\n const { label, rate } = props\n return (\n <Stack\n direction=\"row\"\n spacing={2}\n sx={{ justifyContent: 'space-between', alignItems: 'baseline' }}\n >\n <Typography variant=\"body2\">{label}</Typography>\n {rate ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'baseline' }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 'bold' }}>\n {percent(rate.value)}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${rate.numerator.toLocaleString()} of ${rate.denominator.toLocaleString()} ${rate.denominatorLabel}`}\n </Typography>\n </Stack>\n ) : (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'— not enough recorded to compute'}\n </Typography>\n )}\n </Stack>\n )\n}\nRateRow.displayName = 'RateRow'\n"],"names":["Stack","Typography","measuredRate","numerator","denominator","denominatorLabel","top","Number","bottom","isFinite","value","Section","props","spacing","variant","color","title","children","displayName","Figure","sx","minWidth","toLocaleString","label","note","percent","toFixed","RateRow","rate","direction","justifyContent","alignItems","fontWeight"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BC,GAED,SAASA,KAAK,EAAEC,UAAU,QAAQ,gBAAe;AAoBjD;;;;;;CAMC,GACD,OAAO,SAASC,aACdC,SAAoC,EACpCC,WAAsC,EACtCC,gBAAwB;IAExB,IAAIF,aAAa,QAAQC,eAAe,MAAM,OAAO;IACrD,MAAME,MAAMC,OAAOJ;IACnB,MAAMK,SAASD,OAAOH;IACtB,IAAI,CAACG,OAAOE,QAAQ,CAACH,QAAQ,CAACC,OAAOE,QAAQ,CAACD,WAAWA,UAAU,GAAG;QACpE,OAAO;IACT;IACA,OAAO;QAAEE,OAAOJ,MAAME;QAAQL,WAAWG;QAAKF,aAAaI;QAAQH;IAAiB;AACtF;AAEA,oBAAoB,GACpB,OAAO,SAASM,QAAQC,KAA6C;IACnE,qBACE,MAACZ;QAAMa,SAAS;;0BACd,KAACZ;gBAAWa,SAAQ;gBAAWC,OAAM;0BAClCH,MAAMI,KAAK;;YAEbJ,MAAMK,QAAQ;;;AAGrB;AACAN,QAAQO,WAAW,GAAG;AAEtB;;;;;CAKC,GACD,OAAO,SAASC,OAAOP,KAItB;IACC,qBACE,MAACZ;QAAMoB,IAAI;YAAEC,UAAU;QAAI;;0BACzB,KAACpB;gBAAWa,SAAQ;0BACjBF,MAAMF,KAAK,KAAK,OAAO,MAAME,MAAMF,KAAK,CAACY,cAAc;;0BAE1D,KAACrB;gBAAWa,SAAQ;0BAASF,MAAMW,KAAK;;0BACxC,KAACtB;gBAAWa,SAAQ;gBAAUC,OAAM;0BACjCH,MAAMF,KAAK,KAAK,OAAO,iBAAiBE,MAAMY,IAAI;;;;AAI3D;AACAL,OAAOD,WAAW,GAAG;AAErB,uCAAuC,GACvC,OAAO,SAASO,QAAQf,KAAa;IACnC,OAAO,GAAG,AAACA,CAAAA,QAAQ,GAAE,EAAGgB,OAAO,CAAC,GAAG,CAAC,CAAC;AACvC;AAEA;;;;;;;CAOC,GACD,OAAO,SAASC,QAAQf,KAAmD;IACzE,MAAM,EAAEW,KAAK,EAAEK,IAAI,EAAE,GAAGhB;IACxB,qBACE,MAACZ;QACC6B,WAAU;QACVhB,SAAS;QACTO,IAAI;YAAEU,gBAAgB;YAAiBC,YAAY;QAAW;;0BAE9D,KAAC9B;gBAAWa,SAAQ;0BAASS;;YAC5BK,qBACC,MAAC5B;gBAAM6B,WAAU;gBAAMhB,SAAS;gBAAGO,IAAI;oBAAEW,YAAY;gBAAW;;kCAC9D,KAAC9B;wBAAWa,SAAQ;wBAAQM,IAAI;4BAAEY,YAAY;wBAAO;kCAClDP,QAAQG,KAAKlB,KAAK;;kCAErB,KAACT;wBAAWa,SAAQ;wBAAUC,OAAM;kCACjC,GAAGa,KAAKzB,SAAS,CAACmB,cAAc,GAAG,IAAI,EAAEM,KAAKxB,WAAW,CAACkB,cAAc,GAAG,CAAC,EAAEM,KAAKvB,gBAAgB,EAAE;;;+BAI1G,KAACJ;gBAAWa,SAAQ;gBAAUC,OAAM;0BACjC;;;;AAKX;AACAY,QAAQT,WAAW,GAAG"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type MdiIconProps } from './mdi-icon/mdi-icon';
18
+ import { type BoxProps as MuiBoxProps, type DividerProps, type ListItemIconProps as MuiListItemIconProps, type ListItemTextProps as MuiListItemTextProps, type ListSubheaderProps as MuiListSubheaderProps, type MenuItemProps as MuiMenuItemProps, type MenuProps as MuiMenuProps, type TypographyProps as MuiTypographyProps } from '@mui/material';
19
+ import { type ReactElement } from 'react';
20
+ type ItemTypes = 'item' | 'divider' | 'subheader' | undefined | never;
21
+ type ItemTypeProps = MuiMenuItemProps & {
22
+ type?: 'item';
23
+ icon?: MdiIconProps;
24
+ endIcon?: MdiIconProps;
25
+ ListItemTextProps?: Partial<MuiListItemTextProps>;
26
+ ListItemIconProps?: Partial<MuiListItemIconProps>;
27
+ EndIconTypographyProps?: Partial<MuiTypographyProps>;
28
+ };
29
+ type DividerTypeProps = DividerProps & {
30
+ type: 'divider';
31
+ };
32
+ type SubheaderTypeProps = MuiListSubheaderProps & {
33
+ type: 'subheader';
34
+ };
35
+ export type MenuItemProps<T extends ItemTypes = ItemTypes> = JSX.OverrideableComponentProps & Conditional<T, 'divider', DividerTypeProps, Conditional<T, 'subheader', SubheaderTypeProps, Conditional<T, 'item' | undefined | never, ItemTypeProps, ItemTypeProps>>>;
36
+ export interface MenuProps extends MuiBoxProps {
37
+ items: MenuItemProps[];
38
+ context?: boolean;
39
+ dense?: boolean;
40
+ MenuProps?: Partial<MuiMenuProps>;
41
+ children: ReactElement;
42
+ horizontalOrigin?: MuiMenuProps['anchorOrigin']['horizontal'];
43
+ }
44
+ export declare const Menu: import("react").ForwardRefExoticComponent<Omit<MenuProps, "ref"> & import("react").RefAttributes<any>>;
45
+ export default Menu;
@@ -0,0 +1,229 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ /**
5
+ * @license
6
+ * Copyright 2026 Aglyn LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ import { MdiIcon } from "./mdi-icon/mdi-icon.js";
20
+ import { mergeSxProps } from "@aglyn/shared-ui-theme";
21
+ import { Box, Divider, ListItemIcon, ListItemText, ListSubheader as MuiListSubheader, Menu as MuiMenu, MenuItem as MuiMenuItem, Typography } from "@mui/material";
22
+ import { Children, cloneElement, forwardRef, useCallback, useState } from "react";
23
+ const ITEM_HEIGHT = 48;
24
+ const defaultState = {
25
+ anchorEl: null,
26
+ mouseX: null,
27
+ mouseY: null
28
+ };
29
+ export const Menu = /*#__PURE__*/ forwardRef((props, ref)=>{
30
+ var _ref;
31
+ var _child_props_onClick, _child_props;
32
+ const { children, items = [], context, className, sx, dense, MenuProps, horizontalOrigin } = props, rest = _object_without_properties_loose(props, [
33
+ "children",
34
+ "items",
35
+ "context",
36
+ "className",
37
+ "sx",
38
+ "dense",
39
+ "MenuProps",
40
+ "horizontalOrigin"
41
+ ]);
42
+ const [state, setState] = useState(defaultState);
43
+ // One left edge per menu (AGL-1216): if any row has an icon, the rows
44
+ // that do not get an empty gutter of the same width instead of collapsing
45
+ // against the item padding.
46
+ const hasAnyIcon = items.some((entry)=>{
47
+ var _entry_icon;
48
+ return entry == null ? void 0 : (_entry_icon = entry.icon) == null ? void 0 : _entry_icon.path;
49
+ });
50
+ const child = Children.only(children);
51
+ const onChildClick = (_child_props = child.props) == null ? void 0 : (_child_props_onClick = _child_props.onClick) == null ? void 0 : _child_props_onClick.bind(null);
52
+ const handleClose = ()=>setState(defaultState);
53
+ const handleClick = useCallback((event)=>{
54
+ if (onChildClick) {
55
+ onChildClick.call(null, event);
56
+ }
57
+ if (context) {
58
+ event.preventDefault();
59
+ }
60
+ setState({
61
+ anchorEl: event.currentTarget,
62
+ mouseX: event.clientX - 2,
63
+ mouseY: event.clientY - 4
64
+ });
65
+ }, [
66
+ context,
67
+ onChildClick
68
+ ]);
69
+ const open = Boolean(state.anchorEl || state.mouseY);
70
+ const cloned = /*#__PURE__*/ cloneElement(child, {
71
+ onClick: handleClick,
72
+ 'aria-expanded': open ? 'true' : 'false'
73
+ });
74
+ // MUI v9: PaperProps → slotProps.paper. Accept both for backward compat.
75
+ const _ref1 = MenuProps || {}, { PaperProps: legacyPaperProps, slotProps: menuSlotProps } = _ref1, menuProps = _object_without_properties_loose(_ref1, [
76
+ "PaperProps",
77
+ "slotProps"
78
+ ]);
79
+ const resolvedPaperProps = (_ref = legacyPaperProps != null ? legacyPaperProps : menuSlotProps == null ? void 0 : menuSlotProps.paper) != null ? _ref : {};
80
+ const { sx: paperSx } = resolvedPaperProps, paperProps = _object_without_properties_loose(resolvedPaperProps, [
81
+ "sx"
82
+ ]);
83
+ const arrowPlacement = horizontalOrigin === 'right' ? {
84
+ right: 14
85
+ } : horizontalOrigin === 'center' ? {
86
+ right: 'auto',
87
+ left: 'auto'
88
+ } : {
89
+ left: 14
90
+ };
91
+ return /*#__PURE__*/ _jsxs(Box, _extends({
92
+ ref: ref,
93
+ component: 'div',
94
+ onContextMenu: context && handleClick,
95
+ sx: mergeSxProps(context && {
96
+ cursor: 'context-menu'
97
+ }, sx)
98
+ }, rest, {
99
+ children: [
100
+ cloned,
101
+ /*#__PURE__*/ _jsx(MuiMenu, _extends({
102
+ anchorEl: context ? undefined : state.anchorEl,
103
+ anchorReference: context ? 'anchorPosition' : undefined,
104
+ anchorPosition: !context || !state.mouseY ? undefined : {
105
+ top: state.mouseY,
106
+ left: state.mouseX
107
+ },
108
+ anchorOrigin: context ? undefined : {
109
+ vertical: 'bottom',
110
+ horizontal: horizontalOrigin || 'left'
111
+ },
112
+ transformOrigin: context ? undefined : {
113
+ vertical: 'top',
114
+ horizontal: horizontalOrigin || 'left'
115
+ },
116
+ slotProps: {
117
+ paper: context ? undefined : _extends({
118
+ elevation: 0,
119
+ sx: mergeSxProps({
120
+ maxHeight: ITEM_HEIGHT * 4.5,
121
+ width: '30ch',
122
+ filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
123
+ backgroundColor: 'surface.main',
124
+ marginTop: 0.5,
125
+ '&:before': _extends({
126
+ content: '""',
127
+ display: 'block',
128
+ position: 'absolute',
129
+ top: 0,
130
+ width: 10,
131
+ height: 10,
132
+ bgcolor: 'surface.main',
133
+ transform: 'translateY(-50%) rotate(45deg)',
134
+ zIndex: 0
135
+ }, arrowPlacement)
136
+ }, paperSx)
137
+ }, paperProps)
138
+ },
139
+ // getContentAnchorEl={null}
140
+ open: open,
141
+ onClose: handleClose
142
+ }, menuProps, {
143
+ children: items.map((_0, _1)=>{
144
+ let _ref = [
145
+ _0,
146
+ _1
147
+ ], [_ref1, ..._rest] = _ref, { onClick, children, type, icon, endIcon, ListItemTextProps, ListItemIconProps, EndIconTypographyProps, key: keyProp } = _ref1, item = _object_without_properties_loose(_ref1, [
148
+ "onClick",
149
+ "children",
150
+ "type",
151
+ "icon",
152
+ "endIcon",
153
+ "ListItemTextProps",
154
+ "ListItemIconProps",
155
+ "EndIconTypographyProps",
156
+ "key"
157
+ ]), [i] = _rest;
158
+ var _ref2;
159
+ const key = (_ref2 = keyProp != null ? keyProp : item.id) != null ? _ref2 : i;
160
+ switch(type){
161
+ case 'subheader':
162
+ return /*#__PURE__*/ _jsx(MuiListSubheader, _extends({
163
+ onClick: onClick
164
+ }, item, {
165
+ children: children
166
+ }), key);
167
+ case 'divider':
168
+ return /*#__PURE__*/ _jsx(Divider, _extends({
169
+ onClick: onClick
170
+ }, item, {
171
+ children: children
172
+ }), key);
173
+ case 'item':
174
+ default:
175
+ return /*#__PURE__*/ _jsxs(MuiMenuItem, _extends({
176
+ dense: dense,
177
+ onClick: (e)=>{
178
+ handleClose();
179
+ onClick && onClick(e);
180
+ }
181
+ }, item, {
182
+ children: [
183
+ (icon == null ? void 0 : icon.path) ? /*#__PURE__*/ _jsx(ListItemIcon, _extends({}, ListItemIconProps, {
184
+ children: /*#__PURE__*/ _jsx(MdiIcon, _extends({
185
+ fontSize: "small"
186
+ }, icon))
187
+ })) : hasAnyIcon ? // Reserve the icon gutter so every label in the menu
188
+ // shares one left edge (AGL-1216). Iconless rows used
189
+ // to render no gutter at all, and callers compensated
190
+ // with `ListItemText inset` — but MUI's inset is 56px
191
+ // while a dense ListItemIcon reserves 36px, so a menu
192
+ // mixing icon rows, inset rows and bare rows showed
193
+ // THREE different left edges.
194
+ /*#__PURE__*/ _jsx(ListItemIcon, _extends({}, ListItemIconProps)) : null,
195
+ /*#__PURE__*/ _jsx(ListItemText, _extends({}, ListItemTextProps, {
196
+ // The spacer above already provides the alignment
197
+ // `inset` was standing in for; letting both apply
198
+ // would double-indent every existing caller.
199
+ inset: hasAnyIcon ? false : ListItemTextProps == null ? void 0 : ListItemTextProps.inset,
200
+ children: children
201
+ })),
202
+ !(endIcon == null ? void 0 : endIcon.path) || !endIcon ? null : /*#__PURE__*/ _jsx(Typography, _extends({
203
+ variant: "body2"
204
+ }, EndIconTypographyProps, {
205
+ sx: [
206
+ {
207
+ color: "text.secondary"
208
+ },
209
+ ...Array.isArray(EndIconTypographyProps == null ? void 0 : EndIconTypographyProps.sx) ? EndIconTypographyProps.sx : [
210
+ EndIconTypographyProps == null ? void 0 : EndIconTypographyProps.sx
211
+ ]
212
+ ],
213
+ children: !(endIcon == null ? void 0 : endIcon.path) ? endIcon : /*#__PURE__*/ _jsx(MdiIcon, _extends({
214
+ fontSize: "small"
215
+ }, endIcon))
216
+ }))
217
+ ]
218
+ }), key);
219
+ }
220
+ })
221
+ }))
222
+ ]
223
+ }));
224
+ });
225
+ Menu.displayName = 'Menu';
226
+ Menu.aglyn = true;
227
+ export default Menu;
228
+
229
+ //# sourceMappingURL=menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx/src/lib/components/menu.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { MdiIcon, type MdiIconProps } from './mdi-icon/mdi-icon'\nimport { mergeSxProps } from '@aglyn/shared-ui-theme'\nimport {\n Box,\n type BoxProps as MuiBoxProps,\n Divider,\n type DividerProps,\n ListItemIcon,\n type ListItemIconProps as MuiListItemIconProps,\n ListItemText,\n type ListItemTextProps as MuiListItemTextProps,\n ListSubheader as MuiListSubheader,\n type ListSubheaderProps as MuiListSubheaderProps,\n Menu as MuiMenu,\n MenuItem as MuiMenuItem,\n type MenuItemProps as MuiMenuItemProps,\n type MenuProps as MuiMenuProps,\n Typography,\n type TypographyProps as MuiTypographyProps,\n} from '@mui/material'\nimport {\n Children,\n cloneElement,\n forwardRef,\n type MouseEvent,\n type MouseEventHandler,\n type ReactElement,\n useCallback,\n useState,\n} from 'react'\n\nconst ITEM_HEIGHT = 48\nconst defaultState: { anchorEl: Element; mouseX: number; mouseY: number } = {\n anchorEl: null,\n mouseX: null,\n mouseY: null,\n}\n\ntype ItemTypes = 'item' | 'divider' | 'subheader' | undefined | never\ntype ItemTypeProps = MuiMenuItemProps & {\n type?: 'item'\n icon?: MdiIconProps\n endIcon?: MdiIconProps\n ListItemTextProps?: Partial<MuiListItemTextProps>\n ListItemIconProps?: Partial<MuiListItemIconProps>\n EndIconTypographyProps?: Partial<MuiTypographyProps>\n}\ntype DividerTypeProps = DividerProps & { type: 'divider' }\ntype SubheaderTypeProps = MuiListSubheaderProps & { type: 'subheader' }\n\nexport type MenuItemProps<T extends ItemTypes = ItemTypes> =\n JSX.OverrideableComponentProps &\n Conditional<\n T,\n 'divider',\n DividerTypeProps,\n Conditional<\n T,\n 'subheader',\n SubheaderTypeProps,\n Conditional<T, 'item' | undefined | never, ItemTypeProps, ItemTypeProps>\n >\n >\n\n/* eslint-disable-next-line */\nexport interface MenuProps extends MuiBoxProps {\n items: MenuItemProps[]\n context?: boolean\n dense?: boolean\n MenuProps?: Partial<MuiMenuProps>\n children: ReactElement\n horizontalOrigin?: MuiMenuProps['anchorOrigin']['horizontal']\n}\n\nexport const Menu = forwardRef<any, MenuProps>((props, ref) => {\n const {\n children,\n items = [],\n context,\n className,\n sx,\n dense,\n MenuProps,\n horizontalOrigin,\n ...rest\n } = props\n\n const [state, setState] = useState(defaultState)\n // One left edge per menu (AGL-1216): if any row has an icon, the rows\n // that do not get an empty gutter of the same width instead of collapsing\n // against the item padding.\n const hasAnyIcon = (items as any[]).some(\n (entry) => (entry as any)?.icon?.path,\n )\n const child = Children.only(children) as ReactElement<any>\n const onChildClick = (child.props as any)?.onClick?.bind(null) as MouseEventHandler\n const handleClose = () => setState(defaultState)\n const handleClick = useCallback(\n (event: MouseEvent<any>) => {\n if (onChildClick) {\n onChildClick.call(null, event)\n }\n if (context) {\n event.preventDefault()\n }\n setState({\n anchorEl: event.currentTarget,\n mouseX: event.clientX - 2,\n mouseY: event.clientY - 4,\n })\n },\n [context, onChildClick],\n )\n const open = Boolean(state.anchorEl || state.mouseY)\n const cloned = cloneElement(child, {\n onClick: handleClick,\n 'aria-expanded': open ? 'true' : 'false',\n })\n\n // MUI v9: PaperProps → slotProps.paper. Accept both for backward compat.\n const { PaperProps: legacyPaperProps, slotProps: menuSlotProps, ...menuProps } = MenuProps || ({} as any)\n const resolvedPaperProps = legacyPaperProps ?? menuSlotProps?.paper ?? {}\n const { sx: paperSx, ...paperProps } = resolvedPaperProps\n const arrowPlacement =\n horizontalOrigin === 'right'\n ? { right: 14 }\n : horizontalOrigin === 'center'\n ? { right: 'auto', left: 'auto' }\n : { left: 14 }\n\n return (\n <Box\n ref={ref}\n component={'div'}\n onContextMenu={context && handleClick}\n sx={mergeSxProps(context && { cursor: 'context-menu' }, sx)}\n {...rest}\n >\n {cloned}\n <MuiMenu\n anchorEl={context ? undefined : state.anchorEl}\n anchorReference={context ? 'anchorPosition' : undefined}\n anchorPosition={\n !context || !state.mouseY\n ? undefined\n : {\n top: state.mouseY,\n left: state.mouseX,\n }\n }\n anchorOrigin={\n context\n ? undefined\n : {\n vertical: 'bottom',\n horizontal: horizontalOrigin || 'left',\n }\n }\n transformOrigin={\n context\n ? undefined\n : {\n vertical: 'top',\n horizontal: horizontalOrigin || 'left',\n }\n }\n slotProps={{\n paper: context\n ? undefined\n : {\n elevation: 0,\n sx: mergeSxProps(\n {\n maxHeight: ITEM_HEIGHT * 4.5,\n width: '30ch',\n filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',\n backgroundColor: 'surface.main',\n marginTop: 0.5,\n '&:before': {\n content: '\"\"',\n display: 'block',\n position: 'absolute',\n top: 0,\n width: 10,\n height: 10,\n bgcolor: 'surface.main',\n transform: 'translateY(-50%) rotate(45deg)',\n zIndex: 0,\n ...arrowPlacement,\n },\n },\n paperSx,\n ),\n ...paperProps,\n },\n }}\n // getContentAnchorEl={null}\n open={open}\n onClose={handleClose}\n {...menuProps}\n >\n {/* Whether ANY row in this menu carries an icon decides the gutter\n for the rows that do not — see the ListItemIcon spacer below. */}\n {items.map(\n (\n {\n onClick,\n children,\n type,\n icon,\n endIcon,\n ListItemTextProps,\n ListItemIconProps,\n EndIconTypographyProps,\n key: keyProp,\n ...item\n }: any,\n i,\n ) => {\n const key = keyProp ?? item.id ?? i\n\n switch (type) {\n case 'subheader':\n return (\n <MuiListSubheader\n key={key}\n onClick={onClick}\n {...(item as any)}\n >\n {children}\n </MuiListSubheader>\n )\n case 'divider':\n return (\n <Divider key={key} onClick={onClick} {...(item as any)}>\n {children}\n </Divider>\n )\n case 'item':\n default:\n return (\n <MuiMenuItem\n dense={dense}\n key={key}\n onClick={(e) => {\n handleClose()\n onClick && onClick(e)\n }}\n {...item}\n >\n {icon?.path ? (\n <ListItemIcon {...ListItemIconProps}>\n <MdiIcon fontSize=\"small\" {...icon} />\n </ListItemIcon>\n ) : hasAnyIcon ? (\n // Reserve the icon gutter so every label in the menu\n // shares one left edge (AGL-1216). Iconless rows used\n // to render no gutter at all, and callers compensated\n // with `ListItemText inset` — but MUI's inset is 56px\n // while a dense ListItemIcon reserves 36px, so a menu\n // mixing icon rows, inset rows and bare rows showed\n // THREE different left edges.\n <ListItemIcon {...ListItemIconProps} />\n ) : null}\n <ListItemText\n {...ListItemTextProps}\n // The spacer above already provides the alignment\n // `inset` was standing in for; letting both apply\n // would double-indent every existing caller.\n inset={hasAnyIcon ? false : ListItemTextProps?.inset}\n >\n {children}\n </ListItemText>\n {!endIcon?.path || !endIcon ? null : (\n <Typography\n variant=\"body2\"\n {...EndIconTypographyProps}\n sx={[{\n color: \"text.secondary\"\n }, ...(Array.isArray(EndIconTypographyProps?.sx) ? EndIconTypographyProps.sx : [EndIconTypographyProps?.sx])]}>\n {!endIcon?.path ? (\n endIcon\n ) : (\n <MdiIcon fontSize=\"small\" {...endIcon} />\n )}\n </Typography>\n )}\n </MuiMenuItem>\n );\n }\n },\n )}\n </MuiMenu>\n </Box>\n );\n})\n\nMenu.displayName = 'Menu'\nMenu.aglyn = true\n\nexport default Menu\n"],"names":["MdiIcon","mergeSxProps","Box","Divider","ListItemIcon","ListItemText","ListSubheader","MuiListSubheader","Menu","MuiMenu","MenuItem","MuiMenuItem","Typography","Children","cloneElement","forwardRef","useCallback","useState","ITEM_HEIGHT","defaultState","anchorEl","mouseX","mouseY","props","ref","legacyPaperProps","child","children","items","context","className","sx","dense","MenuProps","horizontalOrigin","rest","state","setState","hasAnyIcon","some","entry","icon","path","only","onChildClick","onClick","bind","handleClose","handleClick","event","call","preventDefault","currentTarget","clientX","clientY","open","Boolean","cloned","PaperProps","slotProps","menuSlotProps","menuProps","resolvedPaperProps","paper","paperSx","paperProps","arrowPlacement","right","left","component","onContextMenu","cursor","undefined","anchorReference","anchorPosition","top","anchorOrigin","vertical","horizontal","transformOrigin","elevation","maxHeight","width","filter","backgroundColor","marginTop","content","display","position","height","bgcolor","transform","zIndex","onClose","map","type","endIcon","ListItemTextProps","ListItemIconProps","EndIconTypographyProps","key","keyProp","item","i","id","e","fontSize","inset","variant","color","Array","isArray","displayName","aglyn"],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ export type MuiShadowRendererProps = {
18
+ container?: Node;
19
+ ssr?: boolean;
20
+ children?: JSX.Children;
21
+ };
22
+ export type MuiShadowRenderer = (props: MuiShadowRendererProps) => JSX.Node;
23
+ export type CreateShadowRootOptions = {
24
+ render: MuiShadowRenderer;
25
+ };
26
+ export interface MuiShadowRootProps {
27
+ mode?: 'open' | 'closed';
28
+ delegatesFocus?: boolean;
29
+ styleSheets?: globalThis.CSSStyleSheet[];
30
+ ssr?: boolean;
31
+ children?: JSX.Children;
32
+ }
33
+ export declare function useMuiShadowDomContext(): Node;
34
+ export declare function withMuiShadowRoot(Tag: any | keyof JSX.IntrinsicElements, options: CreateShadowRootOptions): import("react").ForwardRefExoticComponent<MuiShadowRootProps & import("react").RefAttributes<Element>>;
35
+ export declare function createMuiShadowDomProxy(target?: Partial<JSX.IntrinsicElementMap>, key?: string, render?: MuiShadowRenderer): Partial<JSX.IntrinsicElementMap<any>>;
36
+ export declare const MuiShadowDomRenderer: (props: MuiShadowRendererProps) => import("react").JSX.Element;
37
+ export declare const MuiShadowDom: Partial<JSX.IntrinsicElementMap<any>>;
38
+ export default MuiShadowDom;