@financedistrict/apps-ui 0.1.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.
- package/LICENSE +19 -0
- package/README.md +119 -0
- package/dist/Radio-BYWz1n7p.d.cts +32 -0
- package/dist/Radio-BYWz1n7p.d.ts +32 -0
- package/dist/SelectTrigger-By0iPBI3.d.cts +78 -0
- package/dist/SelectTrigger-By0iPBI3.d.ts +78 -0
- package/dist/accordion.cjs +322 -0
- package/dist/accordion.d.cts +156 -0
- package/dist/accordion.d.ts +156 -0
- package/dist/accordion.js +2 -0
- package/dist/apps-ui.umd.js +1 -0
- package/dist/button.cjs +366 -0
- package/dist/button.d.cts +52 -0
- package/dist/button.d.ts +52 -0
- package/dist/button.js +3 -0
- package/dist/checkbox.cjs +74 -0
- package/dist/checkbox.d.cts +63 -0
- package/dist/checkbox.d.ts +63 -0
- package/dist/checkbox.js +2 -0
- package/dist/chunk-3RU7JMFE.js +27 -0
- package/dist/chunk-5TWRK4NW.js +783 -0
- package/dist/chunk-7EOSDFS3.js +9 -0
- package/dist/chunk-AIQ4UOGK.js +142 -0
- package/dist/chunk-B3MMGTPV.js +200 -0
- package/dist/chunk-DAHQYLUI.js +146 -0
- package/dist/chunk-DGBXADSS.js +1 -0
- package/dist/chunk-E6KPNTWW.js +295 -0
- package/dist/chunk-EOAB6G2D.js +149 -0
- package/dist/chunk-FAOVKDVM.js +32 -0
- package/dist/chunk-FV76Z4Z2.js +78 -0
- package/dist/chunk-GLTLBUZ7.js +285 -0
- package/dist/chunk-GTZFV43T.js +154 -0
- package/dist/chunk-HRGZNL4A.js +88 -0
- package/dist/chunk-IEVN3J2F.js +98 -0
- package/dist/chunk-IRS3T6LF.js +352 -0
- package/dist/chunk-IYYHCQXG.js +146 -0
- package/dist/chunk-JIXW3455.js +89 -0
- package/dist/chunk-N4VAP2GB.js +77 -0
- package/dist/chunk-SJ2ZRYVV.js +167 -0
- package/dist/chunk-SNU4YXOR.js +66 -0
- package/dist/chunk-TT6JQATV.js +99 -0
- package/dist/chunk-UPQ3ZPCO.js +66 -0
- package/dist/chunk-UVUSVFOH.js +264 -0
- package/dist/chunk-WJFPGGJB.js +255 -0
- package/dist/chunk-WXEBQA7A.js +371 -0
- package/dist/chunk-Y2O4YYZQ.js +184 -0
- package/dist/cut-corner.cjs +111 -0
- package/dist/cut-corner.d.cts +49 -0
- package/dist/cut-corner.d.ts +49 -0
- package/dist/cut-corner.js +1 -0
- package/dist/dialog.cjs +441 -0
- package/dist/dialog.d.cts +240 -0
- package/dist/dialog.d.ts +240 -0
- package/dist/dialog.js +3 -0
- package/dist/feature-card.cjs +182 -0
- package/dist/feature-card.d.cts +54 -0
- package/dist/feature-card.d.ts +54 -0
- package/dist/feature-card.js +2 -0
- package/dist/filter.cjs +873 -0
- package/dist/filter.d.cts +129 -0
- package/dist/filter.d.ts +129 -0
- package/dist/filter.js +6 -0
- package/dist/index.cjs +4583 -0
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +27 -0
- package/dist/inline-select.cjs +856 -0
- package/dist/inline-select.d.cts +92 -0
- package/dist/inline-select.d.ts +92 -0
- package/dist/inline-select.js +6 -0
- package/dist/input.cjs +263 -0
- package/dist/input.d.cts +157 -0
- package/dist/input.d.ts +157 -0
- package/dist/input.js +4 -0
- package/dist/panel.cjs +185 -0
- package/dist/panel.d.cts +103 -0
- package/dist/panel.d.ts +103 -0
- package/dist/panel.js +2 -0
- package/dist/property-grid.cjs +110 -0
- package/dist/property-grid.d.cts +56 -0
- package/dist/property-grid.d.ts +56 -0
- package/dist/property-grid.js +2 -0
- package/dist/radio.cjs +74 -0
- package/dist/radio.d.cts +39 -0
- package/dist/radio.d.ts +39 -0
- package/dist/radio.js +2 -0
- package/dist/scrollbar.cjs +34 -0
- package/dist/scrollbar.d.cts +35 -0
- package/dist/scrollbar.d.ts +35 -0
- package/dist/scrollbar.js +1 -0
- package/dist/search-bar.cjs +408 -0
- package/dist/search-bar.d.cts +42 -0
- package/dist/search-bar.d.ts +42 -0
- package/dist/search-bar.js +4 -0
- package/dist/select.cjs +998 -0
- package/dist/select.d.cts +357 -0
- package/dist/select.d.ts +357 -0
- package/dist/select.js +5 -0
- package/dist/selectable-feature-card.cjs +159 -0
- package/dist/selectable-feature-card.d.cts +74 -0
- package/dist/selectable-feature-card.d.ts +74 -0
- package/dist/selectable-feature-card.js +3 -0
- package/dist/sidebar-item.cjs +175 -0
- package/dist/sidebar-item.d.cts +75 -0
- package/dist/sidebar-item.d.ts +75 -0
- package/dist/sidebar-item.js +2 -0
- package/dist/switch.cjs +86 -0
- package/dist/switch.d.cts +72 -0
- package/dist/switch.d.ts +72 -0
- package/dist/switch.js +2 -0
- package/dist/table-cell.cjs +196 -0
- package/dist/table-cell.d.cts +76 -0
- package/dist/table-cell.d.ts +76 -0
- package/dist/table-cell.js +2 -0
- package/dist/table-title.cjs +34 -0
- package/dist/table-title.d.cts +16 -0
- package/dist/table-title.d.ts +16 -0
- package/dist/table-title.js +2 -0
- package/dist/tabs.cjs +299 -0
- package/dist/tabs.d.cts +116 -0
- package/dist/tabs.d.ts +116 -0
- package/dist/tabs.js +2 -0
- package/dist/toast.cjs +87 -0
- package/dist/toast.d.cts +48 -0
- package/dist/toast.d.ts +48 -0
- package/dist/toast.js +2 -0
- package/dist/token-input.cjs +415 -0
- package/dist/token-input.d.cts +90 -0
- package/dist/token-input.d.ts +90 -0
- package/dist/token-input.js +3 -0
- package/dist/tooltip.cjs +384 -0
- package/dist/tooltip.d.cts +142 -0
- package/dist/tooltip.d.ts +142 -0
- package/dist/tooltip.js +2 -0
- package/package.json +200 -0
- package/src/fonts.css +33 -0
package/dist/tooltip.cjs
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var reactDom = require('react-dom');
|
|
5
|
+
var clsx = require('clsx');
|
|
6
|
+
var tailwindMerge = require('tailwind-merge');
|
|
7
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
8
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
29
|
+
|
|
30
|
+
// src/tooltip/Tooltip.tsx
|
|
31
|
+
function cn(...inputs) {
|
|
32
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
33
|
+
}
|
|
34
|
+
var tooltipVariants = classVarianceAuthority.cva([
|
|
35
|
+
"pointer-events-none max-w-[244px] rounded-sm bg-card-reversed-background px-1.5 py-1",
|
|
36
|
+
"body-04 text-center text-card-reversed-foreground shadow-xs"
|
|
37
|
+
]);
|
|
38
|
+
var TOOLTIP_OFFSET = 6;
|
|
39
|
+
var VIEWPORT_MARGIN = 8;
|
|
40
|
+
var OPPOSITE_SIDE = {
|
|
41
|
+
top: "bottom",
|
|
42
|
+
bottom: "top",
|
|
43
|
+
left: "right",
|
|
44
|
+
right: "left"
|
|
45
|
+
};
|
|
46
|
+
function sideFits(trigger, content, side, viewport) {
|
|
47
|
+
switch (side) {
|
|
48
|
+
case "top":
|
|
49
|
+
return trigger.top - TOOLTIP_OFFSET - content.height >= 0;
|
|
50
|
+
case "bottom":
|
|
51
|
+
return trigger.top + trigger.height + TOOLTIP_OFFSET + content.height <= viewport.height;
|
|
52
|
+
case "left":
|
|
53
|
+
return trigger.left - TOOLTIP_OFFSET - content.width >= 0;
|
|
54
|
+
case "right":
|
|
55
|
+
return trigger.left + trigger.width + TOOLTIP_OFFSET + content.width <= viewport.width;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function alignCoord(anchorStart, anchorSize, contentSize, align) {
|
|
59
|
+
switch (align) {
|
|
60
|
+
case "start":
|
|
61
|
+
return anchorStart;
|
|
62
|
+
case "center":
|
|
63
|
+
return anchorStart + anchorSize / 2 - contentSize / 2;
|
|
64
|
+
case "end":
|
|
65
|
+
return anchorStart + anchorSize - contentSize;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function clamp(value, min, max) {
|
|
69
|
+
return Math.max(min, Math.min(value, Math.max(min, max)));
|
|
70
|
+
}
|
|
71
|
+
function computeTooltipPosition(trigger, content, side, align, viewport) {
|
|
72
|
+
const resolvedSide = sideFits(trigger, content, side, viewport) || !sideFits(trigger, content, OPPOSITE_SIDE[side], viewport) ? side : OPPOSITE_SIDE[side];
|
|
73
|
+
const vertical = resolvedSide === "top" || resolvedSide === "bottom";
|
|
74
|
+
let top;
|
|
75
|
+
let left;
|
|
76
|
+
if (vertical) {
|
|
77
|
+
top = resolvedSide === "top" ? trigger.top - TOOLTIP_OFFSET - content.height : trigger.top + trigger.height + TOOLTIP_OFFSET;
|
|
78
|
+
left = alignCoord(trigger.left, trigger.width, content.width, align);
|
|
79
|
+
left = clamp(
|
|
80
|
+
left,
|
|
81
|
+
VIEWPORT_MARGIN,
|
|
82
|
+
viewport.width - content.width - VIEWPORT_MARGIN
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
left = resolvedSide === "left" ? trigger.left - TOOLTIP_OFFSET - content.width : trigger.left + trigger.width + TOOLTIP_OFFSET;
|
|
86
|
+
top = alignCoord(trigger.top, trigger.height, content.height, align);
|
|
87
|
+
top = clamp(
|
|
88
|
+
top,
|
|
89
|
+
VIEWPORT_MARGIN,
|
|
90
|
+
viewport.height - content.height - VIEWPORT_MARGIN
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return { top, left, side: resolvedSide };
|
|
94
|
+
}
|
|
95
|
+
var TooltipContext = React__namespace.createContext(null);
|
|
96
|
+
function useTooltipContext(part) {
|
|
97
|
+
const context = React__namespace.useContext(TooltipContext);
|
|
98
|
+
if (context === null) {
|
|
99
|
+
throw new Error(`${part} must be used within <Tooltip.Root>`);
|
|
100
|
+
}
|
|
101
|
+
return context;
|
|
102
|
+
}
|
|
103
|
+
function setRef(ref, node) {
|
|
104
|
+
if (typeof ref === "function") ref(node);
|
|
105
|
+
else if (ref) ref.current = node;
|
|
106
|
+
}
|
|
107
|
+
function TooltipRoot({
|
|
108
|
+
open: openProp,
|
|
109
|
+
defaultOpen = false,
|
|
110
|
+
onOpenChange,
|
|
111
|
+
delayDuration = 600,
|
|
112
|
+
side = "top",
|
|
113
|
+
align = "center",
|
|
114
|
+
disabled = false,
|
|
115
|
+
children
|
|
116
|
+
}) {
|
|
117
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React__namespace.useState(defaultOpen);
|
|
118
|
+
const isControlled = openProp !== void 0;
|
|
119
|
+
const rawOpen = isControlled ? openProp : uncontrolledOpen;
|
|
120
|
+
const open = disabled ? false : rawOpen;
|
|
121
|
+
const reactId = React__namespace.useId();
|
|
122
|
+
const contentId = `${reactId}-tooltip`;
|
|
123
|
+
const anchorRef = React__namespace.useRef(null);
|
|
124
|
+
const [anchorRect, setAnchorRect] = React__namespace.useState(null);
|
|
125
|
+
const timerRef = React__namespace.useRef(null);
|
|
126
|
+
const setOpen = React__namespace.useCallback(
|
|
127
|
+
(next) => {
|
|
128
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
129
|
+
onOpenChange?.(next);
|
|
130
|
+
},
|
|
131
|
+
[isControlled, onOpenChange]
|
|
132
|
+
);
|
|
133
|
+
const clearTimer = React__namespace.useCallback(() => {
|
|
134
|
+
if (timerRef.current !== null) {
|
|
135
|
+
clearTimeout(timerRef.current);
|
|
136
|
+
timerRef.current = null;
|
|
137
|
+
}
|
|
138
|
+
}, []);
|
|
139
|
+
React__namespace.useEffect(() => clearTimer, [clearTimer]);
|
|
140
|
+
const onTriggerPointerEnter = () => {
|
|
141
|
+
if (disabled) return;
|
|
142
|
+
clearTimer();
|
|
143
|
+
timerRef.current = setTimeout(() => setOpen(true), delayDuration);
|
|
144
|
+
};
|
|
145
|
+
const onTriggerPointerLeave = () => {
|
|
146
|
+
clearTimer();
|
|
147
|
+
setOpen(false);
|
|
148
|
+
};
|
|
149
|
+
const onTriggerFocus = () => {
|
|
150
|
+
if (disabled) return;
|
|
151
|
+
clearTimer();
|
|
152
|
+
setOpen(true);
|
|
153
|
+
};
|
|
154
|
+
const onTriggerBlur = () => {
|
|
155
|
+
clearTimer();
|
|
156
|
+
setOpen(false);
|
|
157
|
+
};
|
|
158
|
+
React__namespace.useLayoutEffect(() => {
|
|
159
|
+
if (!open) {
|
|
160
|
+
setAnchorRect(null);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const measure = () => {
|
|
164
|
+
const node = anchorRef.current;
|
|
165
|
+
if (node) setAnchorRect(node.getBoundingClientRect());
|
|
166
|
+
};
|
|
167
|
+
measure();
|
|
168
|
+
window.addEventListener("scroll", measure, true);
|
|
169
|
+
window.addEventListener("resize", measure);
|
|
170
|
+
return () => {
|
|
171
|
+
window.removeEventListener("scroll", measure, true);
|
|
172
|
+
window.removeEventListener("resize", measure);
|
|
173
|
+
};
|
|
174
|
+
}, [open]);
|
|
175
|
+
React__namespace.useEffect(() => {
|
|
176
|
+
if (!open) return;
|
|
177
|
+
const handleEscape = (event) => {
|
|
178
|
+
if (event.key === "Escape") {
|
|
179
|
+
clearTimer();
|
|
180
|
+
setOpen(false);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
document.addEventListener("keydown", handleEscape);
|
|
184
|
+
return () => document.removeEventListener("keydown", handleEscape);
|
|
185
|
+
}, [open, setOpen, clearTimer]);
|
|
186
|
+
const value = {
|
|
187
|
+
open,
|
|
188
|
+
setOpen,
|
|
189
|
+
disabled,
|
|
190
|
+
contentId,
|
|
191
|
+
side,
|
|
192
|
+
align,
|
|
193
|
+
anchorRef,
|
|
194
|
+
anchorRect,
|
|
195
|
+
onTriggerPointerEnter,
|
|
196
|
+
onTriggerPointerLeave,
|
|
197
|
+
onTriggerFocus,
|
|
198
|
+
onTriggerBlur
|
|
199
|
+
};
|
|
200
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TooltipContext.Provider, { value, children });
|
|
201
|
+
}
|
|
202
|
+
function TooltipTrigger({
|
|
203
|
+
asChild = false,
|
|
204
|
+
className,
|
|
205
|
+
children,
|
|
206
|
+
ref,
|
|
207
|
+
onPointerEnter,
|
|
208
|
+
onPointerLeave,
|
|
209
|
+
onFocus,
|
|
210
|
+
onBlur,
|
|
211
|
+
...props
|
|
212
|
+
}) {
|
|
213
|
+
const {
|
|
214
|
+
open,
|
|
215
|
+
disabled,
|
|
216
|
+
contentId,
|
|
217
|
+
anchorRef,
|
|
218
|
+
onTriggerPointerEnter,
|
|
219
|
+
onTriggerPointerLeave,
|
|
220
|
+
onTriggerFocus,
|
|
221
|
+
onTriggerBlur
|
|
222
|
+
} = useTooltipContext("Tooltip.Trigger");
|
|
223
|
+
const describedBy = !disabled && open ? contentId : void 0;
|
|
224
|
+
const handlePointerEnter = (event) => {
|
|
225
|
+
onPointerEnter?.(event);
|
|
226
|
+
onTriggerPointerEnter();
|
|
227
|
+
};
|
|
228
|
+
const handlePointerLeave = (event) => {
|
|
229
|
+
onPointerLeave?.(event);
|
|
230
|
+
onTriggerPointerLeave();
|
|
231
|
+
};
|
|
232
|
+
const handleFocus = (event) => {
|
|
233
|
+
onFocus?.(event);
|
|
234
|
+
onTriggerFocus();
|
|
235
|
+
};
|
|
236
|
+
const handleBlur = (event) => {
|
|
237
|
+
onBlur?.(event);
|
|
238
|
+
onTriggerBlur();
|
|
239
|
+
};
|
|
240
|
+
if (asChild) {
|
|
241
|
+
if (!React__namespace.isValidElement(children)) {
|
|
242
|
+
throw new Error(
|
|
243
|
+
"Tooltip.Trigger: `asChild` requires a single React element child"
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
const child = children;
|
|
247
|
+
const childProps = child.props;
|
|
248
|
+
const childHandlers = childProps;
|
|
249
|
+
return React__namespace.cloneElement(
|
|
250
|
+
child,
|
|
251
|
+
{
|
|
252
|
+
...props,
|
|
253
|
+
...childProps,
|
|
254
|
+
"data-slot": "tooltip-trigger",
|
|
255
|
+
"aria-describedby": describedBy,
|
|
256
|
+
onPointerEnter: (event) => {
|
|
257
|
+
childHandlers.onPointerEnter?.(event);
|
|
258
|
+
onPointerEnter?.(event);
|
|
259
|
+
onTriggerPointerEnter();
|
|
260
|
+
},
|
|
261
|
+
onPointerLeave: (event) => {
|
|
262
|
+
childHandlers.onPointerLeave?.(event);
|
|
263
|
+
onPointerLeave?.(event);
|
|
264
|
+
onTriggerPointerLeave();
|
|
265
|
+
},
|
|
266
|
+
onFocus: (event) => {
|
|
267
|
+
childHandlers.onFocus?.(event);
|
|
268
|
+
onFocus?.(event);
|
|
269
|
+
onTriggerFocus();
|
|
270
|
+
},
|
|
271
|
+
onBlur: (event) => {
|
|
272
|
+
childHandlers.onBlur?.(event);
|
|
273
|
+
onBlur?.(event);
|
|
274
|
+
onTriggerBlur();
|
|
275
|
+
},
|
|
276
|
+
className: cn(className, childHandlers.className),
|
|
277
|
+
ref: (node) => {
|
|
278
|
+
anchorRef.current = node;
|
|
279
|
+
setRef(ref, node);
|
|
280
|
+
setRef(childHandlers.ref, node);
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
childProps.children
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
287
|
+
"button",
|
|
288
|
+
{
|
|
289
|
+
...props,
|
|
290
|
+
type: props.type ?? "button",
|
|
291
|
+
"data-slot": "tooltip-trigger",
|
|
292
|
+
"aria-describedby": describedBy,
|
|
293
|
+
className,
|
|
294
|
+
onPointerEnter: handlePointerEnter,
|
|
295
|
+
onPointerLeave: handlePointerLeave,
|
|
296
|
+
onFocus: handleFocus,
|
|
297
|
+
onBlur: handleBlur,
|
|
298
|
+
ref: (node) => {
|
|
299
|
+
anchorRef.current = node;
|
|
300
|
+
setRef(ref, node);
|
|
301
|
+
},
|
|
302
|
+
children
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
function TooltipContent({
|
|
307
|
+
className,
|
|
308
|
+
children,
|
|
309
|
+
style,
|
|
310
|
+
ref,
|
|
311
|
+
...props
|
|
312
|
+
}) {
|
|
313
|
+
const { open, contentId, side, align, anchorRect } = useTooltipContext("Tooltip.Content");
|
|
314
|
+
const contentRef = React__namespace.useRef(null);
|
|
315
|
+
const [placement, setPlacement] = React__namespace.useState(null);
|
|
316
|
+
React__namespace.useLayoutEffect(() => {
|
|
317
|
+
if (!open || anchorRect == null) {
|
|
318
|
+
setPlacement(null);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const node = contentRef.current;
|
|
322
|
+
if (!node) return;
|
|
323
|
+
const rect = node.getBoundingClientRect();
|
|
324
|
+
setPlacement(
|
|
325
|
+
computeTooltipPosition(
|
|
326
|
+
anchorRect,
|
|
327
|
+
{ width: rect.width, height: rect.height },
|
|
328
|
+
side,
|
|
329
|
+
align,
|
|
330
|
+
{ width: window.innerWidth, height: window.innerHeight }
|
|
331
|
+
)
|
|
332
|
+
);
|
|
333
|
+
}, [open, anchorRect, side, align]);
|
|
334
|
+
if (!open) return null;
|
|
335
|
+
const positioned = placement !== null;
|
|
336
|
+
const positionStyle = positioned ? {
|
|
337
|
+
position: "absolute",
|
|
338
|
+
top: placement.top + window.scrollY,
|
|
339
|
+
left: placement.left + window.scrollX,
|
|
340
|
+
zIndex: 50,
|
|
341
|
+
...style
|
|
342
|
+
} : {
|
|
343
|
+
position: "absolute",
|
|
344
|
+
top: 0,
|
|
345
|
+
left: 0,
|
|
346
|
+
visibility: "hidden",
|
|
347
|
+
zIndex: 50,
|
|
348
|
+
...style
|
|
349
|
+
};
|
|
350
|
+
const setContentRef = (node) => {
|
|
351
|
+
contentRef.current = node;
|
|
352
|
+
setRef(ref, node);
|
|
353
|
+
};
|
|
354
|
+
return reactDom.createPortal(
|
|
355
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
356
|
+
"div",
|
|
357
|
+
{
|
|
358
|
+
...props,
|
|
359
|
+
ref: setContentRef,
|
|
360
|
+
role: "tooltip",
|
|
361
|
+
id: contentId,
|
|
362
|
+
"data-slot": "tooltip-content",
|
|
363
|
+
"data-side": positioned ? placement.side : side,
|
|
364
|
+
"data-align": align,
|
|
365
|
+
className: cn(tooltipVariants(), className),
|
|
366
|
+
style: positionStyle,
|
|
367
|
+
children
|
|
368
|
+
}
|
|
369
|
+
),
|
|
370
|
+
document.body
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
var Tooltip = {
|
|
374
|
+
Root: TooltipRoot,
|
|
375
|
+
Trigger: TooltipTrigger,
|
|
376
|
+
Content: TooltipContent
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
exports.Tooltip = Tooltip;
|
|
380
|
+
exports.TooltipContent = TooltipContent;
|
|
381
|
+
exports.TooltipRoot = TooltipRoot;
|
|
382
|
+
exports.TooltipTrigger = TooltipTrigger;
|
|
383
|
+
exports.computeTooltipPosition = computeTooltipPosition;
|
|
384
|
+
exports.tooltipVariants = tooltipVariants;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
3
|
+
|
|
4
|
+
/** Preferred side of the trigger the bubble is placed on. */
|
|
5
|
+
type TooltipSide = "top" | "bottom" | "left" | "right";
|
|
6
|
+
/** Alignment of the bubble along the trigger's edge. */
|
|
7
|
+
type TooltipAlign = "start" | "center" | "end";
|
|
8
|
+
/** The minimal rect shape the placement math needs (a `DOMRect` satisfies it). */
|
|
9
|
+
interface TooltipRect {
|
|
10
|
+
top: number;
|
|
11
|
+
left: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Pure placement math for the portaled bubble. Given the trigger rect, the
|
|
17
|
+
* measured bubble size, the preferred `side`/`align`, and the viewport, returns
|
|
18
|
+
* the viewport-relative `top`/`left` and the RESOLVED `side` (after flip). The
|
|
19
|
+
* caller offsets by `scrollX`/`scrollY` for absolute document coordinates.
|
|
20
|
+
*
|
|
21
|
+
* Rules: place on the preferred `side`; **flip** to the opposite side only when
|
|
22
|
+
* the preferred side overflows the viewport AND the opposite side has room
|
|
23
|
+
* (otherwise keep the preferred side); then clamp the CROSS axis into the
|
|
24
|
+
* viewport so the bubble never bleeds off-screen. The main axis is owned by the
|
|
25
|
+
* side/flip, so only the cross axis is clamped. Kept free of the DOM/React so
|
|
26
|
+
* every branch is unit-testable.
|
|
27
|
+
*/
|
|
28
|
+
declare function computeTooltipPosition(trigger: TooltipRect, content: {
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
}, side: TooltipSide, align: TooltipAlign, viewport: {
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
}): {
|
|
35
|
+
top: number;
|
|
36
|
+
left: number;
|
|
37
|
+
side: TooltipSide;
|
|
38
|
+
};
|
|
39
|
+
interface TooltipRootProps {
|
|
40
|
+
/** Controlled open state. Pair with `onOpenChange`. Omit for uncontrolled. */
|
|
41
|
+
open?: boolean;
|
|
42
|
+
/** Initial open state when uncontrolled. Ignored if `open` is provided. Default `false`. */
|
|
43
|
+
defaultOpen?: boolean;
|
|
44
|
+
/** Called with the next open state from hover/focus/leave/blur/Escape. */
|
|
45
|
+
onOpenChange?: (open: boolean) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Milliseconds a pointer must hover the trigger before the tooltip opens.
|
|
48
|
+
* Default `600`. Keyboard focus opens immediately (no delay).
|
|
49
|
+
*/
|
|
50
|
+
delayDuration?: number;
|
|
51
|
+
/** Preferred side of the trigger to place the bubble on. Default `"top"`. */
|
|
52
|
+
side?: TooltipSide;
|
|
53
|
+
/** Alignment of the bubble along the trigger's edge. Default `"center"`. */
|
|
54
|
+
align?: TooltipAlign;
|
|
55
|
+
/**
|
|
56
|
+
* When `true` the tooltip never opens: the trigger still renders, but no
|
|
57
|
+
* `aria-describedby` is wired and no hover/focus fires an open.
|
|
58
|
+
*/
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
children?: React.ReactNode;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* State owner + context provider for the compound `Tooltip`. Renders no DOM of
|
|
64
|
+
* its own (a fragment) — it only coordinates the trigger and the portaled
|
|
65
|
+
* bubble. Owns the open state (controlled via `open`/`onOpenChange`, or
|
|
66
|
+
* uncontrolled via `defaultOpen`), the hover-open timer, the anchor rect + its
|
|
67
|
+
* reposition listeners, and the Escape-to-close listener.
|
|
68
|
+
*/
|
|
69
|
+
declare function TooltipRoot({ open: openProp, defaultOpen, onOpenChange, delayDuration, side, align, disabled, children, }: TooltipRootProps): React.JSX.Element;
|
|
70
|
+
interface TooltipTriggerProps extends React.ComponentProps<"button"> {
|
|
71
|
+
/**
|
|
72
|
+
* Render the single child element as the trigger instead of a `<button>`, so
|
|
73
|
+
* an existing control (an `IconButton`, `Button`, anchor…) becomes the anchor.
|
|
74
|
+
* The clone pattern: merge `ref`, compose event handlers, merge `className`.
|
|
75
|
+
*/
|
|
76
|
+
asChild?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The anchor the tooltip describes. Renders a native `<button type="button">`
|
|
80
|
+
* by default (focusable, correct semantics), or projects its props/ref onto the
|
|
81
|
+
* single child when `asChild`. Binds the pointer/focus handlers that drive
|
|
82
|
+
* open/close (composed with any consumer handler of the same name) and, while
|
|
83
|
+
* open and not `disabled`, wires `aria-describedby` to the bubble. Registers the
|
|
84
|
+
* anchor node for positioning. Forwards `ref` to the trigger element.
|
|
85
|
+
*/
|
|
86
|
+
declare function TooltipTrigger({ asChild, className, children, ref, onPointerEnter, onPointerLeave, onFocus, onBlur, ...props }: TooltipTriggerProps): React.JSX.Element;
|
|
87
|
+
interface TooltipContentProps extends React.ComponentProps<"div"> {
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The bubble. Portaled to `document.body` via `createPortal` (escaping
|
|
91
|
+
* `overflow`/stacking ancestors, like `SelectListbox`/`DialogContent`), rendered
|
|
92
|
+
* **only while open** — closed, it is removed from the DOM and the a11y tree.
|
|
93
|
+
* Absolutely positioned from the trigger rect via {@link computeTooltipPosition}
|
|
94
|
+
* (preferred side, flips when it would overflow, clamps the cross-axis).
|
|
95
|
+
* `role="tooltip"`; `data-side`/`data-align` reflect the RESOLVED placement.
|
|
96
|
+
*
|
|
97
|
+
* **Content must be non-interactive** — the WAI-ARIA tooltip pattern forbids
|
|
98
|
+
* focusable/interactive content inside a tooltip (there is no accessible way to
|
|
99
|
+
* reach it, and the bubble is `pointer-events-none`). Pass text or decorative
|
|
100
|
+
* `ReactNode` only. Forwards `ref` to the bubble.
|
|
101
|
+
*/
|
|
102
|
+
declare function TooltipContent({ className, children, style, ref, ...props }: TooltipContentProps): React.ReactPortal | null;
|
|
103
|
+
/**
|
|
104
|
+
* Compound tooltip — a small floating label shown on hover (after
|
|
105
|
+
* `delayDuration`) or keyboard focus (immediately), describing its trigger.
|
|
106
|
+
* Assemble from its namespaced parts:
|
|
107
|
+
*
|
|
108
|
+
* ```tsx
|
|
109
|
+
* <Tooltip.Root side="top">
|
|
110
|
+
* <Tooltip.Trigger asChild>
|
|
111
|
+
* <IconButton aria-label="Info" />
|
|
112
|
+
* </Tooltip.Trigger>
|
|
113
|
+
* <Tooltip.Content>Explanatory text</Tooltip.Content>
|
|
114
|
+
* </Tooltip.Root>
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
declare const Tooltip: {
|
|
118
|
+
Root: typeof TooltipRoot;
|
|
119
|
+
Trigger: typeof TooltipTrigger;
|
|
120
|
+
Content: typeof TooltipContent;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Tooltip bubble styling — the Figma `Tooltip` (node `5153:4063`). Binds ONLY to
|
|
125
|
+
* the semantic token layer (never primitives); theme switching is automatic via
|
|
126
|
+
* `.dark`, so no `dark:` variants.
|
|
127
|
+
*
|
|
128
|
+
* The surface is the fixed dark "reversed" card — the SAME utilities
|
|
129
|
+
* `toastVariants.ts` binds (`bg-card-reversed-background` /
|
|
130
|
+
* `text-card-reversed-foreground`) — so the two dark surfaces stay in lock-step.
|
|
131
|
+
* There is no `variation`/`size` axis (the Figma frame shows a single bubble),
|
|
132
|
+
* and no arrow/caret element (absent from Figma).
|
|
133
|
+
*
|
|
134
|
+
* `max-w-[244px]` is the one allowed arbitrary value: it is the Figma-exact wrap
|
|
135
|
+
* boundary (long text wraps; the sample's single-word `whitespace-nowrap` is a
|
|
136
|
+
* content artifact and is intentionally NOT carried over). `pointer-events-none`
|
|
137
|
+
* is intrinsic — the bubble is descriptive, never interactive, so it can never
|
|
138
|
+
* steal the pointer or cause a hover-leave flicker.
|
|
139
|
+
*/
|
|
140
|
+
declare const tooltipVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
|
|
141
|
+
|
|
142
|
+
export { Tooltip, type TooltipAlign, TooltipContent, type TooltipContentProps, type TooltipRect, TooltipRoot, type TooltipRootProps, type TooltipSide, TooltipTrigger, type TooltipTriggerProps, computeTooltipPosition, tooltipVariants };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
3
|
+
|
|
4
|
+
/** Preferred side of the trigger the bubble is placed on. */
|
|
5
|
+
type TooltipSide = "top" | "bottom" | "left" | "right";
|
|
6
|
+
/** Alignment of the bubble along the trigger's edge. */
|
|
7
|
+
type TooltipAlign = "start" | "center" | "end";
|
|
8
|
+
/** The minimal rect shape the placement math needs (a `DOMRect` satisfies it). */
|
|
9
|
+
interface TooltipRect {
|
|
10
|
+
top: number;
|
|
11
|
+
left: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Pure placement math for the portaled bubble. Given the trigger rect, the
|
|
17
|
+
* measured bubble size, the preferred `side`/`align`, and the viewport, returns
|
|
18
|
+
* the viewport-relative `top`/`left` and the RESOLVED `side` (after flip). The
|
|
19
|
+
* caller offsets by `scrollX`/`scrollY` for absolute document coordinates.
|
|
20
|
+
*
|
|
21
|
+
* Rules: place on the preferred `side`; **flip** to the opposite side only when
|
|
22
|
+
* the preferred side overflows the viewport AND the opposite side has room
|
|
23
|
+
* (otherwise keep the preferred side); then clamp the CROSS axis into the
|
|
24
|
+
* viewport so the bubble never bleeds off-screen. The main axis is owned by the
|
|
25
|
+
* side/flip, so only the cross axis is clamped. Kept free of the DOM/React so
|
|
26
|
+
* every branch is unit-testable.
|
|
27
|
+
*/
|
|
28
|
+
declare function computeTooltipPosition(trigger: TooltipRect, content: {
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
}, side: TooltipSide, align: TooltipAlign, viewport: {
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
}): {
|
|
35
|
+
top: number;
|
|
36
|
+
left: number;
|
|
37
|
+
side: TooltipSide;
|
|
38
|
+
};
|
|
39
|
+
interface TooltipRootProps {
|
|
40
|
+
/** Controlled open state. Pair with `onOpenChange`. Omit for uncontrolled. */
|
|
41
|
+
open?: boolean;
|
|
42
|
+
/** Initial open state when uncontrolled. Ignored if `open` is provided. Default `false`. */
|
|
43
|
+
defaultOpen?: boolean;
|
|
44
|
+
/** Called with the next open state from hover/focus/leave/blur/Escape. */
|
|
45
|
+
onOpenChange?: (open: boolean) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Milliseconds a pointer must hover the trigger before the tooltip opens.
|
|
48
|
+
* Default `600`. Keyboard focus opens immediately (no delay).
|
|
49
|
+
*/
|
|
50
|
+
delayDuration?: number;
|
|
51
|
+
/** Preferred side of the trigger to place the bubble on. Default `"top"`. */
|
|
52
|
+
side?: TooltipSide;
|
|
53
|
+
/** Alignment of the bubble along the trigger's edge. Default `"center"`. */
|
|
54
|
+
align?: TooltipAlign;
|
|
55
|
+
/**
|
|
56
|
+
* When `true` the tooltip never opens: the trigger still renders, but no
|
|
57
|
+
* `aria-describedby` is wired and no hover/focus fires an open.
|
|
58
|
+
*/
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
children?: React.ReactNode;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* State owner + context provider for the compound `Tooltip`. Renders no DOM of
|
|
64
|
+
* its own (a fragment) — it only coordinates the trigger and the portaled
|
|
65
|
+
* bubble. Owns the open state (controlled via `open`/`onOpenChange`, or
|
|
66
|
+
* uncontrolled via `defaultOpen`), the hover-open timer, the anchor rect + its
|
|
67
|
+
* reposition listeners, and the Escape-to-close listener.
|
|
68
|
+
*/
|
|
69
|
+
declare function TooltipRoot({ open: openProp, defaultOpen, onOpenChange, delayDuration, side, align, disabled, children, }: TooltipRootProps): React.JSX.Element;
|
|
70
|
+
interface TooltipTriggerProps extends React.ComponentProps<"button"> {
|
|
71
|
+
/**
|
|
72
|
+
* Render the single child element as the trigger instead of a `<button>`, so
|
|
73
|
+
* an existing control (an `IconButton`, `Button`, anchor…) becomes the anchor.
|
|
74
|
+
* The clone pattern: merge `ref`, compose event handlers, merge `className`.
|
|
75
|
+
*/
|
|
76
|
+
asChild?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The anchor the tooltip describes. Renders a native `<button type="button">`
|
|
80
|
+
* by default (focusable, correct semantics), or projects its props/ref onto the
|
|
81
|
+
* single child when `asChild`. Binds the pointer/focus handlers that drive
|
|
82
|
+
* open/close (composed with any consumer handler of the same name) and, while
|
|
83
|
+
* open and not `disabled`, wires `aria-describedby` to the bubble. Registers the
|
|
84
|
+
* anchor node for positioning. Forwards `ref` to the trigger element.
|
|
85
|
+
*/
|
|
86
|
+
declare function TooltipTrigger({ asChild, className, children, ref, onPointerEnter, onPointerLeave, onFocus, onBlur, ...props }: TooltipTriggerProps): React.JSX.Element;
|
|
87
|
+
interface TooltipContentProps extends React.ComponentProps<"div"> {
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The bubble. Portaled to `document.body` via `createPortal` (escaping
|
|
91
|
+
* `overflow`/stacking ancestors, like `SelectListbox`/`DialogContent`), rendered
|
|
92
|
+
* **only while open** — closed, it is removed from the DOM and the a11y tree.
|
|
93
|
+
* Absolutely positioned from the trigger rect via {@link computeTooltipPosition}
|
|
94
|
+
* (preferred side, flips when it would overflow, clamps the cross-axis).
|
|
95
|
+
* `role="tooltip"`; `data-side`/`data-align` reflect the RESOLVED placement.
|
|
96
|
+
*
|
|
97
|
+
* **Content must be non-interactive** — the WAI-ARIA tooltip pattern forbids
|
|
98
|
+
* focusable/interactive content inside a tooltip (there is no accessible way to
|
|
99
|
+
* reach it, and the bubble is `pointer-events-none`). Pass text or decorative
|
|
100
|
+
* `ReactNode` only. Forwards `ref` to the bubble.
|
|
101
|
+
*/
|
|
102
|
+
declare function TooltipContent({ className, children, style, ref, ...props }: TooltipContentProps): React.ReactPortal | null;
|
|
103
|
+
/**
|
|
104
|
+
* Compound tooltip — a small floating label shown on hover (after
|
|
105
|
+
* `delayDuration`) or keyboard focus (immediately), describing its trigger.
|
|
106
|
+
* Assemble from its namespaced parts:
|
|
107
|
+
*
|
|
108
|
+
* ```tsx
|
|
109
|
+
* <Tooltip.Root side="top">
|
|
110
|
+
* <Tooltip.Trigger asChild>
|
|
111
|
+
* <IconButton aria-label="Info" />
|
|
112
|
+
* </Tooltip.Trigger>
|
|
113
|
+
* <Tooltip.Content>Explanatory text</Tooltip.Content>
|
|
114
|
+
* </Tooltip.Root>
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
declare const Tooltip: {
|
|
118
|
+
Root: typeof TooltipRoot;
|
|
119
|
+
Trigger: typeof TooltipTrigger;
|
|
120
|
+
Content: typeof TooltipContent;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Tooltip bubble styling — the Figma `Tooltip` (node `5153:4063`). Binds ONLY to
|
|
125
|
+
* the semantic token layer (never primitives); theme switching is automatic via
|
|
126
|
+
* `.dark`, so no `dark:` variants.
|
|
127
|
+
*
|
|
128
|
+
* The surface is the fixed dark "reversed" card — the SAME utilities
|
|
129
|
+
* `toastVariants.ts` binds (`bg-card-reversed-background` /
|
|
130
|
+
* `text-card-reversed-foreground`) — so the two dark surfaces stay in lock-step.
|
|
131
|
+
* There is no `variation`/`size` axis (the Figma frame shows a single bubble),
|
|
132
|
+
* and no arrow/caret element (absent from Figma).
|
|
133
|
+
*
|
|
134
|
+
* `max-w-[244px]` is the one allowed arbitrary value: it is the Figma-exact wrap
|
|
135
|
+
* boundary (long text wraps; the sample's single-word `whitespace-nowrap` is a
|
|
136
|
+
* content artifact and is intentionally NOT carried over). `pointer-events-none`
|
|
137
|
+
* is intrinsic — the bubble is descriptive, never interactive, so it can never
|
|
138
|
+
* steal the pointer or cause a hover-leave flicker.
|
|
139
|
+
*/
|
|
140
|
+
declare const tooltipVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
|
|
141
|
+
|
|
142
|
+
export { Tooltip, type TooltipAlign, TooltipContent, type TooltipContentProps, type TooltipRect, TooltipRoot, type TooltipRootProps, type TooltipSide, TooltipTrigger, type TooltipTriggerProps, computeTooltipPosition, tooltipVariants };
|
package/dist/tooltip.js
ADDED