@hjmds/react 1.1.1 → 1.3.4

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 (203) 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/auth-screen.d.ts +29 -0
  25. package/dist/auth-screen.d.ts.map +1 -0
  26. package/dist/auth-screen.js +26 -0
  27. package/dist/auth-screen.js.map +1 -0
  28. package/dist/bottom-cta.d.ts +32 -0
  29. package/dist/bottom-cta.d.ts.map +1 -0
  30. package/dist/bottom-cta.js +30 -0
  31. package/dist/bottom-cta.js.map +1 -0
  32. package/dist/bottom-info.d.ts +16 -0
  33. package/dist/bottom-info.d.ts.map +1 -0
  34. package/dist/bottom-info.js +12 -0
  35. package/dist/bottom-info.js.map +1 -0
  36. package/dist/breadcrumb.d.ts +9 -0
  37. package/dist/breadcrumb.d.ts.map +1 -0
  38. package/dist/breadcrumb.js +12 -0
  39. package/dist/breadcrumb.js.map +1 -0
  40. package/dist/calendar.d.ts +30 -0
  41. package/dist/calendar.d.ts.map +1 -0
  42. package/dist/calendar.js +69 -0
  43. package/dist/calendar.js.map +1 -0
  44. package/dist/carousel.d.ts +20 -0
  45. package/dist/carousel.d.ts.map +1 -0
  46. package/dist/carousel.js +70 -0
  47. package/dist/carousel.js.map +1 -0
  48. package/dist/clipboard.d.ts +33 -0
  49. package/dist/clipboard.d.ts.map +1 -0
  50. package/dist/clipboard.js +40 -0
  51. package/dist/clipboard.js.map +1 -0
  52. package/dist/collapsible.d.ts +11 -0
  53. package/dist/collapsible.d.ts.map +1 -0
  54. package/dist/collapsible.js +18 -0
  55. package/dist/collapsible.js.map +1 -0
  56. package/dist/command-palette.d.ts +25 -0
  57. package/dist/command-palette.d.ts.map +1 -0
  58. package/dist/command-palette.js +82 -0
  59. package/dist/command-palette.js.map +1 -0
  60. package/dist/context-menu.d.ts +12 -0
  61. package/dist/context-menu.d.ts.map +1 -0
  62. package/dist/context-menu.js +111 -0
  63. package/dist/context-menu.js.map +1 -0
  64. package/dist/data-table.d.ts +30 -0
  65. package/dist/data-table.d.ts.map +1 -0
  66. package/dist/data-table.js +57 -0
  67. package/dist/data-table.js.map +1 -0
  68. package/dist/date-picker.d.ts +3 -1
  69. package/dist/date-picker.d.ts.map +1 -1
  70. package/dist/date-picker.js +16 -31
  71. package/dist/date-picker.js.map +1 -1
  72. package/dist/date-range.d.ts +24 -0
  73. package/dist/date-range.d.ts.map +1 -0
  74. package/dist/date-range.js +29 -0
  75. package/dist/date-range.js.map +1 -0
  76. package/dist/display.d.ts +16 -0
  77. package/dist/display.d.ts.map +1 -1
  78. package/dist/display.js +13 -1
  79. package/dist/display.js.map +1 -1
  80. package/dist/evidence.d.ts +496 -1
  81. package/dist/evidence.d.ts.map +1 -1
  82. package/dist/evidence.js +48 -2
  83. package/dist/evidence.js.map +1 -1
  84. package/dist/feedback.d.ts +18 -2
  85. package/dist/feedback.d.ts.map +1 -1
  86. package/dist/feedback.js +10 -2
  87. package/dist/feedback.js.map +1 -1
  88. package/dist/floating-action-button.d.ts +32 -0
  89. package/dist/floating-action-button.d.ts.map +1 -0
  90. package/dist/floating-action-button.js +58 -0
  91. package/dist/floating-action-button.js.map +1 -0
  92. package/dist/forms.d.ts +3 -3
  93. package/dist/forms.d.ts.map +1 -1
  94. package/dist/forms.js +18 -7
  95. package/dist/forms.js.map +1 -1
  96. package/dist/heading.d.ts +12 -0
  97. package/dist/heading.d.ts.map +1 -0
  98. package/dist/heading.js +25 -0
  99. package/dist/heading.js.map +1 -0
  100. package/dist/index.d.ts +36 -2
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +36 -2
  103. package/dist/index.js.map +1 -1
  104. package/dist/layout.d.ts +1 -1
  105. package/dist/mentions.d.ts +28 -0
  106. package/dist/mentions.d.ts.map +1 -0
  107. package/dist/mentions.js +84 -0
  108. package/dist/mentions.js.map +1 -0
  109. package/dist/menubar.d.ts +11 -0
  110. package/dist/menubar.d.ts.map +1 -0
  111. package/dist/menubar.js +137 -0
  112. package/dist/menubar.js.map +1 -0
  113. package/dist/modal.d.ts +67 -0
  114. package/dist/modal.d.ts.map +1 -0
  115. package/dist/modal.js +307 -0
  116. package/dist/modal.js.map +1 -0
  117. package/dist/overlay-stack.d.ts +28 -0
  118. package/dist/overlay-stack.d.ts.map +1 -0
  119. package/dist/overlay-stack.js +47 -0
  120. package/dist/overlay-stack.js.map +1 -0
  121. package/dist/overlays.d.ts +26 -43
  122. package/dist/overlays.d.ts.map +1 -1
  123. package/dist/overlays.js +62 -302
  124. package/dist/overlays.js.map +1 -1
  125. package/dist/pagination.d.ts +17 -0
  126. package/dist/pagination.d.ts.map +1 -0
  127. package/dist/pagination.js +21 -0
  128. package/dist/pagination.js.map +1 -0
  129. package/dist/popover.d.ts +25 -0
  130. package/dist/popover.d.ts.map +1 -0
  131. package/dist/popover.js +226 -0
  132. package/dist/popover.js.map +1 -0
  133. package/dist/portal.d.ts +5 -1
  134. package/dist/portal.d.ts.map +1 -1
  135. package/dist/portal.js +24 -1
  136. package/dist/portal.js.map +1 -1
  137. package/dist/provider-button.d.ts +21 -0
  138. package/dist/provider-button.d.ts.map +1 -0
  139. package/dist/provider-button.js +26 -0
  140. package/dist/provider-button.js.map +1 -0
  141. package/dist/provider.d.ts +13 -1
  142. package/dist/provider.d.ts.map +1 -1
  143. package/dist/provider.js +12 -2
  144. package/dist/provider.js.map +1 -1
  145. package/dist/selection.d.ts +5 -1
  146. package/dist/selection.d.ts.map +1 -1
  147. package/dist/selection.js +2 -2
  148. package/dist/selection.js.map +1 -1
  149. package/dist/side-panel.d.ts +34 -0
  150. package/dist/side-panel.d.ts.map +1 -0
  151. package/dist/side-panel.js +95 -0
  152. package/dist/side-panel.js.map +1 -0
  153. package/dist/sidebar.d.ts +22 -0
  154. package/dist/sidebar.d.ts.map +1 -0
  155. package/dist/sidebar.js +29 -0
  156. package/dist/sidebar.js.map +1 -0
  157. package/dist/skip-nav.d.ts +12 -0
  158. package/dist/skip-nav.d.ts.map +1 -0
  159. package/dist/skip-nav.js +29 -0
  160. package/dist/skip-nav.js.map +1 -0
  161. package/dist/splitter.d.ts +45 -0
  162. package/dist/splitter.d.ts.map +1 -0
  163. package/dist/splitter.js +116 -0
  164. package/dist/splitter.js.map +1 -0
  165. package/dist/styles.css +1105 -26
  166. package/dist/supplemental-display.d.ts +12 -0
  167. package/dist/supplemental-display.d.ts.map +1 -1
  168. package/dist/supplemental-display.js +6 -2
  169. package/dist/supplemental-display.js.map +1 -1
  170. package/dist/tags-input.d.ts +60 -0
  171. package/dist/tags-input.d.ts.map +1 -0
  172. package/dist/tags-input.js +90 -0
  173. package/dist/tags-input.js.map +1 -0
  174. package/dist/text-formats.d.ts +16 -0
  175. package/dist/text-formats.d.ts.map +1 -0
  176. package/dist/text-formats.js +24 -0
  177. package/dist/text-formats.js.map +1 -0
  178. package/dist/toast.d.ts +1 -1
  179. package/dist/toggle-group.d.ts +13 -0
  180. package/dist/toggle-group.d.ts.map +1 -0
  181. package/dist/toggle-group.js +21 -0
  182. package/dist/toggle-group.js.map +1 -0
  183. package/dist/top-bar.d.ts +27 -0
  184. package/dist/top-bar.d.ts.map +1 -0
  185. package/dist/top-bar.js +30 -0
  186. package/dist/top-bar.js.map +1 -0
  187. package/dist/top.d.ts +15 -0
  188. package/dist/top.d.ts.map +1 -0
  189. package/dist/top.js +18 -0
  190. package/dist/top.js.map +1 -0
  191. package/dist/tour.d.ts +21 -0
  192. package/dist/tour.d.ts.map +1 -0
  193. package/dist/tour.js +122 -0
  194. package/dist/tour.js.map +1 -0
  195. package/dist/transfer-list.d.ts +24 -0
  196. package/dist/transfer-list.d.ts.map +1 -0
  197. package/dist/transfer-list.js +109 -0
  198. package/dist/transfer-list.js.map +1 -0
  199. package/dist/tree.d.ts +29 -0
  200. package/dist/tree.d.ts.map +1 -0
  201. package/dist/tree.js +120 -0
  202. package/dist/tree.js.map +1 -0
  203. package/package.json +178 -3
