@hjmds/react 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/dist/actions.d.ts.map +1 -1
  2. package/dist/actions.js +12 -6
  3. package/dist/actions.js.map +1 -1
  4. package/dist/advanced-display.d.ts +21 -0
  5. package/dist/advanced-display.d.ts.map +1 -1
  6. package/dist/advanced-display.js +11 -0
  7. package/dist/advanced-display.js.map +1 -1
  8. package/dist/advanced-navigation.d.ts +2 -23
  9. package/dist/advanced-navigation.d.ts.map +1 -1
  10. package/dist/advanced-navigation.js +3 -24
  11. package/dist/advanced-navigation.js.map +1 -1
  12. package/dist/agreement.d.ts +20 -0
  13. package/dist/agreement.d.ts.map +1 -0
  14. package/dist/agreement.js +29 -0
  15. package/dist/agreement.js.map +1 -0
  16. package/dist/anchor.d.ts +24 -0
  17. package/dist/anchor.d.ts.map +1 -0
  18. package/dist/anchor.js +110 -0
  19. package/dist/anchor.js.map +1 -0
  20. package/dist/asset.d.ts +40 -0
  21. package/dist/asset.d.ts.map +1 -0
  22. package/dist/asset.js +26 -0
  23. package/dist/asset.js.map +1 -0
  24. package/dist/bottom-cta.d.ts +32 -0
  25. package/dist/bottom-cta.d.ts.map +1 -0
  26. package/dist/bottom-cta.js +30 -0
  27. package/dist/bottom-cta.js.map +1 -0
  28. package/dist/bottom-info.d.ts +16 -0
  29. package/dist/bottom-info.d.ts.map +1 -0
  30. package/dist/bottom-info.js +12 -0
  31. package/dist/bottom-info.js.map +1 -0
  32. package/dist/breadcrumb.d.ts +9 -0
  33. package/dist/breadcrumb.d.ts.map +1 -0
  34. package/dist/breadcrumb.js +12 -0
  35. package/dist/breadcrumb.js.map +1 -0
  36. package/dist/calendar.d.ts +30 -0
  37. package/dist/calendar.d.ts.map +1 -0
  38. package/dist/calendar.js +69 -0
  39. package/dist/calendar.js.map +1 -0
  40. package/dist/carousel.d.ts +20 -0
  41. package/dist/carousel.d.ts.map +1 -0
  42. package/dist/carousel.js +70 -0
  43. package/dist/carousel.js.map +1 -0
  44. package/dist/clipboard.d.ts +33 -0
  45. package/dist/clipboard.d.ts.map +1 -0
  46. package/dist/clipboard.js +40 -0
  47. package/dist/clipboard.js.map +1 -0
  48. package/dist/collapsible.d.ts +11 -0
  49. package/dist/collapsible.d.ts.map +1 -0
  50. package/dist/collapsible.js +18 -0
  51. package/dist/collapsible.js.map +1 -0
  52. package/dist/command-palette.d.ts +25 -0
  53. package/dist/command-palette.d.ts.map +1 -0
  54. package/dist/command-palette.js +82 -0
  55. package/dist/command-palette.js.map +1 -0
  56. package/dist/context-menu.d.ts +12 -0
  57. package/dist/context-menu.d.ts.map +1 -0
  58. package/dist/context-menu.js +111 -0
  59. package/dist/context-menu.js.map +1 -0
  60. package/dist/data-table.d.ts +30 -0
  61. package/dist/data-table.d.ts.map +1 -0
  62. package/dist/data-table.js +57 -0
  63. package/dist/data-table.js.map +1 -0
  64. package/dist/date-picker.d.ts +3 -1
  65. package/dist/date-picker.d.ts.map +1 -1
  66. package/dist/date-picker.js +16 -31
  67. package/dist/date-picker.js.map +1 -1
  68. package/dist/date-range.d.ts +24 -0
  69. package/dist/date-range.d.ts.map +1 -0
  70. package/dist/date-range.js +29 -0
  71. package/dist/date-range.js.map +1 -0
  72. package/dist/display.d.ts +16 -0
  73. package/dist/display.d.ts.map +1 -1
  74. package/dist/display.js +13 -1
  75. package/dist/display.js.map +1 -1
  76. package/dist/evidence.d.ts +481 -1
  77. package/dist/evidence.d.ts.map +1 -1
  78. package/dist/evidence.js +47 -2
  79. package/dist/evidence.js.map +1 -1
  80. package/dist/feedback.d.ts +18 -2
  81. package/dist/feedback.d.ts.map +1 -1
  82. package/dist/feedback.js +10 -2
  83. package/dist/feedback.js.map +1 -1
  84. package/dist/floating-action-button.d.ts +32 -0
  85. package/dist/floating-action-button.d.ts.map +1 -0
  86. package/dist/floating-action-button.js +58 -0
  87. package/dist/floating-action-button.js.map +1 -0
  88. package/dist/forms.d.ts +3 -3
  89. package/dist/forms.d.ts.map +1 -1
  90. package/dist/forms.js +18 -7
  91. package/dist/forms.js.map +1 -1
  92. package/dist/heading.d.ts +12 -0
  93. package/dist/heading.d.ts.map +1 -0
  94. package/dist/heading.js +25 -0
  95. package/dist/heading.js.map +1 -0
  96. package/dist/index.d.ts +35 -2
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +35 -2
  99. package/dist/index.js.map +1 -1
  100. package/dist/layout.d.ts +1 -1
  101. package/dist/mentions.d.ts +28 -0
  102. package/dist/mentions.d.ts.map +1 -0
  103. package/dist/mentions.js +84 -0
  104. package/dist/mentions.js.map +1 -0
  105. package/dist/menubar.d.ts +11 -0
  106. package/dist/menubar.d.ts.map +1 -0
  107. package/dist/menubar.js +137 -0
  108. package/dist/menubar.js.map +1 -0
  109. package/dist/modal.d.ts +67 -0
  110. package/dist/modal.d.ts.map +1 -0
  111. package/dist/modal.js +307 -0
  112. package/dist/modal.js.map +1 -0
  113. package/dist/overlay-stack.d.ts +28 -0
  114. package/dist/overlay-stack.d.ts.map +1 -0
  115. package/dist/overlay-stack.js +47 -0
  116. package/dist/overlay-stack.js.map +1 -0
  117. package/dist/overlays.d.ts +26 -43
  118. package/dist/overlays.d.ts.map +1 -1
  119. package/dist/overlays.js +62 -302
  120. package/dist/overlays.js.map +1 -1
  121. package/dist/pagination.d.ts +17 -0
  122. package/dist/pagination.d.ts.map +1 -0
  123. package/dist/pagination.js +21 -0
  124. package/dist/pagination.js.map +1 -0
  125. package/dist/popover.d.ts +25 -0
  126. package/dist/popover.d.ts.map +1 -0
  127. package/dist/popover.js +226 -0
  128. package/dist/popover.js.map +1 -0
  129. package/dist/portal.d.ts +5 -1
  130. package/dist/portal.d.ts.map +1 -1
  131. package/dist/portal.js +24 -1
  132. package/dist/portal.js.map +1 -1
  133. package/dist/provider-button.d.ts +21 -0
  134. package/dist/provider-button.d.ts.map +1 -0
  135. package/dist/provider-button.js +26 -0
  136. package/dist/provider-button.js.map +1 -0
  137. package/dist/provider.d.ts +13 -1
  138. package/dist/provider.d.ts.map +1 -1
  139. package/dist/provider.js +12 -2
  140. package/dist/provider.js.map +1 -1
  141. package/dist/selection.d.ts +5 -1
  142. package/dist/selection.d.ts.map +1 -1
  143. package/dist/selection.js +2 -2
  144. package/dist/selection.js.map +1 -1
  145. package/dist/side-panel.d.ts +34 -0
  146. package/dist/side-panel.d.ts.map +1 -0
  147. package/dist/side-panel.js +95 -0
  148. package/dist/side-panel.js.map +1 -0
  149. package/dist/sidebar.d.ts +22 -0
  150. package/dist/sidebar.d.ts.map +1 -0
  151. package/dist/sidebar.js +29 -0
  152. package/dist/sidebar.js.map +1 -0
  153. package/dist/skip-nav.d.ts +12 -0
  154. package/dist/skip-nav.d.ts.map +1 -0
  155. package/dist/skip-nav.js +29 -0
  156. package/dist/skip-nav.js.map +1 -0
  157. package/dist/splitter.d.ts +45 -0
  158. package/dist/splitter.d.ts.map +1 -0
  159. package/dist/splitter.js +116 -0
  160. package/dist/splitter.js.map +1 -0
  161. package/dist/styles.css +1068 -26
  162. package/dist/supplemental-display.d.ts +12 -0
  163. package/dist/supplemental-display.d.ts.map +1 -1
  164. package/dist/supplemental-display.js +6 -2
  165. package/dist/supplemental-display.js.map +1 -1
  166. package/dist/tags-input.d.ts +60 -0
  167. package/dist/tags-input.d.ts.map +1 -0
  168. package/dist/tags-input.js +90 -0
  169. package/dist/tags-input.js.map +1 -0
  170. package/dist/text-formats.d.ts +16 -0
  171. package/dist/text-formats.d.ts.map +1 -0
  172. package/dist/text-formats.js +24 -0
  173. package/dist/text-formats.js.map +1 -0
  174. package/dist/toast.d.ts +1 -1
  175. package/dist/toggle-group.d.ts +13 -0
  176. package/dist/toggle-group.d.ts.map +1 -0
  177. package/dist/toggle-group.js +21 -0
  178. package/dist/toggle-group.js.map +1 -0
  179. package/dist/top-bar.d.ts +27 -0
  180. package/dist/top-bar.d.ts.map +1 -0
  181. package/dist/top-bar.js +30 -0
  182. package/dist/top-bar.js.map +1 -0
  183. package/dist/top.d.ts +15 -0
  184. package/dist/top.d.ts.map +1 -0
  185. package/dist/top.js +18 -0
  186. package/dist/top.js.map +1 -0
  187. package/dist/tour.d.ts +21 -0
  188. package/dist/tour.d.ts.map +1 -0
  189. package/dist/tour.js +122 -0
  190. package/dist/tour.js.map +1 -0
  191. package/dist/transfer-list.d.ts +24 -0
  192. package/dist/transfer-list.d.ts.map +1 -0
  193. package/dist/transfer-list.js +109 -0
  194. package/dist/transfer-list.js.map +1 -0
  195. package/dist/tree.d.ts +29 -0
  196. package/dist/tree.d.ts.map +1 -0
  197. package/dist/tree.js +120 -0
  198. package/dist/tree.js.map +1 -0
  199. package/package.json +173 -3
