@hjmds/react 1.12.1 → 1.13.1

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 (356) hide show
  1. package/dist/actions.d.ts +4 -0
  2. package/dist/actions.d.ts.map +1 -1
  3. package/dist/actions.js +4 -1
  4. package/dist/actions.js.map +1 -1
  5. package/dist/activity-heatmap.d.ts +4 -1
  6. package/dist/activity-heatmap.d.ts.map +1 -1
  7. package/dist/activity-heatmap.js +1 -1
  8. package/dist/activity-heatmap.js.map +1 -1
  9. package/dist/advanced-display.d.ts +31 -3
  10. package/dist/advanced-display.d.ts.map +1 -1
  11. package/dist/advanced-display.js +26 -27
  12. package/dist/advanced-display.js.map +1 -1
  13. package/dist/advanced-forms.d.ts +27 -2
  14. package/dist/advanced-forms.d.ts.map +1 -1
  15. package/dist/advanced-forms.js +11 -7
  16. package/dist/advanced-forms.js.map +1 -1
  17. package/dist/affix.d.ts +4 -1
  18. package/dist/affix.d.ts.map +1 -1
  19. package/dist/affix.js +2 -2
  20. package/dist/affix.js.map +1 -1
  21. package/dist/agreement.d.ts +3 -0
  22. package/dist/agreement.d.ts.map +1 -1
  23. package/dist/agreement.js +14 -3
  24. package/dist/agreement.js.map +1 -1
  25. package/dist/anchor.d.ts +5 -0
  26. package/dist/anchor.d.ts.map +1 -1
  27. package/dist/anchor.js +2 -2
  28. package/dist/anchor.js.map +1 -1
  29. package/dist/asset.d.ts +8 -1
  30. package/dist/asset.d.ts.map +1 -1
  31. package/dist/asset.js +4 -4
  32. package/dist/asset.js.map +1 -1
  33. package/dist/auth-screen.d.ts +5 -0
  34. package/dist/auth-screen.d.ts.map +1 -1
  35. package/dist/auth-screen.js +2 -1
  36. package/dist/auth-screen.js.map +1 -1
  37. package/dist/bottom-cta.d.ts +5 -0
  38. package/dist/bottom-cta.d.ts.map +1 -1
  39. package/dist/bottom-cta.js +2 -2
  40. package/dist/bottom-cta.js.map +1 -1
  41. package/dist/bottom-info.d.ts +5 -0
  42. package/dist/bottom-info.d.ts.map +1 -1
  43. package/dist/bottom-info.js +2 -2
  44. package/dist/bottom-info.js.map +1 -1
  45. package/dist/bottom-navigation.d.ts +3 -0
  46. package/dist/bottom-navigation.d.ts.map +1 -1
  47. package/dist/bottom-navigation.js +2 -1
  48. package/dist/bottom-navigation.js.map +1 -1
  49. package/dist/breadcrumb.d.ts +3 -0
  50. package/dist/breadcrumb.d.ts.map +1 -1
  51. package/dist/breadcrumb.js +2 -2
  52. package/dist/breadcrumb.js.map +1 -1
  53. package/dist/calendar.d.ts +4 -1
  54. package/dist/calendar.d.ts.map +1 -1
  55. package/dist/calendar.js +2 -2
  56. package/dist/calendar.js.map +1 -1
  57. package/dist/carousel-motion.d.ts +3 -0
  58. package/dist/carousel-motion.d.ts.map +1 -1
  59. package/dist/carousel-motion.js +1 -1
  60. package/dist/carousel-motion.js.map +1 -1
  61. package/dist/carousel.d.ts +3 -0
  62. package/dist/carousel.d.ts.map +1 -1
  63. package/dist/carousel.js +2 -2
  64. package/dist/carousel.js.map +1 -1
  65. package/dist/celebration.d.ts.map +1 -1
  66. package/dist/celebration.js.map +1 -1
  67. package/dist/clipboard.d.ts.map +1 -1
  68. package/dist/clipboard.js +6 -2
  69. package/dist/clipboard.js.map +1 -1
  70. package/dist/code-block.d.ts +4 -1
  71. package/dist/code-block.d.ts.map +1 -1
  72. package/dist/code-block.js +1 -1
  73. package/dist/code-block.js.map +1 -1
  74. package/dist/collapsible.d.ts +3 -0
  75. package/dist/collapsible.d.ts.map +1 -1
  76. package/dist/collapsible.js +2 -2
  77. package/dist/collapsible.js.map +1 -1
  78. package/dist/color-picker.d.ts +4 -1
  79. package/dist/color-picker.d.ts.map +1 -1
  80. package/dist/color-picker.js +2 -2
  81. package/dist/color-picker.js.map +1 -1
  82. package/dist/command-palette.d.ts +6 -0
  83. package/dist/command-palette.d.ts.map +1 -1
  84. package/dist/command-palette.js +49 -15
  85. package/dist/command-palette.js.map +1 -1
  86. package/dist/composition-style.d.ts +14 -1
  87. package/dist/composition-style.d.ts.map +1 -1
  88. package/dist/composition-style.js.map +1 -1
  89. package/dist/content-transition.d.ts +6 -2
  90. package/dist/content-transition.d.ts.map +1 -1
  91. package/dist/content-transition.js +4 -4
  92. package/dist/content-transition.js.map +1 -1
  93. package/dist/context-menu.d.ts +4 -1
  94. package/dist/context-menu.d.ts.map +1 -1
  95. package/dist/context-menu.js +2 -2
  96. package/dist/context-menu.js.map +1 -1
  97. package/dist/data-table.d.ts +3 -0
  98. package/dist/data-table.d.ts.map +1 -1
  99. package/dist/data-table.js +31 -11
  100. package/dist/data-table.js.map +1 -1
  101. package/dist/date-picker.d.ts +4 -1
  102. package/dist/date-picker.d.ts.map +1 -1
  103. package/dist/date-picker.js +2 -2
  104. package/dist/date-picker.js.map +1 -1
  105. package/dist/date-range.d.ts +4 -1
  106. package/dist/date-range.d.ts.map +1 -1
  107. package/dist/date-range.js +2 -2
  108. package/dist/date-range.js.map +1 -1
  109. package/dist/display.d.ts +4 -0
  110. package/dist/display.d.ts.map +1 -1
  111. package/dist/display.js.map +1 -1
  112. package/dist/duration-field.d.ts +4 -2
  113. package/dist/duration-field.d.ts.map +1 -1
  114. package/dist/duration-field.js +2 -2
  115. package/dist/duration-field.js.map +1 -1
  116. package/dist/effect-surface.d.ts +4 -2
  117. package/dist/effect-surface.d.ts.map +1 -1
  118. package/dist/effect-surface.js +2 -2
  119. package/dist/effect-surface.js.map +1 -1
  120. package/dist/evidence.d.ts +1 -1
  121. package/dist/evidence.js +1 -1
  122. package/dist/evidence.js.map +1 -1
  123. package/dist/feedback.d.ts +24 -13
  124. package/dist/feedback.d.ts.map +1 -1
  125. package/dist/feedback.js +17 -15
  126. package/dist/feedback.js.map +1 -1
  127. package/dist/file-picker.d.ts +5 -0
  128. package/dist/file-picker.d.ts.map +1 -1
  129. package/dist/file-picker.js +2 -2
  130. package/dist/file-picker.js.map +1 -1
  131. package/dist/floating-action-button.d.ts.map +1 -1
  132. package/dist/floating-action-button.js.map +1 -1
  133. package/dist/folder-preview.d.ts +4 -1
  134. package/dist/folder-preview.d.ts.map +1 -1
  135. package/dist/folder-preview.js +2 -2
  136. package/dist/folder-preview.js.map +1 -1
  137. package/dist/forms.d.ts +35 -3
  138. package/dist/forms.d.ts.map +1 -1
  139. package/dist/forms.js +55 -36
  140. package/dist/forms.js.map +1 -1
  141. package/dist/gravity-letters.d.ts +4 -2
  142. package/dist/gravity-letters.d.ts.map +1 -1
  143. package/dist/gravity-letters.js +2 -2
  144. package/dist/gravity-letters.js.map +1 -1
  145. package/dist/grid-reveal.d.ts +4 -2
  146. package/dist/grid-reveal.d.ts.map +1 -1
  147. package/dist/grid-reveal.js +2 -2
  148. package/dist/grid-reveal.js.map +1 -1
  149. package/dist/heading.d.ts +5 -0
  150. package/dist/heading.d.ts.map +1 -1
  151. package/dist/heading.js +8 -1
  152. package/dist/heading.js.map +1 -1
  153. package/dist/inline-confirm.d.ts +3 -0
  154. package/dist/inline-confirm.d.ts.map +1 -1
  155. package/dist/inline-confirm.js +3 -3
  156. package/dist/inline-confirm.js.map +1 -1
  157. package/dist/internal/message-reactions.d.ts +16 -0
  158. package/dist/internal/message-reactions.d.ts.map +1 -0
  159. package/dist/internal/message-reactions.js +42 -0
  160. package/dist/internal/message-reactions.js.map +1 -0
  161. package/dist/internal/spinner.d.ts +18 -0
  162. package/dist/internal/spinner.d.ts.map +1 -0
  163. package/dist/internal/spinner.js +10 -0
  164. package/dist/internal/spinner.js.map +1 -0
  165. package/dist/layout.d.ts +12 -0
  166. package/dist/layout.d.ts.map +1 -1
  167. package/dist/layout.js +6 -6
  168. package/dist/layout.js.map +1 -1
  169. package/dist/masonry.d.ts +4 -1
  170. package/dist/masonry.d.ts.map +1 -1
  171. package/dist/masonry.js +5 -3
  172. package/dist/masonry.js.map +1 -1
  173. package/dist/mentions.d.ts.map +1 -1
  174. package/dist/mentions.js +12 -3
  175. package/dist/mentions.js.map +1 -1
  176. package/dist/menu-morph.d.ts +8 -1
  177. package/dist/menu-morph.d.ts.map +1 -1
  178. package/dist/menu-morph.js +3 -3
  179. package/dist/menu-morph.js.map +1 -1
  180. package/dist/menubar.d.ts +4 -1
  181. package/dist/menubar.d.ts.map +1 -1
  182. package/dist/menubar.js +4 -3
  183. package/dist/menubar.js.map +1 -1
  184. package/dist/modal.d.ts.map +1 -1
  185. package/dist/modal.js +4 -1
  186. package/dist/modal.js.map +1 -1
  187. package/dist/navigation-bar.d.ts +4 -1
  188. package/dist/navigation-bar.d.ts.map +1 -1
  189. package/dist/navigation-bar.js +2 -2
  190. package/dist/navigation-bar.js.map +1 -1
  191. package/dist/navigation.d.ts +5 -0
  192. package/dist/navigation.d.ts.map +1 -1
  193. package/dist/navigation.js +6 -6
  194. package/dist/navigation.js.map +1 -1
  195. package/dist/notification-bell.d.ts +4 -1
  196. package/dist/notification-bell.d.ts.map +1 -1
  197. package/dist/notification-bell.js +5 -3
  198. package/dist/notification-bell.js.map +1 -1
  199. package/dist/number-field.d.ts +11 -0
  200. package/dist/number-field.d.ts.map +1 -1
  201. package/dist/number-field.js +8 -3
  202. package/dist/number-field.js.map +1 -1
  203. package/dist/overlay-stack.d.ts.map +1 -1
  204. package/dist/overlay-stack.js.map +1 -1
  205. package/dist/overlays.d.ts +5 -0
  206. package/dist/overlays.d.ts.map +1 -1
  207. package/dist/overlays.js +35 -11
  208. package/dist/overlays.js.map +1 -1
  209. package/dist/pagination.d.ts +5 -0
  210. package/dist/pagination.d.ts.map +1 -1
  211. package/dist/pagination.js +2 -2
  212. package/dist/pagination.js.map +1 -1
  213. package/dist/popover.d.ts.map +1 -1
  214. package/dist/popover.js +5 -4
  215. package/dist/popover.js.map +1 -1
  216. package/dist/portal.d.ts.map +1 -1
  217. package/dist/portal.js +2 -1
  218. package/dist/portal.js.map +1 -1
  219. package/dist/provider-button.d.ts +5 -0
  220. package/dist/provider-button.d.ts.map +1 -1
  221. package/dist/provider-button.js +2 -2
  222. package/dist/provider-button.js.map +1 -1
  223. package/dist/provider.d.ts.map +1 -1
  224. package/dist/provider.js.map +1 -1
  225. package/dist/qr-code.d.ts +4 -1
  226. package/dist/qr-code.d.ts.map +1 -1
  227. package/dist/qr-code.js +2 -2
  228. package/dist/qr-code.js.map +1 -1
  229. package/dist/reaction-picker.d.ts +6 -2
  230. package/dist/reaction-picker.d.ts.map +1 -1
  231. package/dist/reaction-picker.js +20 -4
  232. package/dist/reaction-picker.js.map +1 -1
  233. package/dist/saved-items.d.ts +33 -0
  234. package/dist/saved-items.d.ts.map +1 -0
  235. package/dist/saved-items.js +19 -0
  236. package/dist/saved-items.js.map +1 -0
  237. package/dist/screen-flows.d.ts +326 -0
  238. package/dist/screen-flows.d.ts.map +1 -0
  239. package/dist/screen-flows.js +222 -0
  240. package/dist/screen-flows.js.map +1 -0
  241. package/dist/screens.d.ts +120 -0
  242. package/dist/screens.d.ts.map +1 -0
  243. package/dist/screens.js +66 -0
  244. package/dist/screens.js.map +1 -0
  245. package/dist/select.d.ts +6 -0
  246. package/dist/select.d.ts.map +1 -1
  247. package/dist/select.js +13 -3
  248. package/dist/select.js.map +1 -1
  249. package/dist/selection.d.ts +28 -1
  250. package/dist/selection.d.ts.map +1 -1
  251. package/dist/selection.js +12 -12
  252. package/dist/selection.js.map +1 -1
  253. package/dist/side-panel.d.ts.map +1 -1
  254. package/dist/side-panel.js.map +1 -1
  255. package/dist/sidebar.d.ts +3 -0
  256. package/dist/sidebar.d.ts.map +1 -1
  257. package/dist/sidebar.js +2 -2
  258. package/dist/sidebar.js.map +1 -1
  259. package/dist/skip-nav.d.ts.map +1 -1
  260. package/dist/skip-nav.js.map +1 -1
  261. package/dist/slider.d.ts +5 -0
  262. package/dist/slider.d.ts.map +1 -1
  263. package/dist/slider.js +2 -1
  264. package/dist/slider.js.map +1 -1
  265. package/dist/sortable.d.ts +3 -0
  266. package/dist/sortable.d.ts.map +1 -1
  267. package/dist/sortable.js +1 -1
  268. package/dist/sortable.js.map +1 -1
  269. package/dist/splitter.d.ts +5 -0
  270. package/dist/splitter.d.ts.map +1 -1
  271. package/dist/splitter.js +28 -3
  272. package/dist/splitter.js.map +1 -1
  273. package/dist/step-player.d.ts +4 -1
  274. package/dist/step-player.d.ts.map +1 -1
  275. package/dist/step-player.js +2 -2
  276. package/dist/step-player.js.map +1 -1
  277. package/dist/steps.d.ts +5 -0
  278. package/dist/steps.d.ts.map +1 -1
  279. package/dist/steps.js +2 -2
  280. package/dist/steps.js.map +1 -1
  281. package/dist/styles.css +256 -70
  282. package/dist/styles.layered.css +256 -70
  283. package/dist/supplemental-display.d.ts +4 -0
  284. package/dist/supplemental-display.d.ts.map +1 -1
  285. package/dist/supplemental-display.js +7 -4
  286. package/dist/supplemental-display.js.map +1 -1
  287. package/dist/supplemental-navigation.d.ts +5 -0
  288. package/dist/supplemental-navigation.d.ts.map +1 -1
  289. package/dist/supplemental-navigation.js +2 -2
  290. package/dist/supplemental-navigation.js.map +1 -1
  291. package/dist/swipe-actions.d.ts +4 -1
  292. package/dist/swipe-actions.d.ts.map +1 -1
  293. package/dist/swipe-actions.js +2 -2
  294. package/dist/swipe-actions.js.map +1 -1
  295. package/dist/tags-input.d.ts +5 -0
  296. package/dist/tags-input.d.ts.map +1 -1
  297. package/dist/tags-input.js +2 -2
  298. package/dist/tags-input.js.map +1 -1
  299. package/dist/task-list.d.ts +4 -1
  300. package/dist/task-list.d.ts.map +1 -1
  301. package/dist/task-list.js +3 -3
  302. package/dist/task-list.js.map +1 -1
  303. package/dist/text-formats.d.ts +5 -0
  304. package/dist/text-formats.d.ts.map +1 -1
  305. package/dist/text-formats.js +2 -1
  306. package/dist/text-formats.js.map +1 -1
  307. package/dist/theme.d.ts.map +1 -1
  308. package/dist/theme.js +22 -2
  309. package/dist/theme.js.map +1 -1
  310. package/dist/thinking-orb.d.ts +4 -1
  311. package/dist/thinking-orb.d.ts.map +1 -1
  312. package/dist/thinking-orb.js +2 -2
  313. package/dist/thinking-orb.js.map +1 -1
  314. package/dist/toast.d.ts.map +1 -1
  315. package/dist/toast.js +10 -4
  316. package/dist/toast.js.map +1 -1
  317. package/dist/toggle-group.d.ts +3 -0
  318. package/dist/toggle-group.d.ts.map +1 -1
  319. package/dist/toggle-group.js +2 -1
  320. package/dist/toggle-group.js.map +1 -1
  321. package/dist/top-bar.d.ts +5 -0
  322. package/dist/top-bar.d.ts.map +1 -1
  323. package/dist/top-bar.js +2 -2
  324. package/dist/top-bar.js.map +1 -1
  325. package/dist/top.d.ts +5 -0
  326. package/dist/top.d.ts.map +1 -1
  327. package/dist/top.js +2 -2
  328. package/dist/top.js.map +1 -1
  329. package/dist/tour.d.ts.map +1 -1
  330. package/dist/tour.js +3 -2
  331. package/dist/tour.js.map +1 -1
  332. package/dist/transfer-list.d.ts +3 -0
  333. package/dist/transfer-list.d.ts.map +1 -1
  334. package/dist/transfer-list.js +2 -2
  335. package/dist/transfer-list.js.map +1 -1
  336. package/dist/tree.d.ts +3 -0
  337. package/dist/tree.d.ts.map +1 -1
  338. package/dist/tree.js +17 -5
  339. package/dist/tree.js.map +1 -1
  340. package/dist/upload-item.d.ts +5 -0
  341. package/dist/upload-item.d.ts.map +1 -1
  342. package/dist/upload-item.js +2 -2
  343. package/dist/upload-item.js.map +1 -1
  344. package/dist/virtual-list.d.ts +4 -1
  345. package/dist/virtual-list.d.ts.map +1 -1
  346. package/dist/virtual-list.js +2 -2
  347. package/dist/virtual-list.js.map +1 -1
  348. package/dist/voice-note.d.ts +4 -1
  349. package/dist/voice-note.d.ts.map +1 -1
  350. package/dist/voice-note.js +2 -2
  351. package/dist/voice-note.js.map +1 -1
  352. package/dist/watermark.d.ts +4 -1
  353. package/dist/watermark.d.ts.map +1 -1
  354. package/dist/watermark.js +2 -2
  355. package/dist/watermark.js.map +1 -1
  356. package/package.json +18 -3