@@ -0,0 +1,111 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { resolveContextMenuAnchor, } from "@hjmds/design-contracts/components/context-menu";
3
+ import { menuRecipe } from "@hjmds/design-contracts/recipes";
4
+ import { useCallback, useEffect, useRef, useState, } from "react";
5
+ import { classNames } from "./internal.js";
6
+ import { HjmPortal, getModalLayer } from "./modal.js";
7
+ const longPressDelay = 500;
8
+ export function ContextMenu({ children, items, accessibilityLabel, onAction, className, }) {
9
+ const hostRef = useRef(null);
10
+ const [anchor, setAnchor] = useState(null);
11
+ const [activeIndex, setActiveIndex] = useState(0);
12
+ const longPress = useRef(undefined);
13
+ const typeahead = useRef("");
14
+ const typeaheadTimer = useRef(undefined);
15
+ const enabled = items.filter((item) => !item.disabled);
16
+ const open = useCallback((reason, pointer) => {
17
+ const rect = hostRef.current?.getBoundingClientRect() ?? null;
18
+ setAnchor(resolveContextMenuAnchor(reason, pointer, rect === null ? null : { left: rect.left, bottom: rect.bottom }));
19
+ setActiveIndex(0);
20
+ }, []);
21
+ useEffect(() => {
22
+ if (anchor === null)
23
+ return;
24
+ const onKeyDown = (event) => {
25
+ if (event.key === "Escape") {
26
+ event.preventDefault();
27
+ setAnchor(null);
28
+ // Focus goes back where the menu was opened from, not to the body.
29
+ hostRef.current?.focus();
30
+ return;
31
+ }
32
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
33
+ event.preventDefault();
34
+ setActiveIndex((previous) => {
35
+ const next = event.key === "ArrowDown" ? previous + 1 : previous - 1;
36
+ return (next + enabled.length) % Math.max(enabled.length, 1);
37
+ });
38
+ return;
39
+ }
40
+ if (event.key === "Home" || event.key === "End") {
41
+ event.preventDefault();
42
+ setActiveIndex(event.key === "Home" ? 0 : Math.max(enabled.length - 1, 0));
43
+ return;
44
+ }
45
+ if (event.key.length === 1 && event.key !== " ") {
46
+ // Typeahead matches `textValue`, not the rendered label: a label may hold
47
+ // markup or a formatted number that nobody would type.
48
+ const query = (typeahead.current += event.key.toLowerCase());
49
+ clearTimeout(typeaheadTimer.current);
50
+ typeaheadTimer.current = setTimeout(() => { typeahead.current = ""; }, 700);
51
+ const match = enabled.findIndex((item) => item.textValue.toLowerCase().startsWith(query));
52
+ if (match >= 0)
53
+ setActiveIndex(match);
54
+ return;
55
+ }
56
+ if (event.key === "Enter" || event.key === " ") {
57
+ event.preventDefault();
58
+ const item = enabled[activeIndex];
59
+ if (item) {
60
+ onAction(item.id);
61
+ setAnchor(null);
62
+ hostRef.current?.focus();
63
+ }
64
+ }
65
+ };
66
+ const onPointerDown = (event) => {
67
+ if (!(event.target instanceof Node) || !document.querySelector(".hjm-context-menu")?.contains(event.target)) {
68
+ setAnchor(null);
69
+ }
70
+ };
71
+ document.addEventListener("keydown", onKeyDown);
72
+ document.addEventListener("pointerdown", onPointerDown);
73
+ return () => {
74
+ document.removeEventListener("keydown", onKeyDown);
75
+ document.removeEventListener("pointerdown", onPointerDown);
76
+ };
77
+ }, [anchor, activeIndex, enabled, onAction]);
78
+ return (_jsxs("div", { ref: hostRef, tabIndex: 0, className: classNames("hjm-context-menu-host", className), onContextMenu: (event) => {
79
+ event.preventDefault();
80
+ open("pointer", { x: event.clientX, y: event.clientY });
81
+ }, onKeyDown: (event) => {
82
+ // Shift+F10 and the Menu key are how a keyboard opens a context menu;
83
+ // without them the feature does not exist without a pointer.
84
+ if ((event.shiftKey && event.key === "F10") || event.key === "ContextMenu") {
85
+ event.preventDefault();
86
+ open("keyboard", null);
87
+ }
88
+ }, onPointerDown: (event) => {
89
+ if (event.pointerType !== "touch")
90
+ return;
91
+ longPress.current = setTimeout(() => open("longPress", { x: event.clientX, y: event.clientY }), longPressDelay);
92
+ }, onPointerUp: () => { if (longPress.current !== undefined)
93
+ clearTimeout(longPress.current); }, onPointerCancel: () => { if (longPress.current !== undefined)
94
+ clearTimeout(longPress.current); }, children: [children, anchor !== null ? (_jsx(HjmPortal, { children: _jsx("div", { role: "menu", "aria-label": accessibilityLabel, className: "hjm-context-menu", style: {
95
+ insetBlockStart: anchor.y,
96
+ insetInlineStart: anchor.x,
97
+ zIndex: getModalLayer(0),
98
+ minInlineSize: menuRecipe.minWidth,
99
+ }, children: items.map((item) => {
100
+ const index = enabled.findIndex((candidate) => candidate.id === item.id);
101
+ return (_jsxs("div", { role: "menuitem", "aria-disabled": item.disabled || undefined, "data-active": index === activeIndex && !item.disabled ? "" : undefined, "data-tone": item.tone, className: "hjm-context-menu__item", onMouseEnter: () => { if (index >= 0)
102
+ setActiveIndex(index); }, onClick: () => {
103
+ if (item.disabled)
104
+ return;
105
+ onAction(item.id);
106
+ setAnchor(null);
107
+ hostRef.current?.focus();
108
+ }, children: [_jsx("span", { children: item.label }), item.shortcut ? _jsx("kbd", { className: "hjm-context-menu__shortcut", children: item.shortcut }) : null] }, item.id));
109
+ }) }) })) : null] }));
110
+ }
111
+ //# sourceMappingURL=context-menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-menu.js","sourceRoot":"","sources":["../src/context-menu.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,wBAAwB,GAIzB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EACL,WAAW,EACX,SAAS,EACT,MAAM,EACN,QAAQ,GAGT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAWtD,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,MAAM,UAAU,WAAW,CAA8B,EACvD,QAAQ,EACR,KAAK,EACL,kBAAkB,EAClB,QAAQ,EACR,SAAS,GACa;IACtB,MAAM,OAAO,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA2B,IAAI,CAAC,CAAC;IACrE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,MAAM,CAA4C,SAAS,CAAC,CAAC;IAC/E,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,cAAc,GAAG,MAAM,CAA4C,SAAS,CAAC,CAAC;IACpF,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEvD,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,MAA6B,EAAE,OAAiC,EAAE,EAAE;QAC5F,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,qBAAqB,EAAE,IAAI,IAAI,CAAC;QAC9D,SAAS,CAAC,wBAAwB,CAChC,MAAM,EACN,OAAO,EACP,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAChE,CAAC,CAAC;QACH,cAAc,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO;QAC5B,MAAM,SAAS,GAAG,CAAC,KAAoB,EAAE,EAAE;YACzC,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBAC3B,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,SAAS,CAAC,IAAI,CAAC,CAAC;gBAChB,mEAAmE;gBACnE,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;gBACzB,OAAO;YACT,CAAC;YACD,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;gBACzD,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,cAAc,CAAC,CAAC,QAAQ,EAAE,EAAE;oBAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;oBACrE,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBAC/D,CAAC,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC;gBAChD,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,cAAc,CAAC,KAAK,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC3E,OAAO;YACT,CAAC;YACD,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBAChD,0EAA0E;gBAC1E,uDAAuD;gBACvD,MAAM,KAAK,GAAG,CAAC,SAAS,CAAC,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;gBAC7D,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBACrC,cAAc,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC1F,IAAI,KAAK,IAAI,CAAC;oBAAE,cAAc,CAAC,KAAK,CAAC,CAAC;gBACtC,OAAO;YACT,CAAC;YACD,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBAC/C,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;gBAClC,IAAI,IAAI,EAAE,CAAC;oBAAC,QAAQ,CAAC,IAAI,CAAC,EAAS,CAAC,CAAC;oBAAC,SAAS,CAAC,IAAI,CAAC,CAAC;oBAAC,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;gBAAC,CAAC;YACpF,CAAC;QACH,CAAC,CAAC;QACF,MAAM,aAAa,GAAG,CAAC,KAAmB,EAAE,EAAE;YAC5C,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,YAAY,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,mBAAmB,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5G,SAAS,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC;QACF,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAChD,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QACxD,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACnD,QAAQ,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QAC7D,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE7C,OAAO,CACL,eACE,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,CAAC,EACX,SAAS,EAAE,UAAU,CAAC,uBAAuB,EAAE,SAAS,CAAC,EACzD,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;YACvB,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1D,CAAC,EACD,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,sEAAsE;YACtE,6DAA6D;YAC7D,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,aAAa,EAAE,CAAC;gBAC3E,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YACzB,CAAC;QACH,CAAC,EACD,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;YACvB,IAAI,KAAK,CAAC,WAAW,KAAK,OAAO;gBAAE,OAAO;YAC1C,SAAS,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC;QAClH,CAAC,EACD,WAAW,EAAE,GAAG,EAAE,GAAG,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS;YAAE,YAAY,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAC5F,eAAe,EAAE,GAAG,EAAE,GAAG,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS;YAAE,YAAY,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAE/F,QAAQ,EACR,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CACjB,KAAC,SAAS,cACR,cACE,IAAI,EAAC,MAAM,gBACC,kBAAkB,EAC9B,SAAS,EAAC,kBAAkB,EAC5B,KAAK,EAAE;wBACL,eAAe,EAAE,MAAM,CAAC,CAAC;wBACzB,gBAAgB,EAAE,MAAM,CAAC,CAAC;wBAC1B,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;wBACxB,aAAa,EAAE,UAAU,CAAC,QAAQ;qBAClB,YAEjB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;wBAClB,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;wBACzE,OAAO,CACL,eAEE,IAAI,EAAC,UAAU,mBACA,IAAI,CAAC,QAAQ,IAAI,SAAS,iBAC5B,KAAK,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,eAC1D,IAAI,CAAC,IAAI,EACpB,SAAS,EAAC,wBAAwB,EAClC,YAAY,EAAE,GAAG,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;gCAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAC9D,OAAO,EAAE,GAAG,EAAE;gCACZ,IAAI,IAAI,CAAC,QAAQ;oCAAE,OAAO;gCAC1B,QAAQ,CAAC,IAAI,CAAC,EAAS,CAAC,CAAC;gCACzB,SAAS,CAAC,IAAI,CAAC,CAAC;gCAChB,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;4BAC3B,CAAC,aAED,yBAAO,IAAI,CAAC,KAAK,GAAQ,EACxB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,4BAA4B,YAAE,IAAI,CAAC,QAAQ,GAAO,CAAC,CAAC,CAAC,IAAI,KAfpF,IAAI,CAAC,EAAE,CAgBR,CACP,CAAC;oBACJ,CAAC,CAAC,GACE,GACI,CACb,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC","sourcesContent":["import {\n resolveContextMenuAnchor,\n type ContextMenuAnchor,\n type ContextMenuItemDescriptor,\n type ContextMenuOpenReason,\n} from \"@hjmds/design-contracts/components/context-menu\";\nimport { menuRecipe } from \"@hjmds/design-contracts/recipes\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { classNames } from \"./internal.js\";\nimport { HjmPortal, getModalLayer } from \"./modal.js\";\n\nexport type ContextMenuProps<Key extends string = string> = Readonly<{\n /** The region the menu belongs to; right-click and long-press are bound here. */\n children: ReactNode;\n items: readonly ContextMenuItemDescriptor<Key>[];\n accessibilityLabel: string;\n onAction: (id: Key) => void;\n className?: string;\n}>;\n\nconst longPressDelay = 500;\n\nexport function ContextMenu<Key extends string = string>({\n children,\n items,\n accessibilityLabel,\n onAction,\n className,\n}: ContextMenuProps<Key>) {\n const hostRef = useRef<HTMLDivElement>(null);\n const [anchor, setAnchor] = useState<ContextMenuAnchor | null>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n const longPress = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const typeahead = useRef(\"\");\n const typeaheadTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const enabled = items.filter((item) => !item.disabled);\n\n const open = useCallback((reason: ContextMenuOpenReason, pointer: ContextMenuAnchor | null) => {\n const rect = hostRef.current?.getBoundingClientRect() ?? null;\n setAnchor(resolveContextMenuAnchor(\n reason,\n pointer,\n rect === null ? null : { left: rect.left, bottom: rect.bottom },\n ));\n setActiveIndex(0);\n }, []);\n\n useEffect(() => {\n if (anchor === null) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n setAnchor(null);\n // Focus goes back where the menu was opened from, not to the body.\n hostRef.current?.focus();\n return;\n }\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((previous) => {\n const next = event.key === \"ArrowDown\" ? previous + 1 : previous - 1;\n return (next + enabled.length) % Math.max(enabled.length, 1);\n });\n return;\n }\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n setActiveIndex(event.key === \"Home\" ? 0 : Math.max(enabled.length - 1, 0));\n return;\n }\n if (event.key.length === 1 && event.key !== \" \") {\n // Typeahead matches `textValue`, not the rendered label: a label may hold\n // markup or a formatted number that nobody would type.\n const query = (typeahead.current += event.key.toLowerCase());\n clearTimeout(typeaheadTimer.current);\n typeaheadTimer.current = setTimeout(() => { typeahead.current = \"\"; }, 700);\n const match = enabled.findIndex((item) => item.textValue.toLowerCase().startsWith(query));\n if (match >= 0) setActiveIndex(match);\n return;\n }\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n const item = enabled[activeIndex];\n if (item) { onAction(item.id as Key); setAnchor(null); hostRef.current?.focus(); }\n }\n };\n const onPointerDown = (event: PointerEvent) => {\n if (!(event.target instanceof Node) || !document.querySelector(\".hjm-context-menu\")?.contains(event.target)) {\n setAnchor(null);\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n document.addEventListener(\"pointerdown\", onPointerDown);\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.removeEventListener(\"pointerdown\", onPointerDown);\n };\n }, [anchor, activeIndex, enabled, onAction]);\n\n return (\n <div\n ref={hostRef}\n tabIndex={0}\n className={classNames(\"hjm-context-menu-host\", className)}\n onContextMenu={(event) => {\n event.preventDefault();\n open(\"pointer\", { x: event.clientX, y: event.clientY });\n }}\n onKeyDown={(event) => {\n // Shift+F10 and the Menu key are how a keyboard opens a context menu;\n // without them the feature does not exist without a pointer.\n if ((event.shiftKey && event.key === \"F10\") || event.key === \"ContextMenu\") {\n event.preventDefault();\n open(\"keyboard\", null);\n }\n }}\n onPointerDown={(event) => {\n if (event.pointerType !== \"touch\") return;\n longPress.current = setTimeout(() => open(\"longPress\", { x: event.clientX, y: event.clientY }), longPressDelay);\n }}\n onPointerUp={() => { if (longPress.current !== undefined) clearTimeout(longPress.current); }}\n onPointerCancel={() => { if (longPress.current !== undefined) clearTimeout(longPress.current); }}\n >\n {children}\n {anchor !== null ? (\n <HjmPortal>\n <div\n role=\"menu\"\n aria-label={accessibilityLabel}\n className=\"hjm-context-menu\"\n style={{\n insetBlockStart: anchor.y,\n insetInlineStart: anchor.x,\n zIndex: getModalLayer(0),\n minInlineSize: menuRecipe.minWidth,\n } as CSSProperties}\n >\n {items.map((item) => {\n const index = enabled.findIndex((candidate) => candidate.id === item.id);\n return (\n <div\n key={item.id}\n role=\"menuitem\"\n aria-disabled={item.disabled || undefined}\n data-active={index === activeIndex && !item.disabled ? \"\" : undefined}\n data-tone={item.tone}\n className=\"hjm-context-menu__item\"\n onMouseEnter={() => { if (index >= 0) setActiveIndex(index); }}\n onClick={() => {\n if (item.disabled) return;\n onAction(item.id as Key);\n setAnchor(null);\n hostRef.current?.focus();\n }}\n >\n <span>{item.label}</span>\n {item.shortcut ? <kbd className=\"hjm-context-menu__shortcut\">{item.shortcut}</kbd> : null}\n </div>\n );\n })}\n </div>\n </HjmPortal>\n ) : null}\n </div>\n );\n}\n"]}
@@ -0,0 +1,30 @@
1
+ import { type DataTableAsyncState, type DataTableColumnDescriptor, type DataTableDensity, type DataTableRowDescriptor, type DataTableSelection, type DataTableSortCycle, type DataTableSortState } from "@hjmds/design-contracts/components/data-table";
2
+ import { type ReactNode } from "react";
3
+ export type DataTableLabels = Readonly<{
4
+ /** Accessible name for the table itself. */
5
+ table: string;
6
+ selectAll: string;
7
+ /** Composes one row's selection control name from its id. */
8
+ selectRow: (rowId: string) => string;
9
+ /** Composes a sortable header's action name, including its current direction. */
10
+ sortColumn: (header: string, direction: DataTableSortState<string>) => string;
11
+ }>;
12
+ export type DataTableProps<ColumnKey extends string = string, RowKey extends string = string> = Readonly<{
13
+ columns: readonly DataTableColumnDescriptor<ColumnKey>[];
14
+ rows: readonly DataTableRowDescriptor<RowKey>[];
15
+ labels: DataTableLabels;
16
+ renderCell: (rowId: RowKey, columnId: ColumnKey) => ReactNode;
17
+ selection?: DataTableSelection<RowKey>;
18
+ sortState?: DataTableSortState<ColumnKey>;
19
+ sortCycle?: DataTableSortCycle;
20
+ onSortChange?: (next: DataTableSortState<ColumnKey>) => void;
21
+ asyncState?: DataTableAsyncState;
22
+ density?: DataTableDensity;
23
+ /** Composed beneath the table by the product — pagination, load more, totals. */
24
+ footer?: ReactNode;
25
+ className?: string;
26
+ }>;
27
+ export declare const DataTable: <ColumnKey extends string = string, RowKey extends string = string>(props: DataTableProps<ColumnKey, RowKey> & {
28
+ ref?: React.Ref<HTMLTableElement>;
29
+ }) => React.ReactElement | null;
30
+ //# sourceMappingURL=data-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../src/data-table.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAkC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvE,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,iFAAiF;IACjF,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC;CAC/E,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,EAAE,MAAM,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IACvG,OAAO,EAAE,SAAS,yBAAyB,CAAC,SAAS,CAAC,EAAE,CAAC;IACzD,IAAI,EAAE,SAAS,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;IAChD,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,KAAK,SAAS,CAAC;IAC9D,SAAS,CAAC,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACvC,SAAS,CAAC,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC1C,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;IAC7D,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,iFAAiF;IACjF,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,eAAO,MAAM,SAAS,EA+IhB,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,EAAE,MAAM,SAAS,MAAM,GAAG,MAAM,EACtE,KAAK,EAAE,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;CAAE,KAC7E,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { dataTableColumnDefaults, dataTableDefaults, getNextDataTableSortState, resolveDataTableSelectAllState, validateDataTableColumns, validateDataTableRows, validateDataTableSortState, } from "@hjmds/design-contracts/components/data-table";
3
+ import { forwardRef } from "react";
4
+ import { useHjmDensityDefault } from "./provider.js";
5
+ import { classNames } from "./internal.js";
6
+ export const DataTable = forwardRef(function DataTable({ columns, rows, labels, renderCell, selection, sortState = null, sortCycle = dataTableDefaults.sortCycle, onSortChange, asyncState = { status: "idle" }, density: densityProp, footer, className, }, forwardedRef) {
7
+ // Unconditional: `??` on the hook call would break the rules of hooks.
8
+ const densityDefault = useHjmDensityDefault({ comfortable: "regular", compact: "compact" });
9
+ const density = densityProp ?? densityDefault;
10
+ validateDataTableColumns(columns);
11
+ validateDataTableRows(rows);
12
+ validateDataTableSortState(sortState, columns);
13
+ const multiple = selection?.mode === "multiple";
14
+ const single = selection?.mode === "single";
15
+ const selectedKeys = multiple
16
+ ? selection.selectedKeys ?? selection.defaultSelectedKeys ?? new Set()
17
+ : single
18
+ ? new Set(((selection.selectedKey ?? selection.defaultSelectedKey) ?? null) === null
19
+ ? []
20
+ : [(selection.selectedKey ?? selection.defaultSelectedKey)])
21
+ : new Set();
22
+ const selectAllState = multiple ? resolveDataTableSelectAllState(rows, selectedKeys) : false;
23
+ const toggleRow = (row) => {
24
+ if (row.disabled || !selection || selection.mode === "none")
25
+ return;
26
+ if (selection.mode === "single") {
27
+ const current = selection.selectedKey ?? selection.defaultSelectedKey ?? null;
28
+ const next = current === row.id && selection.disallowEmptySelection !== true ? null : row.id;
29
+ selection.onSelectionChange?.(next);
30
+ return;
31
+ }
32
+ const next = new Set(selectedKeys);
33
+ if (next.has(row.id))
34
+ next.delete(row.id);
35
+ else
36
+ next.add(row.id);
37
+ selection.onSelectionChange?.(next);
38
+ };
39
+ const toggleAll = () => {
40
+ if (!multiple)
41
+ return;
42
+ // Disabled rows stay out of both the denominator and the result, matching
43
+ // the shared select-all accounting.
44
+ const selectable = rows.filter((row) => !row.disabled);
45
+ const next = selectAllState === true
46
+ ? new Set([...selectedKeys].filter((id) => !selectable.some((row) => row.id === id)))
47
+ : new Set([...selectedKeys, ...selectable.map((row) => row.id)]);
48
+ selection.onSelectionChange?.(next);
49
+ };
50
+ return (_jsxs("div", { className: classNames("hjm-data-table", className), "data-density": density, children: [asyncState.status === "idle" ? null : (_jsx("p", { className: "hjm-data-table__state", role: asyncState.status === "error" ? "alert" : "status", children: asyncState.message })), _jsxs("table", { ref: forwardedRef, className: "hjm-data-table__table", "aria-label": labels.table, "aria-busy": asyncState.status === "loading" || undefined, children: [_jsx("thead", { children: _jsxs("tr", { children: [selection && selection.mode !== "none" ? (_jsx("th", { scope: "col", className: "hjm-data-table__selector", children: multiple ? (_jsx("button", { type: "button", role: "checkbox", "aria-checked": selectAllState === "mixed" ? "mixed" : String(selectAllState === true), "aria-label": labels.selectAll, className: "hjm-data-table__check", onClick: toggleAll, children: selectAllState === true ? "✓" : selectAllState === "mixed" ? "–" : "" })) : null })) : null, columns.map((column) => {
51
+ const sorted = sortState?.columnId === column.id ? sortState.direction : null;
52
+ return (_jsx("th", { scope: "col", "aria-sort": sorted ?? undefined, style: { inlineSize: column.width, textAlign: column.align ?? dataTableColumnDefaults.align }, children: column.sortable ? (
53
+ // A button inside the header, never the header itself.
54
+ _jsxs("button", { type: "button", className: "hjm-data-table__sort", "aria-label": labels.sortColumn(column.header, sortState), onClick: () => onSortChange?.(getNextDataTableSortState(sortState, column.id, sortCycle)), children: [_jsx("span", { children: column.header }), _jsx("span", { "aria-hidden": "true", children: sorted === "ascending" ? "▲" : sorted === "descending" ? "▼" : "↕" })] })) : column.header }, column.id));
55
+ })] }) }), _jsx("tbody", { children: rows.map((row) => (_jsxs("tr", { "aria-selected": selection && selection.mode !== "none" ? selectedKeys.has(row.id) : undefined, "data-disabled": row.disabled || undefined, children: [selection && selection.mode !== "none" ? (_jsx("td", { className: "hjm-data-table__selector", children: _jsx("button", { type: "button", role: multiple ? "checkbox" : "radio", "aria-checked": selectedKeys.has(row.id), "aria-label": labels.selectRow(row.id), "aria-disabled": row.disabled || undefined, className: "hjm-data-table__check", onClick: () => toggleRow(row), children: selectedKeys.has(row.id) ? "✓" : "" }) })) : null, columns.map((column) => (_jsx("td", { style: { textAlign: column.align ?? dataTableColumnDefaults.align }, children: renderCell(row.id, column.id) }, column.id)))] }, row.id))) })] }), footer ? _jsx("div", { className: "hjm-data-table__footer", children: footer }) : null] }));
56
+ });
57
+ //# sourceMappingURL=data-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-table.js","sourceRoot":"","sources":["../src/data-table.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n dataTableColumnDefaults,\n dataTableDefaults,\n getNextDataTableSortState,\n resolveDataTableSelectAllState,\n validateDataTableColumns,\n validateDataTableRows,\n validateDataTableSortState,\n type DataTableAsyncState,\n type DataTableColumnDescriptor,\n type DataTableDensity,\n type DataTableRowDescriptor,\n type DataTableSelection,\n type DataTableSortCycle,\n type DataTableSortState,\n} from \"@hjmds/design-contracts/components/data-table\";\nimport { forwardRef, type CSSProperties, type ReactNode } from \"react\";\nimport { useHjmDensityDefault } from \"./provider.js\";\nimport { classNames } from \"./internal.js\";\n\nexport type DataTableLabels = Readonly<{\n /** Accessible name for the table itself. */\n table: string;\n selectAll: string;\n /** Composes one row's selection control name from its id. */\n selectRow: (rowId: string) => string;\n /** Composes a sortable header's action name, including its current direction. */\n sortColumn: (header: string, direction: DataTableSortState<string>) => string;\n}>;\n\nexport type DataTableProps<ColumnKey extends string = string, RowKey extends string = string> = Readonly<{\n columns: readonly DataTableColumnDescriptor<ColumnKey>[];\n rows: readonly DataTableRowDescriptor<RowKey>[];\n labels: DataTableLabels;\n renderCell: (rowId: RowKey, columnId: ColumnKey) => ReactNode;\n selection?: DataTableSelection<RowKey>;\n sortState?: DataTableSortState<ColumnKey>;\n sortCycle?: DataTableSortCycle;\n onSortChange?: (next: DataTableSortState<ColumnKey>) => void;\n asyncState?: DataTableAsyncState;\n density?: DataTableDensity;\n /** Composed beneath the table by the product — pagination, load more, totals. */\n footer?: ReactNode;\n className?: string;\n}>;\n\nexport const DataTable = forwardRef(function DataTable<\n ColumnKey extends string = string,\n RowKey extends string = string,\n>(\n {\n columns,\n rows,\n labels,\n renderCell,\n selection,\n sortState = null,\n sortCycle = dataTableDefaults.sortCycle,\n onSortChange,\n asyncState = { status: \"idle\" },\n density: densityProp,\n footer,\n className,\n }: DataTableProps<ColumnKey, RowKey>,\n forwardedRef: React.Ref<HTMLTableElement>,\n) {\n // Unconditional: `??` on the hook call would break the rules of hooks.\n const densityDefault = useHjmDensityDefault({ comfortable: \"regular\", compact: \"compact\" });\n const density = densityProp ?? densityDefault;\n validateDataTableColumns(columns);\n validateDataTableRows(rows);\n validateDataTableSortState(sortState, columns);\n const multiple = selection?.mode === \"multiple\";\n const single = selection?.mode === \"single\";\n const selectedKeys: ReadonlySet<RowKey> = multiple\n ? selection.selectedKeys ?? selection.defaultSelectedKeys ?? new Set<RowKey>()\n : single\n ? new Set<RowKey>(((selection.selectedKey ?? selection.defaultSelectedKey) ?? null) === null\n ? []\n : [(selection.selectedKey ?? selection.defaultSelectedKey)!])\n : new Set<RowKey>();\n const selectAllState = multiple ? resolveDataTableSelectAllState(rows, selectedKeys) : false;\n\n const toggleRow = (row: DataTableRowDescriptor<RowKey>) => {\n if (row.disabled || !selection || selection.mode === \"none\") return;\n if (selection.mode === \"single\") {\n const current = selection.selectedKey ?? selection.defaultSelectedKey ?? null;\n const next = current === row.id && selection.disallowEmptySelection !== true ? null : row.id;\n selection.onSelectionChange?.(next);\n return;\n }\n const next = new Set(selectedKeys);\n if (next.has(row.id)) next.delete(row.id); else next.add(row.id);\n selection.onSelectionChange?.(next);\n };\n const toggleAll = () => {\n if (!multiple) return;\n // Disabled rows stay out of both the denominator and the result, matching\n // the shared select-all accounting.\n const selectable = rows.filter((row) => !row.disabled);\n const next = selectAllState === true\n ? new Set([...selectedKeys].filter((id) => !selectable.some((row) => row.id === id)))\n : new Set([...selectedKeys, ...selectable.map((row) => row.id)]);\n selection.onSelectionChange?.(next);\n };\n\n return (\n <div className={classNames(\"hjm-data-table\", className)} data-density={density}>\n {asyncState.status === \"idle\" ? null : (\n <p className=\"hjm-data-table__state\" role={asyncState.status === \"error\" ? \"alert\" : \"status\"}>{asyncState.message}</p>\n )}\n <table ref={forwardedRef} className=\"hjm-data-table__table\" aria-label={labels.table} aria-busy={asyncState.status === \"loading\" || undefined}>\n <thead>\n <tr>\n {selection && selection.mode !== \"none\" ? (\n <th scope=\"col\" className=\"hjm-data-table__selector\">\n {multiple ? (\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={selectAllState === \"mixed\" ? \"mixed\" : String(selectAllState === true) as \"true\" | \"false\"}\n aria-label={labels.selectAll}\n className=\"hjm-data-table__check\"\n onClick={toggleAll}\n >\n {selectAllState === true ? \"✓\" : selectAllState === \"mixed\" ? \"–\" : \"\"}\n </button>\n ) : null}\n </th>\n ) : null}\n {columns.map((column) => {\n const sorted = sortState?.columnId === column.id ? sortState.direction : null;\n return (\n <th\n key={column.id}\n scope=\"col\"\n // The direction passes straight through to aria-sort; the\n // contract already speaks that vocabulary.\n aria-sort={sorted ?? undefined}\n style={{ inlineSize: column.width, textAlign: column.align ?? dataTableColumnDefaults.align } as CSSProperties}\n >\n {column.sortable ? (\n // A button inside the header, never the header itself.\n <button\n type=\"button\"\n className=\"hjm-data-table__sort\"\n aria-label={labels.sortColumn(column.header, sortState as DataTableSortState<string>)}\n onClick={() => onSortChange?.(getNextDataTableSortState(sortState, column.id, sortCycle))}\n >\n <span>{column.header}</span>\n <span aria-hidden=\"true\">{sorted === \"ascending\" ? \"▲\" : sorted === \"descending\" ? \"▼\" : \"↕\"}</span>\n </button>\n ) : column.header}\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => (\n <tr key={row.id} aria-selected={selection && selection.mode !== \"none\" ? selectedKeys.has(row.id) : undefined} data-disabled={row.disabled || undefined}>\n {selection && selection.mode !== \"none\" ? (\n <td className=\"hjm-data-table__selector\">\n <button\n type=\"button\"\n role={multiple ? \"checkbox\" : \"radio\"}\n aria-checked={selectedKeys.has(row.id)}\n aria-label={labels.selectRow(row.id)}\n aria-disabled={row.disabled || undefined}\n className=\"hjm-data-table__check\"\n onClick={() => toggleRow(row)}\n >\n {selectedKeys.has(row.id) ? \"✓\" : \"\"}\n </button>\n </td>\n ) : null}\n {columns.map((column) => (\n <td key={column.id} style={{ textAlign: column.align ?? dataTableColumnDefaults.align } as CSSProperties}>\n {renderCell(row.id, column.id)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n {/* Pagination or load-more is composed beneath the table, never owned by it. */}\n {footer ? <div className=\"hjm-data-table__footer\">{footer}</div> : null}\n </div>\n );\n}) as <ColumnKey extends string = string, RowKey extends string = string>(\n props: DataTableProps<ColumnKey, RowKey> & { ref?: React.Ref<HTMLTableElement> },\n) => React.ReactElement | null;\n"]}
@@ -1,6 +1,7 @@
1
1
  import { type ComposeCalendarAccessibleName, type ResolvedCalendarDateCell } from "@hjmds/design-contracts/components/calendar";