@@ -0,0 +1,28 @@
1
+ import { type ReactElement, type ReactNode } from "react";
2
+ import { type DialogProps } from "./overlays.js";
3
+ import { type SheetProps } from "./overlays.js";
4
+ type DialogRequest = Omit<DialogProps, "open" | "defaultOpen" | "onOpenChange" | "trigger"> & Readonly<{
5
+ children?: ReactNode;
6
+ }>;
7
+ type SheetRequest = Omit<SheetProps, "open" | "defaultOpen" | "onOpenChange" | "trigger"> & Readonly<{
8
+ children?: ReactNode;
9
+ }>;
10
+ export type OverlayHandle = Readonly<{
11
+ /** Resolves once the overlay is gone and focus has been restored. */
12
+ closed: Promise<void>;
13
+ close(): void;
14
+ }>;
15
+ export type OverlayStackApi = Readonly<{
16
+ openDialog(request: DialogRequest): OverlayHandle;
17
+ openSheet(request: SheetRequest): OverlayHandle;
18
+ }>;
19
+ export declare function useOverlayStack(): OverlayStackApi;
20
+ /** Convenience wrappers so a call site reads as the thing it opens. */
21
+ export declare function useDialog(): OverlayStackApi["openDialog"];
22
+ export declare function useSheet(): OverlayStackApi["openSheet"];
23
+ export type OverlayStackProviderProps = Readonly<{
24
+ children: ReactNode;
25
+ }>;
26
+ export declare function OverlayStackProvider({ children }: OverlayStackProviderProps): ReactElement;
27
+ export {};
28
+ //# sourceMappingURL=overlay-stack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay-stack.d.ts","sourceRoot":"","sources":["../src/overlay-stack.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAmBvD,KAAK,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,SAAS,CAAC,GACzF,QAAQ,CAAC;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AACrC,KAAK,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,SAAS,CAAC,GACvF,QAAQ,CAAC;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAErC,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACnC,qEAAqE;IACrE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,IAAI,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,CAAC;IAClD,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,aAAa,CAAC;CACjD,CAAC,CAAC;AAQH,wBAAgB,eAAe,IAAI,eAAe,CAIjD;AAED,uEAAuE;AACvE,wBAAgB,SAAS,IAAI,eAAe,CAAC,YAAY,CAAC,CAEzD;AAED,wBAAgB,QAAQ,IAAI,eAAe,CAAC,WAAW,CAAC,CAEvD;AAED,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAE1E,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,EAAE,yBAAyB,GAAG,YAAY,CAoD1F"}
@@ -0,0 +1,47 @@
1
+ import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createElement as _createElement } from "react";
3
+ import { createContext, useCallback, useContext, useMemo, useRef, useState, } from "react";
4
+ import { Dialog } from "./overlays.js";
5
+ import { Sheet } from "./overlays.js";
6
+ const OverlayStackContext = createContext(null);
7
+ export function useOverlayStack() {
8
+ const value = useContext(OverlayStackContext);
9
+ if (value === null)
10
+ throw new Error("useOverlayStack must be used inside OverlayStackProvider");
11
+ return value;
12
+ }
13
+ /** Convenience wrappers so a call site reads as the thing it opens. */
14
+ export function useDialog() {
15
+ return useOverlayStack().openDialog;
16
+ }
17
+ export function useSheet() {
18
+ return useOverlayStack().openSheet;
19
+ }
20
+ export function OverlayStackProvider({ children }) {
21
+ const [entry, setEntry] = useState(null);
22
+ const [open, setOpen] = useState(false);
23
+ const nextId = useRef(0);
24
+ const openEntry = useCallback((kind, request) => {
25
+ const id = (nextId.current += 1);
26
+ let settle = () => undefined;
27
+ const closed = new Promise((resolve) => { settle = resolve; });
28
+ setEntry({ kind, id, request, settle });
29
+ setOpen(true);
30
+ return {
31
+ closed,
32
+ close: () => setOpen(false),
33
+ };
34
+ }, []);
35
+ const api = useMemo(() => ({
36
+ openDialog: (request) => openEntry("dialog", request),
37
+ openSheet: (request) => openEntry("sheet", request),
38
+ }), [openEntry]);
39
+ // The promise resolves from the renderer's own completion signal, not from a
40
+ // timer: that is the whole reason this layer exists.
41
+ const complete = () => {
42
+ entry?.settle();
43
+ setEntry(null);
44
+ };
45
+ return (_jsxs(OverlayStackContext.Provider, { value: api, children: [children, entry?.kind === "dialog" ? (_createElement(Dialog, { ...entry.request, key: entry.id, open: open, onOpenChange: (next) => setOpen(next), onDismissComplete: () => complete() })) : null, entry?.kind === "sheet" ? (_createElement(Sheet, { ...entry.request, key: entry.id, open: open, onOpenChange: (next) => setOpen(next), onDismissComplete: () => complete() })) : null] }));
46
+ }
47
+ //# sourceMappingURL=overlay-stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay-stack.js","sourceRoot":"","sources":["../src/overlay-stack.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { Dialog, type DialogProps } from \"./overlays.js\";\nimport { Sheet, type SheetProps } from \"./overlays.js\";\n\n/*\n Imperative Dialog and Sheet. `useToast` already has this shape, and the gap\n beside it is why each product rewired \"open state + mount point + completion\n signal\" by hand (BurnTok's AppModal built its own `onDismiss` for exactly this).\n\n This layer only transfers ownership: the provider holds the open state and the\n mount point, and the call site knows just \"open it\" and \"it closed\". Dismiss\n judgement, focus and isolation stay in the Dialog/Sheet contracts — none of it\n is reimplemented here.\n\n One overlay at a time. Stacking needs rules (which one is on top, is the one\n behind inert) that the modal stack already owns; an imperative API that\n bypassed it would fork those rules and produce \"closed it and the one below\n never came back\". Opening a follow-up surface after `closed` resolves is the\n contracted order.\n*/\n\ntype DialogRequest = Omit<DialogProps, \"open\" | \"defaultOpen\" | \"onOpenChange\" | \"trigger\"> &\n Readonly<{ children?: ReactNode }>;\ntype SheetRequest = Omit<SheetProps, \"open\" | \"defaultOpen\" | \"onOpenChange\" | \"trigger\"> &\n Readonly<{ children?: ReactNode }>;\n\nexport type OverlayHandle = Readonly<{\n /** Resolves once the overlay is gone and focus has been restored. */\n closed: Promise<void>;\n close(): void;\n}>;\n\nexport type OverlayStackApi = Readonly<{\n openDialog(request: DialogRequest): OverlayHandle;\n openSheet(request: SheetRequest): OverlayHandle;\n}>;\n\ntype Entry =\n | Readonly<{ kind: \"dialog\"; id: number; request: DialogRequest; settle: () => void }>\n | Readonly<{ kind: \"sheet\"; id: number; request: SheetRequest; settle: () => void }>;\n\nconst OverlayStackContext = createContext<OverlayStackApi | null>(null);\n\nexport function useOverlayStack(): OverlayStackApi {\n const value = useContext(OverlayStackContext);\n if (value === null) throw new Error(\"useOverlayStack must be used inside OverlayStackProvider\");\n return value;\n}\n\n/** Convenience wrappers so a call site reads as the thing it opens. */\nexport function useDialog(): OverlayStackApi[\"openDialog\"] {\n return useOverlayStack().openDialog;\n}\n\nexport function useSheet(): OverlayStackApi[\"openSheet\"] {\n return useOverlayStack().openSheet;\n}\n\nexport type OverlayStackProviderProps = Readonly<{ children: ReactNode }>;\n\nexport function OverlayStackProvider({ children }: OverlayStackProviderProps): ReactElement {\n const [entry, setEntry] = useState<Entry | null>(null);\n const [open, setOpen] = useState(false);\n const nextId = useRef(0);\n\n const openEntry = useCallback((kind: Entry[\"kind\"], request: DialogRequest | SheetRequest): OverlayHandle => {\n const id = (nextId.current += 1);\n let settle: () => void = () => undefined;\n const closed = new Promise<void>((resolve) => { settle = resolve; });\n setEntry({ kind, id, request, settle } as Entry);\n setOpen(true);\n return {\n closed,\n close: () => setOpen(false),\n };\n }, []);\n\n const api = useMemo<OverlayStackApi>(() => ({\n openDialog: (request) => openEntry(\"dialog\", request),\n openSheet: (request) => openEntry(\"sheet\", request),\n }), [openEntry]);\n\n // The promise resolves from the renderer's own completion signal, not from a\n // timer: that is the whole reason this layer exists.\n const complete = () => {\n entry?.settle();\n setEntry(null);\n };\n\n return (\n <OverlayStackContext.Provider value={api}>\n {children}\n {entry?.kind === \"dialog\" ? (\n <Dialog\n {...entry.request}\n key={entry.id}\n open={open}\n onOpenChange={(next) => setOpen(next)}\n onDismissComplete={() => complete()}\n />\n ) : null}\n {entry?.kind === \"sheet\" ? (\n <Sheet\n {...entry.request}\n key={entry.id}\n open={open}\n onOpenChange={(next) => setOpen(next)}\n onDismissComplete={() => complete()}\n />\n ) : null}\n </OverlayStackContext.Provider>\n );\n}\n"]}
@@ -1,49 +1,11 @@
1
1
  import { type AlertDialogOpenChangeReason, type AlertDialogRequest } from "@hjmds/design-contracts/components/alert-dialog";