package/dist/mentions.js CHANGED
@@ -1,10 +1,15 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { layer } from "@hjmds/design-contracts/foundations";
3
+ import { comboboxRecipe } from "@hjmds/design-contracts/recipes";
2
4
  import { findActiveMentionTrigger, resolveMentionInsertion, } from "@hjmds/design-contracts/components/mentions";
3
5
  import { forwardRef, useEffect, useId, useRef, useState, } from "react";
4
6
  import { TextArea } from "./forms.js";
5
7
  import { classNames, composeRefs } from "./internal.js";
6
8
  import { AnchoredPortal, useAnchoredPopup } from "./portal.js";
7
- export const Mentions = forwardRef(function Mentions({ value, onValueChange, triggers, candidates, onMentionQueryChange, emptyMessage, listLabel, renderCandidate, className, ...textAreaProps }, forwardedRef) {
9
+ export const Mentions = forwardRef(function Mentions({ value, onValueChange, triggers, candidates, onMentionQueryChange, emptyMessage, listLabel, renderCandidate, className,
10
+ // Inherited from TextAreaProps; taken here so placement moves the whole
11
+ // mentions block (field + candidate popup anchor), not only the inner field.
12
+ layoutStyle, ...textAreaProps }, forwardedRef) {
8
13
  const inputRef = useRef(null);
9
14
  const [match, setMatch] = useState(null);
10
15
  const [activeIndex, setActiveIndex] = useState(0);
@@ -61,9 +66,13 @@ export const Mentions = forwardRef(function Mentions({ value, onValueChange, tri
61
66
  }
62
67
  };
63
68
  const position = useAnchoredPopup(inputRef, open ? list : null, {
64
- placement: "bottom", align: "start", matchAnchorWidth: true, zIndex: 900,
69
+ placement: "bottom", align: "start", matchAnchorWidth: true, zIndex: layer.dropdown,
70
+ // The candidate list is Combobox's popover contract verbatim (mentions.ts), so its offset and edge padding are
71
+ // comboboxRecipe.popover's 8/8. Until 2026-10-06 the helper defaults (8 and 16) applied, a Web-only 16 edge.
72
+ gap: comboboxRecipe.popover.sideOffset,
73
+ viewportPadding: comboboxRecipe.popover.collisionPadding,
65
74
  });
66
- return (_jsxs("div", { className: classNames("hjm-mentions", className), children: [_jsx(TextArea, { ...textAreaProps, ref: composeRefs(inputRef, forwardedRef), value: value, role: "combobox", "aria-expanded": open, "aria-controls": open ? id : undefined, "aria-autocomplete": "list", "aria-activedescendant": open && activeCandidate ? `${id}-${activeCandidate.id}` : undefined, onChange: (event) => {
75
+ return (_jsxs("div", { className: classNames("hjm-mentions", className), style: layoutStyle, children: [_jsx(TextArea, { ...textAreaProps, ref: composeRefs(inputRef, forwardedRef), value: value, role: "combobox", "aria-expanded": open, "aria-controls": open ? id : undefined, "aria-autocomplete": "list", "aria-activedescendant": open && activeCandidate ? `${id}-${activeCandidate.id}` : undefined, onChange: (event) => {
67
76
  onValueChange(event.target.value);
68
77
  syncMatch(event.target.value, event.target.selectionStart ?? event.target.value.length);
69
78
  }, onKeyUp: (event) => {
@@ -1 +1 @@
1
- {"version":3,"file":"mentions.js","sourceRoot":"","sources":["../src/mentions.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n findActiveMentionTrigger,\n resolveMentionInsertion,\n type MentionMatch,\n type MentionTriggerConfig,\n} from \"@hjmds/design-contracts/components/mentions\";\nimport {\n forwardRef,\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { TextArea, type TextAreaProps } from \"./forms.js\";\nimport { classNames, composeRefs } from \"./internal.js\";\nimport { AnchoredPortal, useAnchoredPopup } from \"./portal.js\";\n\nexport type MentionCandidate = Readonly<{\n id: string;\n label: string;\n /** Text inserted after the trigger character; defaults to `label`. */\n insertText?: string;\n description?: string;\n}>;\n\nexport type MentionsProps<TriggerId extends string = string> =\n Omit<TextAreaProps, \"value\" | \"defaultValue\" | \"onChange\" | \"children\"> &\n Readonly<{\n value: string;\n onValueChange: (value: string) => void;\n triggers: readonly MentionTriggerConfig<TriggerId>[];\n /** Candidates for the active query; the product owns filtering and loading. */\n candidates: readonly MentionCandidate[];\n /** Fires whenever the active trigger match changes, including to null. */\n onMentionQueryChange?: (match: MentionMatch<TriggerId> | null) => void;\n /** Localized message shown when the popup is open with no candidates. */\n emptyMessage: string;\n /** Localized accessible name for the candidate list. */\n listLabel: string;\n renderCandidate?: (candidate: MentionCandidate) => ReactNode;\n }>;\n\nexport const Mentions = forwardRef(function Mentions<TriggerId extends string = string>(\n {\n value,\n onValueChange,\n triggers,\n candidates,\n onMentionQueryChange,\n emptyMessage,\n listLabel,\n renderCandidate,\n className,\n ...textAreaProps\n }: MentionsProps<TriggerId>,\n forwardedRef: React.Ref<HTMLTextAreaElement>,\n) {\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const [match, setMatch] = useState<MentionMatch<TriggerId> | null>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n const [list, setList] = useState<HTMLDivElement | null>(null);\n const id = `${useId().replaceAll(\":\", \"\")}-mentions`;\n const open = match !== null;\n const activeCandidate = candidates[Math.min(activeIndex, Math.max(candidates.length - 1, 0))];\n\n const notifyRef = useRef(onMentionQueryChange);\n notifyRef.current = onMentionQueryChange;\n useEffect(() => { notifyRef.current?.(match); }, [match]);\n\n const syncMatch = (text: string, cursor: number) => {\n // The contract owns trigger detection, including \"a space closes it\" and\n // \"the nearer trigger wins\"; this component only reports the cursor.\n const next = findActiveMentionTrigger(text, cursor, triggers);\n setMatch((previous) => (previous?.triggerStart === next?.triggerStart && previous?.query === next?.query ? previous : next));\n if (next === null || next.query !== match?.query) setActiveIndex(0);\n };\n const commit = (candidate: MentionCandidate) => {\n const input = inputRef.current;\n if (!match || !input) return;\n const result = resolveMentionInsertion(value, match, input.selectionStart ?? value.length, candidate.insertText ?? candidate.label);\n onValueChange(result.text);\n setMatch(null);\n queueMicrotask(() => {\n input.focus();\n input.setSelectionRange(result.cursorPosition, result.cursorPosition);\n });\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n if (!open) return;\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n if (candidates.length === 0) return;\n event.preventDefault();\n setActiveIndex((previous) => {\n const next = event.key === \"ArrowDown\" ? previous + 1 : previous - 1;\n return (next + candidates.length) % candidates.length;\n });\n return;\n }\n if (event.key === \"Escape\") {\n // Dismissing the popup must not touch the text the user already typed.\n event.preventDefault();\n event.stopPropagation();\n setMatch(null);\n return;\n }\n if (event.key === \"Enter\" && activeCandidate && candidates.length > 0) {\n event.preventDefault();\n commit(activeCandidate);\n }\n };\n\n const position = useAnchoredPopup(inputRef, open ? list : null, {\n placement: \"bottom\", align: \"start\", matchAnchorWidth: true, zIndex: 900,\n });\n\n return (\n <div className={classNames(\"hjm-mentions\", className)}>\n <TextArea\n {...textAreaProps}\n ref={composeRefs(inputRef, forwardedRef)}\n value={value}\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={open ? id : undefined}\n aria-autocomplete=\"list\"\n aria-activedescendant={open && activeCandidate ? `${id}-${activeCandidate.id}` : undefined}\n onChange={(event) => {\n onValueChange(event.target.value);\n syncMatch(event.target.value, event.target.selectionStart ?? event.target.value.length);\n }}\n onKeyUp={(event) => {\n // Caret moves without an edit (arrows, clicks) change which trigger is\n // active, so the match is re-read from the caret, not only from input.\n if (open && (event.key === \"ArrowDown\" || event.key === \"ArrowUp\")) return;\n const input = event.currentTarget;\n syncMatch(input.value, input.selectionStart ?? input.value.length);\n }}\n onClick={(event) => {\n const input = event.currentTarget;\n syncMatch(input.value, input.selectionStart ?? input.value.length);\n }}\n onBlur={(event) => { textAreaProps.onBlur?.(event); setMatch(null); }}\n onKeyDown={(event) => { textAreaProps.onKeyDown?.(event); onKeyDown(event); }}\n />\n {open ? (\n <AnchoredPortal anchorRef={inputRef}>\n <div\n ref={setList}\n id={id}\n role=\"listbox\"\n aria-label={listLabel}\n className=\"hjm-mentions__list\"\n style={position.style as CSSProperties}\n >\n {candidates.length === 0 ? (\n <p className=\"hjm-mentions__empty\" role=\"status\">{emptyMessage}</p>\n ) : candidates.map((candidate, index) => (\n <div\n key={candidate.id}\n id={`${id}-${candidate.id}`}\n role=\"option\"\n aria-selected={candidate.id === activeCandidate?.id}\n className=\"hjm-mentions__option\"\n // Pointer commit must not blur the textarea first, or the caret\n // position the insertion depends on would already be gone.\n onMouseDown={(event) => { event.preventDefault(); commit(candidate); }}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {renderCandidate?.(candidate) ?? (\n <>\n <span>{candidate.label}</span>\n {candidate.description ? <span className=\"hjm-mentions__description\">{candidate.description}</span> : null}\n </>\n )}\n </div>\n ))}\n </div>\n </AnchoredPortal>\n ) : null}\n </div>\n );\n}) as <TriggerId extends string = string>(\n props: MentionsProps<TriggerId> & { ref?: React.Ref<HTMLTextAreaElement> },\n) => React.ReactElement | null;\n"]}
1
+ {"version":3,"file":"mentions.js","sourceRoot":"","sources":["../src/mentions.tsx"],"names":[],"mappings":"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","sourcesContent":["import { layer } from \"@hjmds/design-contracts/foundations\";\nimport { comboboxRecipe } from \"@hjmds/design-contracts/recipes\";\nimport {\n findActiveMentionTrigger,\n resolveMentionInsertion,\n type MentionMatch,\n type MentionTriggerConfig,\n} from \"@hjmds/design-contracts/components/mentions\";\nimport {\n forwardRef,\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { TextArea, type TextAreaProps } from \"./forms.js\";\nimport { classNames, composeRefs } from \"./internal.js\";\nimport { AnchoredPortal, useAnchoredPopup } from \"./portal.js\";\n\nexport type MentionCandidate = Readonly<{\n id: string;\n label: string;\n /** Text inserted after the trigger character; defaults to `label`. */\n insertText?: string;\n description?: string;\n}>;\n\nexport type MentionsProps<TriggerId extends string = string> =\n Omit<TextAreaProps, \"value\" | \"defaultValue\" | \"onChange\" | \"children\"> &\n Readonly<{\n value: string;\n onValueChange: (value: string) => void;\n triggers: readonly MentionTriggerConfig<TriggerId>[];\n /** Candidates for the active query; the product owns filtering and loading. */\n candidates: readonly MentionCandidate[];\n /** Fires whenever the active trigger match changes, including to null. */\n onMentionQueryChange?: (match: MentionMatch<TriggerId> | null) => void;\n /** Localized message shown when the popup is open with no candidates. */\n emptyMessage: string;\n /** Localized accessible name for the candidate list. */\n listLabel: string;\n renderCandidate?: (candidate: MentionCandidate) => ReactNode;\n }>;\n\nexport const Mentions = forwardRef(function Mentions<TriggerId extends string = string>(\n {\n value,\n onValueChange,\n triggers,\n candidates,\n onMentionQueryChange,\n emptyMessage,\n listLabel,\n renderCandidate,\n className,\n // Inherited from TextAreaProps; taken here so placement moves the whole\n // mentions block (field + candidate popup anchor), not only the inner field.\n layoutStyle,\n ...textAreaProps\n }: MentionsProps<TriggerId>,\n forwardedRef: React.Ref<HTMLTextAreaElement>,\n) {\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const [match, setMatch] = useState<MentionMatch<TriggerId> | null>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n const [list, setList] = useState<HTMLDivElement | null>(null);\n const id = `${useId().replaceAll(\":\", \"\")}-mentions`;\n const open = match !== null;\n const activeCandidate = candidates[Math.min(activeIndex, Math.max(candidates.length - 1, 0))];\n\n const notifyRef = useRef(onMentionQueryChange);\n notifyRef.current = onMentionQueryChange;\n useEffect(() => { notifyRef.current?.(match); }, [match]);\n\n const syncMatch = (text: string, cursor: number) => {\n // The contract owns trigger detection, including \"a space closes it\" and\n // \"the nearer trigger wins\"; this component only reports the cursor.\n const next = findActiveMentionTrigger(text, cursor, triggers);\n setMatch((previous) => (previous?.triggerStart === next?.triggerStart && previous?.query === next?.query ? previous : next));\n if (next === null || next.query !== match?.query) setActiveIndex(0);\n };\n const commit = (candidate: MentionCandidate) => {\n const input = inputRef.current;\n if (!match || !input) return;\n const result = resolveMentionInsertion(value, match, input.selectionStart ?? value.length, candidate.insertText ?? candidate.label);\n onValueChange(result.text);\n setMatch(null);\n queueMicrotask(() => {\n input.focus();\n input.setSelectionRange(result.cursorPosition, result.cursorPosition);\n });\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n if (!open) return;\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n if (candidates.length === 0) return;\n event.preventDefault();\n setActiveIndex((previous) => {\n const next = event.key === \"ArrowDown\" ? previous + 1 : previous - 1;\n return (next + candidates.length) % candidates.length;\n });\n return;\n }\n if (event.key === \"Escape\") {\n // Dismissing the popup must not touch the text the user already typed.\n event.preventDefault();\n event.stopPropagation();\n setMatch(null);\n return;\n }\n if (event.key === \"Enter\" && activeCandidate && candidates.length > 0) {\n event.preventDefault();\n commit(activeCandidate);\n }\n };\n\n const position = useAnchoredPopup(inputRef, open ? list : null, {\n placement: \"bottom\", align: \"start\", matchAnchorWidth: true, zIndex: layer.dropdown,\n // The candidate list is Combobox's popover contract verbatim (mentions.ts), so its offset and edge padding are\n // comboboxRecipe.popover's 8/8. Until 2026-10-06 the helper defaults (8 and 16) applied, a Web-only 16 edge.\n gap: comboboxRecipe.popover.sideOffset,\n viewportPadding: comboboxRecipe.popover.collisionPadding,\n });\n\n return (\n <div className={classNames(\"hjm-mentions\", className)} style={layoutStyle}>\n <TextArea\n {...textAreaProps}\n ref={composeRefs(inputRef, forwardedRef)}\n value={value}\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={open ? id : undefined}\n aria-autocomplete=\"list\"\n aria-activedescendant={open && activeCandidate ? `${id}-${activeCandidate.id}` : undefined}\n onChange={(event) => {\n onValueChange(event.target.value);\n syncMatch(event.target.value, event.target.selectionStart ?? event.target.value.length);\n }}\n onKeyUp={(event) => {\n // Caret moves without an edit (arrows, clicks) change which trigger is\n // active, so the match is re-read from the caret, not only from input.\n if (open && (event.key === \"ArrowDown\" || event.key === \"ArrowUp\")) return;\n const input = event.currentTarget;\n syncMatch(input.value, input.selectionStart ?? input.value.length);\n }}\n onClick={(event) => {\n const input = event.currentTarget;\n syncMatch(input.value, input.selectionStart ?? input.value.length);\n }}\n onBlur={(event) => { textAreaProps.onBlur?.(event); setMatch(null); }}\n onKeyDown={(event) => { textAreaProps.onKeyDown?.(event); onKeyDown(event); }}\n />\n {open ? (\n <AnchoredPortal anchorRef={inputRef}>\n <div\n ref={setList}\n id={id}\n role=\"listbox\"\n aria-label={listLabel}\n className=\"hjm-mentions__list\"\n style={position.style as CSSProperties}\n >\n {candidates.length === 0 ? (\n <p className=\"hjm-mentions__empty\" role=\"status\">{emptyMessage}</p>\n ) : candidates.map((candidate, index) => (\n <div\n key={candidate.id}\n id={`${id}-${candidate.id}`}\n role=\"option\"\n aria-selected={candidate.id === activeCandidate?.id}\n className=\"hjm-mentions__option\"\n // Pointer commit must not blur the textarea first, or the caret\n // position the insertion depends on would already be gone.\n onMouseDown={(event) => { event.preventDefault(); commit(candidate); }}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {renderCandidate?.(candidate) ?? (\n <>\n <span>{candidate.label}</span>\n {candidate.description ? <span className=\"hjm-mentions__description\">{candidate.description}</span> : null}\n </>\n )}\n </div>\n ))}\n </div>\n </AnchoredPortal>\n ) : null}\n </div>\n );\n}) as <TriggerId extends string = string>(\n props: MentionsProps<TriggerId> & { ref?: React.Ref<HTMLTextAreaElement> },\n) => React.ReactElement | null;\n"]}
@@ -1,4 +1,5 @@
1
1
  import { type MenuItem } from "./overlays.js";
2
+ import type { HjmCompositionStyleProp } from "./composition-style.js";
2
3
  export type MorphingMenuProps = {
3
4
  label: string;
4
5
  items: readonly MenuItem[];
@@ -6,7 +7,13 @@ export type MorphingMenuProps = {
6
7
  disabled?: boolean;
7
8
  open?: boolean;
8
9
  onOpenChange?: (open: boolean) => void;
10
+ /**
11
+ * Canonical layout-only placement. Applied to the morph root, or to the
12
+ * canonical Menu's wrapper when reduced motion/RTL falls back to it, so
13
+ * placement survives the switch.
14
+ */
15
+ layoutStyle?: HjmCompositionStyleProp;
9
16
  };
10
17
  /** Action-only morph presentation. Selection/async menus retain the full Menu. */
11
- export declare function MorphingMenu({ label, items, onAction, disabled, open: controlled, onOpenChange }: MorphingMenuProps): import("react").JSX.Element;
18
+ export declare function MorphingMenu({ label, items, onAction, disabled, open: controlled, onOpenChange, layoutStyle }: MorphingMenuProps): import("react").JSX.Element;
12
19
  //# sourceMappingURL=menu-morph.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"menu-morph.d.ts","sourceRoot":"","sources":["../src/menu-morph.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGpD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAgB,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,iBAAiB,+BAmE3H"}
1
+ {"version":3,"file":"menu-morph.d.ts","sourceRoot":"","sources":["../src/menu-morph.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC;AAEF,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAgB,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,iBAAiB,+BAmExI"}
@@ -6,7 +6,7 @@ import { Button } from "./actions.js";
6
6
  import { Menu } from "./overlays.js";
7
7
  import { useHjmTheme } from "./provider.js";
8
8
  /** Action-only morph presentation. Selection/async menus retain the full Menu. */
9
- export function MorphingMenu({ label, items, onAction, disabled = false, open: controlled, onOpenChange }) {
9
+ export function MorphingMenu({ label, items, onAction, disabled = false, open: controlled, onOpenChange, layoutStyle }) {
10
10
  const theme = useHjmTheme();
11
11
  const [localOpen, setLocalOpen] = useState(false);
12
12
  const open = controlled ?? localOpen;
@@ -33,7 +33,7 @@ export function MorphingMenu({ label, items, onAction, disabled = false, open: c
33
33
  }, [open, label]);
34
34
  // The canonical Menu owns static/RTL behavior; Bloom's left/right geometry is physical.
35
35
  if (theme.environment.reducedMotion || theme.environment.direction === "rtl") {
36
- return _jsx(Menu, { label: label, trigger: _jsx(Button, { tone: "secondary", children: label }), items: items, disabled: disabled, open: open, onOpenChange: change, ...(onAction ? { onAction } : {}) });
36
+ return _jsx(Menu, { label: label, trigger: _jsx(Button, { tone: "secondary", children: label }), items: items, disabled: disabled, open: open, ...(layoutStyle === undefined ? {} : { layoutStyle }), onOpenChange: change, ...(onAction ? { onAction } : {}) });
37
37
  }
38
38
  const keyDown = (event) => {
39
39
  if (!open) {
@@ -75,7 +75,7 @@ export function MorphingMenu({ label, items, onAction, disabled = false, open: c
75
75
  nodes[next]?.focus();
76
76
  }
77
77
  };
78
- return _jsx("div", { ref: root, className: "hjm-menu-morph", onKeyDownCapture: keyDown, children: _jsx(Bloom.Root, { direction: "bottom", open: open, onOpenChange: change, modal: false, children: _jsxs(Bloom.Container, { buttonSize: { width: 160, height: 44 }, menuWidth: 240, style: { background: theme.palette.theme.bg, color: theme.palette.theme.text }, children: [_jsx(Bloom.Trigger, { disabled: disabled, children: label }), _jsx(Bloom.Content, { children: items.map(item => _jsxs("button", { type: "button", role: "menuitem", tabIndex: -1, className: "hjm-menu-morph__item", disabled: !open || (item.disabled ?? false), "data-tone": item.tone, "aria-label": item.textValue, onClick: () => { if (!item.disabled) {
78
+ return _jsx("div", { ref: root, className: "hjm-menu-morph", style: layoutStyle, onKeyDownCapture: keyDown, children: _jsx(Bloom.Root, { direction: "bottom", open: open, onOpenChange: change, modal: false, children: _jsxs(Bloom.Container, { buttonSize: { width: 160, height: 44 }, menuWidth: 240, style: { background: theme.palette.theme.bg, color: theme.palette.theme.text }, children: [_jsx(Bloom.Trigger, { disabled: disabled, children: label }), _jsx(Bloom.Content, { children: items.map(item => _jsxs("button", { type: "button", role: "menuitem", tabIndex: -1, className: "hjm-menu-morph__item", disabled: !open || (item.disabled ?? false), "data-tone": item.tone, "aria-label": item.textValue, onClick: () => { if (!item.disabled) {
79
79
  change(false);
80
80
  onAction?.(item.id);
81
81
  } }, children: [item.leading, item.label, item.trailing] }, item.id)) })] }) }) });
@@ -1 +1 @@
1
- {"version":3,"file":"menu-morph.js","sourceRoot":"","sources":["../src/menu-morph.tsx"],"names":[],"mappings":"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","sourcesContent":["import { resolveMenuTypeahead } from \"./menu-typeahead.js\";\nimport { Menu as Bloom } from \"bloom-menu\";\nimport { useEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport { Button } from \"./actions.js\";\nimport { Menu, type MenuItem } from \"./overlays.js\";\nimport { useHjmTheme } from \"./provider.js\";\n\nexport type MorphingMenuProps = {\n label: string;\n items: readonly MenuItem[];\n onAction?: (id: string) => void;\n disabled?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n};\n\n/** Action-only morph presentation. Selection/async menus retain the full Menu. */\nexport function MorphingMenu({ label, items, onAction, disabled = false, open: controlled, onOpenChange }: MorphingMenuProps) {\n const theme = useHjmTheme();\n const [localOpen, setLocalOpen] = useState(false);\n const open = controlled ?? localOpen;\n const root = useRef<HTMLDivElement>(null);\n const previousOpen = useRef(false);\n const restoreFocus = useRef(true);\n const search = useRef({ value: \"\", time: 0 });\n const change = (value: boolean) => { if (value) restoreFocus.current = true; setLocalOpen(value); onOpenChange?.(value); };\n if (!label.trim() || !items.length || new Set(items.map(item => item.id)).size !== items.length ||\n items.some(item => !item.id.trim() || !(item.textValue ?? (typeof item.label === \"string\" ? item.label : \"\")).trim())) {\n throw new TypeError(\"MorphingMenu needs a label and unique, named items\");\n }\n useEffect(() => {\n const host = root.current;\n if (open) {\n search.current = { value: \"\", time: 0 };\n host?.querySelector('[role=\"menu\"]')?.setAttribute(\"aria-label\", label);\n host?.querySelector<HTMLElement>('[role=\"menuitem\"]:not([disabled])')?.focus();\n } else if (previousOpen.current && restoreFocus.current && (host?.contains(document.activeElement) || document.activeElement === document.body)) host?.querySelector<HTMLElement>('[role=\"button\"]')?.focus();\n previousOpen.current = open;\n }, [open, label]);\n // The canonical Menu owns static/RTL behavior; Bloom's left/right geometry is physical.\n if (theme.environment.reducedMotion || theme.environment.direction === \"rtl\") {\n return <Menu label={label} trigger={<Button tone=\"secondary\">{label}</Button>} items={items} disabled={disabled} open={open}\n onOpenChange={change} {...(onAction ? { onAction } : {})} />;\n }\n const keyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (!open) {\n if (!disabled && [\"ArrowDown\", \"ArrowUp\"].includes(event.key)) { event.preventDefault(); event.stopPropagation(); change(true); }\n return;\n }\n const nodes = Array.from(root.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([disabled])') ?? []);\n const index = nodes.indexOf(document.activeElement as HTMLElement);\n let next: number | undefined;\n if (event.key === \"ArrowDown\") next = (index + 1) % nodes.length;\n if (event.key === \"ArrowUp\") next = (index - 1 + nodes.length) % nodes.length;\n if (event.key === \"Home\") next = 0;\n if (event.key === \"End\") next = nodes.length - 1;\n if (event.key === \"Escape\" || event.key === \"Tab\") { if (event.key === \"Tab\") restoreFocus.current = false; change(false); if (event.key === \"Escape\") event.preventDefault(); }\n if (event.key.length === 1 && !event.altKey && !event.ctrlKey && !event.metaKey && event.key !== \" \") {\n const result = resolveMenuTypeahead(\n items.filter(item => !item.disabled).map(item => ({\n textValue: item.textValue ?? (typeof item.label === \"string\" ? item.label : \"\"),\n })), index, event.key, search.current, Date.now(),\n );\n search.current = result.state;\n next = result.index;\n }\n if (next !== undefined && next >= 0) { event.preventDefault(); event.stopPropagation(); nodes[next]?.focus(); }\n };\n return <div ref={root} className=\"hjm-menu-morph\" onKeyDownCapture={keyDown}>\n {/* Open toward following content; upstream defaults upward and can cover preceding values. */}\n <Bloom.Root direction=\"bottom\" open={open} onOpenChange={change} modal={false}>\n <Bloom.Container buttonSize={{ width: 160, height: 44 }} menuWidth={240}\n style={{ background: theme.palette.theme.bg, color: theme.palette.theme.text }}>\n <Bloom.Trigger disabled={disabled}>{label}</Bloom.Trigger>\n <Bloom.Content>\n {items.map(item => <button type=\"button\" role=\"menuitem\" tabIndex={-1} className=\"hjm-menu-morph__item\" key={item.id} disabled={!open || (item.disabled ?? false)}\n data-tone={item.tone} aria-label={item.textValue}\n onClick={() => { if (!item.disabled) { change(false); onAction?.(item.id); } }}>\n {item.leading}{item.label}{item.trailing}\n </button>)}\n </Bloom.Content>\n </Bloom.Container>\n </Bloom.Root>\n </div>;\n}\n"]}
1
+ {"version":3,"file":"menu-morph.js","sourceRoot":"","sources":["../src/menu-morph.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAsB,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,IAAI,EAAiB,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAkB5C,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAG,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAqB;IACvI,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,UAAU,IAAI,SAAS,CAAC;IACrC,MAAM,IAAI,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,CAAC,KAAc,EAAE,EAAE,GAAG,IAAI,KAAK;QAAE,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3H,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM;QAC7F,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACxH,MAAM,IAAI,SAAS,CAAC,oDAAoD,CAAC,CAAC;IAC5E,CAAC;IACD,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;QAC1B,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACxC,IAAI,EAAE,aAAa,CAAC,eAAe,CAAC,EAAE,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YACxE,IAAI,EAAE,aAAa,CAAc,mCAAmC,CAAC,EAAE,KAAK,EAAE,CAAC;QACjF,CAAC;aAAM,IAAI,YAAY,CAAC,OAAO,IAAI,YAAY,CAAC,OAAO,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,QAAQ,CAAC,aAAa,KAAK,QAAQ,CAAC,IAAI,CAAC;YAAE,IAAI,EAAE,aAAa,CAAc,iBAAiB,CAAC,EAAE,KAAK,EAAE,CAAC;QAC9M,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9B,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAClB,wFAAwF;IACxF,IAAI,KAAK,CAAC,WAAW,CAAC,aAAa,IAAI,KAAK,CAAC,WAAW,CAAC,SAAS,KAAK,KAAK,EAAE,CAAC;QAC7E,OAAO,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAC,MAAM,IAAC,IAAI,EAAC,WAAW,YAAE,KAAK,GAAU,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,KACrH,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,MAAM,KAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAAI,CAAC;IACzH,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,KAAoC,EAAE,EAAE;QACvD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,QAAQ,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAC,KAAK,CAAC,cAAc,EAAE,CAAC;gBAAC,KAAK,CAAC,eAAe,EAAE,CAAC;gBAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;YACjI,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAc,mCAAmC,CAAC,IAAI,EAAE,CAAC,CAAC;QACjH,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,aAA4B,CAAC,CAAC;QACnE,IAAI,IAAwB,CAAC;QAC7B,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW;YAAE,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QACjE,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;YAAE,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QAC9E,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM;YAAE,IAAI,GAAG,CAAC,CAAC;QACnC,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK;YAAE,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACjD,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC;YAAC,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK;gBAAE,YAAY,CAAC,OAAO,GAAG,KAAK,CAAC;YAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAAC,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ;gBAAE,KAAK,CAAC,cAAc,EAAE,CAAC;QAAC,CAAC;QAChL,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;YACrG,MAAM,MAAM,GAAG,oBAAoB,CACjC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAChD,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;aAChF,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAClD,CAAC;YACF,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;YAC9B,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;QACtB,CAAC;QACD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;YAAC,KAAK,CAAC,cAAc,EAAE,CAAC;YAAC,KAAK,CAAC,eAAe,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;QAAC,CAAC;IACjH,CAAC,CAAC;IACF,OAAO,cAAK,GAAG,EAAE,IAAI,EAAE,SAAS,EAAC,gBAAgB,EAAC,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,OAAO,YAE7F,KAAC,KAAK,CAAC,IAAI,IAAC,SAAS,EAAC,QAAQ,EAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,YAC3E,MAAC,KAAK,CAAC,SAAS,IAAC,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EACrE,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,aAC9E,KAAC,KAAK,CAAC,OAAO,IAAC,QAAQ,EAAE,QAAQ,YAAG,KAAK,GAAiB,EAC1D,KAAC,KAAK,CAAC,OAAO,cACX,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,kBAAQ,IAAI,EAAC,QAAQ,EAAC,IAAI,EAAC,UAAU,EAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,EAAC,sBAAsB,EAAe,QAAQ,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,eACpJ,IAAI,CAAC,IAAI,gBAAc,IAAI,CAAC,SAAS,EAChD,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gCAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gCAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BAAC,CAAC,CAAC,CAAC,aAC7E,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,KAHmE,IAAI,CAAC,EAAE,CAI3G,CAAC,GACI,IACA,GACP,GACT,CAAC;AACT,CAAC","sourcesContent":["import { resolveMenuTypeahead } from \"./menu-typeahead.js\";\nimport { Menu as Bloom } from \"bloom-menu\";\nimport { useEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport { Button } from \"./actions.js\";\nimport { Menu, type MenuItem } from \"./overlays.js\";\nimport { useHjmTheme } from \"./provider.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type MorphingMenuProps = {\n label: string;\n items: readonly MenuItem[];\n onAction?: (id: string) => void;\n disabled?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /**\n * Canonical layout-only placement. Applied to the morph root, or to the\n * canonical Menu's wrapper when reduced motion/RTL falls back to it, so\n * placement survives the switch.\n */\n layoutStyle?: HjmCompositionStyleProp;\n};\n\n/** Action-only morph presentation. Selection/async menus retain the full Menu. */\nexport function MorphingMenu({ label, items, onAction, disabled = false, open: controlled, onOpenChange, layoutStyle }: MorphingMenuProps) {\n const theme = useHjmTheme();\n const [localOpen, setLocalOpen] = useState(false);\n const open = controlled ?? localOpen;\n const root = useRef<HTMLDivElement>(null);\n const previousOpen = useRef(false);\n const restoreFocus = useRef(true);\n const search = useRef({ value: \"\", time: 0 });\n const change = (value: boolean) => { if (value) restoreFocus.current = true; setLocalOpen(value); onOpenChange?.(value); };\n if (!label.trim() || !items.length || new Set(items.map(item => item.id)).size !== items.length ||\n items.some(item => !item.id.trim() || !(item.textValue ?? (typeof item.label === \"string\" ? item.label : \"\")).trim())) {\n throw new TypeError(\"MorphingMenu needs a label and unique, named items\");\n }\n useEffect(() => {\n const host = root.current;\n if (open) {\n search.current = { value: \"\", time: 0 };\n host?.querySelector('[role=\"menu\"]')?.setAttribute(\"aria-label\", label);\n host?.querySelector<HTMLElement>('[role=\"menuitem\"]:not([disabled])')?.focus();\n } else if (previousOpen.current && restoreFocus.current && (host?.contains(document.activeElement) || document.activeElement === document.body)) host?.querySelector<HTMLElement>('[role=\"button\"]')?.focus();\n previousOpen.current = open;\n }, [open, label]);\n // The canonical Menu owns static/RTL behavior; Bloom's left/right geometry is physical.\n if (theme.environment.reducedMotion || theme.environment.direction === \"rtl\") {\n return <Menu label={label} trigger={<Button tone=\"secondary\">{label}</Button>} items={items} disabled={disabled} open={open}\n {...(layoutStyle === undefined ? {} : { layoutStyle })} onOpenChange={change} {...(onAction ? { onAction } : {})} />;\n }\n const keyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (!open) {\n if (!disabled && [\"ArrowDown\", \"ArrowUp\"].includes(event.key)) { event.preventDefault(); event.stopPropagation(); change(true); }\n return;\n }\n const nodes = Array.from(root.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([disabled])') ?? []);\n const index = nodes.indexOf(document.activeElement as HTMLElement);\n let next: number | undefined;\n if (event.key === \"ArrowDown\") next = (index + 1) % nodes.length;\n if (event.key === \"ArrowUp\") next = (index - 1 + nodes.length) % nodes.length;\n if (event.key === \"Home\") next = 0;\n if (event.key === \"End\") next = nodes.length - 1;\n if (event.key === \"Escape\" || event.key === \"Tab\") { if (event.key === \"Tab\") restoreFocus.current = false; change(false); if (event.key === \"Escape\") event.preventDefault(); }\n if (event.key.length === 1 && !event.altKey && !event.ctrlKey && !event.metaKey && event.key !== \" \") {\n const result = resolveMenuTypeahead(\n items.filter(item => !item.disabled).map(item => ({\n textValue: item.textValue ?? (typeof item.label === \"string\" ? item.label : \"\"),\n })), index, event.key, search.current, Date.now(),\n );\n search.current = result.state;\n next = result.index;\n }\n if (next !== undefined && next >= 0) { event.preventDefault(); event.stopPropagation(); nodes[next]?.focus(); }\n };\n return <div ref={root} className=\"hjm-menu-morph\" style={layoutStyle} onKeyDownCapture={keyDown}>\n {/* Open toward following content; upstream defaults upward and can cover preceding values. */}\n <Bloom.Root direction=\"bottom\" open={open} onOpenChange={change} modal={false}>\n <Bloom.Container buttonSize={{ width: 160, height: 44 }} menuWidth={240}\n style={{ background: theme.palette.theme.bg, color: theme.palette.theme.text }}>\n <Bloom.Trigger disabled={disabled}>{label}</Bloom.Trigger>\n <Bloom.Content>\n {items.map(item => <button type=\"button\" role=\"menuitem\" tabIndex={-1} className=\"hjm-menu-morph__item\" key={item.id} disabled={!open || (item.disabled ?? false)}\n data-tone={item.tone} aria-label={item.textValue}\n onClick={() => { if (!item.disabled) { change(false); onAction?.(item.id); } }}>\n {item.leading}{item.label}{item.trailing}\n </button>)}\n </Bloom.Content>\n </Bloom.Container>\n </Bloom.Root>\n </div>;\n}\n"]}
package/dist/menubar.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { type MenubarDescriptor } from "@hjmds/design-contracts/components/menubar";
2
+ import type { HjmCompositionStyleProp } from "./composition-style.js";
2
3
  export type MenubarProps<Key extends string = string, MenuKey extends string = string> = Readonly<{
3
4
  descriptor: MenubarDescriptor<Key, MenuKey>;
4
5
  openMenuId?: MenuKey | null;
@@ -6,6 +7,8 @@ export type MenubarProps<Key extends string = string, MenuKey extends string = s
6
7
  onOpenMenuIdChange?: (id: MenuKey | null) => void;
7
8
  onAction: (id: Key, menuId: MenuKey) => void;
8
9
  className?: string;
10
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
11
+ layoutStyle?: HjmCompositionStyleProp;
9
12
  }>;
10
- export declare function Menubar<Key extends string = string, MenuKey extends string = string>({ descriptor, openMenuId: controlledOpen, defaultOpenMenuId, onOpenMenuIdChange, onAction, className, }: MenubarProps<Key, MenuKey>): import("react").JSX.Element;
13
+ export declare function Menubar<Key extends string = string, MenuKey extends string = string>({ descriptor, openMenuId: controlledOpen, defaultOpenMenuId, onOpenMenuIdChange, onAction, className, layoutStyle, }: MenubarProps<Key, MenuKey>): import("react").JSX.Element;
11
14
  //# sourceMappingURL=menubar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"menubar.d.ts","sourceRoot":"","sources":["../src/menubar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,4CAA4C,CAAC;AAKpD,MAAM,MAAM,YAAY,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAChG,UAAU,EAAE,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5C,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,iBAAiB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD,QAAQ,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,wBAAgB,OAAO,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,EACpF,UAAU,EACV,UAAU,EAAE,cAAc,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,SAAS,GACV,EAAE,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,+BAwK5B"}
1
+ {"version":3,"file":"menubar.d.ts","sourceRoot":"","sources":["../src/menubar.tsx"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,4CAA4C,CAAC;AAIpD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,YAAY,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAChG,UAAU,EAAE,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5C,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,iBAAiB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD,QAAQ,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEH,wBAAgB,OAAO,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,EACpF,UAAU,EACV,UAAU,EAAE,cAAc,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,EAAE,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,+BAwK5B"}
package/dist/menubar.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { layer } from "@hjmds/design-contracts/foundations";
2
3
  import { menubarRecipe, resolveMenubarNavigation, validateMenubarDescriptor, } from "@hjmds/design-contracts/components/menubar";
3
4
  import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
4
5
  import { classNames, useControllableState } from "./internal.js";
5
6
  import { AnchoredPortal, useAnchoredPopup } from "./portal.js";
6
- export function Menubar({ descriptor, openMenuId: controlledOpen, defaultOpenMenuId, onOpenMenuIdChange, onAction, className, }) {
7
+ export function Menubar({ descriptor, openMenuId: controlledOpen, defaultOpenMenuId, onOpenMenuIdChange, onAction, className, layoutStyle, }) {
7
8
  validateMenubarDescriptor(descriptor);
8
9
  const [openId, setOpenId] = useControllableState({
9
10
  ...(controlledOpen === undefined ? {} : { value: controlledOpen }),
@@ -26,7 +27,7 @@ export function Menubar({ descriptor, openMenuId: controlledOpen, defaultOpenMen
26
27
  const [panelNode, setPanelNode] = useState(null);
27
28
  const setPanelRef = useCallback((node) => setPanelNode(node), []);
28
29
  const openLabelRef = useMemo(() => ({ get current() { return openId === null ? null : labelRefs.current.get(openId) ?? null; } }), [openId]);
29
- const panelPosition = useAnchoredPopup(openLabelRef, panelNode, { gap: 0, zIndex: 900 });
30
+ const panelPosition = useAnchoredPopup(openLabelRef, panelNode, { gap: 0, zIndex: layer.dropdown });
30
31
  useEffect(() => {
31
32
  if (openId === null)
32
33
  return;
@@ -52,7 +53,7 @@ export function Menubar({ descriptor, openMenuId: controlledOpen, defaultOpenMen
52
53
  setActiveItemIndex(0);
53
54
  }
54
55
  };
55
- return (_jsx("div", { ref: rootRef, role: "menubar", "aria-label": descriptor.accessibilityLabel, className: classNames("hjm-menubar", className), style: {
56
+ return (_jsx("div", { ref: rootRef, role: "menubar", "aria-label": descriptor.accessibilityLabel, className: classNames("hjm-menubar", className), style: { ...layoutStyle,
56
57
  "--hjm-menubar-min-height": `${menubarRecipe.minHeight}px`,
57
58
  "--hjm-menubar-gap": `${menubarRecipe.gap}px`,
58
59
  "--hjm-menubar-padding": `${menubarRecipe.paddingHorizontal}px`,
@@ -1 +1 @@
1
- {"version":3,"file":"menubar.js","sourceRoot":"","sources":["../src/menubar.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n menubarRecipe,\n resolveMenubarNavigation,\n validateMenubarDescriptor,\n type MenubarDescriptor,\n} from \"@hjmds/design-contracts/components/menubar\";\nimport { useCallback, useEffect, useId, useMemo, useRef, useState, type CSSProperties, type RefObject } from \"react\";\nimport { classNames, useControllableState } from \"./internal.js\";\nimport { AnchoredPortal, useAnchoredPopup } from \"./portal.js\";\n\nexport type MenubarProps<Key extends string = string, MenuKey extends string = string> = Readonly<{\n descriptor: MenubarDescriptor<Key, MenuKey>;\n openMenuId?: MenuKey | null;\n defaultOpenMenuId?: MenuKey | null;\n onOpenMenuIdChange?: (id: MenuKey | null) => void;\n onAction: (id: Key, menuId: MenuKey) => void;\n className?: string;\n}>;\n\nexport function Menubar<Key extends string = string, MenuKey extends string = string>({\n descriptor,\n openMenuId: controlledOpen,\n defaultOpenMenuId,\n onOpenMenuIdChange,\n onAction,\n className,\n}: MenubarProps<Key, MenuKey>) {\n validateMenubarDescriptor(descriptor);\n const [openId, setOpenId] = useControllableState<MenuKey | null>({\n ...(controlledOpen === undefined ? {} : { value: controlledOpen }),\n defaultValue: defaultOpenMenuId ?? null,\n ...(onOpenMenuIdChange === undefined ? {} : { onChange: onOpenMenuIdChange }),\n });\n const enabledMenus = descriptor.menus.filter((menu) => menu.disabled !== true);\n // Roving focus: the bar is one tab stop, so the bar — not each label — owns\n // which menu is reachable by Tab.\n const [focusedId, setFocusedId] = useState<MenuKey>(enabledMenus[0]?.id ?? descriptor.menus[0]!.id);\n const [activeItemIndex, setActiveItemIndex] = useState(0);\n const rootRef = useRef<HTMLDivElement>(null);\n const labelRefs = useRef(new Map<MenuKey, HTMLButtonElement>());\n const openMenu = descriptor.menus.find((menu) => menu.id === openId) ?? null;\n const openItems = openMenu?.items.filter((item) => item.disabled !== true) ?? [];\n // The panel was absolute inside the bar, so any overflow ancestor clipped it\n // (2026-09-30 audit WR-0930-4: at 1100px an item could not be hit). It now uses\n // the same portal + fixed positioning as Menu; focus stays on the bar label.\n const panelId = `${useId().replaceAll(\":\", \"\")}-menubar-panel`;\n const [panelNode, setPanelNode] = useState<HTMLDivElement | null>(null);\n const setPanelRef = useCallback((node: HTMLDivElement | null) => setPanelNode(node), []);\n const openLabelRef = useMemo<RefObject<HTMLElement | null>>(\n () => ({ get current() { return openId === null ? null : labelRefs.current.get(openId) ?? null; } }),\n [openId],\n );\n const panelPosition = useAnchoredPopup(openLabelRef, panelNode, { gap: 0, zIndex: 900 });\n\n useEffect(() => {\n if (openId === null) return;\n const onPointerDown = (event: PointerEvent) => {\n if (event.target instanceof Node && (rootRef.current?.contains(event.target) || panelNode?.contains(event.target))) return;\n setOpenId(null);\n };\n document.addEventListener(\"pointerdown\", onPointerDown);\n return () => document.removeEventListener(\"pointerdown\", onPointerDown);\n }, [openId, panelNode, setOpenId]);\n\n const focusLabel = (id: MenuKey) => {\n setFocusedId(id);\n labelRefs.current.get(id)?.focus();\n };\n const move = (direction: \"next\" | \"previous\") => {\n const next = resolveMenubarNavigation(descriptor, focusedId, direction);\n focusLabel(next);\n // Left/right while a menu is open moves to the neighbour already open, which\n // is the whole reason this is a bar and not three independent Menus.\n if (openId !== null) { setOpenId(next); setActiveItemIndex(0); }\n };\n\n return (\n <div\n ref={rootRef}\n role=\"menubar\"\n aria-label={descriptor.accessibilityLabel}\n className={classNames(\"hjm-menubar\", className)}\n style={{\n \"--hjm-menubar-min-height\": `${menubarRecipe.minHeight}px`,\n \"--hjm-menubar-gap\": `${menubarRecipe.gap}px`,\n \"--hjm-menubar-padding\": `${menubarRecipe.paddingHorizontal}px`,\n \"--hjm-menubar-label-padding\": `${menubarRecipe.label.paddingHorizontal}px`,\n \"--hjm-menubar-label-radius\": `${menubarRecipe.label.radius}px`,\n } as CSSProperties}\n onKeyDown={(event) => {\n if (event.key === \"ArrowRight\") { event.preventDefault(); move(\"next\"); return; }\n if (event.key === \"ArrowLeft\") { event.preventDefault(); move(\"previous\"); return; }\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n const target = (event.key === \"Home\" ? enabledMenus[0] : enabledMenus.at(-1))?.id;\n if (target !== undefined) { focusLabel(target); if (openId !== null) { setOpenId(target); setActiveItemIndex(0); } }\n return;\n }\n if (event.key === \"Escape\" && openId !== null) {\n event.preventDefault();\n setOpenId(null);\n focusLabel(focusedId);\n return;\n }\n if (openId === null) {\n if (event.key === \"ArrowDown\" || event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpenId(focusedId);\n setActiveItemIndex(0);\n }\n return;\n }\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveItemIndex((previous) => {\n const next = event.key === \"ArrowDown\" ? previous + 1 : previous - 1;\n return (next + openItems.length) % Math.max(openItems.length, 1);\n });\n return;\n }\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n const item = openItems[activeItemIndex];\n if (item) {\n onAction(item.id as Key, openId);\n // Activation runs an action and leaves nothing selected — unlike Tabs.\n setOpenId(null);\n focusLabel(openId);\n }\n }\n }}\n >\n {descriptor.menus.map((menu) => {\n const open = menu.id === openId;\n return (\n <div key={menu.id} className=\"hjm-menubar__menu\">\n <button\n type=\"button\"\n ref={(node) => { if (node) labelRefs.current.set(menu.id, node); else labelRefs.current.delete(menu.id); }}\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? panelId : undefined}\n disabled={menu.disabled}\n tabIndex={menu.id === focusedId ? 0 : -1}\n data-open={open || undefined}\n className=\"hjm-menubar__label\"\n onClick={() => {\n setFocusedId(menu.id);\n setOpenId(open ? null : menu.id);\n setActiveItemIndex(0);\n }}\n onMouseEnter={() => {\n // Once one menu is open, hovering the bar switches menus — the\n // desktop convention; with nothing open, hover opens nothing.\n if (openId !== null && menu.disabled !== true) { setOpenId(menu.id); setFocusedId(menu.id); setActiveItemIndex(0); }\n }}\n >\n {menu.label}\n </button>\n {open ? (\n <AnchoredPortal anchorRef={openLabelRef} ssrFallback=\"inline\">\n <div ref={setPanelRef} id={panelId} role=\"menu\" aria-label={menu.label} className=\"hjm-menubar__panel\" data-placement={panelPosition.placement} style={panelPosition.style}>\n {menu.items.map((item) => {\n const index = openItems.findIndex((candidate) => candidate.id === item.id);\n return (\n <div\n key={item.id}\n role=\"menuitem\"\n aria-disabled={item.disabled || undefined}\n data-active={index === activeItemIndex && item.disabled !== true ? \"\" : undefined}\n data-tone={item.tone}\n className=\"hjm-menubar__item\"\n onMouseEnter={() => { if (index >= 0) setActiveItemIndex(index); }}\n onClick={() => {\n if (item.disabled) return;\n onAction(item.id as Key, menu.id);\n setOpenId(null);\n focusLabel(menu.id);\n }}\n >\n <span>{item.label}</span>\n {item.shortcut ? <kbd className=\"hjm-menubar__shortcut\">{item.shortcut}</kbd> : null}\n </div>\n );\n })}\n </div>\n </AnchoredPortal>\n ) : null}\n </div>\n );\n })}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"menubar.js","sourceRoot":"","sources":["../src/menubar.tsx"],"names":[],"mappings":"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","sourcesContent":["import { layer } from \"@hjmds/design-contracts/foundations\";\nimport {\n menubarRecipe,\n resolveMenubarNavigation,\n validateMenubarDescriptor,\n type MenubarDescriptor,\n} from \"@hjmds/design-contracts/components/menubar\";\nimport { useCallback, useEffect, useId, useMemo, useRef, useState, type CSSProperties, type RefObject } from \"react\";\nimport { classNames, useControllableState } from \"./internal.js\";\nimport { AnchoredPortal, useAnchoredPopup } from \"./portal.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type MenubarProps<Key extends string = string, MenuKey extends string = string> = Readonly<{\n descriptor: MenubarDescriptor<Key, MenuKey>;\n openMenuId?: MenuKey | null;\n defaultOpenMenuId?: MenuKey | null;\n onOpenMenuIdChange?: (id: MenuKey | null) => void;\n onAction: (id: Key, menuId: MenuKey) => void;\n className?: string;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\nexport function Menubar<Key extends string = string, MenuKey extends string = string>({\n descriptor,\n openMenuId: controlledOpen,\n defaultOpenMenuId,\n onOpenMenuIdChange,\n onAction,\n className,\n layoutStyle,\n}: MenubarProps<Key, MenuKey>) {\n validateMenubarDescriptor(descriptor);\n const [openId, setOpenId] = useControllableState<MenuKey | null>({\n ...(controlledOpen === undefined ? {} : { value: controlledOpen }),\n defaultValue: defaultOpenMenuId ?? null,\n ...(onOpenMenuIdChange === undefined ? {} : { onChange: onOpenMenuIdChange }),\n });\n const enabledMenus = descriptor.menus.filter((menu) => menu.disabled !== true);\n // Roving focus: the bar is one tab stop, so the bar — not each label — owns\n // which menu is reachable by Tab.\n const [focusedId, setFocusedId] = useState<MenuKey>(enabledMenus[0]?.id ?? descriptor.menus[0]!.id);\n const [activeItemIndex, setActiveItemIndex] = useState(0);\n const rootRef = useRef<HTMLDivElement>(null);\n const labelRefs = useRef(new Map<MenuKey, HTMLButtonElement>());\n const openMenu = descriptor.menus.find((menu) => menu.id === openId) ?? null;\n const openItems = openMenu?.items.filter((item) => item.disabled !== true) ?? [];\n // The panel was absolute inside the bar, so any overflow ancestor clipped it\n // (2026-09-30 audit WR-0930-4: at 1100px an item could not be hit). It now uses\n // the same portal + fixed positioning as Menu; focus stays on the bar label.\n const panelId = `${useId().replaceAll(\":\", \"\")}-menubar-panel`;\n const [panelNode, setPanelNode] = useState<HTMLDivElement | null>(null);\n const setPanelRef = useCallback((node: HTMLDivElement | null) => setPanelNode(node), []);\n const openLabelRef = useMemo<RefObject<HTMLElement | null>>(\n () => ({ get current() { return openId === null ? null : labelRefs.current.get(openId) ?? null; } }),\n [openId],\n );\n const panelPosition = useAnchoredPopup(openLabelRef, panelNode, { gap: 0, zIndex: layer.dropdown });\n\n useEffect(() => {\n if (openId === null) return;\n const onPointerDown = (event: PointerEvent) => {\n if (event.target instanceof Node && (rootRef.current?.contains(event.target) || panelNode?.contains(event.target))) return;\n setOpenId(null);\n };\n document.addEventListener(\"pointerdown\", onPointerDown);\n return () => document.removeEventListener(\"pointerdown\", onPointerDown);\n }, [openId, panelNode, setOpenId]);\n\n const focusLabel = (id: MenuKey) => {\n setFocusedId(id);\n labelRefs.current.get(id)?.focus();\n };\n const move = (direction: \"next\" | \"previous\") => {\n const next = resolveMenubarNavigation(descriptor, focusedId, direction);\n focusLabel(next);\n // Left/right while a menu is open moves to the neighbour already open, which\n // is the whole reason this is a bar and not three independent Menus.\n if (openId !== null) { setOpenId(next); setActiveItemIndex(0); }\n };\n\n return (\n <div\n ref={rootRef}\n role=\"menubar\"\n aria-label={descriptor.accessibilityLabel}\n className={classNames(\"hjm-menubar\", className)}\n style={{ ...layoutStyle,\n \"--hjm-menubar-min-height\": `${menubarRecipe.minHeight}px`,\n \"--hjm-menubar-gap\": `${menubarRecipe.gap}px`,\n \"--hjm-menubar-padding\": `${menubarRecipe.paddingHorizontal}px`,\n \"--hjm-menubar-label-padding\": `${menubarRecipe.label.paddingHorizontal}px`,\n \"--hjm-menubar-label-radius\": `${menubarRecipe.label.radius}px`,\n } as CSSProperties}\n onKeyDown={(event) => {\n if (event.key === \"ArrowRight\") { event.preventDefault(); move(\"next\"); return; }\n if (event.key === \"ArrowLeft\") { event.preventDefault(); move(\"previous\"); return; }\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n const target = (event.key === \"Home\" ? enabledMenus[0] : enabledMenus.at(-1))?.id;\n if (target !== undefined) { focusLabel(target); if (openId !== null) { setOpenId(target); setActiveItemIndex(0); } }\n return;\n }\n if (event.key === \"Escape\" && openId !== null) {\n event.preventDefault();\n setOpenId(null);\n focusLabel(focusedId);\n return;\n }\n if (openId === null) {\n if (event.key === \"ArrowDown\" || event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpenId(focusedId);\n setActiveItemIndex(0);\n }\n return;\n }\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveItemIndex((previous) => {\n const next = event.key === \"ArrowDown\" ? previous + 1 : previous - 1;\n return (next + openItems.length) % Math.max(openItems.length, 1);\n });\n return;\n }\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n const item = openItems[activeItemIndex];\n if (item) {\n onAction(item.id as Key, openId);\n // Activation runs an action and leaves nothing selected — unlike Tabs.\n setOpenId(null);\n focusLabel(openId);\n }\n }\n }}\n >\n {descriptor.menus.map((menu) => {\n const open = menu.id === openId;\n return (\n <div key={menu.id} className=\"hjm-menubar__menu\">\n <button\n type=\"button\"\n ref={(node) => { if (node) labelRefs.current.set(menu.id, node); else labelRefs.current.delete(menu.id); }}\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? panelId : undefined}\n disabled={menu.disabled}\n tabIndex={menu.id === focusedId ? 0 : -1}\n data-open={open || undefined}\n className=\"hjm-menubar__label\"\n onClick={() => {\n setFocusedId(menu.id);\n setOpenId(open ? null : menu.id);\n setActiveItemIndex(0);\n }}\n onMouseEnter={() => {\n // Once one menu is open, hovering the bar switches menus — the\n // desktop convention; with nothing open, hover opens nothing.\n if (openId !== null && menu.disabled !== true) { setOpenId(menu.id); setFocusedId(menu.id); setActiveItemIndex(0); }\n }}\n >\n {menu.label}\n </button>\n {open ? (\n <AnchoredPortal anchorRef={openLabelRef} ssrFallback=\"inline\">\n <div ref={setPanelRef} id={panelId} role=\"menu\" aria-label={menu.label} className=\"hjm-menubar__panel\" data-placement={panelPosition.placement} style={panelPosition.style}>\n {menu.items.map((item) => {\n const index = openItems.findIndex((candidate) => candidate.id === item.id);\n return (\n <div\n key={item.id}\n role=\"menuitem\"\n aria-disabled={item.disabled || undefined}\n data-active={index === activeItemIndex && item.disabled !== true ? \"\" : undefined}\n data-tone={item.tone}\n className=\"hjm-menubar__item\"\n onMouseEnter={() => { if (index >= 0) setActiveItemIndex(index); }}\n onClick={() => {\n if (item.disabled) return;\n onAction(item.id as Key, menu.id);\n setOpenId(null);\n focusLabel(menu.id);\n }}\n >\n <span>{item.label}</span>\n {item.shortcut ? <kbd className=\"hjm-menubar__shortcut\">{item.shortcut}</kbd> : null}\n </div>\n );\n })}\n </div>\n </AnchoredPortal>\n ) : null}\n </div>\n );\n })}\n </div>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,GAAG,EACT,MAAM,OAAO,CAAC;AAef,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACzC,YAAY,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC9C,YAAY,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC9C,aAAa,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACvD,cAAc,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACxD,cAAc,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACxD,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC9C,SAAS,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC;IACpD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;IAClD,eAAe,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;IAClD,eAAe,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;CACnD,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;AAE/D,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,IAAI,GAAG,IAAI,EACtB,MAAM,EAAE,WAAW,GAAG,IAAI,GACzB,OAAO,CAIT;AAED,KAAK,gBAAgB,GAAG,QAAQ,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB,CAAC,CAAC;AAEH,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,gBAAgB,sCAsBlE;AAED,MAAM,MAAM,SAAS,CAAC,MAAM,IACxB,QAAQ,CAAC;IACP,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxD,CAAC,CAAC;AAEP,MAAM,MAAM,cAAc,CAAC,MAAM,IAC7B,QAAQ,CAAC;IACP,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,wEAAwE;IACxE,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,kEAAkE;IAClE,OAAO,EAAE,cAAc,CAAC;CACzB,CAAC,CAAC;AAEP,wBAAgB,YAAY,CAAC,MAAM,EAAE,EACnC,IAAI,EACJ,WAAmB,EACnB,YAAY,GACb,EAAE,QAAQ,CAAC;IACV,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxD,CAAC,iCAWa,OAAO,UAAU,MAAM,WAmBrC;AAWD,wBAAgB,YAAY,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,EAAE,CAMlE;AAoCD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOtD;AAkGD,KAAK,iBAAiB,GAAG,QAAQ,CAAC;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAChD,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACtD,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACrD,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACxD,QAAQ,IAAI,IAAI,CAAC;CAClB,CAAC,CAAC;AAEH,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,QAAY,EACZ,UAAU,EACV,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,QAAQ,GACT,EAAE,iBAAiB,GAAG,IAAI,CAoG1B;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAC/C,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,QAAQ,GAAG,MAAM,EACxB,MAAM,EAAE,MAAM,IAAI,GACjB,YAAY,CAYd"}
package/dist/modal.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { layer } from "@hjmds/design-contracts/foundations";
2
3
  import { isLargeTextScale } from "@hjmds/design-contracts/components/design-system-provider";
3
4
  import { cloneElement, useCallback, useEffect, useRef, useState, } from "react";
4
5
  import { createPortal } from "react-dom";
@@ -87,7 +88,9 @@ export function getModalLayer(priority) {
87
88
  if (!Number.isSafeInteger(priority)) {
88
89
  throw new TypeError("modalPriority must be a safe integer");
89
90
  }
90
- return 1000 + priority;
91
+ // Keep priority ordering inside the shared modal tier; copied Web-only bases
92
+ // made product layer tokens disagree with actual overlay order.
93
+ return layer.modal + priority;
91
94
  }
92
95
  function getTopModal() {
93
96
  let top;
package/dist/modal.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"modal.js","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { isLargeTextScale } from \"@hjmds/design-contracts/components/design-system-provider\";\nimport {\n cloneElement,\n useCallback,\n useEffect,\n useRef,\n useState,\n type AriaAttributes,\n type MouseEventHandler,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { composeRefs } from \"./internal.js\";\nimport { getPopoverOwner } from \"./portal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport { createHjmThemeStyle } from \"./theme.js\";\n\n/*\n Shared modal machinery for Dialog, AlertDialog, Sheet, and SidePanel. Keeping it\n inside overlays.tsx would drag the Menu and Tooltip graph into SidePanel's granular\n entry; copying it would split `activeModalStack` in two, so a Dialog and a SidePanel\n would each believe they are topmost. The stack, the body-scroll lock, and background\n isolation must stay single module-level instances, so they live here alone.\n*/\n\nexport type TriggerElementProps = Readonly<{\n ref?: Ref<HTMLElement>;\n disabled?: boolean;\n onClick?: MouseEventHandler<HTMLElement>;\n onMouseEnter?: MouseEventHandler<HTMLElement>;\n onMouseLeave?: MouseEventHandler<HTMLElement>;\n onPointerDown?: React.PointerEventHandler<HTMLElement>;\n onPointerEnter?: React.PointerEventHandler<HTMLElement>;\n onPointerLeave?: React.PointerEventHandler<HTMLElement>;\n onFocus?: React.FocusEventHandler<HTMLElement>;\n onBlur?: React.FocusEventHandler<HTMLElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLElement>;\n \"aria-controls\"?: string;\n \"aria-describedby\"?: string;\n \"aria-disabled\"?: AriaAttributes[\"aria-disabled\"];\n \"aria-expanded\"?: AriaAttributes[\"aria-expanded\"];\n \"aria-haspopup\"?: AriaAttributes[\"aria-haspopup\"];\n}>;\n\nexport type OverlayTrigger = ReactElement<TriggerElementProps>;\n\nexport function containsEventTarget(\n container: Node | null,\n target: EventTarget | null,\n): boolean {\n return target !== null &&\n \"nodeType\" in target &&\n container?.contains(target as Node) === true;\n}\n\ntype ModalPortalProps = Readonly<{\n children: ReactNode;\n container?: HTMLElement;\n}>;\n\nexport function HjmPortal({ children, container }: ModalPortalProps) {\n const [mounted, setMounted] = useState(false);\n const theme = useOptionalHjmTheme();\n useEffect(() => setMounted(true), []);\n if (!mounted) return null;\n return createPortal(\n theme ? (\n <div\n className=\"hjm-root hjm-portal\"\n data-hjm-portal=\"\"\n data-motion={theme.environment.reducedMotion ? \"reduced\" : \"full\"}\n data-theme={theme.environment.theme}\n data-text-scale={theme.environment.textScale}\n data-large-text={isLargeTextScale(theme.environment.textScale) ? \"true\" : undefined}\n dir={theme.environment.direction}\n style={createHjmThemeStyle(theme)}\n >\n {children}\n </div>\n ) : children,\n container ?? document.body,\n );\n}\n\nexport type OpenState<Detail> =\n | Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange: (open: boolean, detail: Detail) => void;\n }>\n | Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: Detail) => void;\n }>;\n\nexport type ModalOpenState<Detail> =\n | Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange: (open: boolean, detail: Detail) => void;\n /** Optional for product-owned, programmatically controlled overlays. */\n trigger?: OverlayTrigger;\n }>\n | Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: Detail) => void;\n /** Uncontrolled overlays need a first-party activation target. */\n trigger: OverlayTrigger;\n }>;\n\nexport function useOpenState<Detail>({\n open,\n defaultOpen = false,\n onOpenChange,\n}: Readonly<{\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: Detail) => void;\n}>) {\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const controlled = open !== undefined;\n const currentOpen = controlled ? open : internalOpen;\n const pendingRequestRef = useRef<boolean | undefined>(undefined);\n useEffect(() => {\n if (pendingRequestRef.current === currentOpen) {\n pendingRequestRef.current = undefined;\n }\n }, [currentOpen]);\n const changeOpen = useCallback(\n (nextOpen: boolean, detail: Detail) => {\n if (\n nextOpen === currentOpen ||\n pendingRequestRef.current === nextOpen\n ) return;\n pendingRequestRef.current = nextOpen;\n if (!controlled) setInternalOpen(nextOpen);\n onOpenChange?.(nextOpen, detail);\n if (controlled && nextOpen) {\n queueMicrotask(() => {\n if (pendingRequestRef.current === true) {\n pendingRequestRef.current = undefined;\n }\n });\n }\n },\n [controlled, currentOpen, onOpenChange],\n );\n return [currentOpen, changeOpen] as const;\n}\n\nconst focusableSelector = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n \"[tabindex]:not([tabindex='-1'])\",\n].join(\",\");\n\nexport function getFocusable(container: HTMLElement): HTMLElement[] {\n return [...container.querySelectorAll<HTMLElement>(focusableSelector)].filter(\n (element) => element.tabIndex >= 0 && !element.matches(\":disabled\") &&\n !element.closest('[hidden],[inert],[aria-hidden=\"true\"]') &&\n element.getClientRects().length > 0 && getComputedStyle(element).visibility !== \"hidden\",\n );\n}\n\nlet bodyLockCount = 0;\nlet previousBodyOverflow = \"\";\ntype ActiveModal = Readonly<{\n element: HTMLElement;\n order: number;\n priority: number;\n}>;\nconst activeModalStack: ActiveModal[] = [];\nlet activeModalOrder = 0;\nconst isolatedModalBackground = new Map<\n HTMLElement,\n Readonly<{ ariaHidden: string | null; inert: boolean }>\n>();\nlet modalIsolationObserver: MutationObserver | null = null;\n\nfunction getOwnedPopupHosts(modal: ActiveModal): HTMLElement[] {\n const ownerId = modal.element.id;\n if (ownerId.length === 0) return [];\n return [...document.querySelectorAll<HTMLElement>(\"[data-hjm-popup-owner]\")]\n .filter((host) => host.getAttribute(\"data-hjm-popup-owner\") === ownerId);\n}\n\nfunction modalContainsNode(modal: ActiveModal, node: Node): boolean {\n return modal.element.contains(node) ||\n getOwnedPopupHosts(modal).some((host) => host.contains(node));\n}\n\nfunction getModalFocusable(modal: ActiveModal): HTMLElement[] {\n return [\n ...getFocusable(modal.element),\n ...getOwnedPopupHosts(modal).flatMap((host) => getFocusable(host)),\n ];\n}\n\nexport function getModalLayer(priority: number): number {\n if (!Number.isSafeInteger(priority)) {\n throw new TypeError(\"modalPriority must be a safe integer\");\n }\n return 1000 + priority;\n}\n\nfunction getTopModal(): ActiveModal | undefined {\n let top: ActiveModal | undefined;\n for (const modal of activeModalStack) {\n if (!modal.element.isConnected) continue;\n if (\n top === undefined ||\n modal.priority > top.priority ||\n (modal.priority === top.priority && modal.order > top.order)\n ) top = modal;\n }\n return top;\n}\n\nfunction modalRanksAbove(candidate: ActiveModal, reference: ActiveModal): boolean {\n return candidate.priority > reference.priority ||\n (candidate.priority === reference.priority && candidate.order > reference.order);\n}\n\nfunction restoreModalBackground(): void {\n for (const [element, previous] of isolatedModalBackground) {\n element.inert = previous.inert;\n if (previous.ariaHidden === null) element.removeAttribute(\"aria-hidden\");\n else element.setAttribute(\"aria-hidden\", previous.ariaHidden);\n }\n isolatedModalBackground.clear();\n}\n\nfunction isolateModalBackgroundElement(element: HTMLElement): void {\n if (isolatedModalBackground.has(element)) return;\n isolatedModalBackground.set(element, {\n ariaHidden: element.getAttribute(\"aria-hidden\"),\n inert: element.inert,\n });\n element.inert = true;\n element.setAttribute(\"aria-hidden\", \"true\");\n}\n\n/** Keeps only the top modal's ancestor path interactive, including late portals. */\nfunction synchronizeModalBackgroundIsolation(): void {\n restoreModalBackground();\n for (let index = activeModalStack.length - 1; index >= 0; index -= 1) {\n if (!activeModalStack[index]?.element.isConnected) activeModalStack.splice(index, 1);\n }\n const top = getTopModal();\n if (!top) {\n modalIsolationObserver?.disconnect();\n modalIsolationObserver = null;\n return;\n }\n\n const interactivePath = new Set<HTMLElement>();\n for (const root of [top.element, ...getOwnedPopupHosts(top)]) {\n let pathNode: HTMLElement | null = root;\n while (pathNode) {\n if (pathNode === document.body) break;\n interactivePath.add(pathNode);\n pathNode = pathNode.parentElement;\n }\n }\n const inspectedParents = new Set<HTMLElement>();\n for (const pathNode of interactivePath) {\n const parent = pathNode.parentElement;\n if (!parent || inspectedParents.has(parent)) continue;\n inspectedParents.add(parent);\n for (const sibling of parent.children) {\n if (sibling instanceof HTMLElement && !interactivePath.has(sibling)) {\n isolateModalBackgroundElement(sibling);\n }\n }\n }\n\n if (modalIsolationObserver === null) {\n modalIsolationObserver = new MutationObserver(() => {\n synchronizeModalBackgroundIsolation();\n });\n modalIsolationObserver.observe(document.body, {\n attributes: true,\n attributeFilter: [\"data-hjm-popup-owner\"],\n childList: true,\n subtree: true,\n });\n }\n}\n\nfunction lockBodyScroll(): () => void {\n if (bodyLockCount === 0) {\n previousBodyOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n }\n bodyLockCount += 1;\n return () => {\n bodyLockCount = Math.max(0, bodyLockCount - 1);\n if (bodyLockCount === 0) document.body.style.overflow = previousBodyOverflow;\n };\n}\n\ntype ModalFocusOptions = Readonly<{\n active: boolean;\n priority?: number;\n contentRef: React.RefObject<HTMLElement | null>;\n initialFocusRef?: React.RefObject<HTMLElement | null>;\n returnFocusRef?: React.RefObject<HTMLElement | null>;\n fallbackReturnRef?: React.RefObject<HTMLElement | null>;\n onEscape(): void;\n}>;\n\nexport function useModalFocus({\n active,\n priority = 0,\n contentRef,\n initialFocusRef,\n returnFocusRef,\n fallbackReturnRef,\n onEscape,\n}: ModalFocusOptions): void {\n const escapeRef = useRef(onEscape);\n escapeRef.current = onEscape;\n\n useEffect(() => {\n if (!active) return;\n let retryTimer: ReturnType<typeof setTimeout> | undefined;\n let release: (() => void) | undefined;\n let cancelled = false;\n\n const activate = () => {\n const content = contentRef.current;\n if (!content) {\n retryTimer = setTimeout(activate, 0);\n return;\n }\n const previouslyFocused = document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n const releaseScroll = lockBodyScroll();\n const modal: ActiveModal = {\n element: content,\n order: activeModalOrder += 1,\n priority,\n };\n activeModalStack.push(modal);\n synchronizeModalBackgroundIsolation();\n const initial = initialFocusRef?.current ?? getFocusable(content)[0] ?? content;\n if (getTopModal() === modal) initial.focus();\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (getTopModal() !== modal) return;\n if (event.key === \"Escape\") {\n // A focused non-modal child owns its first Escape. Let its content (or\n // nested menu) handle it before dismissing the containing modal.\n if (event.target instanceof Node && getPopoverOwner(event.target)) return;\n event.preventDefault();\n escapeRef.current();\n return;\n }\n if (event.key !== \"Tab\") return;\n const focusable = getModalFocusable(modal);\n if (focusable.length === 0) {\n event.preventDefault();\n content.focus();\n return;\n }\n const first = focusable[0]!;\n const last = focusable.at(-1)!;\n const current = document.activeElement;\n if (event.shiftKey && (current === first || !(current instanceof Node) || !modalContainsNode(modal, current))) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (current === last || !(current instanceof Node) || !modalContainsNode(modal, current))) {\n event.preventDefault();\n first.focus();\n }\n };\n const handleFocusIn = (event: FocusEvent) => {\n if (getTopModal() !== modal) return;\n if (event.target instanceof Node && !modalContainsNode(modal, event.target)) {\n (initialFocusRef?.current ?? getFocusable(content)[0] ?? content).focus();\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown, true);\n document.addEventListener(\"focusin\", handleFocusIn, true);\n release = () => {\n const wasTop = !activeModalStack.some(\n (candidate) =>\n candidate !== modal && candidate.element.isConnected && modalRanksAbove(candidate, modal),\n );\n document.removeEventListener(\"keydown\", handleKeyDown, true);\n document.removeEventListener(\"focusin\", handleFocusIn, true);\n const stackIndex = activeModalStack.lastIndexOf(modal);\n if (stackIndex >= 0) activeModalStack.splice(stackIndex, 1);\n synchronizeModalBackgroundIsolation();\n releaseScroll();\n const returnTarget =\n returnFocusRef?.current ?? fallbackReturnRef?.current ?? previouslyFocused;\n if (wasTop) {\n queueMicrotask(() => {\n const nextTop = getTopModal();\n if (!nextTop) {\n returnTarget?.focus();\n return;\n }\n if (returnTarget && modalContainsNode(nextTop, returnTarget)) returnTarget.focus();\n else (getModalFocusable(nextTop)[0] ?? nextTop.element).focus();\n });\n }\n };\n if (cancelled) release();\n };\n activate();\n return () => {\n cancelled = true;\n if (retryTimer !== undefined) clearTimeout(retryTimer);\n release?.();\n };\n }, [active, contentRef, fallbackReturnRef, initialFocusRef, priority, returnFocusRef]);\n}\n\nexport function renderTrigger(\n trigger: OverlayTrigger,\n triggerRef: React.RefObject<HTMLElement | null>,\n open: boolean,\n contentId: string,\n popup: \"dialog\" | \"menu\",\n onOpen: () => void,\n): ReactElement {\n const props = trigger.props;\n return cloneElement(trigger, {\n ref: composeRefs(props.ref, triggerRef),\n \"aria-controls\": contentId,\n \"aria-expanded\": open,\n \"aria-haspopup\": popup,\n onClick: (event) => {\n props.onClick?.(event);\n if (!event.defaultPrevented && !props.disabled) onOpen();\n },\n });\n}\n\n"]}
1
+ {"version":3,"file":"modal.js","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { layer } from \"@hjmds/design-contracts/foundations\";\nimport { isLargeTextScale } from \"@hjmds/design-contracts/components/design-system-provider\";\nimport {\n cloneElement,\n useCallback,\n useEffect,\n useRef,\n useState,\n type AriaAttributes,\n type MouseEventHandler,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { composeRefs } from \"./internal.js\";\nimport { getPopoverOwner } from \"./portal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport { createHjmThemeStyle } from \"./theme.js\";\n\n/*\n Shared modal machinery for Dialog, AlertDialog, Sheet, and SidePanel. Keeping it\n inside overlays.tsx would drag the Menu and Tooltip graph into SidePanel's granular\n entry; copying it would split `activeModalStack` in two, so a Dialog and a SidePanel\n would each believe they are topmost. The stack, the body-scroll lock, and background\n isolation must stay single module-level instances, so they live here alone.\n*/\n\nexport type TriggerElementProps = Readonly<{\n ref?: Ref<HTMLElement>;\n disabled?: boolean;\n onClick?: MouseEventHandler<HTMLElement>;\n onMouseEnter?: MouseEventHandler<HTMLElement>;\n onMouseLeave?: MouseEventHandler<HTMLElement>;\n onPointerDown?: React.PointerEventHandler<HTMLElement>;\n onPointerEnter?: React.PointerEventHandler<HTMLElement>;\n onPointerLeave?: React.PointerEventHandler<HTMLElement>;\n onFocus?: React.FocusEventHandler<HTMLElement>;\n onBlur?: React.FocusEventHandler<HTMLElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLElement>;\n \"aria-controls\"?: string;\n \"aria-describedby\"?: string;\n \"aria-disabled\"?: AriaAttributes[\"aria-disabled\"];\n \"aria-expanded\"?: AriaAttributes[\"aria-expanded\"];\n \"aria-haspopup\"?: AriaAttributes[\"aria-haspopup\"];\n}>;\n\nexport type OverlayTrigger = ReactElement<TriggerElementProps>;\n\nexport function containsEventTarget(\n container: Node | null,\n target: EventTarget | null,\n): boolean {\n return target !== null &&\n \"nodeType\" in target &&\n container?.contains(target as Node) === true;\n}\n\ntype ModalPortalProps = Readonly<{\n children: ReactNode;\n container?: HTMLElement;\n}>;\n\nexport function HjmPortal({ children, container }: ModalPortalProps) {\n const [mounted, setMounted] = useState(false);\n const theme = useOptionalHjmTheme();\n useEffect(() => setMounted(true), []);\n if (!mounted) return null;\n return createPortal(\n theme ? (\n <div\n className=\"hjm-root hjm-portal\"\n data-hjm-portal=\"\"\n data-motion={theme.environment.reducedMotion ? \"reduced\" : \"full\"}\n data-theme={theme.environment.theme}\n data-text-scale={theme.environment.textScale}\n data-large-text={isLargeTextScale(theme.environment.textScale) ? \"true\" : undefined}\n dir={theme.environment.direction}\n style={createHjmThemeStyle(theme)}\n >\n {children}\n </div>\n ) : children,\n container ?? document.body,\n );\n}\n\nexport type OpenState<Detail> =\n | Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange: (open: boolean, detail: Detail) => void;\n }>\n | Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: Detail) => void;\n }>;\n\nexport type ModalOpenState<Detail> =\n | Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange: (open: boolean, detail: Detail) => void;\n /** Optional for product-owned, programmatically controlled overlays. */\n trigger?: OverlayTrigger;\n }>\n | Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: Detail) => void;\n /** Uncontrolled overlays need a first-party activation target. */\n trigger: OverlayTrigger;\n }>;\n\nexport function useOpenState<Detail>({\n open,\n defaultOpen = false,\n onOpenChange,\n}: Readonly<{\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, detail: Detail) => void;\n}>) {\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const controlled = open !== undefined;\n const currentOpen = controlled ? open : internalOpen;\n const pendingRequestRef = useRef<boolean | undefined>(undefined);\n useEffect(() => {\n if (pendingRequestRef.current === currentOpen) {\n pendingRequestRef.current = undefined;\n }\n }, [currentOpen]);\n const changeOpen = useCallback(\n (nextOpen: boolean, detail: Detail) => {\n if (\n nextOpen === currentOpen ||\n pendingRequestRef.current === nextOpen\n ) return;\n pendingRequestRef.current = nextOpen;\n if (!controlled) setInternalOpen(nextOpen);\n onOpenChange?.(nextOpen, detail);\n if (controlled && nextOpen) {\n queueMicrotask(() => {\n if (pendingRequestRef.current === true) {\n pendingRequestRef.current = undefined;\n }\n });\n }\n },\n [controlled, currentOpen, onOpenChange],\n );\n return [currentOpen, changeOpen] as const;\n}\n\nconst focusableSelector = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n \"[tabindex]:not([tabindex='-1'])\",\n].join(\",\");\n\nexport function getFocusable(container: HTMLElement): HTMLElement[] {\n return [...container.querySelectorAll<HTMLElement>(focusableSelector)].filter(\n (element) => element.tabIndex >= 0 && !element.matches(\":disabled\") &&\n !element.closest('[hidden],[inert],[aria-hidden=\"true\"]') &&\n element.getClientRects().length > 0 && getComputedStyle(element).visibility !== \"hidden\",\n );\n}\n\nlet bodyLockCount = 0;\nlet previousBodyOverflow = \"\";\ntype ActiveModal = Readonly<{\n element: HTMLElement;\n order: number;\n priority: number;\n}>;\nconst activeModalStack: ActiveModal[] = [];\nlet activeModalOrder = 0;\nconst isolatedModalBackground = new Map<\n HTMLElement,\n Readonly<{ ariaHidden: string | null; inert: boolean }>\n>();\nlet modalIsolationObserver: MutationObserver | null = null;\n\nfunction getOwnedPopupHosts(modal: ActiveModal): HTMLElement[] {\n const ownerId = modal.element.id;\n if (ownerId.length === 0) return [];\n return [...document.querySelectorAll<HTMLElement>(\"[data-hjm-popup-owner]\")]\n .filter((host) => host.getAttribute(\"data-hjm-popup-owner\") === ownerId);\n}\n\nfunction modalContainsNode(modal: ActiveModal, node: Node): boolean {\n return modal.element.contains(node) ||\n getOwnedPopupHosts(modal).some((host) => host.contains(node));\n}\n\nfunction getModalFocusable(modal: ActiveModal): HTMLElement[] {\n return [\n ...getFocusable(modal.element),\n ...getOwnedPopupHosts(modal).flatMap((host) => getFocusable(host)),\n ];\n}\n\nexport function getModalLayer(priority: number): number {\n if (!Number.isSafeInteger(priority)) {\n throw new TypeError(\"modalPriority must be a safe integer\");\n }\n // Keep priority ordering inside the shared modal tier; copied Web-only bases\n // made product layer tokens disagree with actual overlay order.\n return layer.modal + priority;\n}\n\nfunction getTopModal(): ActiveModal | undefined {\n let top: ActiveModal | undefined;\n for (const modal of activeModalStack) {\n if (!modal.element.isConnected) continue;\n if (\n top === undefined ||\n modal.priority > top.priority ||\n (modal.priority === top.priority && modal.order > top.order)\n ) top = modal;\n }\n return top;\n}\n\nfunction modalRanksAbove(candidate: ActiveModal, reference: ActiveModal): boolean {\n return candidate.priority > reference.priority ||\n (candidate.priority === reference.priority && candidate.order > reference.order);\n}\n\nfunction restoreModalBackground(): void {\n for (const [element, previous] of isolatedModalBackground) {\n element.inert = previous.inert;\n if (previous.ariaHidden === null) element.removeAttribute(\"aria-hidden\");\n else element.setAttribute(\"aria-hidden\", previous.ariaHidden);\n }\n isolatedModalBackground.clear();\n}\n\nfunction isolateModalBackgroundElement(element: HTMLElement): void {\n if (isolatedModalBackground.has(element)) return;\n isolatedModalBackground.set(element, {\n ariaHidden: element.getAttribute(\"aria-hidden\"),\n inert: element.inert,\n });\n element.inert = true;\n element.setAttribute(\"aria-hidden\", \"true\");\n}\n\n/** Keeps only the top modal's ancestor path interactive, including late portals. */\nfunction synchronizeModalBackgroundIsolation(): void {\n restoreModalBackground();\n for (let index = activeModalStack.length - 1; index >= 0; index -= 1) {\n if (!activeModalStack[index]?.element.isConnected) activeModalStack.splice(index, 1);\n }\n const top = getTopModal();\n if (!top) {\n modalIsolationObserver?.disconnect();\n modalIsolationObserver = null;\n return;\n }\n\n const interactivePath = new Set<HTMLElement>();\n for (const root of [top.element, ...getOwnedPopupHosts(top)]) {\n let pathNode: HTMLElement | null = root;\n while (pathNode) {\n if (pathNode === document.body) break;\n interactivePath.add(pathNode);\n pathNode = pathNode.parentElement;\n }\n }\n const inspectedParents = new Set<HTMLElement>();\n for (const pathNode of interactivePath) {\n const parent = pathNode.parentElement;\n if (!parent || inspectedParents.has(parent)) continue;\n inspectedParents.add(parent);\n for (const sibling of parent.children) {\n if (sibling instanceof HTMLElement && !interactivePath.has(sibling)) {\n isolateModalBackgroundElement(sibling);\n }\n }\n }\n\n if (modalIsolationObserver === null) {\n modalIsolationObserver = new MutationObserver(() => {\n synchronizeModalBackgroundIsolation();\n });\n modalIsolationObserver.observe(document.body, {\n attributes: true,\n attributeFilter: [\"data-hjm-popup-owner\"],\n childList: true,\n subtree: true,\n });\n }\n}\n\nfunction lockBodyScroll(): () => void {\n if (bodyLockCount === 0) {\n previousBodyOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n }\n bodyLockCount += 1;\n return () => {\n bodyLockCount = Math.max(0, bodyLockCount - 1);\n if (bodyLockCount === 0) document.body.style.overflow = previousBodyOverflow;\n };\n}\n\ntype ModalFocusOptions = Readonly<{\n active: boolean;\n priority?: number;\n contentRef: React.RefObject<HTMLElement | null>;\n initialFocusRef?: React.RefObject<HTMLElement | null>;\n returnFocusRef?: React.RefObject<HTMLElement | null>;\n fallbackReturnRef?: React.RefObject<HTMLElement | null>;\n onEscape(): void;\n}>;\n\nexport function useModalFocus({\n active,\n priority = 0,\n contentRef,\n initialFocusRef,\n returnFocusRef,\n fallbackReturnRef,\n onEscape,\n}: ModalFocusOptions): void {\n const escapeRef = useRef(onEscape);\n escapeRef.current = onEscape;\n\n useEffect(() => {\n if (!active) return;\n let retryTimer: ReturnType<typeof setTimeout> | undefined;\n let release: (() => void) | undefined;\n let cancelled = false;\n\n const activate = () => {\n const content = contentRef.current;\n if (!content) {\n retryTimer = setTimeout(activate, 0);\n return;\n }\n const previouslyFocused = document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n const releaseScroll = lockBodyScroll();\n const modal: ActiveModal = {\n element: content,\n order: activeModalOrder += 1,\n priority,\n };\n activeModalStack.push(modal);\n synchronizeModalBackgroundIsolation();\n const initial = initialFocusRef?.current ?? getFocusable(content)[0] ?? content;\n if (getTopModal() === modal) initial.focus();\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (getTopModal() !== modal) return;\n if (event.key === \"Escape\") {\n // A focused non-modal child owns its first Escape. Let its content (or\n // nested menu) handle it before dismissing the containing modal.\n if (event.target instanceof Node && getPopoverOwner(event.target)) return;\n event.preventDefault();\n escapeRef.current();\n return;\n }\n if (event.key !== \"Tab\") return;\n const focusable = getModalFocusable(modal);\n if (focusable.length === 0) {\n event.preventDefault();\n content.focus();\n return;\n }\n const first = focusable[0]!;\n const last = focusable.at(-1)!;\n const current = document.activeElement;\n if (event.shiftKey && (current === first || !(current instanceof Node) || !modalContainsNode(modal, current))) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (current === last || !(current instanceof Node) || !modalContainsNode(modal, current))) {\n event.preventDefault();\n first.focus();\n }\n };\n const handleFocusIn = (event: FocusEvent) => {\n if (getTopModal() !== modal) return;\n if (event.target instanceof Node && !modalContainsNode(modal, event.target)) {\n (initialFocusRef?.current ?? getFocusable(content)[0] ?? content).focus();\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown, true);\n document.addEventListener(\"focusin\", handleFocusIn, true);\n release = () => {\n const wasTop = !activeModalStack.some(\n (candidate) =>\n candidate !== modal && candidate.element.isConnected && modalRanksAbove(candidate, modal),\n );\n document.removeEventListener(\"keydown\", handleKeyDown, true);\n document.removeEventListener(\"focusin\", handleFocusIn, true);\n const stackIndex = activeModalStack.lastIndexOf(modal);\n if (stackIndex >= 0) activeModalStack.splice(stackIndex, 1);\n synchronizeModalBackgroundIsolation();\n releaseScroll();\n const returnTarget =\n returnFocusRef?.current ?? fallbackReturnRef?.current ?? previouslyFocused;\n if (wasTop) {\n queueMicrotask(() => {\n const nextTop = getTopModal();\n if (!nextTop) {\n returnTarget?.focus();\n return;\n }\n if (returnTarget && modalContainsNode(nextTop, returnTarget)) returnTarget.focus();\n else (getModalFocusable(nextTop)[0] ?? nextTop.element).focus();\n });\n }\n };\n if (cancelled) release();\n };\n activate();\n return () => {\n cancelled = true;\n if (retryTimer !== undefined) clearTimeout(retryTimer);\n release?.();\n };\n }, [active, contentRef, fallbackReturnRef, initialFocusRef, priority, returnFocusRef]);\n}\n\nexport function renderTrigger(\n trigger: OverlayTrigger,\n triggerRef: React.RefObject<HTMLElement | null>,\n open: boolean,\n contentId: string,\n popup: \"dialog\" | \"menu\",\n onOpen: () => void,\n): ReactElement {\n const props = trigger.props;\n return cloneElement(trigger, {\n ref: composeRefs(props.ref, triggerRef),\n \"aria-controls\": contentId,\n \"aria-expanded\": open,\n \"aria-haspopup\": popup,\n onClick: (event) => {\n props.onClick?.(event);\n if (!event.defaultPrevented && !props.disabled) onOpen();\n },\n });\n}\n\n"]}
@@ -1,10 +1,13 @@
1
1
  import type { ReactNode } from "react";
2
+ import type { HjmCompositionStyleProp } from "./composition-style.js";
2
3
  export type NavigationBarProps = Readonly<{
3
4
  label: string;
4
5
  brand: ReactNode;
5
6
  children: ReactNode;
6
7
  actions?: ReactNode;
8
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
9
+ layoutStyle?: HjmCompositionStyleProp;
7
10
  }>;
8
11
  /** Site navigation composition; Menu/SearchField continue to own their behavior. */
9
- export declare function NavigationBar({ label, brand, children, actions }: NavigationBarProps): import("react").JSX.Element;
12
+ export declare function NavigationBar({ label, brand, children, actions, layoutStyle }: NavigationBarProps): import("react").JSX.Element;
10
13
  //# sourceMappingURL=navigation-bar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"navigation-bar.d.ts","sourceRoot":"","sources":["../src/navigation-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB,CAAC,CAAC;AAEH,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,kBAAkB,+BAQpF"}
1
+ {"version":3,"file":"navigation-bar.d.ts","sourceRoot":"","sources":["../src/navigation-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEH,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,kBAAkB,+BAQjG"}
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useOptionalHjmTheme } from "./provider.js";
3
3
  /** Site navigation composition; Menu/SearchField continue to own their behavior. */
4
- export function NavigationBar({ label, brand, children, actions }) {
4
+ export function NavigationBar({ label, brand, children, actions, layoutStyle }) {
5
5
  const theme = useOptionalHjmTheme();
6
6
  if (!label.trim())
7
7
  throw new TypeError("NavigationBar requires an accessible label");
8
- return _jsxs("nav", { "aria-label": label, className: "hjm-navigation-bar", dir: theme?.environment.direction, children: [_jsx("div", { className: "hjm-navigation-bar__brand", children: brand }), _jsx("div", { className: "hjm-navigation-bar__destinations", children: children }), actions && _jsx("div", { className: "hjm-navigation-bar__actions", children: actions })] });
8
+ return _jsxs("nav", { "aria-label": label, className: "hjm-navigation-bar", style: layoutStyle, dir: theme?.environment.direction, children: [_jsx("div", { className: "hjm-navigation-bar__brand", children: brand }), _jsx("div", { className: "hjm-navigation-bar__destinations", children: children }), actions && _jsx("div", { className: "hjm-navigation-bar__actions", children: actions })] });
9
9
  }
10
10
  //# sourceMappingURL=navigation-bar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"navigation-bar.js","sourceRoot":"","sources":["../src/navigation-bar.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AASpD,oFAAoF;AACpF,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAsB;IACnF,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;IACpC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,4CAA4C,CAAC,CAAC;IACrF,OAAO,6BAAiB,KAAK,EAAE,SAAS,EAAC,oBAAoB,EAAC,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,SAAS,aAC7F,cAAK,SAAS,EAAC,2BAA2B,YAAE,KAAK,GAAO,EACxD,cAAK,SAAS,EAAC,kCAAkC,YAAE,QAAQ,GAAO,EACjE,OAAO,IAAI,cAAK,SAAS,EAAC,6BAA6B,YAAE,OAAO,GAAO,IACpE,CAAC;AACT,CAAC","sourcesContent":["import type { ReactNode } from \"react\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\n\nexport type NavigationBarProps = Readonly<{\n label: string;\n brand: ReactNode;\n children: ReactNode;\n actions?: ReactNode;\n}>;\n\n/** Site navigation composition; Menu/SearchField continue to own their behavior. */\nexport function NavigationBar({ label, brand, children, actions }: NavigationBarProps) {\n const theme = useOptionalHjmTheme();\n if (!label.trim()) throw new TypeError(\"NavigationBar requires an accessible label\");\n return <nav aria-label={label} className=\"hjm-navigation-bar\" dir={theme?.environment.direction}>\n <div className=\"hjm-navigation-bar__brand\">{brand}</div>\n <div className=\"hjm-navigation-bar__destinations\">{children}</div>\n {actions && <div className=\"hjm-navigation-bar__actions\">{actions}</div>}\n </nav>;\n}\n"]}
1
+ {"version":3,"file":"navigation-bar.js","sourceRoot":"","sources":["../src/navigation-bar.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAYpD,oFAAoF;AACpF,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAsB;IAChG,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;IACpC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,4CAA4C,CAAC,CAAC;IACrF,OAAO,6BAAiB,KAAK,EAAE,SAAS,EAAC,oBAAoB,EAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,SAAS,aACjH,cAAK,SAAS,EAAC,2BAA2B,YAAE,KAAK,GAAO,EACxD,cAAK,SAAS,EAAC,kCAAkC,YAAE,QAAQ,GAAO,EACjE,OAAO,IAAI,cAAK,SAAS,EAAC,6BAA6B,YAAE,OAAO,GAAO,IACpE,CAAC;AACT,CAAC","sourcesContent":["import type { ReactNode } from \"react\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type NavigationBarProps = Readonly<{\n label: string;\n brand: ReactNode;\n children: ReactNode;\n actions?: ReactNode;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\n/** Site navigation composition; Menu/SearchField continue to own their behavior. */\nexport function NavigationBar({ label, brand, children, actions, layoutStyle }: NavigationBarProps) {\n const theme = useOptionalHjmTheme();\n if (!label.trim()) throw new TypeError(\"NavigationBar requires an accessible label\");\n return <nav aria-label={label} className=\"hjm-navigation-bar\" style={layoutStyle} dir={theme?.environment.direction}>\n <div className=\"hjm-navigation-bar__brand\">{brand}</div>\n <div className=\"hjm-navigation-bar__destinations\">{children}</div>\n {actions && <div className=\"hjm-navigation-bar__actions\">{actions}</div>}\n </nav>;\n}\n"]}