@molecule/app-ui-react 1.0.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 (179) hide show
  1. package/LICENSE +115 -0
  2. package/README.md +2786 -0
  3. package/dist/components/Accordion.d.ts +12 -0
  4. package/dist/components/Accordion.d.ts.map +1 -0
  5. package/dist/components/Accordion.js +80 -0
  6. package/dist/components/Accordion.js.map +1 -0
  7. package/dist/components/Alert.d.ts +26 -0
  8. package/dist/components/Alert.d.ts.map +1 -0
  9. package/dist/components/Alert.js +53 -0
  10. package/dist/components/Alert.js.map +1 -0
  11. package/dist/components/AuthGuard.d.ts +66 -0
  12. package/dist/components/AuthGuard.d.ts.map +1 -0
  13. package/dist/components/AuthGuard.js +42 -0
  14. package/dist/components/AuthGuard.js.map +1 -0
  15. package/dist/components/Avatar.d.ts +12 -0
  16. package/dist/components/Avatar.d.ts.map +1 -0
  17. package/dist/components/Avatar.js +25 -0
  18. package/dist/components/Avatar.js.map +1 -0
  19. package/dist/components/Badge.d.ts +12 -0
  20. package/dist/components/Badge.d.ts.map +1 -0
  21. package/dist/components/Badge.js +18 -0
  22. package/dist/components/Badge.js.map +1 -0
  23. package/dist/components/Button.d.ts +12 -0
  24. package/dist/components/Button.d.ts.map +1 -0
  25. package/dist/components/Button.js +19 -0
  26. package/dist/components/Button.js.map +1 -0
  27. package/dist/components/Card.d.ts +34 -0
  28. package/dist/components/Card.d.ts.map +1 -0
  29. package/dist/components/Card.js +71 -0
  30. package/dist/components/Card.js.map +1 -0
  31. package/dist/components/Checkbox.d.ts +12 -0
  32. package/dist/components/Checkbox.d.ts.map +1 -0
  33. package/dist/components/Checkbox.js +41 -0
  34. package/dist/components/Checkbox.js.map +1 -0
  35. package/dist/components/Dropdown.d.ts +38 -0
  36. package/dist/components/Dropdown.d.ts.map +1 -0
  37. package/dist/components/Dropdown.js +352 -0
  38. package/dist/components/Dropdown.js.map +1 -0
  39. package/dist/components/EmptyState.d.ts +15 -0
  40. package/dist/components/EmptyState.d.ts.map +1 -0
  41. package/dist/components/EmptyState.js +20 -0
  42. package/dist/components/EmptyState.js.map +1 -0
  43. package/dist/components/FloatingInput.d.ts +22 -0
  44. package/dist/components/FloatingInput.d.ts.map +1 -0
  45. package/dist/components/FloatingInput.js +38 -0
  46. package/dist/components/FloatingInput.js.map +1 -0
  47. package/dist/components/Form.d.ts +22 -0
  48. package/dist/components/Form.d.ts.map +1 -0
  49. package/dist/components/Form.js +81 -0
  50. package/dist/components/Form.js.map +1 -0
  51. package/dist/components/Icon.d.ts +48 -0
  52. package/dist/components/Icon.d.ts.map +1 -0
  53. package/dist/components/Icon.js +46 -0
  54. package/dist/components/Icon.js.map +1 -0
  55. package/dist/components/Input.d.ts +12 -0
  56. package/dist/components/Input.d.ts.map +1 -0
  57. package/dist/components/Input.js +25 -0
  58. package/dist/components/Input.js.map +1 -0
  59. package/dist/components/LanguagePicker.d.ts +60 -0
  60. package/dist/components/LanguagePicker.d.ts.map +1 -0
  61. package/dist/components/LanguagePicker.js +45 -0
  62. package/dist/components/LanguagePicker.js.map +1 -0
  63. package/dist/components/Layout.d.ts +24 -0
  64. package/dist/components/Layout.d.ts.map +1 -0
  65. package/dist/components/Layout.js +104 -0
  66. package/dist/components/Layout.js.map +1 -0
  67. package/dist/components/Modal.d.ts +32 -0
  68. package/dist/components/Modal.d.ts.map +1 -0
  69. package/dist/components/Modal.js +235 -0
  70. package/dist/components/Modal.js.map +1 -0
  71. package/dist/components/PageHeader.d.ts +15 -0
  72. package/dist/components/PageHeader.d.ts.map +1 -0
  73. package/dist/components/PageHeader.js +20 -0
  74. package/dist/components/PageHeader.js.map +1 -0
  75. package/dist/components/PageShell.d.ts +15 -0
  76. package/dist/components/PageShell.d.ts.map +1 -0
  77. package/dist/components/PageShell.js +20 -0
  78. package/dist/components/PageShell.js.map +1 -0
  79. package/dist/components/Pagination.d.ts +12 -0
  80. package/dist/components/Pagination.d.ts.map +1 -0
  81. package/dist/components/Pagination.js +78 -0
  82. package/dist/components/Pagination.js.map +1 -0
  83. package/dist/components/PanelClose.d.ts +40 -0
  84. package/dist/components/PanelClose.d.ts.map +1 -0
  85. package/dist/components/PanelClose.js +32 -0
  86. package/dist/components/PanelClose.js.map +1 -0
  87. package/dist/components/Progress.d.ts +45 -0
  88. package/dist/components/Progress.d.ts.map +1 -0
  89. package/dist/components/Progress.js +21 -0
  90. package/dist/components/Progress.js.map +1 -0
  91. package/dist/components/RadioGroup.d.ts +12 -0
  92. package/dist/components/RadioGroup.d.ts.map +1 -0
  93. package/dist/components/RadioGroup.js +34 -0
  94. package/dist/components/RadioGroup.js.map +1 -0
  95. package/dist/components/Select.d.ts +12 -0
  96. package/dist/components/Select.d.ts.map +1 -0
  97. package/dist/components/Select.js +57 -0
  98. package/dist/components/Select.js.map +1 -0
  99. package/dist/components/Separator.d.ts +25 -0
  100. package/dist/components/Separator.d.ts.map +1 -0
  101. package/dist/components/Separator.js +18 -0
  102. package/dist/components/Separator.js.map +1 -0
  103. package/dist/components/SidebarUserCard.d.ts +60 -0
  104. package/dist/components/SidebarUserCard.d.ts.map +1 -0
  105. package/dist/components/SidebarUserCard.js +45 -0
  106. package/dist/components/SidebarUserCard.js.map +1 -0
  107. package/dist/components/Skeleton.d.ts +26 -0
  108. package/dist/components/Skeleton.d.ts.map +1 -0
  109. package/dist/components/Skeleton.js +45 -0
  110. package/dist/components/Skeleton.js.map +1 -0
  111. package/dist/components/Spinner.d.ts +17 -0
  112. package/dist/components/Spinner.d.ts.map +1 -0
  113. package/dist/components/Spinner.js +32 -0
  114. package/dist/components/Spinner.js.map +1 -0
  115. package/dist/components/Switch.d.ts +12 -0
  116. package/dist/components/Switch.d.ts.map +1 -0
  117. package/dist/components/Switch.js +52 -0
  118. package/dist/components/Switch.js.map +1 -0
  119. package/dist/components/Table.d.ts +12 -0
  120. package/dist/components/Table.d.ts.map +1 -0
  121. package/dist/components/Table.js +53 -0
  122. package/dist/components/Table.js.map +1 -0
  123. package/dist/components/Tabs.d.ts +12 -0
  124. package/dist/components/Tabs.d.ts.map +1 -0
  125. package/dist/components/Tabs.js +72 -0
  126. package/dist/components/Tabs.js.map +1 -0
  127. package/dist/components/Textarea.d.ts +12 -0
  128. package/dist/components/Textarea.d.ts.map +1 -0
  129. package/dist/components/Textarea.js +66 -0
  130. package/dist/components/Textarea.js.map +1 -0
  131. package/dist/components/ThemeToggle.d.ts +43 -0
  132. package/dist/components/ThemeToggle.d.ts.map +1 -0
  133. package/dist/components/ThemeToggle.js +30 -0
  134. package/dist/components/ThemeToggle.js.map +1 -0
  135. package/dist/components/Toast.d.ts +61 -0
  136. package/dist/components/Toast.d.ts.map +1 -0
  137. package/dist/components/Toast.js +159 -0
  138. package/dist/components/Toast.js.map +1 -0
  139. package/dist/components/Tooltip.d.ts +21 -0
  140. package/dist/components/Tooltip.d.ts.map +1 -0
  141. package/dist/components/Tooltip.js +245 -0
  142. package/dist/components/Tooltip.js.map +1 -0
  143. package/dist/components/UserMenu.d.ts +59 -0
  144. package/dist/components/UserMenu.d.ts.map +1 -0
  145. package/dist/components/UserMenu.js +34 -0
  146. package/dist/components/UserMenu.js.map +1 -0
  147. package/dist/components/UserMenuPopover.d.ts +139 -0
  148. package/dist/components/UserMenuPopover.d.ts.map +1 -0
  149. package/dist/components/UserMenuPopover.js +173 -0
  150. package/dist/components/UserMenuPopover.js.map +1 -0
  151. package/dist/components/index.d.ts +43 -0
  152. package/dist/components/index.d.ts.map +1 -0
  153. package/dist/components/index.js +43 -0
  154. package/dist/components/index.js.map +1 -0
  155. package/dist/index.d.ts +131 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +131 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/types.d.ts +7 -0
  160. package/dist/types.d.ts.map +1 -0
  161. package/dist/types.js +7 -0
  162. package/dist/types.js.map +1 -0
  163. package/dist/utilities/index.d.ts +8 -0
  164. package/dist/utilities/index.d.ts.map +1 -0
  165. package/dist/utilities/index.js +8 -0
  166. package/dist/utilities/index.js.map +1 -0
  167. package/dist/utilities/initials.d.ts +13 -0
  168. package/dist/utilities/initials.d.ts.map +1 -0
  169. package/dist/utilities/initials.js +23 -0
  170. package/dist/utilities/initials.js.map +1 -0
  171. package/dist/utilities/renderIcon.d.ts +21 -0
  172. package/dist/utilities/renderIcon.d.ts.map +1 -0
  173. package/dist/utilities/renderIcon.js +40 -0
  174. package/dist/utilities/renderIcon.js.map +1 -0
  175. package/dist/utilities.d.ts +12 -0
  176. package/dist/utilities.d.ts.map +1 -0
  177. package/dist/utilities.js +14 -0
  178. package/dist/utilities.js.map +1 -0
  179. package/package.json +68 -0