2
- import { type SheetDismissPolicy, type SheetDismissReason, type SheetOpenChangeDetails } from "@hjmds/design-contracts/components/sheet";
2
+ import { type SheetDetent, type SheetDismissPolicy, type SheetDismissReason, type SheetOpenChangeDetails } from "@hjmds/design-contracts/components/sheet";
3
3
  import { type TooltipAlign, type TooltipOpenChangeDetails, type TooltipPlacement } from "@hjmds/design-contracts/components/tooltip";
4
4
  import { type DialogSize, type MenuDensity, type MenuItemTone } from "@hjmds/design-contracts/recipes";
5
5
  import type { MenuSectionDescriptor } from "@hjmds/design-contracts/behaviors";
6
- import { type AriaAttributes, type MouseEventHandler, type ReactElement, type ReactNode, type Ref } from "react";
7
- type TriggerElementProps = Readonly<{
8
- ref?: Ref<HTMLElement>;
9
- disabled?: boolean;
10
- onClick?: MouseEventHandler<HTMLElement>;
11
- onMouseEnter?: MouseEventHandler<HTMLElement>;
12
- onMouseLeave?: MouseEventHandler<HTMLElement>;
13
- onPointerEnter?: React.PointerEventHandler<HTMLElement>;
14
- onPointerLeave?: React.PointerEventHandler<HTMLElement>;
15
- onFocus?: React.FocusEventHandler<HTMLElement>;
16
- onBlur?: React.FocusEventHandler<HTMLElement>;
17
- onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
18
- "aria-controls"?: string;
19
- "aria-describedby"?: string;
20
- "aria-disabled"?: AriaAttributes["aria-disabled"];
21
- "aria-expanded"?: AriaAttributes["aria-expanded"];
22
- "aria-haspopup"?: AriaAttributes["aria-haspopup"];
23
- }>;
24
- export type OverlayTrigger = ReactElement<TriggerElementProps>;
25
- type OpenState<Detail> = Readonly<{
26
- open: boolean;
27
- defaultOpen?: never;
28
- onOpenChange: (open: boolean, detail: Detail) => void;
29
- }> | Readonly<{
30
- open?: never;
31
- defaultOpen?: boolean;
32
- onOpenChange?: (open: boolean, detail: Detail) => void;
33
- }>;
34
- type ModalOpenState<Detail> = Readonly<{
35
- open: boolean;
36
- defaultOpen?: never;
37
- onOpenChange: (open: boolean, detail: Detail) => void;
38
- /** Optional for product-owned, programmatically controlled overlays. */
39
- trigger?: OverlayTrigger;
40
- }> | Readonly<{
41
- open?: never;
42
- defaultOpen?: boolean;
43
- onOpenChange?: (open: boolean, detail: Detail) => void;
44
- /** Uncontrolled overlays need a first-party activation target. */
45
- trigger: OverlayTrigger;
46
- }>;
6
+ import { type ReactNode } from "react";
7
+ import { type ModalOpenState, type OpenState, type OverlayTrigger } from "./modal.js";
8
+ export type { OverlayTrigger } from "./modal.js";
47
9
  export type DialogOpenChangeReason = "trigger" | "close-action" | "escape" | "outside";