2
2
  import { type DatePickerDescriptor, type DatePickerSize } from "@hjmds/design-contracts/components/date-picker";
3
3
  import { type ReactNode } from "react";
4
+ import { type CalendarOverflow, type CalendarHandle } from "./calendar.js";
4
5
  export type DatePickerMonthAction = Readonly<{
5
6
  month: string;
6
7
  label: string;
@@ -16,9 +17,10 @@ export type DatePickerProps<Content = unknown> = Readonly<{
16
17
  size?: DatePickerSize;
17
18
  description?: ReactNode;
18
19
  error?: ReactNode;
20
+ onNavigateBeyondGrid?: (detail: CalendarOverflow, focusDate: CalendarHandle["focusDate"]) => void;
19
21
  renderCellContent?: (cell: ResolvedCalendarDateCell<Content>) => ReactNode;
20
22
  className?: string;
21
23
  }>;
22
24
  /** Single-date field with an anchored, focus-bearing calendar dialog. */
23
- export declare function DatePicker<Content>({ descriptor, monthLabel, composeAccessibleName, previousMonth, nextMonth, clearLabel, closeLabel, size, description, error, renderCellContent, className, }: DatePickerProps<Content>): import("react").JSX.Element;
25
+ export declare function DatePicker<Content>({ descriptor, monthLabel, composeAccessibleName, previousMonth, nextMonth, clearLabel, closeLabel, size, description, error, renderCellContent, onNavigateBeyondGrid, className, }: DatePickerProps<Content>): import("react").JSX.Element;
24
26
  //# sourceMappingURL=date-picker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"date-picker.d.ts","sourceRoot":"","sources":["../src/date-picker.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC9B,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAIL,KAAK,oBAAoB,EAEzB,KAAK,cAAc,EACpB,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE/E,MAAM,MAAM,eAAe,CAAC,OAAO,GAAG,OAAO,IAAI,QAAQ,CAAC;IACxD,UAAU,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB,EAAE,6BAA6B,CAAC,OAAO,CAAC,CAAC;IAC9D,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,wBAAwB,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,OAAO,EAAE,EAClC,UAAU,EACV,UAAU,EACV,qBAAqB,EACrB,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,IAAe,EACf,WAAW,EACX,KAAK,EACL,iBAAiB,EACjB,SAAS,GACV,EAAE,eAAe,CAAC,OAAO,CAAC,+BAiJ1B"}
1
+ {"version":3,"file":"date-picker.d.ts","sourceRoot":"","sources":["../src/date-picker.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC9B,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAGL,KAAK,oBAAoB,EAEzB,KAAK,cAAc,EACpB,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAY,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAGrF,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE/E,MAAM,MAAM,eAAe,CAAC,OAAO,GAAG,OAAO,IAAI,QAAQ,CAAC;IACxD,UAAU,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB,EAAE,6BAA6B,CAAC,OAAO,CAAC,CAAC;IAC9D,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,cAAc,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAClG,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,wBAAwB,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,OAAO,EAAE,EAClC,UAAU,EACV,UAAU,EACV,qBAAqB,EACrB,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,IAAe,EACf,WAAW,EACX,KAAK,EACL,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,GACV,EAAE,eAAe,CAAC,OAAO,CAAC,+BAyF1B"}
@@ -1,13 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { getCalendarNavigationIntent, getCalendarNavigationTarget, } from "@hjmds/design-contracts/components/calendar";
3
- import { resolveDatePickerGrid, resolveDatePickerTriggerText, validateDatePickerDescriptor, } from "@hjmds/design-contracts/components/date-picker";
2
+ import {} from "@hjmds/design-contracts/components/calendar";
3
+ import { resolveDatePickerTriggerText, validateDatePickerDescriptor, } from "@hjmds/design-contracts/components/date-picker";
4
4
  import { useEffect, useId, useRef, useState, } from "react";
5
+ import { Calendar } from "./calendar.js";
5
6
  import { classNames } from "./internal.js";
6
- import { useOptionalHjmTheme } from "./provider.js";
7
7
  /** Single-date field with an anchored, focus-bearing calendar dialog. */
8
- export function DatePicker({ descriptor, monthLabel, composeAccessibleName, previousMonth, nextMonth, clearLabel, closeLabel, size = "medium", description, error, renderCellContent, className, }) {
8
+ export function DatePicker({ descriptor, monthLabel, composeAccessibleName, previousMonth, nextMonth, clearLabel, closeLabel, size = "medium", description, error, renderCellContent, onNavigateBeyondGrid, className, }) {
9
9
  validateDatePickerDescriptor(descriptor);
10
- const theme = useOptionalHjmTheme();
11
10
  const generatedId = useId().replaceAll(":", "");
12
11
  const dialogId = `hjm-date-picker-${generatedId}`;
13
12
  const triggerRef = useRef(null);
@@ -18,16 +17,15 @@ export function DatePicker({ descriptor, monthLabel, composeAccessibleName, prev
18
17
  const controlledSelection = descriptor.selectedDate !== undefined;
19
18
  const [internalSelection, setInternalSelection] = useState(descriptor.defaultSelectedDate ?? null);
20
19
  const selectedDate = controlledSelection ? descriptor.selectedDate ?? null : internalSelection;
21
- const gridDescriptor = { ...descriptor, selectedDate };
22
- const cells = resolveDatePickerGrid(gridDescriptor, { composeAccessibleName });
23
- const firstDate = cells.find((cell) => !("filler" in cell));
24
- const [focusedDate, setFocusedDate] = useState(selectedDate ?? firstDate?.date ?? "");
25
20
  const requestOpen = (next, reason) => {
26
21
  if (!controlledOpen)
27
22
  setInternalOpen(next);
28
23
  descriptor.onOpenChange?.(next, reason);
29
24
  };
30
25
  const commit = (date, reason) => {
26
+ // A controlled open field can become read-only while its grid remains mounted.
27
+ if (descriptor.disabled || descriptor.readOnly)
28
+ return;
31
29
  if (!controlledSelection)
32
30
  setInternalSelection(date);
33
31
  descriptor.onSelectionChange?.(date, reason);
@@ -42,10 +40,6 @@ export function DatePicker({ descriptor, monthLabel, composeAccessibleName, prev
42
40
  triggerRef.current?.focus();
43
41
  return;
44
42
  }
45
- setFocusedDate(selectedDate ?? firstDate?.date ?? "");
46
- const frame = requestAnimationFrame(() => {
47
- dialogRef.current?.querySelector("[data-focus-date='true']")?.focus();
48
- });
49
43
  const outside = (event) => {
50
44
  const target = event.target;
51
45
  if (!dialogRef.current?.contains(target) && !triggerRef.current?.contains(target)) {
@@ -54,28 +48,19 @@ export function DatePicker({ descriptor, monthLabel, composeAccessibleName, prev
54
48
  };
55
49
  document.addEventListener("pointerdown", outside);
56
50
  return () => {
57
- cancelAnimationFrame(frame);
58
51
  document.removeEventListener("pointerdown", outside);
59
52
  };
60
53
  }, [open]);
61
- const handleGridKey = (event, date) => {
62
- if (event.key === "Escape") {
63
- event.preventDefault();
64
- requestOpen(false, "escape");
65
- return;
66
- }
67
- const intent = getCalendarNavigationIntent(event.key, theme?.environment.direction ?? "ltr");
68
- if (!intent)
69
- return;
70
- event.preventDefault();
71
- const target = getCalendarNavigationTarget(descriptor.grid, date, intent);
72
- if ("date" in target && target.date) {
73
- setFocusedDate(target.date);
74
- queueMicrotask(() => dialogRef.current?.querySelector(`[data-date='${target.date}']`)?.focus());
75
- }
76
- };
54
+ // The outer field owns selection; the shared grid receives only its resolved controlled value.
55
+ const { defaultSelectedDate: _defaultSelectedDate, ...calendarDescriptor } = descriptor;
56
+ const calendarGrid = descriptor.disabled || descriptor.readOnly
57
+ ? { ...descriptor.grid, cells: descriptor.grid.cells.map((cell) => cell.date ? { ...cell, disabled: true } : cell) }
58
+ : descriptor.grid;
77
59
  const label = descriptor.label ?? descriptor.accessibilityLabel;
78
60
  const triggerText = resolveDatePickerTriggerText(descriptor);
79
- return (_jsxs("div", { className: classNames("hjm-date-picker", className), "data-invalid": descriptor.invalid || error !== undefined || undefined, "data-size": size, children: [descriptor.label === undefined ? null : _jsx("span", { className: "hjm-date-picker__label", children: descriptor.label }), _jsxs("div", { className: "hjm-date-picker__anchor", children: [_jsxs("button", { "aria-controls": open ? dialogId : undefined, "aria-expanded": open, "aria-haspopup": "dialog", "aria-label": descriptor.accessibilityLabel, className: "hjm-date-picker__trigger", disabled: descriptor.disabled, onClick: () => !descriptor.readOnly && requestOpen(!open, "trigger"), ref: triggerRef, type: "button", children: [_jsx("span", { "aria-hidden": "true", children: "\u25A3" }), _jsx("span", { "data-placeholder": descriptor.displayValue === null || undefined, children: triggerText })] }), selectedDate === null ? null : (_jsx("button", { "aria-label": clearLabel, className: "hjm-date-picker__clear", disabled: descriptor.disabled || descriptor.readOnly, onClick: () => commit(null, "clear"), type: "button", children: "\u00D7" })), open ? (_jsxs("div", { "aria-label": label, className: "hjm-date-picker__popover", id: dialogId, ref: dialogRef, role: "dialog", children: [_jsxs("header", { className: "hjm-date-picker__calendar-header", children: [previousMonth ? _jsx("button", { "aria-label": previousMonth.label, onClick: () => descriptor.onFocusedMonthChange?.(previousMonth.month, "previous"), type: "button", children: "\u2039" }) : _jsx("span", { "aria-hidden": "true" }), _jsx("strong", { children: monthLabel }), nextMonth ? _jsx("button", { "aria-label": nextMonth.label, onClick: () => descriptor.onFocusedMonthChange?.(nextMonth.month, "next"), type: "button", children: "\u203A" }) : _jsx("span", { "aria-hidden": "true" }), _jsx("button", { "aria-label": closeLabel, onClick: () => requestOpen(false, "trigger"), type: "button", children: "\u00D7" })] }), _jsx("div", { className: "hjm-date-picker__weekdays", "aria-hidden": "true", children: descriptor.grid.weekdayLabels.map((weekday, index) => _jsx("span", { children: weekday }, `${weekday}-${index}`)) }), _jsx("div", { "aria-label": monthLabel, className: "hjm-date-picker__grid", role: "grid", children: Array.from({ length: cells.length / 7 }, (_, row) => (_jsx("div", { className: "hjm-date-picker__week", role: "row", children: cells.slice(row * 7, row * 7 + 7).map((cell, column) => "filler" in cell ? (_jsx("span", { "aria-hidden": "true", className: "hjm-date-picker__day", role: "gridcell" }, `filler-${row}-${column}`)) : (_jsxs("button", { "aria-label": cell.accessibleName, "aria-selected": cell.isSelected, className: "hjm-date-picker__day", "data-date": cell.date, "data-disabled": !cell.selectable || undefined, "data-focus-date": cell.date === focusedDate || undefined, "data-outside": cell.outsideFocusedMonth || undefined, "data-selected": cell.isSelected || undefined, "data-today": cell.isToday || undefined, onClick: () => cell.selectable && commit(cell.date, "activate"), onKeyDown: (event) => handleGridKey(event, cell.date), role: "gridcell", tabIndex: cell.date === focusedDate ? 0 : -1, type: "button", children: [_jsx("span", { children: Number(cell.date.slice(-2)) }), renderCellContent?.(cell)] }, cell.date))) }, row))) })] })) : null] }), description === undefined ? null : _jsx("span", { className: "hjm-date-picker__description", children: description }), error === undefined ? null : _jsx("span", { className: "hjm-date-picker__error", role: "alert", children: error })] }));
61
+ return (_jsxs("div", { className: classNames("hjm-date-picker", className), "data-invalid": descriptor.invalid || error !== undefined || undefined, "data-size": size, children: [descriptor.label === undefined ? null : _jsx("span", { className: "hjm-date-picker__label", children: descriptor.label }), _jsxs("div", { className: "hjm-date-picker__anchor", children: [_jsxs("button", { "aria-controls": open ? dialogId : undefined, "aria-expanded": open, "aria-haspopup": "dialog", "aria-label": descriptor.accessibilityLabel, className: "hjm-date-picker__trigger", disabled: descriptor.disabled, onClick: () => !descriptor.readOnly && requestOpen(!open, "trigger"), ref: triggerRef, type: "button", children: [_jsx("span", { "aria-hidden": "true", children: "\u25A3" }), _jsx("span", { "data-placeholder": descriptor.displayValue === null || undefined, children: triggerText })] }), selectedDate === null ? null : (_jsx("button", { "aria-label": clearLabel, className: "hjm-date-picker__clear", disabled: descriptor.disabled || descriptor.readOnly, onClick: () => commit(null, "clear"), type: "button", children: "\u00D7" })), open ? (_jsxs("div", { "aria-label": label, className: "hjm-date-picker__popover", id: dialogId, ref: dialogRef, role: "dialog", onKeyDown: (event) => { if (event.key === "Escape") {
62
+ event.preventDefault();
63
+ requestOpen(false, "escape");
64
+ } }, children: [_jsx("button", { "aria-label": closeLabel, className: "hjm-date-picker__calendar-close", onClick: () => requestOpen(false, "trigger"), type: "button", children: "\u00D7" }), _jsx(Calendar, { descriptor: { ...calendarDescriptor, grid: calendarGrid, monthLabel, selectedDate, onSelectionChange: (date) => commit(date, "activate") }, composeAccessibleName: composeAccessibleName, size: size, autoFocus: true, ...(previousMonth ? { previousMonth } : {}), ...(nextMonth ? { nextMonth } : {}), ...(renderCellContent ? { renderCellContent } : {}), ...(onNavigateBeyondGrid ? { onNavigateBeyondGrid } : {}) })] })) : null] }), description === undefined ? null : _jsx("span", { className: "hjm-date-picker__description", children: description }), error === undefined ? null : _jsx("span", { className: "hjm-date-picker__error", role: "alert", children: error })] }));
80
65
  }
81
66
  //# sourceMappingURL=date-picker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"date-picker.js","sourceRoot":"","sources":["../src/date-picker.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n getCalendarNavigationIntent,\n getCalendarNavigationTarget,\n type ComposeCalendarAccessibleName,\n type ResolvedCalendarDateCell,\n} from \"@hjmds/design-contracts/components/calendar\";\nimport {\n resolveDatePickerGrid,\n resolveDatePickerTriggerText,\n validateDatePickerDescriptor,\n type DatePickerDescriptor,\n type DatePickerOpenChangeReason,\n type DatePickerSize,\n} from \"@hjmds/design-contracts/components/date-picker\";\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\n\nimport { classNames } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\n\nexport type DatePickerMonthAction = Readonly<{ month: string; label: string }>;\n\nexport type DatePickerProps<Content = unknown> = Readonly<{\n descriptor: DatePickerDescriptor<Content>;\n monthLabel: string;\n composeAccessibleName: ComposeCalendarAccessibleName<Content>;\n previousMonth?: DatePickerMonthAction;\n nextMonth?: DatePickerMonthAction;\n clearLabel: string;\n closeLabel: string;\n size?: DatePickerSize;\n description?: ReactNode;\n error?: ReactNode;\n renderCellContent?: (cell: ResolvedCalendarDateCell<Content>) => ReactNode;\n className?: string;\n}>;\n\n/** Single-date field with an anchored, focus-bearing calendar dialog. */\nexport function DatePicker<Content>({\n descriptor,\n monthLabel,\n composeAccessibleName,\n previousMonth,\n nextMonth,\n clearLabel,\n closeLabel,\n size = \"medium\",\n description,\n error,\n renderCellContent,\n className,\n}: DatePickerProps<Content>) {\n validateDatePickerDescriptor(descriptor);\n const theme = useOptionalHjmTheme();\n const generatedId = useId().replaceAll(\":\", \"\");\n const dialogId = `hjm-date-picker-${generatedId}`;\n const triggerRef = useRef<HTMLButtonElement>(null);\n const dialogRef = useRef<HTMLDivElement>(null);\n const controlledOpen = descriptor.open !== undefined;\n const [internalOpen, setInternalOpen] = useState(descriptor.defaultOpen ?? false);\n const open = controlledOpen ? descriptor.open === true : internalOpen;\n const controlledSelection = descriptor.selectedDate !== undefined;\n const [internalSelection, setInternalSelection] = useState(\n descriptor.defaultSelectedDate ?? null,\n );\n const selectedDate = controlledSelection ? descriptor.selectedDate ?? null : internalSelection;\n const gridDescriptor = { ...descriptor, selectedDate } as DatePickerDescriptor<Content>;\n const cells = resolveDatePickerGrid(gridDescriptor, { composeAccessibleName });\n const firstDate = cells.find((cell): cell is ResolvedCalendarDateCell<Content> => !(\"filler\" in cell));\n const [focusedDate, setFocusedDate] = useState(selectedDate ?? firstDate?.date ?? \"\");\n\n const requestOpen = (next: boolean, reason: DatePickerOpenChangeReason) => {\n if (!controlledOpen) setInternalOpen(next);\n descriptor.onOpenChange?.(next, reason);\n };\n const commit = (date: string | null, reason: \"activate\" | \"clear\") => {\n if (!controlledSelection) setInternalSelection(date);\n descriptor.onSelectionChange?.(date, reason);\n requestOpen(false, reason === \"activate\" ? \"selection\" : \"clear\");\n };\n\n const wasOpenRef = useRef(open);\n useEffect(() => {\n const wasOpen = wasOpenRef.current;\n wasOpenRef.current = open;\n if (!open) {\n if (wasOpen) triggerRef.current?.focus();\n return;\n }\n setFocusedDate(selectedDate ?? firstDate?.date ?? \"\");\n const frame = requestAnimationFrame(() => {\n dialogRef.current?.querySelector<HTMLElement>(\"[data-focus-date='true']\")?.focus();\n });\n const outside = (event: PointerEvent) => {\n const target = event.target as Node;\n if (!dialogRef.current?.contains(target) && !triggerRef.current?.contains(target)) {\n requestOpen(false, \"outside\");\n }\n };\n document.addEventListener(\"pointerdown\", outside);\n return () => {\n cancelAnimationFrame(frame);\n document.removeEventListener(\"pointerdown\", outside);\n };\n }, [open]);\n\n const handleGridKey = (event: KeyboardEvent<HTMLButtonElement>, date: string) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n requestOpen(false, \"escape\");\n return;\n }\n const intent = getCalendarNavigationIntent(\n event.key as Parameters<typeof getCalendarNavigationIntent>[0],\n theme?.environment.direction ?? \"ltr\",\n );\n if (!intent) return;\n event.preventDefault();\n const target = getCalendarNavigationTarget(descriptor.grid, date, intent);\n if (\"date\" in target && target.date) {\n setFocusedDate(target.date);\n queueMicrotask(() => dialogRef.current?.querySelector<HTMLElement>(`[data-date='${target.date}']`)?.focus());\n }\n };\n\n const label = descriptor.label ?? descriptor.accessibilityLabel;\n const triggerText = resolveDatePickerTriggerText(descriptor);\n return (\n <div className={classNames(\"hjm-date-picker\", className)} data-invalid={descriptor.invalid || error !== undefined || undefined} data-size={size}>\n {descriptor.label === undefined ? null : <span className=\"hjm-date-picker__label\">{descriptor.label}</span>}\n <div className=\"hjm-date-picker__anchor\">\n <button\n aria-controls={open ? dialogId : undefined}\n aria-expanded={open}\n aria-haspopup=\"dialog\"\n aria-label={descriptor.accessibilityLabel}\n className=\"hjm-date-picker__trigger\"\n disabled={descriptor.disabled}\n onClick={() => !descriptor.readOnly && requestOpen(!open, \"trigger\")}\n ref={triggerRef}\n type=\"button\"\n >\n <span aria-hidden=\"true\">▣</span>\n <span data-placeholder={descriptor.displayValue === null || undefined}>{triggerText}</span>\n </button>\n {selectedDate === null ? null : (\n <button aria-label={clearLabel} className=\"hjm-date-picker__clear\" disabled={descriptor.disabled || descriptor.readOnly} onClick={() => commit(null, \"clear\")} type=\"button\">×</button>\n )}\n {open ? (\n <div aria-label={label} className=\"hjm-date-picker__popover\" id={dialogId} ref={dialogRef} role=\"dialog\">\n <header className=\"hjm-date-picker__calendar-header\">\n {previousMonth ? <button aria-label={previousMonth.label} onClick={() => descriptor.onFocusedMonthChange?.(previousMonth.month, \"previous\")} type=\"button\">‹</button> : <span aria-hidden=\"true\" />}\n <strong>{monthLabel}</strong>\n {nextMonth ? <button aria-label={nextMonth.label} onClick={() => descriptor.onFocusedMonthChange?.(nextMonth.month, \"next\")} type=\"button\">›</button> : <span aria-hidden=\"true\" />}\n <button aria-label={closeLabel} onClick={() => requestOpen(false, \"trigger\")} type=\"button\">×</button>\n </header>\n <div className=\"hjm-date-picker__weekdays\" aria-hidden=\"true\">\n {descriptor.grid.weekdayLabels.map((weekday, index) => <span key={`${weekday}-${index}`}>{weekday}</span>)}\n </div>\n <div aria-label={monthLabel} className=\"hjm-date-picker__grid\" role=\"grid\">\n {Array.from({ length: cells.length / 7 }, (_, row) => (\n <div className=\"hjm-date-picker__week\" key={row} role=\"row\">\n {cells.slice(row * 7, row * 7 + 7).map((cell, column) => \"filler\" in cell ? (\n <span aria-hidden=\"true\" className=\"hjm-date-picker__day\" key={`filler-${row}-${column}`} role=\"gridcell\" />\n ) : (\n <button\n aria-label={cell.accessibleName}\n aria-selected={cell.isSelected}\n className=\"hjm-date-picker__day\"\n data-date={cell.date}\n data-disabled={!cell.selectable || undefined}\n data-focus-date={cell.date === focusedDate || undefined}\n data-outside={cell.outsideFocusedMonth || undefined}\n data-selected={cell.isSelected || undefined}\n data-today={cell.isToday || undefined}\n key={cell.date}\n onClick={() => cell.selectable && commit(cell.date, \"activate\")}\n onKeyDown={(event) => handleGridKey(event, cell.date)}\n role=\"gridcell\"\n tabIndex={cell.date === focusedDate ? 0 : -1}\n type=\"button\"\n >\n <span>{Number(cell.date.slice(-2))}</span>\n {renderCellContent?.(cell)}\n </button>\n ))}\n </div>\n ))}\n </div>\n </div>\n ) : null}\n </div>\n {description === undefined ? null : <span className=\"hjm-date-picker__description\">{description}</span>}\n {error === undefined ? null : <span className=\"hjm-date-picker__error\" role=\"alert\">{error}</span>}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"date-picker.js","sourceRoot":"","sources":["../src/date-picker.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n type ComposeCalendarAccessibleName,\n type ResolvedCalendarDateCell,\n} from \"@hjmds/design-contracts/components/calendar\";\nimport {\n resolveDatePickerTriggerText,\n validateDatePickerDescriptor,\n type DatePickerDescriptor,\n type DatePickerOpenChangeReason,\n type DatePickerSize,\n} from \"@hjmds/design-contracts/components/date-picker\";\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\n\nimport { Calendar, type CalendarOverflow, type CalendarHandle } from \"./calendar.js\";\nimport { classNames } from \"./internal.js\";\n\nexport type DatePickerMonthAction = Readonly<{ month: string; label: string }>;\n\nexport type DatePickerProps<Content = unknown> = Readonly<{\n descriptor: DatePickerDescriptor<Content>;\n monthLabel: string;\n composeAccessibleName: ComposeCalendarAccessibleName<Content>;\n previousMonth?: DatePickerMonthAction;\n nextMonth?: DatePickerMonthAction;\n clearLabel: string;\n closeLabel: string;\n size?: DatePickerSize;\n description?: ReactNode;\n error?: ReactNode;\n onNavigateBeyondGrid?: (detail: CalendarOverflow, focusDate: CalendarHandle[\"focusDate\"]) => void;\n renderCellContent?: (cell: ResolvedCalendarDateCell<Content>) => ReactNode;\n className?: string;\n}>;\n\n/** Single-date field with an anchored, focus-bearing calendar dialog. */\nexport function DatePicker<Content>({\n descriptor,\n monthLabel,\n composeAccessibleName,\n previousMonth,\n nextMonth,\n clearLabel,\n closeLabel,\n size = \"medium\",\n description,\n error,\n renderCellContent,\n onNavigateBeyondGrid,\n className,\n}: DatePickerProps<Content>) {\n validateDatePickerDescriptor(descriptor);\n const generatedId = useId().replaceAll(\":\", \"\");\n const dialogId = `hjm-date-picker-${generatedId}`;\n const triggerRef = useRef<HTMLButtonElement>(null);\n const dialogRef = useRef<HTMLDivElement>(null);\n const controlledOpen = descriptor.open !== undefined;\n const [internalOpen, setInternalOpen] = useState(descriptor.defaultOpen ?? false);\n const open = controlledOpen ? descriptor.open === true : internalOpen;\n const controlledSelection = descriptor.selectedDate !== undefined;\n const [internalSelection, setInternalSelection] = useState(\n descriptor.defaultSelectedDate ?? null,\n );\n const selectedDate = controlledSelection ? descriptor.selectedDate ?? null : internalSelection;\n\n const requestOpen = (next: boolean, reason: DatePickerOpenChangeReason) => {\n if (!controlledOpen) setInternalOpen(next);\n descriptor.onOpenChange?.(next, reason);\n };\n const commit = (date: string | null, reason: \"activate\" | \"clear\") => {\n // A controlled open field can become read-only while its grid remains mounted.\n if (descriptor.disabled || descriptor.readOnly) return;\n if (!controlledSelection) setInternalSelection(date);\n descriptor.onSelectionChange?.(date, reason);\n requestOpen(false, reason === \"activate\" ? \"selection\" : \"clear\");\n };\n\n const wasOpenRef = useRef(open);\n useEffect(() => {\n const wasOpen = wasOpenRef.current;\n wasOpenRef.current = open;\n if (!open) {\n if (wasOpen) triggerRef.current?.focus();\n return;\n }\n const outside = (event: PointerEvent) => {\n const target = event.target as Node;\n if (!dialogRef.current?.contains(target) && !triggerRef.current?.contains(target)) {\n requestOpen(false, \"outside\");\n }\n };\n document.addEventListener(\"pointerdown\", outside);\n return () => {\n document.removeEventListener(\"pointerdown\", outside);\n };\n }, [open]);\n\n // The outer field owns selection; the shared grid receives only its resolved controlled value.\n const { defaultSelectedDate: _defaultSelectedDate, ...calendarDescriptor } = descriptor;\n const calendarGrid = descriptor.disabled || descriptor.readOnly\n ? { ...descriptor.grid, cells: descriptor.grid.cells.map((cell) => cell.date ? { ...cell, disabled: true } : cell) }\n : descriptor.grid;\n const label = descriptor.label ?? descriptor.accessibilityLabel;\n const triggerText = resolveDatePickerTriggerText(descriptor);\n return (\n <div className={classNames(\"hjm-date-picker\", className)} data-invalid={descriptor.invalid || error !== undefined || undefined} data-size={size}>\n {descriptor.label === undefined ? null : <span className=\"hjm-date-picker__label\">{descriptor.label}</span>}\n <div className=\"hjm-date-picker__anchor\">\n <button\n aria-controls={open ? dialogId : undefined}\n aria-expanded={open}\n aria-haspopup=\"dialog\"\n aria-label={descriptor.accessibilityLabel}\n className=\"hjm-date-picker__trigger\"\n disabled={descriptor.disabled}\n onClick={() => !descriptor.readOnly && requestOpen(!open, \"trigger\")}\n ref={triggerRef}\n type=\"button\"\n >\n <span aria-hidden=\"true\">▣</span>\n <span data-placeholder={descriptor.displayValue === null || undefined}>{triggerText}</span>\n </button>\n {selectedDate === null ? null : (\n <button aria-label={clearLabel} className=\"hjm-date-picker__clear\" disabled={descriptor.disabled || descriptor.readOnly} onClick={() => commit(null, \"clear\")} type=\"button\">×</button>\n )}\n {open ? (\n <div aria-label={label} className=\"hjm-date-picker__popover\" id={dialogId} ref={dialogRef} role=\"dialog\" onKeyDown={(event) => { if (event.key === \"Escape\") { event.preventDefault(); requestOpen(false, \"escape\"); } }}>\n <button aria-label={closeLabel} className=\"hjm-date-picker__calendar-close\" onClick={() => requestOpen(false, \"trigger\")} type=\"button\">×</button>\n <Calendar descriptor={{ ...calendarDescriptor, grid: calendarGrid, monthLabel, selectedDate, onSelectionChange: (date) => commit(date, \"activate\") }}\n composeAccessibleName={composeAccessibleName} size={size} autoFocus\n {...(previousMonth ? { previousMonth } : {})} {...(nextMonth ? { nextMonth } : {})}\n {...(renderCellContent ? { renderCellContent } : {})} {...(onNavigateBeyondGrid ? { onNavigateBeyondGrid } : {})} />\n </div>\n ) : null}\n </div>\n {description === undefined ? null : <span className=\"hjm-date-picker__description\">{description}</span>}\n {error === undefined ? null : <span className=\"hjm-date-picker__error\" role=\"alert\">{error}</span>}\n </div>\n );\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import { type DateRangeValue } from "@hjmds/design-contracts/components/date-range";
2
+ import type { CalendarDescriptor, ComposeCalendarAccessibleName } from "@hjmds/design-contracts/components/calendar";
3
+ import { type ReactNode } from "react";
4
+ import { type CalendarMonthAction } from "./calendar.js";
5
+ export type DateRangePickerProps<Content = unknown> = Readonly<{
6
+ /** The same grid Calendar renders; the product still owns month data. */
7
+ descriptor: Omit<CalendarDescriptor<Content>, "selectedDate" | "defaultSelectedDate" | "onSelectionChange">;
8
+ composeAccessibleName: ComposeCalendarAccessibleName<Content>;
9
+ value?: DateRangeValue;
10
+ defaultValue?: DateRangeValue;
11
+ onValueChange?: (value: DateRangeValue) => void;
12
+ previousMonth?: CalendarMonthAction;
13
+ nextMonth?: CalendarMonthAction;
14
+ /** Localized suffixes appended to a day's name when it is a range edge. */
15
+ rangeLabels: Readonly<{
16
+ start: string;
17
+ end: string;
18
+ between: string;
19
+ }>;
20
+ renderCellContent?: (date: string) => ReactNode;
21
+ className?: string;
22
+ }>;
23
+ export declare function DateRangePicker<Content = unknown>({ descriptor, composeAccessibleName, value: controlledValue, defaultValue, onValueChange, previousMonth, nextMonth, rangeLabels, renderCellContent, className, }: DateRangePickerProps<Content>): import("react").JSX.Element;
24
+ //# sourceMappingURL=date-range.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-range.d.ts","sourceRoot":"","sources":["../src/date-range.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,cAAc,EACpB,MAAM,+CAA+C,CAAC;AACvD,OAAO,KAAK,EACV,kBAAkB,EAClB,6BAA6B,EAC9B,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,EAAY,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGnE,MAAM,MAAM,oBAAoB,CAAC,OAAO,GAAG,OAAO,IAAI,QAAQ,CAAC;IAC7D,yEAAyE;IACzE,UAAU,EAAE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,qBAAqB,GAAG,mBAAmB,CAAC,CAAC;IAC5G,qBAAqB,EAAE,6BAA6B,CAAC,OAAO,CAAC,CAAC;IAC9D,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAChD,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,2EAA2E;IAC3E,WAAW,EAAE,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvE,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,wBAAgB,eAAe,CAAC,OAAO,GAAG,OAAO,EAAE,EACjD,UAAU,EACV,qBAAqB,EACrB,KAAK,EAAE,eAAe,EACtB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,SAAS,GACV,EAAE,oBAAoB,CAAC,OAAO,CAAC,+BA6C/B"}
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { emptyDateRange, isCompleteDateRange, resolveDateRangeCellState, resolveDateRangeSelection, validateDateRange, } from "@hjmds/design-contracts/components/date-range";
3
+ import { useState } from "react";
4
+ import { Calendar } from "./calendar.js";
5
+ import { classNames, useControllableState } from "./internal.js";
6
+ export function DateRangePicker({ descriptor, composeAccessibleName, value: controlledValue, defaultValue, onValueChange, previousMonth, nextMonth, rangeLabels, renderCellContent, className, }) {
7
+ const [value, setValue] = useControllableState({
8
+ ...(controlledValue === undefined ? {} : { value: controlledValue }),
9
+ defaultValue: defaultValue ?? emptyDateRange,
10
+ ...(onValueChange === undefined ? {} : { onChange: onValueChange }),
11
+ });
12
+ validateDateRange(value);
13
+ // The hovered date previews the not-yet-committed end through the same cell
14
+ // state function the committed range uses.
15
+ const [hovered, setHovered] = useState(null);
16
+ return (_jsx("div", { className: classNames("hjm-date-range", className), "data-selecting": value.start !== null && value.end === null ? "" : undefined, "data-complete": isCompleteDateRange(value) || undefined, onMouseLeave: () => setHovered(null), children: _jsx(Calendar, { descriptor: {
17
+ ...descriptor,
18
+ // Calendar keeps single selection: the range's own edges are painted
19
+ // through cell content and data attributes, not by lying to it.
20
+ selectedDate: value.end ?? value.start,
21
+ onSelectionChange: (date) => { if (date !== null)
22
+ setValue(resolveDateRangeSelection(value, date)); },
23
+ }, composeAccessibleName: (info) => {
24
+ const state = resolveDateRangeCellState(value, info.date, hovered);
25
+ const base = composeAccessibleName(info);
26
+ return state === "none" ? base : `${base}, ${rangeLabels[state]}`;
27
+ }, ...(previousMonth === undefined ? {} : { previousMonth }), ...(nextMonth === undefined ? {} : { nextMonth }), renderCellContent: (cell) => (_jsx("span", { className: "hjm-date-range__cell", "data-range": resolveDateRangeCellState(value, cell.date, hovered), onMouseEnter: () => setHovered(cell.date), children: renderCellContent?.(cell.date) ?? null })) }) }));
28
+ }
29
+ //# sourceMappingURL=date-range.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-range.js","sourceRoot":"","sources":["../src/date-range.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n emptyDateRange,\n isCompleteDateRange,\n resolveDateRangeCellState,\n resolveDateRangeSelection,\n validateDateRange,\n type DateRangeValue,\n} from \"@hjmds/design-contracts/components/date-range\";\nimport type {\n CalendarDescriptor,\n ComposeCalendarAccessibleName,\n} from \"@hjmds/design-contracts/components/calendar\";\nimport { useState, type ReactNode } from \"react\";\nimport { Calendar, type CalendarMonthAction } from \"./calendar.js\";\nimport { classNames, useControllableState } from \"./internal.js\";\n\nexport type DateRangePickerProps<Content = unknown> = Readonly<{\n /** The same grid Calendar renders; the product still owns month data. */\n descriptor: Omit<CalendarDescriptor<Content>, \"selectedDate\" | \"defaultSelectedDate\" | \"onSelectionChange\">;\n composeAccessibleName: ComposeCalendarAccessibleName<Content>;\n value?: DateRangeValue;\n defaultValue?: DateRangeValue;\n onValueChange?: (value: DateRangeValue) => void;\n previousMonth?: CalendarMonthAction;\n nextMonth?: CalendarMonthAction;\n /** Localized suffixes appended to a day's name when it is a range edge. */\n rangeLabels: Readonly<{ start: string; end: string; between: string }>;\n renderCellContent?: (date: string) => ReactNode;\n className?: string;\n}>;\n\nexport function DateRangePicker<Content = unknown>({\n descriptor,\n composeAccessibleName,\n value: controlledValue,\n defaultValue,\n onValueChange,\n previousMonth,\n nextMonth,\n rangeLabels,\n renderCellContent,\n className,\n}: DateRangePickerProps<Content>) {\n const [value, setValue] = useControllableState<DateRangeValue>({\n ...(controlledValue === undefined ? {} : { value: controlledValue }),\n defaultValue: defaultValue ?? emptyDateRange,\n ...(onValueChange === undefined ? {} : { onChange: onValueChange }),\n });\n validateDateRange(value);\n // The hovered date previews the not-yet-committed end through the same cell\n // state function the committed range uses.\n const [hovered, setHovered] = useState<string | null>(null);\n\n return (\n <div\n className={classNames(\"hjm-date-range\", className)}\n data-selecting={value.start !== null && value.end === null ? \"\" : undefined}\n data-complete={isCompleteDateRange(value) || undefined}\n onMouseLeave={() => setHovered(null)}\n >\n <Calendar<Content>\n descriptor={{\n ...descriptor,\n // Calendar keeps single selection: the range's own edges are painted\n // through cell content and data attributes, not by lying to it.\n selectedDate: value.end ?? value.start,\n onSelectionChange: (date) => { if (date !== null) setValue(resolveDateRangeSelection(value, date)); },\n } as CalendarDescriptor<Content>}\n composeAccessibleName={(info) => {\n const state = resolveDateRangeCellState(value, info.date, hovered);\n const base = composeAccessibleName(info);\n return state === \"none\" ? base : `${base}, ${rangeLabels[state]}`;\n }}\n {...(previousMonth === undefined ? {} : { previousMonth })}\n {...(nextMonth === undefined ? {} : { nextMonth })}\n renderCellContent={(cell) => (\n <span\n className=\"hjm-date-range__cell\"\n data-range={resolveDateRangeCellState(value, cell.date, hovered)}\n onMouseEnter={() => setHovered(cell.date)}\n >\n {renderCellContent?.(cell.date) ?? null}\n </span>\n )}\n />\n </div>\n );\n}\n"]}
package/dist/display.d.ts CHANGED
@@ -71,6 +71,14 @@ export type ListRowProps = Omit<HTMLAttributes<HTMLElement>, "title" | "onClick"
71
71
  leadingShape?: ListRowLeadingShape;
72
72
  selected?: boolean;
73
73
  disabled?: boolean;
74
+ /**
75
+ * Placeholder row while the real one loads. It keeps the row's own height
76
+ * and slot geometry, so a list does not jump when the content arrives —
77
+ * which is exactly what a product-owned skeleton next to the list cannot do.
78
+ */
79
+ loading?: boolean;
80
+ /** Localized status text announced while `loading`. */
81
+ loadingLabel?: string;
74
82
  href?: string;
75
83
  onClick?: MouseEventHandler<HTMLElement>;
76
84
  /** Canonical layout-only placement. Controlled visual keys are excluded. */
@@ -86,6 +94,14 @@ export declare const ListRow: import("react").ForwardRefExoticComponent<Omit<HTM
86
94
  leadingShape?: ListRowLeadingShape;
87
95
  selected?: boolean;
88
96
  disabled?: boolean;
97
+ /**
98
+ * Placeholder row while the real one loads. It keeps the row's own height
99
+ * and slot geometry, so a list does not jump when the content arrives —
100
+ * which is exactly what a product-owned skeleton next to the list cannot do.
101
+ */
102
+ loading?: boolean;
103
+ /** Localized status text announced while `loading`. */
104
+ loadingLabel?: string;
89
105
  href?: string;
90
106
  onClick?: MouseEventHandler<HTMLElement>;
91
107
  /** Canonical layout-only placement. Controlled visual keys are excluded. */
@@ -1 +1 @@
1
- {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../src/display.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../src/display.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,YAAY,IAAI,oBAAoB,EACzC,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,KAAK,OAAO,EACb,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAChF,YAAY,EAAE,OAAO,EAAE,MAAM,wCAAwC,CAAC;AACtE,MAAM,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAEhD,MAAM,MAAM,UAAU,GAAG,cAAc,CAAC,eAAe,CAAC,GACtD,QAAQ,CAAC;IACP,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,SAAS,CAAC;IAClB,4EAA4E;IAC9E,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACzC,CAAC,CAAC;AAEH,eAAO,MAAM,KAAK;WARP,SAAS;WACT,SAAS;cACN,YAAY;cACZ,SAAS;IACjB,4EAA4E;kBAChE,uBAAuB;oDAmCvC,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,EAAE,UAAU,CAAC,GACtE,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACb,4EAA4E;IAC9E,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACzC,CAAC,CAAC;AAEH,eAAO,MAAM,GAAG;cANF,MAAM;WACT,OAAO;IACZ,4EAA4E;kBAChE,uBAAuB;oDAsBvC,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,GAChE,QAAQ,CAAC;IACP,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC,CAAC;AAEL,eAAO,MAAM,IAAI;YAbL,SAAS;kBACH,SAAS;cACb,SAAS;YACX,SAAS;cACP,SAAS;mBACJ,gBAAgB;eACpB,OAAO;WACX,WAAW;eACP,OAAO;cACR,cAAc;aACf,aAAa;gDA6ExB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC,GAC/E,QAAQ,CAAC;IACP,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACvC,4EAA4E;IAC9E,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACzC,CAAC,CAAC;AAEH,eAAO,MAAM,OAAO;WAvBT,SAAS;kBACF,SAAS;cACb,SAAS;eACR,SAAS;cACV,cAAc;IACxB,2EAA2E;mBAC5D,mBAAmB;eACvB,OAAO;eACP,OAAO;IAClB;;;;OAIG;cACO,OAAO;IACjB,uDAAuD;mBACxC,MAAM;WACd,MAAM;cACH,iBAAiB,CAAC,WAAW,CAAC;IACtC,4EAA4E;kBAChE,uBAAuB;gDAkGvC,CAAC"}