@@ -0,0 +1,245 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Tooltip component.
4
+ *
5
+ * @module
6
+ */
7
+ import React, { forwardRef, useCallback, useEffect, useId, useLayoutEffect, useRef, useState, } from 'react';
8
+ import { createPortal } from 'react-dom';
9
+ import { getClassMap } from '@molecule/app-ui';
10
+ /** Arrow square size (px) before the 45° rotation that turns it into a diamond. */
11
+ const ARROW_SIZE = 8;
12
+ /**
13
+ * Returns the arrow's inline position style for a given placement. The arrow
14
+ * has no dedicated ClassMap resolver (`tooltip()` takes no options), so its
15
+ * shape/position is expressed via a small inline style — the sanctioned
16
+ * exception for values ClassMap cannot express. Its color is NOT hardcoded:
17
+ * `var(--color-surface)` / `var(--color-border)` are the same CSS custom
18
+ * properties the `bg-surface`/`border` Tailwind utilities in `tooltipContent`
19
+ * resolve to (see `@molecule/app-ui-tailwind/base.css`), so the arrow always
20
+ * matches the tooltip body in both themes.
21
+ * @param placement - The tooltip's resolved placement.
22
+ * @returns Inline style positioning the rotated-square arrow for that placement.
23
+ */
24
+ function getArrowStyle(placement) {
25
+ const half = ARROW_SIZE / 2;
26
+ const base = {
27
+ position: 'absolute',
28
+ width: ARROW_SIZE,
29
+ height: ARROW_SIZE,
30
+ background: 'var(--color-surface)',
31
+ border: '1px solid var(--color-border)',
32
+ };
33
+ switch (placement) {
34
+ case 'top':
35
+ return { ...base, bottom: -half, left: '50%', transform: 'translateX(-50%) rotate(45deg)' };
36
+ case 'top-start':
37
+ return { ...base, bottom: -half, left: 12, transform: 'rotate(45deg)' };
38
+ case 'top-end':
39
+ return { ...base, bottom: -half, right: 12, transform: 'rotate(45deg)' };
40
+ case 'bottom':
41
+ return { ...base, top: -half, left: '50%', transform: 'translateX(-50%) rotate(45deg)' };
42
+ case 'bottom-start':
43
+ return { ...base, top: -half, left: 12, transform: 'rotate(45deg)' };
44
+ case 'bottom-end':
45
+ return { ...base, top: -half, right: 12, transform: 'rotate(45deg)' };
46
+ case 'left':
47
+ return { ...base, right: -half, top: '50%', transform: 'translateY(-50%) rotate(45deg)' };
48
+ case 'right':
49
+ return { ...base, left: -half, top: '50%', transform: 'translateY(-50%) rotate(45deg)' };
50
+ default:
51
+ return base;
52
+ }
53
+ }
54
+ // Position the tooltip in a LAYOUT effect (synchronous, before the browser paints) so
55
+ // it's measured + placed in the same frame it mounts. With a plain useEffect (which
56
+ // runs AFTER paint) the tooltip paints once at the default {0,0} top-left and then jumps
57
+ // to the correct spot — the flicker. Fall back to useEffect on the server (no DOM) to
58
+ // avoid React's SSR useLayoutEffect warning.
59
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
60
+ /**
61
+ * Calculate tooltip position based on trigger element and placement.
62
+ * @param triggerRect - The bounding rectangle of the trigger element.
63
+ * @param tooltipRect - The bounding rectangle of the tooltip element.
64
+ * @param placement - The desired tooltip placement direction.
65
+ * @param offset - The pixel offset from the trigger element.
66
+ * @returns The computed top and left position.
67
+ */
68
+ function calculatePosition(triggerRect, tooltipRect, placement, offset = 8) {
69
+ const { top, left, width, height } = triggerRect;
70
+ const tooltipWidth = tooltipRect.width;
71
+ const tooltipHeight = tooltipRect.height;
72
+ const positions = {
73
+ top: {
74
+ top: top + window.scrollY - tooltipHeight - offset,
75
+ left: left + window.scrollX + width / 2 - tooltipWidth / 2,
76
+ },
77
+ bottom: {
78
+ top: top + window.scrollY + height + offset,
79
+ left: left + window.scrollX + width / 2 - tooltipWidth / 2,
80
+ },
81
+ left: {
82
+ top: top + window.scrollY + height / 2 - tooltipHeight / 2,
83
+ left: left + window.scrollX - tooltipWidth - offset,
84
+ },
85
+ right: {
86
+ top: top + window.scrollY + height / 2 - tooltipHeight / 2,
87
+ left: left + window.scrollX + width + offset,
88
+ },
89
+ 'top-start': {
90
+ top: top + window.scrollY - tooltipHeight - offset,
91
+ left: left + window.scrollX,
92
+ },
93
+ 'top-end': {
94
+ top: top + window.scrollY - tooltipHeight - offset,
95
+ left: left + window.scrollX + width - tooltipWidth,
96
+ },
97
+ 'bottom-start': {
98
+ top: top + window.scrollY + height + offset,
99
+ left: left + window.scrollX,
100
+ },
101
+ 'bottom-end': {
102
+ top: top + window.scrollY + height + offset,
103
+ left: left + window.scrollX + width - tooltipWidth,
104
+ },
105
+ };
106
+ return positions[placement];
107
+ }
108
+ /**
109
+ * Tooltip component.
110
+ *
111
+ * `children` must be a single valid React element (e.g. one `<button>` or
112
+ * one custom component that forwards `aria-describedby`) for the tooltip's
113
+ * content to be programmatically associated with it — this is what lets a
114
+ * screen reader announce the tooltip text for the actually-focused control.
115
+ * A non-element `children` (plain text, a fragment, multiple nodes) still
116
+ * shows the tooltip visually on hover/focus, but without that association.
117
+ * `hasArrow` renders a small themed pointer at the resolved `placement`
118
+ * edge.
119
+ */
120
+ export const Tooltip = forwardRef(({ content, children, placement = 'top', delay = 0, hasArrow = false, className, style, testId }, _ref) => {
121
+ const [isVisible, setIsVisible] = useState(false);
122
+ const [position, setPosition] = useState({ top: 0, left: 0 });
123
+ const triggerRef = useRef(null);
124
+ const tooltipRef = useRef(null);
125
+ const timeoutRef = useRef(undefined);
126
+ // Programmatically associates the tooltip with its trigger. A previous
127
+ // version relied on the WRAPPER div's hover/focus — but the wrapper is
128
+ // not itself the focused element, so its `aria-describedby` would never
129
+ // be announced for the child that actually receives focus (see the
130
+ // single-child cloning below).
131
+ const tooltipId = useId();
132
+ const cm = getClassMap();
133
+ const updatePosition = useCallback(() => {
134
+ // Guard against the effect firing without a DOM — SSR, or after the test
135
+ // environment / portal root has been torn down while a show timer or a
136
+ // pending effect was still queued. Accessing window/document then throws a
137
+ // leaked "window is not defined" async error (the component already guards
138
+ // `typeof document` at its portal site for the same reason).
139
+ if (typeof window === 'undefined' || typeof document === 'undefined')
140
+ return;
141
+ if (triggerRef.current && tooltipRef.current) {
142
+ const triggerRect = triggerRef.current.getBoundingClientRect();
143
+ const tooltipRect = tooltipRef.current.getBoundingClientRect();
144
+ const newPosition = calculatePosition(triggerRect, tooltipRect, placement);
145
+ // Clamp into the viewport so a wide/edge tooltip never spills off the page
146
+ // (which would spawn a horizontal scrollbar). Positions are in document
147
+ // space (they already include scrollX/scrollY); use clientWidth/clientHeight
148
+ // — NOT innerWidth/innerHeight — so the page scrollbar is excluded. The
149
+ // Math.max(min, max) guard keeps it on-screen even when the tooltip is wider
150
+ // than the viewport.
151
+ const margin = 8;
152
+ const minLeft = window.scrollX + margin;
153
+ const maxLeft = window.scrollX + document.documentElement.clientWidth - tooltipRect.width - margin;
154
+ const minTop = window.scrollY + margin;
155
+ const maxTop = window.scrollY + document.documentElement.clientHeight - tooltipRect.height - margin;
156
+ newPosition.left = Math.min(Math.max(newPosition.left, minLeft), Math.max(minLeft, maxLeft));
157
+ newPosition.top = Math.min(Math.max(newPosition.top, minTop), Math.max(minTop, maxTop));
158
+ setPosition(newPosition);
159
+ }
160
+ }, [placement]);
161
+ const show = useCallback(() => {
162
+ if (delay > 0) {
163
+ timeoutRef.current = setTimeout(() => {
164
+ setIsVisible(true);
165
+ }, delay);
166
+ }
167
+ else {
168
+ setIsVisible(true);
169
+ }
170
+ }, [delay]);
171
+ const hide = useCallback(() => {
172
+ if (timeoutRef.current) {
173
+ clearTimeout(timeoutRef.current);
174
+ }
175
+ setIsVisible(false);
176
+ }, []);
177
+ // Show on focus ONLY for keyboard focus (:focus-visible). A mouse click or a
178
+ // programmatic .focus() — e.g. a dropdown/menu returning focus to its trigger
179
+ // after it closes — must NOT re-show a tooltip the click was meant to dismiss
180
+ // (which is why the "Device frame" tooltip lingered after opening + selecting).
181
+ // Guarded: engines without :focus-visible support (older browsers, jsdom) throw
182
+ // on the unknown selector — there we simply skip the focus-show (hover still
183
+ // works), the safe default.
184
+ const handleFocus = useCallback((event) => {
185
+ const target = event.target;
186
+ try {
187
+ if (typeof target.matches === 'function' && target.matches(':focus-visible')) {
188
+ show();
189
+ }
190
+ }
191
+ catch (_error) {
192
+ // :focus-visible unsupported here — don't show on focus; hover still applies.
193
+ }
194
+ }, [show]);
195
+ useIsomorphicLayoutEffect(() => {
196
+ if (isVisible) {
197
+ updatePosition();
198
+ }
199
+ }, [isVisible, updatePosition]);
200
+ useEffect(() => {
201
+ return () => {
202
+ if (timeoutRef.current) {
203
+ clearTimeout(timeoutRef.current);
204
+ }
205
+ };
206
+ }, []);
207
+ // Outer positioned wrapper carries the top/left/zIndex placement; the
208
+ // arrow renders as its SIBLING (not nested inside the visible box),
209
+ // because `tooltipContent` sets `overflow-hidden` — an arrow meant to
210
+ // poke past the box's own edge would be clipped invisible if it were a
211
+ // descendant of that element instead.
212
+ const tooltipElement = isVisible && (_jsxs("div", { style: { position: 'absolute', top: position.top, left: position.left, zIndex: 9999 }, children: [_jsx("div", { ref: tooltipRef, id: tooltipId, role: "tooltip", className: cm.cn(cm.tooltipContent, className), style: style, "data-testid": testId, children: content }), hasArrow && _jsx("span", { "aria-hidden": "true", style: getArrowStyle(placement) })] }));
213
+ // Single-child API (mirrors every mainstream tooltip library): when
214
+ // `children` is exactly one valid element, clone it to inject
215
+ // `aria-describedby` onto the actual focused/hovered node while the
216
+ // tooltip is visible — that id is what a screen reader announces
217
+ // alongside the element's accessible name. `children` is typed as
218
+ // `ReactNode` (it could be a string, a fragment, or multiple nodes); for
219
+ // anything other than a single element there is no single DOM node to
220
+ // attach the id to, so the association is skipped rather than guessed —
221
+ // documented in the module JSDoc as the supported contract.
222
+ const isCloneableChild = React.isValidElement(children) && children.type !== React.Fragment;
223
+ const describedChildren = isCloneableChild
224
+ ? React.cloneElement(children, {
225
+ 'aria-describedby': isVisible ? tooltipId : undefined,
226
+ })
227
+ : children;
228
+ return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, onMouseEnter: show, onMouseLeave: hide, onFocus: handleFocus, onBlur: hide,
229
+ // WCAG 1.4.13: hover/focus-triggered content must be dismissable
230
+ // WITHOUT moving the pointer or focus — Escape hides the tooltip
231
+ // (the keydown on the focused child bubbles up to this wrapper).
232
+ onKeyDown: (e) => {
233
+ if (e.key === 'Escape')
234
+ hide();
235
+ },
236
+ // Any click on a tooltip-wrapped control hides the tooltip — clicking a
237
+ // button shouldn't leave its hover/focus tooltip lingering. The wrapper
238
+ // wraps children directly, so this single handler covers every
239
+ // button-with-tooltip consumer.
240
+ onClick: hide, className: cm.tooltipTrigger, children: describedChildren }), typeof document !== 'undefined' &&
241
+ tooltipElement &&
242
+ createPortal(tooltipElement, document.body)] }));
243
+ });
244
+ Tooltip.displayName = 'Tooltip';
245
+ //# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.js","sourceRoot":"","sources":["../../src/components/Tooltip.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ import type { IconName } from '@molecule/app-icons';
3
+ /**
4
+ * Props for {@link UserMenu}.
5
+ *
6
+ * The inner trigger is a Molecule `<Button>` whose own prop set
7
+ * conflicts with raw `ButtonHTMLAttributes` (color, value, size enums),
8
+ * so this component exposes a curated set of customization points
9
+ * instead of extending HTML attributes. For one-off extra attributes,
10
+ * pass them via `dataMolId` / `className` / `style` props.
11
+ */
12
+ export interface UserMenuProps {
13
+ /**
14
+ * Panel content shown inside the drawer/modal (typically the app's
15
+ * `SettingsPanel`). It can dismiss the drawer by calling
16
+ * `usePanelClose()` — no `onClose` prop-threading required.
17
+ */
18
+ children: ReactNode;
19
+ /**
20
+ * i18n key for the trigger button's aria-label. Defaults to
21
+ * `'userMenu.open'`. Apps whose existing locales use a different key
22
+ * (e.g. `'userMenu.openButton'`) can override.
23
+ */
24
+ ariaLabelKey?: string;
25
+ /** Fallback aria-label if the i18n key is missing. Defaults to `"Open user menu"`. */
26
+ ariaLabelDefault?: string;
27
+ /** Icon name for the trigger button. Defaults to `'user'`. */
28
+ triggerIcon?: IconName;
29
+ /** Pixel size for the trigger icon. Defaults to 20. */
30
+ triggerIconSize?: number;
31
+ /**
32
+ * `data-mol-id` for the trigger button. Defaults to `'user-menu'`.
33
+ * Pass an explicit value to disambiguate when the same page mounts
34
+ * more than one UserMenu.
35
+ */
36
+ dataMolId?: string;
37
+ /** Extra className composed onto the trigger button. */
38
+ className?: string;
39
+ /** Whether the trigger button is disabled. */
40
+ disabled?: boolean;
41
+ /**
42
+ * Override the trigger button's click handler. When provided, called
43
+ * instead of opening the panel — hosts use this to intercept the click
44
+ * (e.g. to open an auth modal for guest users).
45
+ */
46
+ onClick?: () => void;
47
+ }
48
+ /**
49
+ * Avatar-style trigger that opens the app's settings panel in a drawer.
50
+ *
51
+ * The panel content is passed as `children` so apps can mount their own
52
+ * `SettingsPanel` (which diverges per app) inside the shared drawer
53
+ * chrome. Panel content dismisses the drawer via `usePanelClose()`.
54
+ *
55
+ * Ships with `data-mol-id="user-menu"` on the trigger button by
56
+ * default for AI-agent / e2e selection.
57
+ */
58
+ export declare function UserMenu({ children, ariaLabelKey, ariaLabelDefault, triggerIcon, triggerIconSize, dataMolId, className, disabled, onClick, }: UserMenuProps): JSX.Element;
59
+ //# sourceMappingURL=UserMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserMenu.d.ts","sourceRoot":"","sources":["../../src/components/UserMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAI3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AASnD;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,CAAA;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,sFAAsF;IACtF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,QAAQ,CAAA;IACtB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,YAA8B,EAC9B,gBAAmC,EACnC,WAAoB,EACpB,eAAoB,EACpB,SAAuB,EACvB,SAAS,EACT,QAAQ,EACR,OAAO,GACR,EAAE,aAAa,GAAG,GAAG,CAAC,OAAO,CAuC7B"}
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { useLocation } from 'react-router';
4
+ import { useTranslation } from '@molecule/app-react';
5
+ import { getClassMap } from '@molecule/app-ui';
6
+ import { Button } from './Button.js';
7
+ import { Icon } from './Icon.js';
8
+ import { Modal } from './Modal.js';
9
+ import { PanelCloseProvider } from './PanelClose.js';
10
+ /**
11
+ * Avatar-style trigger that opens the app's settings panel in a drawer.
12
+ *
13
+ * The panel content is passed as `children` so apps can mount their own
14
+ * `SettingsPanel` (which diverges per app) inside the shared drawer
15
+ * chrome. Panel content dismisses the drawer via `usePanelClose()`.
16
+ *
17
+ * Ships with `data-mol-id="user-menu"` on the trigger button by
18
+ * default for AI-agent / e2e selection.
19
+ */
20
+ export function UserMenu({ children, ariaLabelKey = 'userMenu.open', ariaLabelDefault = 'Open user menu', triggerIcon = 'user', triggerIconSize = 20, dataMolId = 'user-menu', className, disabled, onClick, }) {
21
+ const cm = getClassMap();
22
+ const { t } = useTranslation();
23
+ const [open, setOpen] = useState(false);
24
+ const location = useLocation();
25
+ // Close the drawer whenever the route changes. React Router updates
26
+ // `location` on both in-app navigation and browser back/forward
27
+ // (popstate), so a single effect covers both — without it the drawer
28
+ // stays mounted over the next page and blocks clicks underneath.
29
+ useEffect(() => {
30
+ setOpen(false);
31
+ }, [location.pathname, location.search]);
32
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: onClick ?? (() => setOpen(true)), "aria-label": t(ariaLabelKey, {}, { defaultValue: ariaLabelDefault }), "data-mol-id": dataMolId, className: className, disabled: disabled, children: _jsx(Icon, { name: triggerIcon, size: triggerIconSize }) }), _jsx(Modal, { open: open, onClose: () => setOpen(false), className: cm.drawer, "aria-label": t('userMenu.panelLabel', {}, { defaultValue: 'Account menu' }), children: _jsx(PanelCloseProvider, { close: () => setOpen(false), children: children }) })] }));
33
+ }
34
+ //# sourceMappingURL=UserMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserMenu.js","sourceRoot":"","sources":["../../src/components/UserMenu.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAG1C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAgDpD;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ,CAAC,EACvB,QAAQ,EACR,YAAY,GAAG,eAAe,EAC9B,gBAAgB,GAAG,gBAAgB,EACnC,WAAW,GAAG,MAAM,EACpB,eAAe,GAAG,EAAE,EACpB,SAAS,GAAG,WAAW,EACvB,SAAS,EACT,QAAQ,EACR,OAAO,GACO;IACd,MAAM,EAAE,GAAG,WAAW,EAAE,CAAA;IACxB,MAAM,EAAE,CAAC,EAAE,GAAG,cAAc,EAAE,CAAA;IAC9B,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACvC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAE9B,oEAAoE;IACpE,gEAAgE;IAChE,qEAAqE;IACrE,iEAAiE;IACjE,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,KAAK,CAAC,CAAA;IAChB,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;IAExC,OAAO,CACL,8BACE,KAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,gBAC7B,CAAC,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,gBAAgB,EAAE,CAAC,iBACtD,SAAS,EACtB,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,YAElB,KAAC,IAAI,IAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,GAAI,GAC3C,EACT,KAAC,KAAK,IACJ,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAC7B,SAAS,EAAE,EAAE,CAAC,MAAM,gBAGR,CAAC,CAAC,qBAAqB,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC,YAE1E,KAAC,kBAAkB,IAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,YAAG,QAAQ,GAAsB,GAC1E,IACP,CACJ,CAAA;AACH,CAAC"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * UserMenuPopover — an inline (non-modal) popover account menu.
3
+ *
4
+ * Unlike `UserMenu` / `SidebarUserCard` (which open their panel in a
5
+ * `<Modal>` drawer), this family renders the panel inline as an
6
+ * absolutely-positioned popover. It auto-dismisses on route change, raw
7
+ * `popstate`, outside click, and `Escape` — so an SPA navigation never
8
+ * leaves the menu hovering over the next page.
9
+ *
10
+ * Compose it:
11
+ *
12
+ * ```tsx
13
+ * <UserMenuPopover guestName={t('userMenu.guestName', {}, { defaultValue: 'Analyst' })}>
14
+ * <UserMenuPopoverTrigger />
15
+ * <UserMenuPopoverPanel>
16
+ * <Link to="/settings">Settings</Link>
17
+ * <Link to="/datasets">My datasets</Link>
18
+ * <UserMenuPopoverSignOut />
19
+ * </UserMenuPopoverPanel>
20
+ * </UserMenuPopover>
21
+ * ```
22
+ *
23
+ * @module
24
+ */
25
+ import React, { type ReactNode } from 'react';
26
+ /**
27
+ * Props for {@link UserMenuPopover}.
28
+ */
29
+ export interface UserMenuPopoverProps {
30
+ /**
31
+ * The trigger and panel — typically `<UserMenuPopoverTrigger />` and
32
+ * `<UserMenuPopoverPanel>`.
33
+ */
34
+ children: ReactNode;
35
+ /**
36
+ * Label shown when there is no authenticated user. Defaults to the
37
+ * `userMenuPopover.guest` translation (English fallback `"Account"`).
38
+ */
39
+ guestName?: string;
40
+ /** Extra className composed onto the relative-positioned container. */
41
+ className?: string;
42
+ }
43
+ /**
44
+ * Container for the inline popover account menu. Owns the open state and
45
+ * the auto-dismiss behaviour (route change, `popstate`, outside click,
46
+ * `Escape`), and provides the resolved account identity to its
47
+ * sub-components via context.
48
+ *
49
+ * @param props - The popover children, optional guest label, and className.
50
+ * @returns The relative-positioned popover container.
51
+ */
52
+ export declare function UserMenuPopover({ children, guestName, className, }: UserMenuPopoverProps): React.JSX.Element;
53
+ /**
54
+ * Props for {@link UserMenuPopoverTrigger}.
55
+ */
56
+ export interface UserMenuPopoverTriggerProps {
57
+ /** i18n key for the trigger's aria-label. Default: `'userMenu.open'`. */
58
+ ariaLabelKey?: string;
59
+ /** Fallback aria-label if the i18n key is missing. Default: `'Open user menu'`. */
60
+ ariaLabelDefault?: string;
61
+ /** `data-mol-id` for the trigger button. Default: `'user-menu'`. */
62
+ dataMolId?: string;
63
+ /** Extra className composed onto the trigger button. */
64
+ className?: string;
65
+ }
66
+ /**
67
+ * The trigger button: an initials avatar plus the account name and email,
68
+ * styled as a full-width sidebar card. Toggles the popover panel.
69
+ *
70
+ * @param props - aria-label overrides, `data-mol-id`, and className.
71
+ * @returns The popover trigger button.
72
+ */
73
+ export declare function UserMenuPopoverTrigger({ ariaLabelKey, ariaLabelDefault, dataMolId, className, }: UserMenuPopoverTriggerProps): React.JSX.Element;
74
+ /**
75
+ * Props for {@link UserMenuPopoverPanel}.
76
+ */
77
+ export interface UserMenuPopoverPanelProps {
78
+ /**
79
+ * Panel body — typically a set of `<Link>` nav items and a
80
+ * `<UserMenuPopoverSignOut />`. Rendered inside a `<nav>` below the
81
+ * built-in identity header.
82
+ */
83
+ children: ReactNode;
84
+ /** Extra className composed onto the absolute-positioned panel. */
85
+ className?: string;
86
+ /** i18n key for the panel's aria-label. Default: `'userMenu.panelLabel'`. */
87
+ ariaLabelKey?: string;
88
+ /** Fallback aria-label if the i18n key is missing. Default: `'Account menu'`. */
89
+ ariaLabelDefault?: string;
90
+ /** `data-mol-id` for the panel. Default: `'user-menu-panel'`. */
91
+ dataMolId?: string;
92
+ }
93
+ /**
94
+ * The popover panel: an absolutely-positioned card with a built-in
95
+ * identity header (name + email) and a `<nav>` wrapping the caller's nav
96
+ * items. Renders nothing while the popover is closed.
97
+ *
98
+ * Provides only the structural concerns (absolute positioning above the
99
+ * trigger, `rounded-xl` border frame, the header/nav layout). Cosmetic
100
+ * choices — width, background, padding, shadow — are per-app: pass them
101
+ * via `className`. `cn()` concatenates (it does not tailwind-merge), so
102
+ * the panel never bakes a width/background the caller would have to
103
+ * fight.
104
+ *
105
+ * @param props - The nav children, className, and aria-label overrides.
106
+ * @returns The popover panel, or `null` when closed.
107
+ */
108
+ export declare function UserMenuPopoverPanel({ children, className, ariaLabelKey, ariaLabelDefault, dataMolId, }: UserMenuPopoverPanelProps): React.JSX.Element | null;
109
+ /**
110
+ * Returns a callback that closes the enclosing `UserMenuPopover`. Useful
111
+ * for nav-item `onClick` handlers that should dismiss the popover even
112
+ * when they don't change the route. Returns a no-op when called outside
113
+ * a `UserMenuPopover`.
114
+ *
115
+ * @returns A function that closes the popover.
116
+ */
117
+ export declare function useUserMenuPopoverClose(): () => void;
118
+ /**
119
+ * Props for {@link UserMenuPopoverSignOut}.
120
+ */
121
+ export interface UserMenuPopoverSignOutProps {
122
+ /** i18n key for the button label. Default: `'userMenu.signOut'`. */
123
+ labelKey?: string;
124
+ /** Fallback label if the i18n key is missing. Default: `'Sign out'`. */
125
+ labelDefault?: string;
126
+ /** `data-mol-id` for the button. Default: `'user-menu-sign-out'`. */
127
+ dataMolId?: string;
128
+ /** Extra className composed onto the button. */
129
+ className?: string;
130
+ }
131
+ /**
132
+ * The sign-out nav item — closes the popover and calls `auth.logout()`.
133
+ * Drop it in as the last child of `<UserMenuPopoverPanel>`.
134
+ *
135
+ * @param props - Label overrides, `data-mol-id`, and className.
136
+ * @returns The sign-out button.
137
+ */
138
+ export declare function UserMenuPopoverSignOut({ labelKey, labelDefault, dataMolId, className, }: UserMenuPopoverSignOutProps): React.JSX.Element;
139
+ //# sourceMappingURL=UserMenuPopover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserMenuPopover.d.ts","sourceRoot":"","sources":["../../src/components/UserMenuPopover.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,EAEZ,KAAK,SAAS,EAMf,MAAM,OAAO,CAAA;AA4Cd;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,EAAE,SAAS,CAAA;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,SAAS,EACT,SAAS,GACV,EAAE,oBAAoB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAqD1C;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,YAA8B,EAC9B,gBAAmC,EACnC,SAAuB,EACvB,SAAS,GACV,EAAE,2BAA2B,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA+DjD;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,QAAQ,EAAE,SAAS,CAAA;IACnB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,SAAS,EACT,YAAoC,EACpC,gBAAiC,EACjC,SAA6B,GAC9B,EAAE,yBAAyB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAkCtD;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,IAAI,CAIpD;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,QAA6B,EAC7B,YAAyB,EACzB,SAAgC,EAChC,SAAS,GACV,EAAE,2BAA2B,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAkCjD"}