48
10
  export type DialogProps = ModalOpenState<Readonly<{
49
11
  reason: DialogOpenChangeReason;
@@ -59,6 +21,15 @@ export type DialogProps = ModalOpenState<Readonly<{
59
21
  closeLabel: string;
60
22
  initialFocusRef?: React.RefObject<HTMLElement | null>;
61
23
  returnFocusRef?: React.RefObject<HTMLElement | null>;
24
+ /**
25
+ * Fires once per visible cycle, after the portal is gone and focus has been
26
+ * restored — the signal a product needs before opening the next overlay.
27
+ * Sheet already owns this split; Dialog kept only the request side, which is
28
+ * why products reached for a 0ms timer to guess when cleanup had finished.
29
+ */
30
+ onDismissComplete?: (detail: Readonly<{
31
+ reason: Exclude<DialogOpenChangeReason, "trigger"> | "programmatic";
32
+ }>) => void;
62
33
  /** Higher-priority modals remain interactive above later lower-priority modals. */
63
34
  modalPriority?: number;
64
35
  portalContainer?: HTMLElement;
@@ -85,6 +56,19 @@ export type SheetProps = ModalOpenState<SheetOpenChangeDetails> & Readonly<{
85
56
  children?: ReactNode;
86
57
  footer?: ReactNode;
87
58
  placement?: SheetPlacement;
59
+ /**
60
+ * Heights the user may step between while the sheet is open, smallest
61
+ * first. `sheetRecipe.sizes` is what the *product* opens at; this is what
62
+ * the *user* can change afterwards.
63
+ */
64
+ detents?: readonly SheetDetent[];
65
+ activeDetent?: SheetDetent;
66
+ onDetentChange?: (detent: SheetDetent) => void;
67
+ /** Localized names for the handle in each direction; required with detents. */
68
+ detentLabels?: Readonly<{
69
+ expand: string;
70
+ collapse: string;
71
+ }>;
88
72
  busy?: boolean;
89
73
  dismissPolicy?: Partial<SheetDismissPolicy>;
90
74
  /** Localized accessible name for the close action. */
@@ -188,5 +172,4 @@ export type MenuProps = OpenState<Readonly<{
188
172
  reason: MenuOpenChangeReason;
189
173
  }>> & MenuBaseProps & (MenuActionSelection | MenuSingleSelection | MenuMultipleSelection);
190
174
  export declare const Menu: import("react").ForwardRefExoticComponent<MenuProps & import("react").RefAttributes<HTMLDivElement>>;
191
- export {};
192
175
  //# sourceMappingURL=overlays.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../src/overlays.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../src/overlays.tsx"],"names":[],"mappings":"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"}
package/dist/overlays.js CHANGED
@@ -1,309 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { isLargeTextScale } from "@hjmds/design-contracts/components/design-system-provider";
3
2
  import { createAlertDialogSession, getAlertDialogInitialFocus, validateAlertDialogRequest, } from "@hjmds/design-contracts/components/alert-dialog";
4
- import { createSheetLifecycle, sheetBehaviorDefaults, } from "@hjmds/design-contracts/components/sheet";
3
+ import { createSheetLifecycle, resolveNextSheetDetent, sheetBehaviorDefaults, } from "@hjmds/design-contracts/components/sheet";
5
4
  import { resolveTooltipDescriptor, tooltipBehaviorDefaults, } from "@hjmds/design-contracts/components/tooltip";
6
5
  import { dialogRecipe, menuRecipe, sheetRecipe, } from "@hjmds/design-contracts/recipes";
7
6
  import { cloneElement, forwardRef, useCallback, useEffect, useId, useRef, useState, useSyncExternalStore, } from "react";
8
- import { createPortal } from "react-dom";
9
7
  import { Button } from "./actions.js";
10
8
  import { classNames, composeRefs, useControllableState } from "./internal.js";
11
- import { AnchoredPortal, useAnchoredPopup, } from "./portal.js";
12
- import { useOptionalHjmTheme, useTooltipCoordinator } from "./provider.js";
13
- import { createHjmThemeStyle } from "./theme.js";
14
- function containsEventTarget(container, target) {
15
- return target !== null &&
16
- "nodeType" in target &&
17
- container?.contains(target) === true;
18
- }
19
- function HjmPortal({ children, container }) {
20
- const [mounted, setMounted] = useState(false);
21
- const theme = useOptionalHjmTheme();
22
- useEffect(() => setMounted(true), []);
23
- if (!mounted)
24
- return null;
25
- return createPortal(theme ? (_jsx("div", { className: "hjm-root hjm-portal", "data-hjm-portal": "", "data-motion": theme.environment.reducedMotion ? "reduced" : "full", "data-theme": theme.environment.theme, "data-text-scale": theme.environment.textScale, "data-large-text": isLargeTextScale(theme.environment.textScale) ? "true" : undefined, dir: theme.environment.direction, style: createHjmThemeStyle(theme), children: children })) : children, container ?? document.body);
26
- }
27
- function useOpenState({ open, defaultOpen = false, onOpenChange, }) {
28
- const [internalOpen, setInternalOpen] = useState(defaultOpen);
29
- const controlled = open !== undefined;
30
- const currentOpen = controlled ? open : internalOpen;
31
- const pendingRequestRef = useRef(undefined);
32
- useEffect(() => {
33
- if (pendingRequestRef.current === currentOpen) {
34
- pendingRequestRef.current = undefined;
35
- }
36
- }, [currentOpen]);
37
- const changeOpen = useCallback((nextOpen, detail) => {
38
- if (nextOpen === currentOpen ||
39
- pendingRequestRef.current === nextOpen)
40
- return;
41
- pendingRequestRef.current = nextOpen;
42
- if (!controlled)
43
- setInternalOpen(nextOpen);
44
- onOpenChange?.(nextOpen, detail);
45
- if (controlled && nextOpen) {
46
- queueMicrotask(() => {
47
- if (pendingRequestRef.current === true) {
48
- pendingRequestRef.current = undefined;
49
- }
50
- });
51
- }
52
- }, [controlled, currentOpen, onOpenChange]);
53
- return [currentOpen, changeOpen];
54
- }
55
- const focusableSelector = [
56
- "a[href]",
57
- "button:not([disabled])",
58
- "input:not([disabled])",
59
- "select:not([disabled])",
60
- "textarea:not([disabled])",
61
- "[tabindex]:not([tabindex='-1'])",
62
- ].join(",");
63
- function getFocusable(container) {
64
- return [...container.querySelectorAll(focusableSelector)].filter((element) => !element.hidden && element.getAttribute("aria-hidden") !== "true");
65
- }
66
- let bodyLockCount = 0;
67
- let previousBodyOverflow = "";
68
- const activeModalStack = [];
69
- let activeModalOrder = 0;
70
- const isolatedModalBackground = new Map();
71
- let modalIsolationObserver = null;
72
- function getOwnedPopupHosts(modal) {
73
- const ownerId = modal.element.id;
74
- if (ownerId.length === 0)
75
- return [];
76
- return [...document.querySelectorAll("[data-hjm-popup-owner]")]
77
- .filter((host) => host.getAttribute("data-hjm-popup-owner") === ownerId);
78
- }
79
- function modalContainsNode(modal, node) {
80
- return modal.element.contains(node) ||
81
- getOwnedPopupHosts(modal).some((host) => host.contains(node));
82
- }
83
- function getModalFocusable(modal) {
84
- return [
85
- ...getFocusable(modal.element),
86
- ...getOwnedPopupHosts(modal).flatMap((host) => getFocusable(host)),
87
- ];
88
- }
89
- function getModalLayer(priority) {
90
- if (!Number.isSafeInteger(priority)) {
91
- throw new TypeError("modalPriority must be a safe integer");
92
- }
93
- return 1000 + priority;
94
- }
95
- function getTopModal() {
96
- let top;
97
- for (const modal of activeModalStack) {
98
- if (!modal.element.isConnected)
99
- continue;
100
- if (top === undefined ||
101
- modal.priority > top.priority ||
102
- (modal.priority === top.priority && modal.order > top.order))
103
- top = modal;
104
- }
105
- return top;
106
- }
107
- function modalRanksAbove(candidate, reference) {
108
- return candidate.priority > reference.priority ||
109
- (candidate.priority === reference.priority && candidate.order > reference.order);
110
- }
111
- function restoreModalBackground() {
112
- for (const [element, previous] of isolatedModalBackground) {
113
- element.inert = previous.inert;
114
- if (previous.ariaHidden === null)
115
- element.removeAttribute("aria-hidden");
116
- else
117
- element.setAttribute("aria-hidden", previous.ariaHidden);
118
- }
119
- isolatedModalBackground.clear();
120
- }
121
- function isolateModalBackgroundElement(element) {
122
- if (isolatedModalBackground.has(element))
123
- return;
124
- isolatedModalBackground.set(element, {
125
- ariaHidden: element.getAttribute("aria-hidden"),
126
- inert: element.inert,
127
- });
128
- element.inert = true;
129
- element.setAttribute("aria-hidden", "true");
130
- }
131
- /** Keeps only the top modal's ancestor path interactive, including late portals. */
132
- function synchronizeModalBackgroundIsolation() {
133
- restoreModalBackground();
134
- for (let index = activeModalStack.length - 1; index >= 0; index -= 1) {
135
- if (!activeModalStack[index]?.element.isConnected)
136
- activeModalStack.splice(index, 1);
137
- }
138
- const top = getTopModal();
139
- if (!top) {
140
- modalIsolationObserver?.disconnect();
141
- modalIsolationObserver = null;
142
- return;
143
- }
144
- const interactivePath = new Set();
145
- for (const root of [top.element, ...getOwnedPopupHosts(top)]) {
146
- let pathNode = root;
147
- while (pathNode) {
148
- if (pathNode === document.body)
149
- break;
150
- interactivePath.add(pathNode);
151
- pathNode = pathNode.parentElement;
152
- }
153
- }
154
- const inspectedParents = new Set();
155
- for (const pathNode of interactivePath) {
156
- const parent = pathNode.parentElement;
157
- if (!parent || inspectedParents.has(parent))
158
- continue;
159
- inspectedParents.add(parent);
160
- for (const sibling of parent.children) {
161
- if (sibling instanceof HTMLElement && !interactivePath.has(sibling)) {
162
- isolateModalBackgroundElement(sibling);
163
- }
164
- }
165
- }
166
- if (modalIsolationObserver === null) {
167
- modalIsolationObserver = new MutationObserver(() => {
168
- synchronizeModalBackgroundIsolation();
169
- });
170
- modalIsolationObserver.observe(document.body, {
171
- attributes: true,
172
- attributeFilter: ["data-hjm-popup-owner"],
173
- childList: true,
174
- subtree: true,
175
- });
176
- }
177
- }
178
- function lockBodyScroll() {
179
- if (bodyLockCount === 0) {
180
- previousBodyOverflow = document.body.style.overflow;
181
- document.body.style.overflow = "hidden";
182
- }
183
- bodyLockCount += 1;
184
- return () => {
185
- bodyLockCount = Math.max(0, bodyLockCount - 1);
186
- if (bodyLockCount === 0)
187
- document.body.style.overflow = previousBodyOverflow;
188
- };
189
- }
190
- function useModalFocus({ active, priority = 0, contentRef, initialFocusRef, returnFocusRef, fallbackReturnRef, onEscape, }) {
191
- const escapeRef = useRef(onEscape);
192
- escapeRef.current = onEscape;
193
- useEffect(() => {
194
- if (!active)
195
- return;
196
- let retryTimer;
197
- let release;
198
- let cancelled = false;
199
- const activate = () => {
200
- const content = contentRef.current;
201
- if (!content) {
202
- retryTimer = setTimeout(activate, 0);
203
- return;
204
- }
205
- const previouslyFocused = document.activeElement instanceof HTMLElement
206
- ? document.activeElement
207
- : null;
208
- const releaseScroll = lockBodyScroll();
209
- const modal = {
210
- element: content,
211
- order: activeModalOrder += 1,
212
- priority,
213
- };
214
- activeModalStack.push(modal);
215
- synchronizeModalBackgroundIsolation();
216
- const initial = initialFocusRef?.current ?? getFocusable(content)[0] ?? content;
217
- if (getTopModal() === modal)
218
- initial.focus();
219
- const handleKeyDown = (event) => {
220
- if (getTopModal() !== modal)
221
- return;
222
- if (event.key === "Escape") {
223
- event.preventDefault();
224
- escapeRef.current();
225
- return;
226
- }
227
- if (event.key !== "Tab")
228
- return;
229
- const focusable = getModalFocusable(modal);
230
- if (focusable.length === 0) {
231
- event.preventDefault();
232
- content.focus();
233
- return;
234
- }
235
- const first = focusable[0];
236
- const last = focusable.at(-1);
237
- const current = document.activeElement;
238
- if (event.shiftKey && (current === first || !(current instanceof Node) || !modalContainsNode(modal, current))) {
239
- event.preventDefault();
240
- last.focus();
241
- }
242
- else if (!event.shiftKey && (current === last || !(current instanceof Node) || !modalContainsNode(modal, current))) {
243
- event.preventDefault();
244
- first.focus();
245
- }
246
- };
247
- const handleFocusIn = (event) => {
248
- if (getTopModal() !== modal)
249
- return;
250
- if (event.target instanceof Node && !modalContainsNode(modal, event.target)) {
251
- (initialFocusRef?.current ?? getFocusable(content)[0] ?? content).focus();
252
- }
253
- };
254
- document.addEventListener("keydown", handleKeyDown, true);
255
- document.addEventListener("focusin", handleFocusIn, true);
256
- release = () => {
257
- const wasTop = !activeModalStack.some((candidate) => candidate !== modal && candidate.element.isConnected && modalRanksAbove(candidate, modal));
258
- document.removeEventListener("keydown", handleKeyDown, true);
259
- document.removeEventListener("focusin", handleFocusIn, true);
260
- const stackIndex = activeModalStack.lastIndexOf(modal);
261
- if (stackIndex >= 0)
262
- activeModalStack.splice(stackIndex, 1);
263
- synchronizeModalBackgroundIsolation();
264
- releaseScroll();
265
- const returnTarget = returnFocusRef?.current ?? fallbackReturnRef?.current ?? previouslyFocused;
266
- if (wasTop) {
267
- queueMicrotask(() => {
268
- const nextTop = getTopModal();
269
- if (!nextTop) {
270
- returnTarget?.focus();
271
- return;
272
- }
273
- if (returnTarget && modalContainsNode(nextTop, returnTarget))
274
- returnTarget.focus();
275
- else
276
- (getModalFocusable(nextTop)[0] ?? nextTop.element).focus();
277
- });
278
- }
279
- };
280
- if (cancelled)
281
- release();
282
- };
283
- activate();
284
- return () => {
285
- cancelled = true;
286
- if (retryTimer !== undefined)
287
- clearTimeout(retryTimer);
288
- release?.();
289
- };
290
- }, [active, contentRef, fallbackReturnRef, initialFocusRef, priority, returnFocusRef]);
291
- }
292
- function renderTrigger(trigger, triggerRef, open, contentId, popup, onOpen) {
293
- const props = trigger.props;
294
- return cloneElement(trigger, {
295
- ref: composeRefs(props.ref, triggerRef),
296
- "aria-controls": contentId,
297
- "aria-expanded": open,
298
- "aria-haspopup": popup,
299
- onClick: (event) => {
300
- props.onClick?.(event);
301
- if (!event.defaultPrevented && !props.disabled)
302
- onOpen();
303
- },
304
- });
305
- }
306
- export const Dialog = forwardRef(function Dialog({ trigger, title, description, children, footer, size = dialogRecipe.defaults.size, dismissible = dialogRecipe.defaults.dismissible, busy = false, closeLabel, initialFocusRef, returnFocusRef, modalPriority = 0, portalContainer, open: openProp, defaultOpen, onOpenChange, className, }, forwardedRef) {
9
+ import { AnchoredPortal, useAnchoredPopup } from "./portal.js";
10
+ import { useHjmDensityDefault, useTooltipCoordinator } from "./provider.js";
11
+ import { containsEventTarget, getModalLayer, HjmPortal, renderTrigger, useModalFocus, useOpenState, } from "./modal.js";
12
+ export const Dialog = forwardRef(function Dialog({ trigger, title, description, children, footer, size = dialogRecipe.defaults.size, dismissible = dialogRecipe.defaults.dismissible, busy = false, closeLabel, initialFocusRef, returnFocusRef, onDismissComplete, modalPriority = 0, portalContainer, open: openProp, defaultOpen, onOpenChange, className, }, forwardedRef) {
307
13
  const modalLayer = getModalLayer(modalPriority);
308
14
  const [open, changeOpen] = useOpenState({
309
15
  ...(openProp === undefined ? {} : { open: openProp }),
@@ -317,11 +23,52 @@ export const Dialog = forwardRef(function Dialog({ trigger, title, description,
317
23
  const contentId = `${id}-dialog`;
318
24
  const titleId = `${id}-title`;
319
25
  const descriptionId = `${id}-description`;
26
+ const dismissReasonRef = useRef(undefined);
27
+ const wasOpenRef = useRef(open);
28
+ const completeRef = useRef(onDismissComplete);
29
+ completeRef.current = onDismissComplete;
30
+ const openRef = useRef(open);
31
+ openRef.current = open;
320
32
  const requestClose = (reason) => {
321
33
  if (!dismissible || busy)
322
34
  return;
35
+ dismissReasonRef.current = reason;
323
36
  changeOpen(false, { reason });
324
37
  };
38
+ const settle = () => {
39
+ const reason = dismissReasonRef.current ?? "programmatic";
40
+ dismissReasonRef.current = undefined;
41
+ // After the portal is unmounted and `useModalFocus` has restored focus in
42
+ // its own microtask, so the next overlay can open without a 0ms guess.
43
+ queueMicrotask(() => queueMicrotask(() => completeRef.current?.({ reason })));
44
+ };
45
+ useEffect(() => {
46
+ if (open) {
47
+ wasOpenRef.current = true;
48
+ dismissReasonRef.current = undefined;
49
+ return;
50
+ }
51
+ if (!wasOpenRef.current)
52
+ return;
53
+ wasOpenRef.current = false;
54
+ settle();
55
+ }, [open]);
56
+ const epochRef = useRef(0);
57
+ useEffect(() => {
58
+ const epoch = epochRef.current + 1;
59
+ epochRef.current = epoch;
60
+ return () => {
61
+ queueMicrotask(() => {
62
+ // StrictMode re-runs setup right after its probe cleanup; only a real
63
+ // unmount has no later epoch. An open Dialog torn down that way still
64
+ // settles exactly once.
65
+ if (epochRef.current !== epoch || !openRef.current || !wasOpenRef.current)
66
+ return;
67
+ wasOpenRef.current = false;
68
+ settle();
69
+ });
70
+ };
71
+ }, []);
325
72
  useModalFocus({
326
73
  active: open,
327
74
  priority: modalPriority,
@@ -420,7 +167,7 @@ export const AlertDialog = forwardRef(function AlertDialog({ trigger, request, i
420
167
  changeOpen(true, { reason: "trigger" });
421
168
  }), open ? (_jsx(HjmPortal, { ...(portalContainer === undefined ? {} : { container: portalContainer }), children: _jsx("div", { className: "hjm-overlay", "data-kind": "alert-dialog", "data-modal-priority": modalPriority, "data-state": "open", style: { zIndex: modalLayer }, children: _jsxs("div", { ref: composeRefs(contentRef, forwardedRef), id: contentId, role: "alertdialog", "aria-modal": "true", "aria-labelledby": titleId, "aria-describedby": `${descriptionId}${error ? ` ${errorId}` : ""}`, "aria-busy": busy || undefined, tabIndex: -1, className: classNames("hjm-alert-dialog", className), "data-hjm-modal-content": "", "data-size": size, "data-tone": tone, "data-state": busy ? "busy" : error ? "error" : "idle", children: [icon ? _jsx("div", { className: "hjm-alert-dialog__icon", "aria-hidden": "true", children: icon }) : null, _jsx("h2", { id: titleId, className: "hjm-alert-dialog__title", children: request.title }), _jsx("p", { id: descriptionId, className: "hjm-alert-dialog__description", children: request.description }), error ? _jsx("p", { id: errorId, className: "hjm-alert-dialog__error", role: "alert", children: error }) : null, _jsxs("div", { className: "hjm-alert-dialog__actions", children: [request.mode === "confirm" ? (_jsx(Button, { ref: cancelRef, tone: "secondary", disabled: busy || closing, onClick: () => cancel("cancel-action"), children: request.cancelLabel })) : null, _jsx(Button, { ref: confirmRef, tone: tone === "danger" ? "danger" : "primary", loading: busy, disabled: closing, onClick: () => void confirm(), children: request.confirmLabel })] })] }) }) })) : null] }));
422
169
  });
423
- export const Sheet = forwardRef(function Sheet({ trigger, title, description, children, footer, placement = sheetRecipe.defaults.placement, busy = false, dismissPolicy, closeLabel, initialFocusRef, returnFocusRef, onDismissComplete, modalPriority = 0, portalContainer, open: openProp, defaultOpen, onOpenChange, className, }, forwardedRef) {
170
+ export const Sheet = forwardRef(function Sheet({ trigger, title, description, children, footer, placement = sheetRecipe.defaults.placement, detents, activeDetent, onDetentChange, detentLabels, busy = false, dismissPolicy, closeLabel, initialFocusRef, returnFocusRef, onDismissComplete, modalPriority = 0, portalContainer, open: openProp, defaultOpen, onOpenChange, className, }, forwardedRef) {
424
171
  const modalLayer = getModalLayer(modalPriority);
425
172
  const [open, changeOpen] = useOpenState({
426
173
  ...(openProp === undefined ? {} : { open: openProp }),
@@ -494,7 +241,14 @@ export const Sheet = forwardRef(function Sheet({ trigger, title, description, ch
494
241
  return (_jsxs(_Fragment, { children: [trigger === undefined ? null : renderTrigger(trigger, triggerRef, open, contentId, "dialog", () => changeOpen(true, { reason: "trigger" })), open ? (_jsx(HjmPortal, { ...(portalContainer === undefined ? {} : { container: portalContainer }), children: _jsx("div", { className: "hjm-overlay hjm-sheet-positioner", "data-kind": "sheet", "data-modal-priority": modalPriority, "data-placement": placement, "data-state": "open", style: { zIndex: modalLayer }, onMouseDown: (event) => {
495
242
  if (event.target === event.currentTarget)
496
243
  requestClose("outside");
497
- }, children: _jsxs("div", { ref: composeRefs(contentRef, forwardedRef), id: contentId, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, "aria-describedby": description ? descriptionId : undefined, "aria-busy": busy || undefined, tabIndex: -1, className: classNames("hjm-sheet", className), "data-hjm-modal-content": "", "data-placement": placement, "data-has-footer": footer ? true : undefined, "data-state": busy ? "busy" : "idle", children: [_jsxs("header", { className: "hjm-sheet__header", children: [_jsxs("div", { children: [_jsx("h2", { id: titleId, className: "hjm-sheet__title", children: title }), description ? _jsx("p", { id: descriptionId, className: "hjm-sheet__description", children: description }) : null] }), policy.dismissible ? (_jsx("button", { type: "button", className: "hjm-dialog__close", "aria-label": closeLabel, disabled: busy && !policy.dismissWhileBusy, onClick: () => requestClose("close-action"), children: "\u00D7" })) : null] }), children ? _jsx("div", { className: "hjm-sheet__body", children: children }) : null, footer ? _jsx("footer", { className: "hjm-sheet__footer", children: footer }) : null] }) }) })) : null] }));
244
+ }, children: _jsxs("div", { ref: composeRefs(contentRef, forwardedRef), id: contentId, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, "aria-describedby": description ? descriptionId : undefined, "aria-busy": busy || undefined, tabIndex: -1, className: classNames("hjm-sheet", className), "data-hjm-modal-content": "", "data-placement": placement, "data-detent": activeDetent, "data-has-footer": footer ? true : undefined, "data-state": busy ? "busy" : "idle", children: [detents && detentLabels && activeDetent ? (_jsx("div", { className: "hjm-sheet__handle-row", children: _jsx("button", { type: "button", className: "hjm-sheet__handle", "aria-label": resolveNextSheetDetent(detents, activeDetent, "expand") === null
245
+ ? detentLabels.collapse
246
+ : detentLabels.expand, onClick: () => {
247
+ const expand = resolveNextSheetDetent(detents, activeDetent, "expand");
248
+ const next = expand ?? resolveNextSheetDetent(detents, activeDetent, "collapse");
249
+ if (next !== null)
250
+ onDetentChange?.(next);
251
+ }, children: _jsx("span", { "aria-hidden": "true", className: "hjm-sheet__handle-bar" }) }) })) : null, _jsxs("header", { className: "hjm-sheet__header", children: [_jsxs("div", { children: [_jsx("h2", { id: titleId, className: "hjm-sheet__title", children: title }), description ? _jsx("p", { id: descriptionId, className: "hjm-sheet__description", children: description }) : null] }), policy.dismissible ? (_jsx("button", { type: "button", className: "hjm-dialog__close", "aria-label": closeLabel, disabled: busy && !policy.dismissWhileBusy, onClick: () => requestClose("close-action"), children: "\u00D7" })) : null] }), children ? _jsx("div", { className: "hjm-sheet__body", children: children }) : null, footer ? _jsx("footer", { className: "hjm-sheet__footer", children: footer }) : null] }) }) })) : null] }));
498
252
  });
499
253
  export const Tooltip = forwardRef(function Tooltip({ trigger, content, placement, align, pointerOpenDelayMs = tooltipBehaviorDefaults.pointerOpenDelayMs, focusOpenDelayMs = tooltipBehaviorDefaults.focusOpenDelayMs, portalContainer, open: openProp, defaultOpen, onOpenChange, className, }, ref) {
500
254
  const descriptor = resolveTooltipDescriptor({
@@ -683,7 +437,13 @@ function validateMenuItems(items, sections, asyncState) {
683
437
  }
684
438
  }
685
439
  export const Menu = forwardRef(function Menu(props, ref) {
686
- const { trigger, label, density = menuRecipe.defaults.density, align = "start", disabled = false, asyncState = { status: "idle" }, onAction, onActionAfterDismiss, portalContainer, open: openProp, defaultOpen, onOpenChange, className, } = props;
440
+ // Unconditional: `??` on the hook call would break the rules of hooks.
441
+ const densityDefault = useHjmDensityDefault({
442
+ comfortable: menuRecipe.defaults.density,
443
+ compact: "compact",
444
+ });
445
+ const { trigger, label, density: densityProp, align = "start", disabled = false, asyncState = { status: "idle" }, onAction, onActionAfterDismiss, portalContainer, open: openProp, defaultOpen, onOpenChange, className, } = props;
446
+ const density = densityProp ?? densityDefault;
687
447
  const sections = props.sections;
688
448
  const items = sections === undefined ? props.items : sections.flatMap((section) => section.items);
689
449
  if (label.trim().length === 0)