@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/affix.js CHANGED
@@ -2,7 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import { useEffect, useRef, useState } from "react";
3
3
  import { affixRecipe, validateAffixOffset } from "@hjmds/design-contracts/components/affix";
4
4
  /** CSS keeps natural flow, parent boundaries and focus intact; JS only observes state and oversize content. */
5
- export function Affix({ children, offset = affixRecipe.offset, disabled = false, onChange }) {
5
+ export function Affix({ children, offset = affixRecipe.offset, disabled = false, onChange, layoutStyle }) {
6
6
  validateAffixOffset(offset);
7
7
  const marker = useRef(null);
8
8
  const content = useRef(null);
@@ -46,6 +46,6 @@ export function Affix({ children, offset = affixRecipe.offset, disabled = false,
46
46
  window.addEventListener("resize", schedule);
47
47
  return () => { cancelAnimationFrame(frame); resize.disconnect(); document.removeEventListener("scroll", schedule, true); window.removeEventListener("resize", schedule); };
48
48
  }, [offset, disabled, oversize]);
49
- return _jsxs(_Fragment, { children: [_jsx("span", { ref: marker, className: "hjm-affix__marker", "aria-hidden": "true" }), _jsx("div", { ref: content, "data-hjm-affix": true, "data-affixed": affixed, "data-oversize": oversize, className: "hjm-affix", style: { position: disabled || oversize ? "relative" : affixRecipe.position, top: disabled || oversize ? undefined : offset }, children: children })] });
49
+ return _jsxs(_Fragment, { children: [_jsx("span", { ref: marker, className: "hjm-affix__marker", "aria-hidden": "true" }), _jsx("div", { ref: content, "data-hjm-affix": true, "data-affixed": affixed, "data-oversize": oversize, className: "hjm-affix", style: { ...layoutStyle, position: disabled || oversize ? "relative" : affixRecipe.position, top: disabled || oversize ? undefined : offset }, children: children })] });
50
50
  }
51
51
  //# sourceMappingURL=affix.js.map
package/dist/affix.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"affix.js","sourceRoot":"","sources":["../src/affix.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { affixRecipe, validateAffixOffset } from \"@hjmds/design-contracts/components/affix\";\nexport type AffixProps = Readonly<{ children: ReactNode; offset?: number; disabled?: boolean; onChange?: (affixed: boolean) => void }>;\n/** CSS keeps natural flow, parent boundaries and focus intact; JS only observes state and oversize content. */\nexport function Affix({ children, offset = affixRecipe.offset, disabled = false, onChange }: AffixProps) {\n validateAffixOffset(offset);\n const marker = useRef<HTMLSpanElement>(null);\n const content = useRef<HTMLDivElement>(null);\n const callback = useRef(onChange); callback.current = onChange;\n const [affixed, setAffixed] = useState(false);\n const [oversize, setOversize] = useState(false);\n const reported = useRef<boolean | undefined>(undefined);\n useEffect(() => {\n const node = content.current; const sentinel = marker.current;\n if (!node || !sentinel) return;\n let frame = 0;\n function measure() {\n frame = 0;\n let scrollRoot = node!.parentElement;\n while (scrollRoot && !/(auto|scroll|hidden|overlay)/.test(getComputedStyle(scrollRoot).overflowY)) scrollRoot = scrollRoot.parentElement;\n const viewportHeight = scrollRoot?.clientHeight ?? document.documentElement.clientHeight;\n const edge = (scrollRoot ? scrollRoot.getBoundingClientRect().top + scrollRoot.clientTop : 0) + offset;\n const rect = node!.getBoundingClientRect();\n const tooTall = rect.height > viewportHeight - offset;\n setOversize(tooTall);\n // One CSS pixel tolerates subpixel scroll rounding, not a second positioning system.\n const next = !disabled && !tooTall && sentinel!.getBoundingClientRect().top < edge && Math.abs(rect.top - edge) <= 1;\n setAffixed(next);\n if (reported.current !== next) { reported.current = next; callback.current?.(next); }\n }\n const schedule = () => { if (!frame) frame = requestAnimationFrame(measure); };\n const resize = new ResizeObserver(schedule);\n resize.observe(node);\n for (let parent = node.parentElement; parent; parent = parent.parentElement) resize.observe(parent);\n measure(); document.addEventListener(\"scroll\", schedule, true); window.addEventListener(\"resize\", schedule);\n return () => { cancelAnimationFrame(frame); resize.disconnect(); document.removeEventListener(\"scroll\", schedule, true); window.removeEventListener(\"resize\", schedule); };\n }, [offset, disabled, oversize]);\n return <><span ref={marker} className=\"hjm-affix__marker\" aria-hidden=\"true\" /><div ref={content} data-hjm-affix data-affixed={affixed} data-oversize={oversize} className=\"hjm-affix\" style={{ position: disabled || oversize ? \"relative\" : affixRecipe.position, top: disabled || oversize ? undefined : offset }}>{children}</div></>;\n}\n"]}
1
+ {"version":3,"file":"affix.js","sourceRoot":"","sources":["../src/affix.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { affixRecipe, validateAffixOffset } from \"@hjmds/design-contracts/components/affix\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\nexport type AffixProps = Readonly<{ children: ReactNode; offset?: number; disabled?: boolean; onChange?: (affixed: boolean) => void;\n /** Canonical layout-only placement on the sticky box. `position`/`top` stay Affix-owned. */\n layoutStyle?: HjmCompositionStyleProp }>;\n/** CSS keeps natural flow, parent boundaries and focus intact; JS only observes state and oversize content. */\nexport function Affix({ children, offset = affixRecipe.offset, disabled = false, onChange, layoutStyle }: AffixProps) {\n validateAffixOffset(offset);\n const marker = useRef<HTMLSpanElement>(null);\n const content = useRef<HTMLDivElement>(null);\n const callback = useRef(onChange); callback.current = onChange;\n const [affixed, setAffixed] = useState(false);\n const [oversize, setOversize] = useState(false);\n const reported = useRef<boolean | undefined>(undefined);\n useEffect(() => {\n const node = content.current; const sentinel = marker.current;\n if (!node || !sentinel) return;\n let frame = 0;\n function measure() {\n frame = 0;\n let scrollRoot = node!.parentElement;\n while (scrollRoot && !/(auto|scroll|hidden|overlay)/.test(getComputedStyle(scrollRoot).overflowY)) scrollRoot = scrollRoot.parentElement;\n const viewportHeight = scrollRoot?.clientHeight ?? document.documentElement.clientHeight;\n const edge = (scrollRoot ? scrollRoot.getBoundingClientRect().top + scrollRoot.clientTop : 0) + offset;\n const rect = node!.getBoundingClientRect();\n const tooTall = rect.height > viewportHeight - offset;\n setOversize(tooTall);\n // One CSS pixel tolerates subpixel scroll rounding, not a second positioning system.\n const next = !disabled && !tooTall && sentinel!.getBoundingClientRect().top < edge && Math.abs(rect.top - edge) <= 1;\n setAffixed(next);\n if (reported.current !== next) { reported.current = next; callback.current?.(next); }\n }\n const schedule = () => { if (!frame) frame = requestAnimationFrame(measure); };\n const resize = new ResizeObserver(schedule);\n resize.observe(node);\n for (let parent = node.parentElement; parent; parent = parent.parentElement) resize.observe(parent);\n measure(); document.addEventListener(\"scroll\", schedule, true); window.addEventListener(\"resize\", schedule);\n return () => { cancelAnimationFrame(frame); resize.disconnect(); document.removeEventListener(\"scroll\", schedule, true); window.removeEventListener(\"resize\", schedule); };\n }, [offset, disabled, oversize]);\n return <><span ref={marker} className=\"hjm-affix__marker\" aria-hidden=\"true\" /><div ref={content} data-hjm-affix data-affixed={affixed} data-oversize={oversize} className=\"hjm-affix\" style={{ ...layoutStyle, position: disabled || oversize ? \"relative\" : affixRecipe.position, top: disabled || oversize ? undefined : offset }}>{children}</div></>;\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { type AgreementDescriptor, type AgreementState } from "@hjmds/design-contracts/components/agreement";
2
+ import type { HjmCompositionStyleProp } from "./composition-style.js";
2
3
  export type AgreementProps<Id extends string = string> = Readonly<{
3
4
  descriptor: AgreementDescriptor<Id>;
4
5
  checkedIds?: ReadonlySet<Id>;
@@ -13,6 +14,8 @@ export type AgreementProps<Id extends string = string> = Readonly<{
13
14
  /** Localized suffix marking an optional row, supplied by the product. */
14
15
  optionalLabel: string;
15
16
  className?: string;
17
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
18
+ layoutStyle?: HjmCompositionStyleProp;
16
19
  }>;
17
20
  export declare const Agreement: <Id extends string = string>(props: AgreementProps<Id> & {
18
21
  ref?: React.Ref<HTMLDivElement>;
@@ -1 +1 @@
1
- {"version":3,"file":"agreement.d.ts","sourceRoot":"","sources":["../src/agreement.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACpB,MAAM,8CAA8C,CAAC;AAItD,MAAM,MAAM,cAAc,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAChE,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7B,iBAAiB,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;IACpC,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IACpD,4EAA4E;IAC5E,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IACpD,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;IAC5B,wEAAwE;IACxE,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAUH,eAAO,MAAM,SAAS,EAoGhB,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,EAC/B,KAAK,EAAE,cAAc,CAAC,EAAE,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;CAAE,KAC5D,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"agreement.d.ts","sourceRoot":"","sources":["../src/agreement.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACpB,MAAM,8CAA8C,CAAC;AAGtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,cAAc,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAChE,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7B,iBAAiB,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;IACpC,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IACpD,4EAA4E;IAC5E,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IACpD,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;IAC5B,wEAAwE;IACxE,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAUH,eAAO,MAAM,SAAS,EAiHhB,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,EAC/B,KAAK,EAAE,cAAc,CAAC,EAAE,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;CAAE,KAC5D,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC"}
package/dist/agreement.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { reconcileAgreementSelection, resolveAgreementState, toggleAgreementAll, toggleAgreementItem, validateAgreementDescriptor, } from "@hjmds/design-contracts/components/agreement";
3
- import { forwardRef, useId, useMemo } from "react";
3
+ import { forwardRef, useEffect, useId, useMemo, useRef } from "react";
4
4
  import { classNames, useControllableState } from "./internal.js";
5
5
  function Mark({ state }) {
6
6
  return (_jsx("span", { "aria-hidden": "true", className: "hjm-agreement__mark", "data-state": String(state), children: state === true ? "✓" : state === "mixed" ? "–" : "" }));
7
7
  }
8
- export const Agreement = forwardRef(function Agreement({ descriptor, checkedIds: controlledChecked, defaultCheckedIds, onCheckedIdsChange, onStateChange, onDetail, requiredLabel, optionalLabel, className, }, forwardedRef) {
8
+ export const Agreement = forwardRef(function Agreement({ descriptor, checkedIds: controlledChecked, defaultCheckedIds, onCheckedIdsChange, onStateChange, onDetail, requiredLabel, optionalLabel, className, layoutStyle, }, forwardedRef) {
9
9
  validateAgreementDescriptor(descriptor);
10
10
  const [rawChecked, setChecked] = useControllableState({
11
11
  ...(controlledChecked === undefined ? {} : { value: controlledChecked }),
@@ -16,11 +16,22 @@ export const Agreement = forwardRef(function Agreement({ descriptor, checkedIds:
16
16
  const checked = useMemo(() => reconcileAgreementSelection(descriptor, rawChecked), [descriptor, rawChecked]);
17
17
  const state = resolveAgreementState(descriptor, checked);
18
18
  const id = `${useId().replaceAll(":", "")}-agreement`;
19
+ // Report the initial state once on mount. Until 2026-10-06 only user toggles reported, so
20
+ // `defaultCheckedIds`/`checkedIds` that already satisfied every required item never produced a
21
+ // first `satisfied: true` and a submit button wired to this callback stayed disabled. Mount-only
22
+ // (not on every derived change) keeps the callback count to "initial + one per toggle"; StrictMode
23
+ // may repeat the same snapshot, which is idempotent for a consumer that stores it.
24
+ const initialStateRef = useRef(state);
25
+ const onStateChangeRef = useRef(onStateChange);
26
+ onStateChangeRef.current = onStateChange;
27
+ useEffect(() => {
28
+ onStateChangeRef.current?.(initialStateRef.current);
29
+ }, []);
19
30
  const commit = (next) => {
20
31
  setChecked(next);
21
32
  onStateChange?.(resolveAgreementState(descriptor, next));
22
33
  };
23
- return (_jsxs("div", { ref: forwardedRef, role: "group", "aria-label": descriptor.accessibilityLabel, className: classNames("hjm-agreement", className), children: [_jsxs("button", { type: "button", role: "checkbox", "aria-checked": state.all === "mixed" ? "mixed" : String(state.all === true), className: "hjm-agreement__all", onClick: () => commit(toggleAgreementAll(descriptor, checked)), children: [_jsx(Mark, { state: state.all }), _jsx("span", { children: descriptor.allLabel })] }), _jsx("div", { className: "hjm-agreement__list", children: descriptor.items.map((item) => {
34
+ return (_jsxs("div", { ref: forwardedRef, role: "group", "aria-label": descriptor.accessibilityLabel, style: layoutStyle, className: classNames("hjm-agreement", className), children: [_jsxs("button", { type: "button", role: "checkbox", "aria-checked": state.all === "mixed" ? "mixed" : String(state.all === true), className: "hjm-agreement__all", onClick: () => commit(toggleAgreementAll(descriptor, checked)), children: [_jsx(Mark, { state: state.all }), _jsx("span", { children: descriptor.allLabel })] }), _jsx("div", { className: "hjm-agreement__list", children: descriptor.items.map((item) => {
24
35
  const itemChecked = checked.has(item.id);
25
36
  return (_jsxs("div", { className: "hjm-agreement__item", "data-disabled": item.disabled || undefined, children: [_jsxs("button", { type: "button", role: "checkbox", id: `${id}-${item.id}`, "aria-checked": itemChecked, "aria-disabled": item.disabled || undefined, "aria-describedby": item.description ? `${id}-${item.id}-description` : undefined, className: "hjm-agreement__toggle", onClick: () => { if (!item.disabled)
26
37
  commit(toggleAgreementItem(descriptor, checked, item.id)); }, children: [_jsx(Mark, { state: itemChecked }), _jsxs("span", { className: "hjm-agreement__copy", children: [_jsx("span", { children: item.label }), _jsx("span", { className: "hjm-agreement__required", "data-required": item.required || undefined, children: item.required ? requiredLabel : optionalLabel })] })] }), item.description ? (_jsx("p", { id: `${id}-${item.id}-description`, className: "hjm-agreement__description", children: item.description })) : null, item.detail ? (item.detail.href ? (_jsx("a", { className: "hjm-agreement__detail", href: item.detail.href, children: item.detail.label })) : (_jsx("button", { type: "button", className: "hjm-agreement__detail", onClick: () => onDetail?.(item.id), children: item.detail.label }))) : null] }, item.id));
@@ -1 +1 @@
1
- {"version":3,"file":"agreement.js","sourceRoot":"","sources":["../src/agreement.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n reconcileAgreementSelection,\n resolveAgreementState,\n toggleAgreementAll,\n toggleAgreementItem,\n validateAgreementDescriptor,\n type AgreementDescriptor,\n type AgreementState,\n} from \"@hjmds/design-contracts/components/agreement\";\nimport { forwardRef, useId, useMemo } from \"react\";\nimport { classNames, useControllableState } from \"./internal.js\";\n\nexport type AgreementProps<Id extends string = string> = Readonly<{\n descriptor: AgreementDescriptor<Id>;\n checkedIds?: ReadonlySet<Id>;\n defaultCheckedIds?: ReadonlySet<Id>;\n onCheckedIdsChange?: (ids: ReadonlySet<Id>) => void;\n /** Fires the derived state on every change, for a submit button to read. */\n onStateChange?: (state: AgreementState<Id>) => void;\n /** Called when an item's full text is requested and it carries no href. */\n onDetail?: (id: Id) => void;\n /** Localized suffix marking a required row, supplied by the product. */\n requiredLabel: string;\n /** Localized suffix marking an optional row, supplied by the product. */\n optionalLabel: string;\n className?: string;\n}>;\n\nfunction Mark({ state }: { state: boolean | \"mixed\" }) {\n return (\n <span aria-hidden=\"true\" className=\"hjm-agreement__mark\" data-state={String(state)}>\n {state === true ? \"✓\" : state === \"mixed\" ? \"–\" : \"\"}\n </span>\n );\n}\n\nexport const Agreement = forwardRef(function Agreement<Id extends string = string>(\n {\n descriptor,\n checkedIds: controlledChecked,\n defaultCheckedIds,\n onCheckedIdsChange,\n onStateChange,\n onDetail,\n requiredLabel,\n optionalLabel,\n className,\n }: AgreementProps<Id>,\n forwardedRef: React.Ref<HTMLDivElement>,\n) {\n validateAgreementDescriptor(descriptor);\n const [rawChecked, setChecked] = useControllableState<ReadonlySet<Id>>({\n ...(controlledChecked === undefined ? {} : { value: controlledChecked }),\n defaultValue: defaultCheckedIds ?? new Set<Id>(),\n ...(onCheckedIdsChange === undefined ? {} : { onChange: onCheckedIdsChange }),\n });\n // An item that left the list must not keep an orphan consent behind it.\n const checked = useMemo(\n () => reconcileAgreementSelection(descriptor, rawChecked),\n [descriptor, rawChecked],\n );\n const state = resolveAgreementState(descriptor, checked);\n const id = `${useId().replaceAll(\":\", \"\")}-agreement`;\n\n const commit = (next: ReadonlySet<Id>) => {\n setChecked(next);\n onStateChange?.(resolveAgreementState(descriptor, next));\n };\n\n return (\n <div\n ref={forwardedRef}\n role=\"group\"\n aria-label={descriptor.accessibilityLabel}\n className={classNames(\"hjm-agreement\", className)}\n >\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={state.all === \"mixed\" ? \"mixed\" : String(state.all === true) as \"true\" | \"false\"}\n className=\"hjm-agreement__all\"\n onClick={() => commit(toggleAgreementAll(descriptor, checked))}\n >\n <Mark state={state.all} />\n <span>{descriptor.allLabel}</span>\n </button>\n <div className=\"hjm-agreement__list\">\n {descriptor.items.map((item) => {\n const itemChecked = checked.has(item.id);\n return (\n <div key={item.id} className=\"hjm-agreement__item\" data-disabled={item.disabled || undefined}>\n <button\n type=\"button\"\n role=\"checkbox\"\n id={`${id}-${item.id}`}\n aria-checked={itemChecked}\n aria-disabled={item.disabled || undefined}\n aria-describedby={item.description ? `${id}-${item.id}-description` : undefined}\n className=\"hjm-agreement__toggle\"\n onClick={() => { if (!item.disabled) commit(toggleAgreementItem(descriptor, checked, item.id)); }}\n >\n <Mark state={itemChecked} />\n <span className=\"hjm-agreement__copy\">\n {/*\n Required/optional rides inside the control's own name: a\n visual-only marker would leave a screen reader unable to\n tell which rows block the submit button.\n */}\n <span>{item.label}</span>\n <span className=\"hjm-agreement__required\" data-required={item.required || undefined}>\n {item.required ? requiredLabel : optionalLabel}\n </span>\n </span>\n </button>\n {item.description ? (\n <p id={`${id}-${item.id}-description`} className=\"hjm-agreement__description\">{item.description}</p>\n ) : null}\n {/*\n A separate tab stop that never toggles consent — opening the\n text and agreeing to it are different acts.\n */}\n {item.detail ? (\n item.detail.href ? (\n <a className=\"hjm-agreement__detail\" href={item.detail.href}>{item.detail.label}</a>\n ) : (\n <button type=\"button\" className=\"hjm-agreement__detail\" onClick={() => onDetail?.(item.id)}>\n {item.detail.label}\n </button>\n )\n ) : null}\n </div>\n );\n })}\n </div>\n </div>\n );\n}) as <Id extends string = string>(\n props: AgreementProps<Id> & { ref?: React.Ref<HTMLDivElement> },\n) => React.ReactElement | null;\n\n"]}
1
+ {"version":3,"file":"agreement.js","sourceRoot":"","sources":["../src/agreement.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n reconcileAgreementSelection,\n resolveAgreementState,\n toggleAgreementAll,\n toggleAgreementItem,\n validateAgreementDescriptor,\n type AgreementDescriptor,\n type AgreementState,\n} from \"@hjmds/design-contracts/components/agreement\";\nimport { forwardRef, useEffect, useId, useMemo, useRef } from \"react\";\nimport { classNames, useControllableState } from \"./internal.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type AgreementProps<Id extends string = string> = Readonly<{\n descriptor: AgreementDescriptor<Id>;\n checkedIds?: ReadonlySet<Id>;\n defaultCheckedIds?: ReadonlySet<Id>;\n onCheckedIdsChange?: (ids: ReadonlySet<Id>) => void;\n /** Fires the derived state on every change, for a submit button to read. */\n onStateChange?: (state: AgreementState<Id>) => void;\n /** Called when an item's full text is requested and it carries no href. */\n onDetail?: (id: Id) => void;\n /** Localized suffix marking a required row, supplied by the product. */\n requiredLabel: string;\n /** Localized suffix marking an optional row, supplied by the product. */\n optionalLabel: string;\n className?: string;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\nfunction Mark({ state }: { state: boolean | \"mixed\" }) {\n return (\n <span aria-hidden=\"true\" className=\"hjm-agreement__mark\" data-state={String(state)}>\n {state === true ? \"✓\" : state === \"mixed\" ? \"–\" : \"\"}\n </span>\n );\n}\n\nexport const Agreement = forwardRef(function Agreement<Id extends string = string>(\n {\n descriptor,\n checkedIds: controlledChecked,\n defaultCheckedIds,\n onCheckedIdsChange,\n onStateChange,\n onDetail,\n requiredLabel,\n optionalLabel,\n className,\n layoutStyle,\n }: AgreementProps<Id>,\n forwardedRef: React.Ref<HTMLDivElement>,\n) {\n validateAgreementDescriptor(descriptor);\n const [rawChecked, setChecked] = useControllableState<ReadonlySet<Id>>({\n ...(controlledChecked === undefined ? {} : { value: controlledChecked }),\n defaultValue: defaultCheckedIds ?? new Set<Id>(),\n ...(onCheckedIdsChange === undefined ? {} : { onChange: onCheckedIdsChange }),\n });\n // An item that left the list must not keep an orphan consent behind it.\n const checked = useMemo(\n () => reconcileAgreementSelection(descriptor, rawChecked),\n [descriptor, rawChecked],\n );\n const state = resolveAgreementState(descriptor, checked);\n const id = `${useId().replaceAll(\":\", \"\")}-agreement`;\n\n // Report the initial state once on mount. Until 2026-10-06 only user toggles reported, so\n // `defaultCheckedIds`/`checkedIds` that already satisfied every required item never produced a\n // first `satisfied: true` and a submit button wired to this callback stayed disabled. Mount-only\n // (not on every derived change) keeps the callback count to \"initial + one per toggle\"; StrictMode\n // may repeat the same snapshot, which is idempotent for a consumer that stores it.\n const initialStateRef = useRef(state);\n const onStateChangeRef = useRef(onStateChange);\n onStateChangeRef.current = onStateChange;\n useEffect(() => {\n onStateChangeRef.current?.(initialStateRef.current);\n }, []);\n const commit = (next: ReadonlySet<Id>) => {\n setChecked(next);\n onStateChange?.(resolveAgreementState(descriptor, next));\n };\n\n return (\n <div\n ref={forwardedRef}\n role=\"group\"\n aria-label={descriptor.accessibilityLabel}\n style={layoutStyle}\n className={classNames(\"hjm-agreement\", className)}\n >\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={state.all === \"mixed\" ? \"mixed\" : String(state.all === true) as \"true\" | \"false\"}\n className=\"hjm-agreement__all\"\n onClick={() => commit(toggleAgreementAll(descriptor, checked))}\n >\n <Mark state={state.all} />\n <span>{descriptor.allLabel}</span>\n </button>\n <div className=\"hjm-agreement__list\">\n {descriptor.items.map((item) => {\n const itemChecked = checked.has(item.id);\n return (\n <div key={item.id} className=\"hjm-agreement__item\" data-disabled={item.disabled || undefined}>\n <button\n type=\"button\"\n role=\"checkbox\"\n id={`${id}-${item.id}`}\n aria-checked={itemChecked}\n aria-disabled={item.disabled || undefined}\n aria-describedby={item.description ? `${id}-${item.id}-description` : undefined}\n className=\"hjm-agreement__toggle\"\n onClick={() => { if (!item.disabled) commit(toggleAgreementItem(descriptor, checked, item.id)); }}\n >\n <Mark state={itemChecked} />\n <span className=\"hjm-agreement__copy\">\n {/*\n Required/optional rides inside the control's own name: a\n visual-only marker would leave a screen reader unable to\n tell which rows block the submit button.\n */}\n <span>{item.label}</span>\n <span className=\"hjm-agreement__required\" data-required={item.required || undefined}>\n {item.required ? requiredLabel : optionalLabel}\n </span>\n </span>\n </button>\n {item.description ? (\n <p id={`${id}-${item.id}-description`} className=\"hjm-agreement__description\">{item.description}</p>\n ) : null}\n {/*\n A separate tab stop that never toggles consent — opening the\n text and agreeing to it are different acts.\n */}\n {item.detail ? (\n item.detail.href ? (\n <a className=\"hjm-agreement__detail\" href={item.detail.href}>{item.detail.label}</a>\n ) : (\n <button type=\"button\" className=\"hjm-agreement__detail\" onClick={() => onDetail?.(item.id)}>\n {item.detail.label}\n </button>\n )\n ) : null}\n </div>\n );\n })}\n </div>\n </div>\n );\n}) as <Id extends string = string>(\n props: AgreementProps<Id> & { ref?: React.Ref<HTMLDivElement> },\n) => React.ReactElement | null;\n\n"]}
package/dist/anchor.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type HTMLAttributes, type MouseEvent } from "react";
2
2
  import { type AnchorItem } from "@hjmds/design-contracts/components/anchor";
3
+ import type { HjmCompositionStyleProp } from "./composition-style.js";
3
4
  export type AnchorProps = Omit<HTMLAttributes<HTMLElement>, "children"> & Readonly<{
4
5
  label: string;
5
6
  items: readonly AnchorItem[];
@@ -9,6 +10,8 @@ export type AnchorProps = Omit<HTMLAttributes<HTMLElement>, "children"> & Readon
9
10
  orientation?: "vertical" | "horizontal";
10
11
  historyMode?: "push" | "replace" | "none";
11
12
  onNavigate?: (id: string, event: MouseEvent<HTMLAnchorElement>) => void;
13
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
14
+ layoutStyle?: HjmCompositionStyleProp;
12
15
  }>;
13
16
  /** Same-document table of contents; sticky positioning belongs to its host layout. */
14
17
  export declare const Anchor: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLElement>, "children"> & Readonly<{
@@ -20,5 +23,7 @@ export declare const Anchor: import("react").ForwardRefExoticComponent<Omit<HTML
20
23
  orientation?: "vertical" | "horizontal";
21
24
  historyMode?: "push" | "replace" | "none";
22
25
  onNavigate?: (id: string, event: MouseEvent<HTMLAnchorElement>) => void;
26
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
27
+ layoutStyle?: HjmCompositionStyleProp;
23
28
  }> & import("react").RefAttributes<HTMLElement>>;
24
29
  //# sourceMappingURL=anchor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../src/anchor.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2C,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AACtG,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,2CAA2C,CAAC;AAGpH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACxC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAC1C,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;CACzE,CAAC,CAAC;AAEH,sFAAsF;AACtF,eAAO,MAAM,MAAM;WAXV,MAAM;WACN,SAAS,UAAU,EAAE;IAC5B,2EAA2E;gBAC/D,WAAW,GAAG,IAAI;aACrB,MAAM;kBACD,UAAU,GAAG,YAAY;kBACzB,MAAM,GAAG,SAAS,GAAG,MAAM;iBAC5B,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI;gDA2EvE,CAAC"}
1
+ {"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../src/anchor.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2C,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AACtG,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,2CAA2C,CAAC;AAGpH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACxC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAC1C,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACxE,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEH,sFAAsF;AACtF,eAAO,MAAM,MAAM;WAbV,MAAM;WACN,SAAS,UAAU,EAAE;IAC5B,2EAA2E;gBAC/D,WAAW,GAAG,IAAI;aACrB,MAAM;kBACD,UAAU,GAAG,YAAY;kBACzB,MAAM,GAAG,SAAS,GAAG,MAAM;iBAC5B,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI;IACvE,gGAAgG;kBAClF,uBAAuB;gDA2ErC,CAAC"}
package/dist/anchor.js CHANGED
@@ -4,7 +4,7 @@ import { getAnchorCurrentId, resolveAnchorItems } from "@hjmds/design-contracts/
4
4
  import { classNames } from "./internal.js";
5
5
  import { useOptionalHjmTheme } from "./provider.js";
6
6
  /** Same-document table of contents; sticky positioning belongs to its host layout. */
7
- export const Anchor = forwardRef(function Anchor({ label, items, container, offset = 0, orientation = "vertical", historyMode = "push", onNavigate, className, ...props }, ref) {
7
+ export const Anchor = forwardRef(function Anchor({ label, items, container, offset = 0, orientation = "vertical", historyMode = "push", onNavigate, className, layoutStyle, ...props }, ref) {
8
8
  const resolved = resolveAnchorItems(items);
9
9
  if (!label.trim())
10
10
  throw new TypeError("Anchor label must not be empty");
@@ -92,7 +92,7 @@ export const Anchor = forwardRef(function Anchor({ label, items, container, offs
92
92
  window.addEventListener("popstate", restoreHash);
93
93
  return () => { cancelAnimationFrame(frame); resize.disconnect(); mutation.disconnect(); source.removeEventListener("scroll", schedule); window.removeEventListener("resize", schedule); window.removeEventListener("hashchange", restoreHash); window.removeEventListener("popstate", restoreHash); };
94
94
  }, [idsKey, container, offset]);
95
- return _jsx("nav", { ...props, ref: ref, "aria-label": label, className: classNames("hjm-anchor", className), "data-orientation": orientation, children: _jsx("ul", { className: "hjm-anchor__list", children: resolved.map((item) => _jsx("li", { children: _jsx("a", { href: item.href, className: "hjm-anchor__link", "aria-current": current === item.id ? "location" : undefined, onClick: (event) => {
95
+ return _jsx("nav", { ...props, style: { ...props.style, ...layoutStyle }, ref: ref, "aria-label": label, className: classNames("hjm-anchor", className), "data-orientation": orientation, children: _jsx("ul", { className: "hjm-anchor__list", children: resolved.map((item) => _jsx("li", { children: _jsx("a", { href: item.href, className: "hjm-anchor__link", "aria-current": current === item.id ? "location" : undefined, onClick: (event) => {
96
96
  onNavigate?.(item.id, event);
97
97
  if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey)
98
98
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"anchor.js","sourceRoot":"","sources":["../src/anchor.tsx"],"names":[],"mappings":"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","sourcesContent":["import { forwardRef, useEffect, useRef, useState, type HTMLAttributes, type MouseEvent } from \"react\";\nimport { getAnchorCurrentId, resolveAnchorItems, type AnchorItem } from \"@hjmds/design-contracts/components/anchor\";\nimport { classNames } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nexport type AnchorProps = Omit<HTMLAttributes<HTMLElement>, \"children\"> & Readonly<{\n label: string;\n items: readonly AnchorItem[];\n /** undefined observes the document; null waits for a custom scroll ref. */\n container?: HTMLElement | null;\n offset?: number;\n orientation?: \"vertical\" | \"horizontal\";\n historyMode?: \"push\" | \"replace\" | \"none\";\n onNavigate?: (id: string, event: MouseEvent<HTMLAnchorElement>) => void;\n}>;\n\n/** Same-document table of contents; sticky positioning belongs to its host layout. */\nexport const Anchor = forwardRef<HTMLElement, AnchorProps>(function Anchor({ label, items, container, offset = 0,\n orientation = \"vertical\", historyMode = \"push\", onNavigate, className, ...props }, ref) {\n const resolved = resolveAnchorItems(items);\n if (!label.trim()) throw new TypeError(\"Anchor label must not be empty\");\n getAnchorCurrentId([], offset);\n const theme = useOptionalHjmTheme();\n const [current, setCurrent] = useState<string>();\n const restoredTargets = useRef(new Map<HTMLElement, () => void>());\n const idsKey = JSON.stringify(resolved.map(({ id }) => id));\n const findTarget = (id: string) => {\n const target = document.getElementById(id);\n return target && (container === undefined || container?.contains(target)) ? target : null;\n };\n function scrollToTarget(target: HTMLElement, behavior: ScrollBehavior) {\n const top = container === undefined ? window.scrollY + target.getBoundingClientRect().top - offset\n : container === null ? 0 : container.scrollTop + target.getBoundingClientRect().top - container.getBoundingClientRect().top - container.clientTop - offset;\n if (container === undefined) window.scrollTo({ top, behavior });\n else container?.scrollTo({ top, behavior });\n }\n function focusTarget(target: HTMLElement) {\n if (!target.hasAttribute(\"tabindex\")) {\n // Headings/sections are often not focusable. Restore our temporary attribute\n // on blur/unmount so navigation does not permanently change product markup.\n restoredTargets.current.get(target)?.();\n target.setAttribute(\"tabindex\", \"-1\");\n const restore = () => { if (target.getAttribute(\"tabindex\") === \"-1\") target.removeAttribute(\"tabindex\"); target.removeEventListener(\"blur\", restore); restoredTargets.current.delete(target); };\n restoredTargets.current.set(target, restore); target.addEventListener(\"blur\", restore, { once: true });\n }\n target.focus({ preventScroll: true });\n }\n useEffect(() => () => { for (const restore of [...restoredTargets.current.values()]) restore(); }, []);\n useEffect(() => {\n if (container === null) return;\n const source = container ?? window;\n const content = container ?? document.body;\n let frame = 0;\n const update = () => {\n frame = 0;\n const top = container ? container.getBoundingClientRect().top + container.clientTop : 0;\n const scroll = container ?? document.scrollingElement;\n // One CSS pixel covers scroll-height rounding without prematurely selecting a short final section.\n const atEnd = !!scroll && scroll.scrollHeight > scroll.clientHeight && scroll.scrollTop + scroll.clientHeight >= scroll.scrollHeight - 1;\n const positions = resolved.flatMap(({ id }) => { const node = findTarget(id); return node ? [{ id, top: node.getBoundingClientRect().top - top }] : []; });\n setCurrent(getAnchorCurrentId(positions, offset, atEnd));\n };\n const schedule = () => { if (!frame) frame = requestAnimationFrame(update); };\n const resize = new ResizeObserver(schedule);\n const observe = () => { resize.disconnect(); resize.observe(content); for (const item of resolved) { const node = findTarget(item.id); if (node) { resize.observe(node); if (node.parentElement) resize.observe(node.parentElement); } } };\n const mutation = new MutationObserver(() => { observe(); schedule(); });\n mutation.observe(content, { childList: true, subtree: true, characterData: true });\n const restoreHash = () => {\n let id: string; try { id = decodeURIComponent(window.location.hash.slice(1)); } catch { return; }\n if (!resolved.some((item) => item.id === id)) return;\n const target = findTarget(id); if (target) scrollToTarget(target, \"instant\"); schedule();\n };\n observe(); update(); restoreHash(); source.addEventListener(\"scroll\", schedule, { passive: true });\n window.addEventListener(\"resize\", schedule); window.addEventListener(\"hashchange\", restoreHash); window.addEventListener(\"popstate\", restoreHash);\n return () => { cancelAnimationFrame(frame); resize.disconnect(); mutation.disconnect(); source.removeEventListener(\"scroll\", schedule); window.removeEventListener(\"resize\", schedule); window.removeEventListener(\"hashchange\", restoreHash); window.removeEventListener(\"popstate\", restoreHash); };\n }, [idsKey, container, offset]);\n return <nav {...props} ref={ref} aria-label={label} className={classNames(\"hjm-anchor\", className)} data-orientation={orientation}>\n <ul className=\"hjm-anchor__list\">{resolved.map((item) => <li key={item.id}><a href={item.href} className=\"hjm-anchor__link\" aria-current={current === item.id ? \"location\" : undefined}\n onClick={(event) => {\n onNavigate?.(item.id, event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;\n const target = findTarget(item.id); if (!target) return;\n event.preventDefault();\n const reduced = theme?.environment.reducedMotion ?? window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n scrollToTarget(target, reduced ? \"instant\" : \"smooth\"); focusTarget(target);\n if (historyMode !== \"none\" && window.location.hash !== item.href) window.history[historyMode === \"replace\" ? \"replaceState\" : \"pushState\"](window.history.state, \"\", item.href);\n }}>{item.label}</a></li>)}</ul>\n </nav>;\n});\n"]}
1
+ {"version":3,"file":"anchor.js","sourceRoot":"","sources":["../src/anchor.tsx"],"names":[],"mappings":"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","sourcesContent":["import { forwardRef, useEffect, useRef, useState, type HTMLAttributes, type MouseEvent } from \"react\";\nimport { getAnchorCurrentId, resolveAnchorItems, type AnchorItem } from \"@hjmds/design-contracts/components/anchor\";\nimport { classNames } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\nexport type AnchorProps = Omit<HTMLAttributes<HTMLElement>, \"children\"> & Readonly<{\n label: string;\n items: readonly AnchorItem[];\n /** undefined observes the document; null waits for a custom scroll ref. */\n container?: HTMLElement | null;\n offset?: number;\n orientation?: \"vertical\" | \"horizontal\";\n historyMode?: \"push\" | \"replace\" | \"none\";\n onNavigate?: (id: string, event: MouseEvent<HTMLAnchorElement>) => void;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\n/** Same-document table of contents; sticky positioning belongs to its host layout. */\nexport const Anchor = forwardRef<HTMLElement, AnchorProps>(function Anchor({ label, items, container, offset = 0,\n orientation = \"vertical\", historyMode = \"push\", onNavigate, className, layoutStyle, ...props }, ref) {\n const resolved = resolveAnchorItems(items);\n if (!label.trim()) throw new TypeError(\"Anchor label must not be empty\");\n getAnchorCurrentId([], offset);\n const theme = useOptionalHjmTheme();\n const [current, setCurrent] = useState<string>();\n const restoredTargets = useRef(new Map<HTMLElement, () => void>());\n const idsKey = JSON.stringify(resolved.map(({ id }) => id));\n const findTarget = (id: string) => {\n const target = document.getElementById(id);\n return target && (container === undefined || container?.contains(target)) ? target : null;\n };\n function scrollToTarget(target: HTMLElement, behavior: ScrollBehavior) {\n const top = container === undefined ? window.scrollY + target.getBoundingClientRect().top - offset\n : container === null ? 0 : container.scrollTop + target.getBoundingClientRect().top - container.getBoundingClientRect().top - container.clientTop - offset;\n if (container === undefined) window.scrollTo({ top, behavior });\n else container?.scrollTo({ top, behavior });\n }\n function focusTarget(target: HTMLElement) {\n if (!target.hasAttribute(\"tabindex\")) {\n // Headings/sections are often not focusable. Restore our temporary attribute\n // on blur/unmount so navigation does not permanently change product markup.\n restoredTargets.current.get(target)?.();\n target.setAttribute(\"tabindex\", \"-1\");\n const restore = () => { if (target.getAttribute(\"tabindex\") === \"-1\") target.removeAttribute(\"tabindex\"); target.removeEventListener(\"blur\", restore); restoredTargets.current.delete(target); };\n restoredTargets.current.set(target, restore); target.addEventListener(\"blur\", restore, { once: true });\n }\n target.focus({ preventScroll: true });\n }\n useEffect(() => () => { for (const restore of [...restoredTargets.current.values()]) restore(); }, []);\n useEffect(() => {\n if (container === null) return;\n const source = container ?? window;\n const content = container ?? document.body;\n let frame = 0;\n const update = () => {\n frame = 0;\n const top = container ? container.getBoundingClientRect().top + container.clientTop : 0;\n const scroll = container ?? document.scrollingElement;\n // One CSS pixel covers scroll-height rounding without prematurely selecting a short final section.\n const atEnd = !!scroll && scroll.scrollHeight > scroll.clientHeight && scroll.scrollTop + scroll.clientHeight >= scroll.scrollHeight - 1;\n const positions = resolved.flatMap(({ id }) => { const node = findTarget(id); return node ? [{ id, top: node.getBoundingClientRect().top - top }] : []; });\n setCurrent(getAnchorCurrentId(positions, offset, atEnd));\n };\n const schedule = () => { if (!frame) frame = requestAnimationFrame(update); };\n const resize = new ResizeObserver(schedule);\n const observe = () => { resize.disconnect(); resize.observe(content); for (const item of resolved) { const node = findTarget(item.id); if (node) { resize.observe(node); if (node.parentElement) resize.observe(node.parentElement); } } };\n const mutation = new MutationObserver(() => { observe(); schedule(); });\n mutation.observe(content, { childList: true, subtree: true, characterData: true });\n const restoreHash = () => {\n let id: string; try { id = decodeURIComponent(window.location.hash.slice(1)); } catch { return; }\n if (!resolved.some((item) => item.id === id)) return;\n const target = findTarget(id); if (target) scrollToTarget(target, \"instant\"); schedule();\n };\n observe(); update(); restoreHash(); source.addEventListener(\"scroll\", schedule, { passive: true });\n window.addEventListener(\"resize\", schedule); window.addEventListener(\"hashchange\", restoreHash); window.addEventListener(\"popstate\", restoreHash);\n return () => { cancelAnimationFrame(frame); resize.disconnect(); mutation.disconnect(); source.removeEventListener(\"scroll\", schedule); window.removeEventListener(\"resize\", schedule); window.removeEventListener(\"hashchange\", restoreHash); window.removeEventListener(\"popstate\", restoreHash); };\n }, [idsKey, container, offset]);\n return <nav {...props} style={{ ...props.style, ...layoutStyle }} ref={ref} aria-label={label} className={classNames(\"hjm-anchor\", className)} data-orientation={orientation}>\n <ul className=\"hjm-anchor__list\">{resolved.map((item) => <li key={item.id}><a href={item.href} className=\"hjm-anchor__link\" aria-current={current === item.id ? \"location\" : undefined}\n onClick={(event) => {\n onNavigate?.(item.id, event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;\n const target = findTarget(item.id); if (!target) return;\n event.preventDefault();\n const reduced = theme?.environment.reducedMotion ?? window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n scrollToTarget(target, reduced ? \"instant\" : \"smooth\"); focusTarget(target);\n if (historyMode !== \"none\" && window.location.hash !== item.href) window.history[historyMode === \"replace\" ? \"replaceState\" : \"pushState\"](window.history.state, \"\", item.href);\n }}>{item.label}</a></li>)}</ul>\n </nav>;\n});\n"]}
package/dist/asset.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type AssetDescriptor } from "@hjmds/design-contracts/components/asset";
2
2
  import { type ReactNode } from "react";
3
+ import type { HjmCompositionStyleProp } from "./composition-style.js";
3
4
  export type AssetProps = Readonly<{
4
5
  descriptor: AssetDescriptor;
5
6
  /**
@@ -13,6 +14,8 @@ export type AssetProps = Readonly<{
13
14
  /** A small mark on the frame's outer corner (play, status dot). */
14
15
  accessory?: ReactNode;
15
16
  className?: string;
17
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
18
+ layoutStyle?: HjmCompositionStyleProp;
16
19
  }>;
17
20
  export declare const Asset: import("react").ForwardRefExoticComponent<Readonly<{
18
21
  descriptor: AssetDescriptor;
@@ -27,6 +30,8 @@ export declare const Asset: import("react").ForwardRefExoticComponent<Readonly<{
27
30
  /** A small mark on the frame's outer corner (play, status dot). */
28
31
  accessory?: ReactNode;
29
32
  className?: string;
33
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
34
+ layoutStyle?: HjmCompositionStyleProp;
30
35
  }> & import("react").RefAttributes<HTMLDivElement>>;
31
36
  export type AssetGroupProps = Readonly<{
32
37
  /** Accessible name for the group; the overlap alone does not say what it is. */
@@ -34,7 +39,9 @@ export type AssetGroupProps = Readonly<{
34
39
  size?: AssetDescriptor["size"];
35
40
  children: ReactNode;
36
41
  className?: string;
42
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
43
+ layoutStyle?: HjmCompositionStyleProp;
37
44
  }>;
38
45
  /** Overlaps assets with the same ratio Avatar uses — they share a row on purpose. */
39
- export declare function AssetGroup({ label, size, children, className }: AssetGroupProps): import("react").JSX.Element;
46
+ export declare function AssetGroup({ label, size, children, className, layoutStyle }: AssetGroupProps): import("react").JSX.Element;
40
47
  //# sourceMappingURL=asset.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../src/asset.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAkC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,UAAU,EAAE,eAAe,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,KAAK,SAAS,CAAC,CAAC;IAC7E,mEAAmE;IACnE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,eAAO,MAAM,KAAK;gBAZJ,eAAe;IAC3B;;;;OAIG;cACO,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,KAAK,SAAS,CAAC;IAC5E,mEAAmE;gBACvD,SAAS;gBACT,MAAM;mDAoClB,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,IAAgC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,eAAe,+BAY3G"}
1
+ {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../src/asset.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAkC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,UAAU,EAAE,eAAe,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,KAAK,SAAS,CAAC,CAAC;IAC7E,mEAAmE;IACnE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEH,eAAO,MAAM,KAAK;gBAdJ,eAAe;IAC3B;;;;OAIG;cACO,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,KAAK,SAAS,CAAC;IAC5E,mEAAmE;gBACvD,SAAS;gBACT,MAAM;IAClB,gGAAgG;kBAClF,uBAAuB;mDAoCrC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEH,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,IAAgC,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,eAAe,+BAYxH"}
package/dist/asset.js CHANGED
@@ -3,7 +3,7 @@ import { assetRecipe, shouldAnimateAsset, validateAssetDescriptor, } from "@hjmd
3
3
  import { forwardRef } from "react";
4
4
  import { classNames } from "./internal.js";
5
5
  import { useOptionalHjmTheme } from "./provider.js";
6
- export const Asset = forwardRef(function Asset({ descriptor, children, accessory, className }, forwardedRef) {
6
+ export const Asset = forwardRef(function Asset({ descriptor, children, accessory, className, layoutStyle }, forwardedRef) {
7
7
  validateAssetDescriptor(descriptor);
8
8
  const theme = useOptionalHjmTheme();
9
9
  const size = assetRecipe.sizes[descriptor.size ?? assetRecipe.defaults.size];
@@ -12,15 +12,15 @@ export const Asset = forwardRef(function Asset({ descriptor, children, accessory
12
12
  // The frame reports whether motion is allowed so the product's player can
13
13
  // read one answer instead of re-deriving the preference per surface.
14
14
  const animate = shouldAnimateAsset(descriptor.kind, theme?.environment.reducedMotion ?? false);
15
- return (_jsxs("div", { ref: forwardedRef, className: classNames("hjm-asset", className), "data-kind": descriptor.kind, "data-animate": animate || undefined, role: decorative ? "presentation" : "img", "aria-hidden": decorative || undefined, "aria-label": decorative ? undefined : descriptor.accessibilityLabel, style: {
15
+ return (_jsxs("div", { ref: forwardedRef, className: classNames("hjm-asset", className), "data-kind": descriptor.kind, "data-animate": animate || undefined, role: decorative ? "presentation" : "img", "aria-hidden": decorative || undefined, "aria-label": decorative ? undefined : descriptor.accessibilityLabel, style: { ...layoutStyle,
16
16
  "--hjm-asset-size": `${size}px`,
17
17
  "--hjm-asset-radius": `${shape}px`,
18
18
  "--hjm-asset-accessory-offset": `${assetRecipe.accessory.offset}px`,
19
19
  }, children: [_jsx("div", { className: "hjm-asset__frame", children: _jsx("div", { className: "hjm-asset__media", children: typeof children === "function" ? children({ animate }) : children }) }), accessory ? _jsx("span", { className: "hjm-asset__accessory", children: accessory }) : null] }));
20
20
  });
21
21
  /** Overlaps assets with the same ratio Avatar uses — they share a row on purpose. */
22
- export function AssetGroup({ label, size = assetRecipe.defaults.size, children, className }) {
22
+ export function AssetGroup({ label, size = assetRecipe.defaults.size, children, className, layoutStyle }) {
23
23
  const pixels = assetRecipe.sizes[size];
24
- return (_jsx("div", { className: classNames("hjm-asset-group", className), role: "group", "aria-label": label, style: { "--hjm-asset-overlap": `${-Math.round(pixels * assetRecipe.overlapRatio)}px` }, children: children }));
24
+ return (_jsx("div", { className: classNames("hjm-asset-group", className), role: "group", "aria-label": label, style: { ...layoutStyle, "--hjm-asset-overlap": `${-Math.round(pixels * assetRecipe.overlapRatio)}px` }, children: children }));
25
25
  }
26
26
  //# sourceMappingURL=asset.js.map
package/dist/asset.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"asset.js","sourceRoot":"","sources":["../src/asset.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,uBAAuB,GAExB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,UAAU,EAAsC,MAAM,OAAO,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAepD,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA6B,SAAS,KAAK,CACxE,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,EAC9C,YAAY;IAEZ,uBAAuB,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjF,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,IAAI,KAAK,CAAC;IAClD,0EAA0E;IAC1E,qEAAqE;IACrE,MAAM,OAAO,GAAG,kBAAkB,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,aAAa,IAAI,KAAK,CAAC,CAAC;IAC/F,OAAO,CACL,eACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,eAClC,UAAU,CAAC,IAAI,kBACZ,OAAO,IAAI,SAAS,EAClC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,iBAC5B,UAAU,IAAI,SAAS,gBACxB,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,EAClE,KAAK,EAAE;YACL,kBAAkB,EAAE,GAAG,IAAI,IAAI;YAC/B,oBAAoB,EAAE,GAAG,KAAK,IAAI;YAClC,8BAA8B,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,MAAM,IAAI;SACnD,aAElB,cAAK,SAAS,EAAC,kBAAkB,YAC/B,cAAK,SAAS,EAAC,kBAAkB,YAAE,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAO,GACvG,EACL,SAAS,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,sBAAsB,YAAE,SAAS,GAAQ,CAAC,CAAC,CAAC,IAAI,IACzE,CACP,CAAC;AACJ,CAAC,CAAC,CAAC;AAUH,qFAAqF;AACrF,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAmB;IAC1G,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,CACL,cACE,SAAS,EAAE,UAAU,CAAC,iBAAiB,EAAE,SAAS,CAAC,EACnD,IAAI,EAAC,OAAO,gBACA,KAAK,EACjB,KAAK,EAAE,EAAE,qBAAqB,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC,YAAY,CAAC,IAAI,EAAmB,YAEvG,QAAQ,GACL,CACP,CAAC;AACJ,CAAC","sourcesContent":["import {\n assetRecipe,\n shouldAnimateAsset,\n validateAssetDescriptor,\n type AssetDescriptor,\n} from \"@hjmds/design-contracts/components/asset\";\nimport { forwardRef, type CSSProperties, type ReactNode } from \"react\";\nimport { classNames } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\n\nexport type AssetProps = Readonly<{\n descriptor: AssetDescriptor;\n /**\n * The media itself. A player is the product's dependency, never this\n * package's — the frame is all the contract owns. `animate` is the\n * already-resolved answer to \"may this move right now\".\n */\n children: ReactNode | ((state: Readonly<{ animate: boolean }>) => ReactNode);\n /** A small mark on the frame's outer corner (play, status dot). */\n accessory?: ReactNode;\n className?: string;\n}>;\n\nexport const Asset = forwardRef<HTMLDivElement, AssetProps>(function Asset(\n { descriptor, children, accessory, className },\n forwardedRef,\n) {\n validateAssetDescriptor(descriptor);\n const theme = useOptionalHjmTheme();\n const size = assetRecipe.sizes[descriptor.size ?? assetRecipe.defaults.size];\n const shape = assetRecipe.shapes[descriptor.shape ?? assetRecipe.defaults.shape];\n const decorative = descriptor.decorative ?? false;\n // The frame reports whether motion is allowed so the product's player can\n // read one answer instead of re-deriving the preference per surface.\n const animate = shouldAnimateAsset(descriptor.kind, theme?.environment.reducedMotion ?? false);\n return (\n <div\n ref={forwardedRef}\n className={classNames(\"hjm-asset\", className)}\n data-kind={descriptor.kind}\n data-animate={animate || undefined}\n role={decorative ? \"presentation\" : \"img\"}\n aria-hidden={decorative || undefined}\n aria-label={decorative ? undefined : descriptor.accessibilityLabel}\n style={{\n \"--hjm-asset-size\": `${size}px`,\n \"--hjm-asset-radius\": `${shape}px`,\n \"--hjm-asset-accessory-offset\": `${assetRecipe.accessory.offset}px`,\n } as CSSProperties}\n >\n <div className=\"hjm-asset__frame\">\n <div className=\"hjm-asset__media\">{typeof children === \"function\" ? children({ animate }) : children}</div>\n </div>\n {accessory ? <span className=\"hjm-asset__accessory\">{accessory}</span> : null}\n </div>\n );\n});\n\nexport type AssetGroupProps = Readonly<{\n /** Accessible name for the group; the overlap alone does not say what it is. */\n label: string;\n size?: AssetDescriptor[\"size\"];\n children: ReactNode;\n className?: string;\n}>;\n\n/** Overlaps assets with the same ratio Avatar uses — they share a row on purpose. */\nexport function AssetGroup({ label, size = assetRecipe.defaults.size, children, className }: AssetGroupProps) {\n const pixels = assetRecipe.sizes[size];\n return (\n <div\n className={classNames(\"hjm-asset-group\", className)}\n role=\"group\"\n aria-label={label}\n style={{ \"--hjm-asset-overlap\": `${-Math.round(pixels * assetRecipe.overlapRatio)}px` } as CSSProperties}\n >\n {children}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"asset.js","sourceRoot":"","sources":["../src/asset.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,uBAAuB,GAExB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,UAAU,EAAsC,MAAM,OAAO,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAkBpD,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA6B,SAAS,KAAK,CACxE,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,EAC3D,YAAY;IAEZ,uBAAuB,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjF,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,IAAI,KAAK,CAAC;IAClD,0EAA0E;IAC1E,qEAAqE;IACrE,MAAM,OAAO,GAAG,kBAAkB,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,aAAa,IAAI,KAAK,CAAC,CAAC;IAC/F,OAAO,CACL,eACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,eAClC,UAAU,CAAC,IAAI,kBACZ,OAAO,IAAI,SAAS,EAClC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,iBAC5B,UAAU,IAAI,SAAS,gBACxB,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,EAClE,KAAK,EAAE,EAAE,GAAG,WAAW;YACrB,kBAAkB,EAAE,GAAG,IAAI,IAAI;YAC/B,oBAAoB,EAAE,GAAG,KAAK,IAAI;YAClC,8BAA8B,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,MAAM,IAAI;SACnD,aAElB,cAAK,SAAS,EAAC,kBAAkB,YAC/B,cAAK,SAAS,EAAC,kBAAkB,YAAE,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAO,GACvG,EACL,SAAS,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,sBAAsB,YAAE,SAAS,GAAQ,CAAC,CAAC,CAAC,IAAI,IACzE,CACP,CAAC;AACJ,CAAC,CAAC,CAAC;AAYH,qFAAqF;AACrF,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAmB;IACvH,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,CACL,cACE,SAAS,EAAE,UAAU,CAAC,iBAAiB,EAAE,SAAS,CAAC,EACnD,IAAI,EAAC,OAAO,gBACA,KAAK,EACjB,KAAK,EAAE,EAAE,GAAG,WAAW,EAAE,qBAAqB,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC,YAAY,CAAC,IAAI,EAAmB,YAEvH,QAAQ,GACL,CACP,CAAC;AACJ,CAAC","sourcesContent":["import {\n assetRecipe,\n shouldAnimateAsset,\n validateAssetDescriptor,\n type AssetDescriptor,\n} from \"@hjmds/design-contracts/components/asset\";\nimport { forwardRef, type CSSProperties, type ReactNode } from \"react\";\nimport { classNames } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type AssetProps = Readonly<{\n descriptor: AssetDescriptor;\n /**\n * The media itself. A player is the product's dependency, never this\n * package's — the frame is all the contract owns. `animate` is the\n * already-resolved answer to \"may this move right now\".\n */\n children: ReactNode | ((state: Readonly<{ animate: boolean }>) => ReactNode);\n /** A small mark on the frame's outer corner (play, status dot). */\n accessory?: ReactNode;\n className?: string;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\nexport const Asset = forwardRef<HTMLDivElement, AssetProps>(function Asset(\n { descriptor, children, accessory, className, layoutStyle },\n forwardedRef,\n) {\n validateAssetDescriptor(descriptor);\n const theme = useOptionalHjmTheme();\n const size = assetRecipe.sizes[descriptor.size ?? assetRecipe.defaults.size];\n const shape = assetRecipe.shapes[descriptor.shape ?? assetRecipe.defaults.shape];\n const decorative = descriptor.decorative ?? false;\n // The frame reports whether motion is allowed so the product's player can\n // read one answer instead of re-deriving the preference per surface.\n const animate = shouldAnimateAsset(descriptor.kind, theme?.environment.reducedMotion ?? false);\n return (\n <div\n ref={forwardedRef}\n className={classNames(\"hjm-asset\", className)}\n data-kind={descriptor.kind}\n data-animate={animate || undefined}\n role={decorative ? \"presentation\" : \"img\"}\n aria-hidden={decorative || undefined}\n aria-label={decorative ? undefined : descriptor.accessibilityLabel}\n style={{ ...layoutStyle,\n \"--hjm-asset-size\": `${size}px`,\n \"--hjm-asset-radius\": `${shape}px`,\n \"--hjm-asset-accessory-offset\": `${assetRecipe.accessory.offset}px`,\n } as CSSProperties}\n >\n <div className=\"hjm-asset__frame\">\n <div className=\"hjm-asset__media\">{typeof children === \"function\" ? children({ animate }) : children}</div>\n </div>\n {accessory ? <span className=\"hjm-asset__accessory\">{accessory}</span> : null}\n </div>\n );\n});\n\nexport type AssetGroupProps = Readonly<{\n /** Accessible name for the group; the overlap alone does not say what it is. */\n label: string;\n size?: AssetDescriptor[\"size\"];\n children: ReactNode;\n className?: string;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\n/** Overlaps assets with the same ratio Avatar uses — they share a row on purpose. */\nexport function AssetGroup({ label, size = assetRecipe.defaults.size, children, className, layoutStyle }: AssetGroupProps) {\n const pixels = assetRecipe.sizes[size];\n return (\n <div\n className={classNames(\"hjm-asset-group\", className)}\n role=\"group\"\n aria-label={label}\n style={{ ...layoutStyle, \"--hjm-asset-overlap\": `${-Math.round(pixels * assetRecipe.overlapRatio)}px` } as CSSProperties}\n >\n {children}\n </div>\n );\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { type AuthScreenDescriptor } from "@hjmds/design-contracts/components/auth-screen";
2
2
  import { type HTMLAttributes, type ReactNode } from "react";
3
+ import type { HjmCompositionStyleProp } from "./composition-style.js";
3
4
  export type AuthScreenLayoutProps = Omit<HTMLAttributes<HTMLElement>, "children"> & AuthScreenDescriptor & Readonly<{
4
5
  /** Use section inside a product shell that already owns the main landmark. */
5
6
  as?: "main" | "section";
@@ -14,6 +15,8 @@ export type AuthScreenLayoutProps = Omit<HTMLAttributes<HTMLElement>, "children"
14
15
  /** Consent notice and policy links. Omit with `hasFooter: false`. */
15
16
  footer?: ReactNode;
16
17
  className?: string;
18
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
19
+ layoutStyle?: HjmCompositionStyleProp;
17
20
  }>;
18
21
  /**
19
22
  * Two regions: hero + main stay one vertically centred block, the footer sits at
@@ -37,5 +40,7 @@ export declare const AuthScreenLayout: import("react").ForwardRefExoticComponent
37
40
  /** Consent notice and policy links. Omit with `hasFooter: false`. */
38
41
  footer?: ReactNode;
39
42
  className?: string;
43
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
44
+ layoutStyle?: HjmCompositionStyleProp;
40
45
  }> & import("react").RefAttributes<HTMLElement>>;
41
46
  //# sourceMappingURL=auth-screen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-screen.d.ts","sourceRoot":"","sources":["../src/auth-screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAAc,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGxE,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,GAC/E,oBAAoB,GACpB,QAAQ,CAAC;IACP,8EAA8E;IAC9E,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,+EAA+E;IAC/E,IAAI,EAAE,SAAS,CAAC;IAChB,sFAAsF;IACtF,IAAI,EAAE,SAAS,CAAC;IAChB,2FAA2F;IAC3F,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qEAAqE;IACrE,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;IApBzB,8EAA8E;SACzE,MAAM,GAAG,SAAS;IACvB,+EAA+E;UACzE,SAAS;IACf,sFAAsF;UAChF,SAAS;IACf,2FAA2F;mBAC5E,MAAM;IACrB,4FAA4F;eACjF,OAAO;IAClB,qEAAqE;aAC5D,SAAS;gBACN,MAAM;gDAmDrB,CAAC"}
1
+ {"version":3,"file":"auth-screen.d.ts","sourceRoot":"","sources":["../src/auth-screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAAc,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAExE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,GAC/E,oBAAoB,GACpB,QAAQ,CAAC;IACP,8EAA8E;IAC9E,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,+EAA+E;IAC/E,IAAI,EAAE,SAAS,CAAC;IAChB,sFAAsF;IACtF,IAAI,EAAE,SAAS,CAAC;IAChB,2FAA2F;IAC3F,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qEAAqE;IACrE,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;IAtBzB,8EAA8E;SACzE,MAAM,GAAG,SAAS;IACvB,+EAA+E;UACzE,SAAS;IACf,sFAAsF;UAChF,SAAS;IACf,2FAA2F;mBAC5E,MAAM;IACrB,4FAA4F;eACjF,OAAO;IAClB,qEAAqE;aAC5D,SAAS;gBACN,MAAM;IAClB,gGAAgG;kBAClF,uBAAuB;gDAoDxC,CAAC"}
@@ -7,7 +7,7 @@ import { classNames } from "./internal.js";
7
7
  * the bottom. The measurements come from the resolved descriptor as custom
8
8
  * properties so the stylesheet keeps one source of truth with the contract.
9
9
  */
10
- export const AuthScreenLayout = forwardRef(function AuthScreenLayout({ hero, main, footer, density, hasFooter, pendingLabel, mainCard = false, className, as: Element = "main", ...props }, forwardedRef) {
10
+ export const AuthScreenLayout = forwardRef(function AuthScreenLayout({ hero, main, footer, density, hasFooter, pendingLabel, mainCard = false, className, as: Element = "main", layoutStyle, ...props }, forwardedRef) {
11
11
  const resolved = resolveAuthScreenDescriptor({
12
12
  ...(density === undefined ? {} : { density }),
13
13
  ...(hasFooter === undefined ? {} : { hasFooter }),
@@ -24,6 +24,7 @@ export const AuthScreenLayout = forwardRef(function AuthScreenLayout({ hero, mai
24
24
  ["--hjm-auth-screen-padding-inline"]: `${resolved.paddingInline}px`,
25
25
  ["--hjm-auth-screen-padding-block"]: `${resolved.paddingBlock}px`,
26
26
  ...props.style,
27
+ ...layoutStyle,
27
28
  }, children: [_jsxs("div", { className: "hjm-auth-screen__block", children: [_jsx("div", { className: "hjm-auth-screen__hero", children: hero }), _jsxs("div", { className: "hjm-auth-screen__main", "data-card": mainCard || undefined, "aria-busy": pending || undefined, children: [_jsx("div", { className: "hjm-auth-screen__actions", inert: pending, "aria-hidden": pending || undefined, style: pending ? { visibility: "hidden" } : undefined, children: main }), pending ? _jsx("div", { className: "hjm-auth-screen__pending", role: "status", "aria-label": pendingLabel, children: _jsx("span", { className: "hjm-auth-provider-button__spinner", "aria-hidden": "true" }) }) : null] })] }), showFooter ? _jsx("div", { className: "hjm-auth-screen__footer", children: footer }) : null] }));
28
29
  });
29
30
  //# sourceMappingURL=auth-screen.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-screen.js","sourceRoot":"","sources":["../src/auth-screen.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,2BAA2B,GAE5B,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAAE,UAAU,EAAuC,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAoB3C;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CACxC,SAAS,gBAAgB,CACvB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,GAAG,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,EACrH,YAAY;IAEZ,MAAM,QAAQ,GAAG,2BAA2B,CAAC;QAC3C,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;QAC7C,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;KAClD,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,CAAC;IACjF,MAAM,OAAO,GAAG,YAAY,KAAK,SAAS,CAAC;IAC3C,IAAI,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,2CAA2C,CAAC,CAAC;IACtG,OAAO,CACL,MAAC,OAAO,OACF,KAAK,EACT,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,UAAU,CAAC,iBAAiB,EAAE,SAAS,CAAC,kBACrC,QAAQ,CAAC,OAAO,EAC9B,KAAK,EAAE;YACL,CAAC,6BAAuC,CAAC,EAAE,GAAG,QAAQ,CAAC,QAAQ,IAAI;YACnE,CAAC,4BAAsC,CAAC,EAAE,GAAG,QAAQ,CAAC,OAAO,IAAI;YACjE,CAAC,4BAAsC,CAAC,EAAE,GAAG,QAAQ,CAAC,OAAO,IAAI;YACjE,CAAC,8BAAwC,CAAC,EAAE,GAAG,QAAQ,CAAC,SAAS,IAAI;YACrE,CAAC,kCAA4C,CAAC,EAAE,GAAG,QAAQ,CAAC,aAAa,IAAI;YAC7E,CAAC,iCAA2C,CAAC,EAAE,GAAG,QAAQ,CAAC,YAAY,IAAI;YAC3E,GAAG,KAAK,CAAC,KAAK;SACf,aAED,eAAK,SAAS,EAAC,wBAAwB,aACrC,cAAK,SAAS,EAAC,uBAAuB,YAAE,IAAI,GAAO,EACnD,eAAK,SAAS,EAAC,uBAAuB,eAAY,QAAQ,IAAI,SAAS,eAAa,OAAO,IAAI,SAAS,aAEtG,cAAK,SAAS,EAAC,0BAA0B,EAAC,KAAK,EAAE,OAAO,iBAAe,OAAO,IAAI,SAAS,EACzF,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,YAAG,IAAI,GAAO,EACpE,OAAO,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,0BAA0B,EAAC,IAAI,EAAC,QAAQ,gBAAa,YAAY,YACzF,eAAM,SAAS,EAAC,mCAAmC,iBAAa,MAAM,GAAG,GACrE,CAAC,CAAC,CAAC,IAAI,IACT,IACF,EACL,UAAU,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,yBAAyB,YAAE,MAAM,GAAO,CAAC,CAAC,CAAC,IAAI,IACpE,CACX,CAAC;AACJ,CAAC,CACF,CAAC","sourcesContent":["import {\n resolveAuthScreenDescriptor,\n type AuthScreenDescriptor,\n} from \"@hjmds/design-contracts/components/auth-screen\";\nimport { forwardRef, type HTMLAttributes, type ReactNode } from \"react\";\nimport { classNames } from \"./internal.js\";\n\nexport type AuthScreenLayoutProps = Omit<HTMLAttributes<HTMLElement>, \"children\"> &\n AuthScreenDescriptor &\n Readonly<{\n /** Use section inside a product shell that already owns the main landmark. */\n as?: \"main\" | \"section\";\n /** Product mark, title and description. The product owns every string here. */\n hero: ReactNode;\n /** The primary action block — provider buttons, or a product's own sign-in bundle. */\n main: ReactNode;\n /** Product-localized progress label; presence replaces actions with one centred loader. */\n pendingLabel?: string;\n /** Let the layout own the action card; omit when the product already supplies a surface. */\n mainCard?: boolean;\n /** Consent notice and policy links. Omit with `hasFooter: false`. */\n footer?: ReactNode;\n className?: string;\n }>;\n\n/**\n * Two regions: hero + main stay one vertically centred block, the footer sits at\n * the bottom. The measurements come from the resolved descriptor as custom\n * properties so the stylesheet keeps one source of truth with the contract.\n */\nexport const AuthScreenLayout = forwardRef<HTMLElement, AuthScreenLayoutProps>(\n function AuthScreenLayout(\n { hero, main, footer, density, hasFooter, pendingLabel, mainCard = false, className, as: Element = \"main\", ...props },\n forwardedRef,\n ) {\n const resolved = resolveAuthScreenDescriptor({\n ...(density === undefined ? {} : { density }),\n ...(hasFooter === undefined ? {} : { hasFooter }),\n });\n const showFooter = resolved.hasFooter && footer !== undefined && footer !== null;\n const pending = pendingLabel !== undefined;\n if (pending && !pendingLabel.trim()) throw new TypeError(\"AuthScreen pendingLabel must not be empty\");\n return (\n <Element\n {...props}\n ref={forwardedRef}\n className={classNames(\"hjm-auth-screen\", className)}\n data-density={resolved.density}\n style={{\n [\"--hjm-auth-screen-max-width\" as string]: `${resolved.maxWidth}px`,\n [\"--hjm-auth-screen-hero-gap\" as string]: `${resolved.heroGap}px`,\n [\"--hjm-auth-screen-main-gap\" as string]: `${resolved.mainGap}px`,\n [\"--hjm-auth-screen-footer-gap\" as string]: `${resolved.footerGap}px`,\n [\"--hjm-auth-screen-padding-inline\" as string]: `${resolved.paddingInline}px`,\n [\"--hjm-auth-screen-padding-block\" as string]: `${resolved.paddingBlock}px`,\n ...props.style,\n }}\n >\n <div className=\"hjm-auth-screen__block\">\n <div className=\"hjm-auth-screen__hero\">{hero}</div>\n <div className=\"hjm-auth-screen__main\" data-card={mainCard || undefined} aria-busy={pending || undefined}>\n {/* Keep the action block in flow so the card never collapses; inert also removes keyboard access. */}\n <div className=\"hjm-auth-screen__actions\" inert={pending} aria-hidden={pending || undefined}\n style={pending ? { visibility: \"hidden\" } : undefined}>{main}</div>\n {pending ? <div className=\"hjm-auth-screen__pending\" role=\"status\" aria-label={pendingLabel}>\n <span className=\"hjm-auth-provider-button__spinner\" aria-hidden=\"true\" />\n </div> : null}\n </div>\n </div>\n {showFooter ? <div className=\"hjm-auth-screen__footer\">{footer}</div> : null}\n </Element>\n );\n },\n);\n"]}
1
+ {"version":3,"file":"auth-screen.js","sourceRoot":"","sources":["../src/auth-screen.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,2BAA2B,GAE5B,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAAE,UAAU,EAAuC,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAuB3C;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CACxC,SAAS,gBAAgB,CACvB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,GAAG,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,EAAE,EAClI,YAAY;IAEZ,MAAM,QAAQ,GAAG,2BAA2B,CAAC;QAC3C,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;QAC7C,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;KAClD,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,CAAC;IACjF,MAAM,OAAO,GAAG,YAAY,KAAK,SAAS,CAAC;IAC3C,IAAI,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,2CAA2C,CAAC,CAAC;IACtG,OAAO,CACL,MAAC,OAAO,OACF,KAAK,EACT,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,UAAU,CAAC,iBAAiB,EAAE,SAAS,CAAC,kBACrC,QAAQ,CAAC,OAAO,EAC9B,KAAK,EAAE;YACL,CAAC,6BAAuC,CAAC,EAAE,GAAG,QAAQ,CAAC,QAAQ,IAAI;YACnE,CAAC,4BAAsC,CAAC,EAAE,GAAG,QAAQ,CAAC,OAAO,IAAI;YACjE,CAAC,4BAAsC,CAAC,EAAE,GAAG,QAAQ,CAAC,OAAO,IAAI;YACjE,CAAC,8BAAwC,CAAC,EAAE,GAAG,QAAQ,CAAC,SAAS,IAAI;YACrE,CAAC,kCAA4C,CAAC,EAAE,GAAG,QAAQ,CAAC,aAAa,IAAI;YAC7E,CAAC,iCAA2C,CAAC,EAAE,GAAG,QAAQ,CAAC,YAAY,IAAI;YAC3E,GAAG,KAAK,CAAC,KAAK;YACd,GAAG,WAAW;SACf,aAED,eAAK,SAAS,EAAC,wBAAwB,aACrC,cAAK,SAAS,EAAC,uBAAuB,YAAE,IAAI,GAAO,EACnD,eAAK,SAAS,EAAC,uBAAuB,eAAY,QAAQ,IAAI,SAAS,eAAa,OAAO,IAAI,SAAS,aAEtG,cAAK,SAAS,EAAC,0BAA0B,EAAC,KAAK,EAAE,OAAO,iBAAe,OAAO,IAAI,SAAS,EACzF,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,YAAG,IAAI,GAAO,EACpE,OAAO,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,0BAA0B,EAAC,IAAI,EAAC,QAAQ,gBAAa,YAAY,YACzF,eAAM,SAAS,EAAC,mCAAmC,iBAAa,MAAM,GAAG,GACrE,CAAC,CAAC,CAAC,IAAI,IACT,IACF,EACL,UAAU,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,yBAAyB,YAAE,MAAM,GAAO,CAAC,CAAC,CAAC,IAAI,IACpE,CACX,CAAC;AACJ,CAAC,CACF,CAAC","sourcesContent":["import {\n resolveAuthScreenDescriptor,\n type AuthScreenDescriptor,\n} from \"@hjmds/design-contracts/components/auth-screen\";\nimport { forwardRef, type HTMLAttributes, type ReactNode } from \"react\";\nimport { classNames } from \"./internal.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type AuthScreenLayoutProps = Omit<HTMLAttributes<HTMLElement>, \"children\"> &\n AuthScreenDescriptor &\n Readonly<{\n /** Use section inside a product shell that already owns the main landmark. */\n as?: \"main\" | \"section\";\n /** Product mark, title and description. The product owns every string here. */\n hero: ReactNode;\n /** The primary action block — provider buttons, or a product's own sign-in bundle. */\n main: ReactNode;\n /** Product-localized progress label; presence replaces actions with one centred loader. */\n pendingLabel?: string;\n /** Let the layout own the action card; omit when the product already supplies a surface. */\n mainCard?: boolean;\n /** Consent notice and policy links. Omit with `hasFooter: false`. */\n footer?: ReactNode;\n className?: string;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n }>;\n\n/**\n * Two regions: hero + main stay one vertically centred block, the footer sits at\n * the bottom. The measurements come from the resolved descriptor as custom\n * properties so the stylesheet keeps one source of truth with the contract.\n */\nexport const AuthScreenLayout = forwardRef<HTMLElement, AuthScreenLayoutProps>(\n function AuthScreenLayout(\n { hero, main, footer, density, hasFooter, pendingLabel, mainCard = false, className, as: Element = \"main\", layoutStyle, ...props },\n forwardedRef,\n ) {\n const resolved = resolveAuthScreenDescriptor({\n ...(density === undefined ? {} : { density }),\n ...(hasFooter === undefined ? {} : { hasFooter }),\n });\n const showFooter = resolved.hasFooter && footer !== undefined && footer !== null;\n const pending = pendingLabel !== undefined;\n if (pending && !pendingLabel.trim()) throw new TypeError(\"AuthScreen pendingLabel must not be empty\");\n return (\n <Element\n {...props}\n ref={forwardedRef}\n className={classNames(\"hjm-auth-screen\", className)}\n data-density={resolved.density}\n style={{\n [\"--hjm-auth-screen-max-width\" as string]: `${resolved.maxWidth}px`,\n [\"--hjm-auth-screen-hero-gap\" as string]: `${resolved.heroGap}px`,\n [\"--hjm-auth-screen-main-gap\" as string]: `${resolved.mainGap}px`,\n [\"--hjm-auth-screen-footer-gap\" as string]: `${resolved.footerGap}px`,\n [\"--hjm-auth-screen-padding-inline\" as string]: `${resolved.paddingInline}px`,\n [\"--hjm-auth-screen-padding-block\" as string]: `${resolved.paddingBlock}px`,\n ...props.style,\n ...layoutStyle,\n }}\n >\n <div className=\"hjm-auth-screen__block\">\n <div className=\"hjm-auth-screen__hero\">{hero}</div>\n <div className=\"hjm-auth-screen__main\" data-card={mainCard || undefined} aria-busy={pending || undefined}>\n {/* Keep the action block in flow so the card never collapses; inert also removes keyboard access. */}\n <div className=\"hjm-auth-screen__actions\" inert={pending} aria-hidden={pending || undefined}\n style={pending ? { visibility: \"hidden\" } : undefined}>{main}</div>\n {pending ? <div className=\"hjm-auth-screen__pending\" role=\"status\" aria-label={pendingLabel}>\n <span className=\"hjm-auth-provider-button__spinner\" aria-hidden=\"true\" />\n </div> : null}\n </div>\n </div>\n {showFooter ? <div className=\"hjm-auth-screen__footer\">{footer}</div> : null}\n </Element>\n );\n },\n);\n"]}
@@ -1,5 +1,6 @@
1
1
  import { type HTMLAttributes, type MouseEventHandler, type ReactNode } from "react";
2
2
  import { type ButtonSize, type ButtonTone } from "./actions.js";
3
+ import type { HjmCompositionStyleProp } from "./composition-style.js";
3
4
  export type BottomCTAAction = Readonly<{
4
5
  label: string;
5
6
  onClick: MouseEventHandler<HTMLButtonElement>;
@@ -18,6 +19,8 @@ export type BottomCTAProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> &
18
19
  safeAreaBottom?: number;
19
20
  /** Sticky remains in document flow; fixed overlays would need a measured content spacer. */
20
21
  position?: "flow" | "sticky";
22
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
23
+ layoutStyle?: HjmCompositionStyleProp;
21
24
  }>;
22
25
  /** One primary action with optional supporting copy and a secondary action, matching Native's slots. */
23
26
  export declare const BottomCTA: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & Readonly<{
@@ -28,5 +31,7 @@ export declare const BottomCTA: import("react").ForwardRefExoticComponent<Omit<H
28
31
  safeAreaBottom?: number;
29
32
  /** Sticky remains in document flow; fixed overlays would need a measured content spacer. */
30
33
  position?: "flow" | "sticky";
34
+ /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */
35
+ layoutStyle?: HjmCompositionStyleProp;
31
36
  }> & import("react").RefAttributes<HTMLDivElement>>;
32
37
  //# sourceMappingURL=bottom-cta.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bottom-cta.d.ts","sourceRoot":"","sources":["../src/bottom-cta.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkC,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACpH,OAAO,EAAU,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAIxE,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAC9C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC;IACvF,aAAa,EAAE,eAAe,CAAC;IAC/B,eAAe,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC9B,CAAC,CAAC;AAeH,wGAAwG;AACxG,eAAO,MAAM,SAAS;mBAvBL,eAAe;sBACZ,eAAe,GAAG,SAAS;kBAC/B,MAAM;yBACC,MAAM;qBACV,MAAM;IACvB,4FAA4F;eACjF,MAAM,GAAG,QAAQ;mDAwC5B,CAAC"}
1
+ {"version":3,"file":"bottom-cta.d.ts","sourceRoot":"","sources":["../src/bottom-cta.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkC,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACpH,OAAO,EAAU,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAGxE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAC9C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC;IACvF,aAAa,EAAE,eAAe,CAAC;IAC/B,eAAe,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAeH,wGAAwG;AACxG,eAAO,MAAM,SAAS;mBAzBL,eAAe;sBACZ,eAAe,GAAG,SAAS;kBAC/B,MAAM;yBACC,MAAM;qBACV,MAAM;IACvB,4FAA4F;eACjF,MAAM,GAAG,QAAQ;IAC5B,gGAAgG;kBAClF,uBAAuB;mDAwCrC,CAAC"}
@@ -14,7 +14,7 @@ function isAction(value) {
14
14
  return typeof value === "object" && value !== null && "label" in value && "onClick" in value;
15
15
  }
16
16
  /** One primary action with optional supporting copy and a secondary action, matching Native's slots. */
17
- export const BottomCTA = forwardRef(function BottomCTA({ primaryAction, secondaryAction, description, accessibilityLabel, safeAreaBottom = 0, position = "flow", className, style, ...props }, ref) {
17
+ export const BottomCTA = forwardRef(function BottomCTA({ primaryAction, secondaryAction, description, accessibilityLabel, safeAreaBottom = 0, position = "flow", className, style, layoutStyle, ...props }, ref) {
18
18
  const theme = useOptionalHjmTheme();
19
19
  if (!Number.isFinite(safeAreaBottom) || safeAreaBottom < 0)
20
20
  throw new RangeError("BottomCTA safeAreaBottom must be non-negative");
@@ -24,7 +24,7 @@ export const BottomCTA = forwardRef(function BottomCTA({ primaryAction, secondar
24
24
  "--hjm-bottom-cta-padding-top": `${bottomCtaRecipe.paddingTop}px`,
25
25
  "--hjm-bottom-cta-padding-bottom": `${bottomCtaRecipe.paddingBottom}px`,
26
26
  "--hjm-bottom-cta-gap": `${bottomCtaRecipe.gap}px`,
27
- "--hjm-bottom-cta-safe-area": `${safeAreaBottom}px`, ...style,
27
+ "--hjm-bottom-cta-safe-area": `${safeAreaBottom}px`, ...style, ...layoutStyle,
28
28
  }, children: [description ? _jsx("p", { className: "hjm-bottom-cta__description", children: description }) : null, _jsxs("div", { className: "hjm-bottom-cta__actions", children: [secondaryAction == null ? null : _jsx("div", { className: "hjm-bottom-cta__secondary", children: isAction(secondaryAction) ? _jsx(Action, { action: secondaryAction, tone: "secondary" }) : secondaryAction }), _jsx("div", { className: "hjm-bottom-cta__primary", children: _jsx(Action, { action: primaryAction, tone: "primary" }) })] })] });
29
29
  });
30
30
  //# sourceMappingURL=bottom-cta.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bottom-cta.js","sourceRoot":"","sources":["../src/bottom-cta.tsx"],"names":[],"mappings":"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","sourcesContent":["import { bottomCtaRecipe } from \"@hjmds/design-contracts/recipes\";\nimport { isLargeTextScale } from \"@hjmds/design-contracts/components/design-system-provider\";\nimport { forwardRef, type CSSProperties, type HTMLAttributes, type MouseEventHandler, type ReactNode } from \"react\";\nimport { Button, type ButtonSize, type ButtonTone } from \"./actions.js\";\nimport { classNames } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\n\nexport type BottomCTAAction = Readonly<{\n label: string;\n onClick: MouseEventHandler<HTMLButtonElement>;\n accessibilityLabel?: string;\n disabled?: boolean;\n loading?: boolean;\n loadingLabel?: string;\n size?: ButtonSize;\n tone?: ButtonTone;\n}>;\n\nexport type BottomCTAProps = Omit<HTMLAttributes<HTMLDivElement>, \"children\"> & Readonly<{\n primaryAction: BottomCTAAction;\n secondaryAction?: BottomCTAAction | ReactNode;\n description?: string;\n accessibilityLabel?: string;\n safeAreaBottom?: number;\n /** Sticky remains in document flow; fixed overlays would need a measured content spacer. */\n position?: \"flow\" | \"sticky\";\n}>;\n\nfunction Action({ action, tone }: { action: BottomCTAAction; tone: ButtonTone }) {\n if (!action.label.trim()) throw new TypeError(\"BottomCTA action label must not be empty\");\n return <Button onClick={action.onClick} tone={action.tone ?? tone} size={action.size ?? \"medium\"}\n disabled={action.disabled} loading={action.loading ?? false}\n aria-label={action.loading ? action.loadingLabel ?? action.accessibilityLabel ?? action.label : action.accessibilityLabel}>\n {action.label}\n </Button>;\n}\n\nfunction isAction(value: BottomCTAAction | ReactNode): value is BottomCTAAction {\n return typeof value === \"object\" && value !== null && \"label\" in value && \"onClick\" in value;\n}\n\n/** One primary action with optional supporting copy and a secondary action, matching Native's slots. */\nexport const BottomCTA = forwardRef<HTMLDivElement, BottomCTAProps>(function BottomCTA({\n primaryAction, secondaryAction, description, accessibilityLabel, safeAreaBottom = 0,\n position = \"flow\", className, style, ...props\n}, ref) {\n const theme = useOptionalHjmTheme();\n if (!Number.isFinite(safeAreaBottom) || safeAreaBottom < 0) throw new RangeError(\"BottomCTA safeAreaBottom must be non-negative\");\n return <div {...props} ref={ref} role=\"group\" aria-label={accessibilityLabel}\n className={classNames(\"hjm-bottom-cta\", className)} data-position={position}\n data-large-text={isLargeTextScale(theme?.environment.textScale ?? 1)}\n style={{\n \"--hjm-bottom-cta-min-height\": `${bottomCtaRecipe.minHeight}px`,\n \"--hjm-bottom-cta-padding-inline\": `${bottomCtaRecipe.paddingHorizontal}px`,\n \"--hjm-bottom-cta-padding-top\": `${bottomCtaRecipe.paddingTop}px`,\n \"--hjm-bottom-cta-padding-bottom\": `${bottomCtaRecipe.paddingBottom}px`,\n \"--hjm-bottom-cta-gap\": `${bottomCtaRecipe.gap}px`,\n \"--hjm-bottom-cta-safe-area\": `${safeAreaBottom}px`, ...style,\n } as CSSProperties}>\n {description ? <p className=\"hjm-bottom-cta__description\">{description}</p> : null}\n <div className=\"hjm-bottom-cta__actions\">\n {secondaryAction == null ? null : <div className=\"hjm-bottom-cta__secondary\">{isAction(secondaryAction) ? <Action action={secondaryAction} tone=\"secondary\" /> : secondaryAction}</div>}\n <div className=\"hjm-bottom-cta__primary\"><Action action={primaryAction} tone=\"primary\" /></div>\n </div>\n </div>;\n});\n"]}
1
+ {"version":3,"file":"bottom-cta.js","sourceRoot":"","sources":["../src/bottom-cta.tsx"],"names":[],"mappings":"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","sourcesContent":["import { bottomCtaRecipe } from \"@hjmds/design-contracts/recipes\";\nimport { isLargeTextScale } from \"@hjmds/design-contracts/components/design-system-provider\";\nimport { forwardRef, type CSSProperties, type HTMLAttributes, type MouseEventHandler, type ReactNode } from \"react\";\nimport { Button, type ButtonSize, type ButtonTone } from \"./actions.js\";\nimport { classNames } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type BottomCTAAction = Readonly<{\n label: string;\n onClick: MouseEventHandler<HTMLButtonElement>;\n accessibilityLabel?: string;\n disabled?: boolean;\n loading?: boolean;\n loadingLabel?: string;\n size?: ButtonSize;\n tone?: ButtonTone;\n}>;\n\nexport type BottomCTAProps = Omit<HTMLAttributes<HTMLDivElement>, \"children\"> & Readonly<{\n primaryAction: BottomCTAAction;\n secondaryAction?: BottomCTAAction | ReactNode;\n description?: string;\n accessibilityLabel?: string;\n safeAreaBottom?: number;\n /** Sticky remains in document flow; fixed overlays would need a measured content spacer. */\n position?: \"flow\" | \"sticky\";\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\nfunction Action({ action, tone }: { action: BottomCTAAction; tone: ButtonTone }) {\n if (!action.label.trim()) throw new TypeError(\"BottomCTA action label must not be empty\");\n return <Button onClick={action.onClick} tone={action.tone ?? tone} size={action.size ?? \"medium\"}\n disabled={action.disabled} loading={action.loading ?? false}\n aria-label={action.loading ? action.loadingLabel ?? action.accessibilityLabel ?? action.label : action.accessibilityLabel}>\n {action.label}\n </Button>;\n}\n\nfunction isAction(value: BottomCTAAction | ReactNode): value is BottomCTAAction {\n return typeof value === \"object\" && value !== null && \"label\" in value && \"onClick\" in value;\n}\n\n/** One primary action with optional supporting copy and a secondary action, matching Native's slots. */\nexport const BottomCTA = forwardRef<HTMLDivElement, BottomCTAProps>(function BottomCTA({\n primaryAction, secondaryAction, description, accessibilityLabel, safeAreaBottom = 0,\n position = \"flow\", className, style, layoutStyle, ...props\n}, ref) {\n const theme = useOptionalHjmTheme();\n if (!Number.isFinite(safeAreaBottom) || safeAreaBottom < 0) throw new RangeError(\"BottomCTA safeAreaBottom must be non-negative\");\n return <div {...props} ref={ref} role=\"group\" aria-label={accessibilityLabel}\n className={classNames(\"hjm-bottom-cta\", className)} data-position={position}\n data-large-text={isLargeTextScale(theme?.environment.textScale ?? 1)}\n style={{\n \"--hjm-bottom-cta-min-height\": `${bottomCtaRecipe.minHeight}px`,\n \"--hjm-bottom-cta-padding-inline\": `${bottomCtaRecipe.paddingHorizontal}px`,\n \"--hjm-bottom-cta-padding-top\": `${bottomCtaRecipe.paddingTop}px`,\n \"--hjm-bottom-cta-padding-bottom\": `${bottomCtaRecipe.paddingBottom}px`,\n \"--hjm-bottom-cta-gap\": `${bottomCtaRecipe.gap}px`,\n \"--hjm-bottom-cta-safe-area\": `${safeAreaBottom}px`, ...style, ...layoutStyle,\n } as CSSProperties}>\n {description ? <p className=\"hjm-bottom-cta__description\">{description}</p> : null}\n <div className=\"hjm-bottom-cta__actions\">\n {secondaryAction == null ? null : <div className=\"hjm-bottom-cta__secondary\">{isAction(secondaryAction) ? <Action action={secondaryAction} tone=\"secondary\" /> : secondaryAction}</div>}\n <div className=\"hjm-bottom-cta__primary\"><Action action={primaryAction} tone=\"primary\" /></div>\n </div>\n </div>;\n});\n"]}