@mindlogic-ai/logician-ui 3.1.0-alpha.8 → 3.1.0-alpha.9
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/dist/components/InfoSprinkle/InfoSprinkle.d.ts +1 -1
- package/dist/components/InfoSprinkle/InfoSprinkle.d.ts.map +1 -1
- package/dist/components/InfoSprinkle/InfoSprinkle.js +25 -2
- package/dist/components/InfoSprinkle/InfoSprinkle.js.map +1 -1
- package/dist/components/InfoSprinkle/InfoSprinkle.mjs +25 -2
- package/dist/components/InfoSprinkle/InfoSprinkle.mjs.map +1 -1
- package/dist/hooks/useHasHover.d.ts +13 -0
- package/dist/hooks/useHasHover.d.ts.map +1 -0
- package/dist/hooks/useHasHover.js +34 -0
- package/dist/hooks/useHasHover.js.map +1 -0
- package/dist/hooks/useHasHover.mjs +29 -0
- package/dist/hooks/useHasHover.mjs.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/InfoSprinkle/InfoSprinkle.tsx +32 -0
- package/src/hooks/useHasHover.ts +32 -0
- package/src/index.ts +1 -0
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { InfoSprinkleProps } from './InfoSprinkle.types';
|
|
2
|
-
export declare const InfoSprinkle: ({ children, iconButtonProps, contentProps, baseFontSize, ...rest }: InfoSprinkleProps) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare const InfoSprinkle: ({ children, iconButtonProps, contentProps, baseFontSize, open: openProp, defaultOpen, onOpenChange, ...rest }: InfoSprinkleProps) => import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
//# sourceMappingURL=InfoSprinkle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfoSprinkle.d.ts","sourceRoot":"","sources":["../../../src/components/InfoSprinkle/InfoSprinkle.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InfoSprinkle.d.ts","sourceRoot":"","sources":["../../../src/components/InfoSprinkle/InfoSprinkle.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,eAAO,MAAM,YAAY,GAAI,+GAS1B,iBAAiB,4CA4DnB,CAAC"}
|
|
@@ -2,14 +2,37 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var React = require('react');
|
|
5
6
|
var react = require('@chakra-ui/react');
|
|
7
|
+
var useHasHover = require('../../hooks/useHasHover.js');
|
|
6
8
|
var index = require('../Icon/index.js');
|
|
7
9
|
var IconButton = require('../IconButton/IconButton.js');
|
|
8
10
|
require('../IconButton/IconButton.styles.js');
|
|
9
11
|
var ScaledContext = require('../ScaledContext/ScaledContext.js');
|
|
10
12
|
|
|
11
|
-
const InfoSprinkle = ({ children, iconButtonProps, contentProps, baseFontSize = '14px', ...rest }) => {
|
|
12
|
-
|
|
13
|
+
const InfoSprinkle = ({ children, iconButtonProps, contentProps, baseFontSize = '14px', open: openProp, defaultOpen, onOpenChange, ...rest }) => {
|
|
14
|
+
// HoverCard (zag-js) opens on mouse hover and on focus, but its pointer
|
|
15
|
+
// handlers ignore `pointerType: 'touch'`. Browsers that focus the trigger on
|
|
16
|
+
// tap (e.g. Android Chrome) therefore open it for free, but those that don't
|
|
17
|
+
// focus buttons on tap (e.g. iOS Safari) never open it. To cover both, on
|
|
18
|
+
// non-hover devices we open the card on tap. Closing stays with the machine's
|
|
19
|
+
// own dismissal (tap-outside / blur), and opening is idempotent with the
|
|
20
|
+
// focus-open path so it doesn't fight devices that already open on tap.
|
|
21
|
+
const hasHover = useHasHover.useHasHover();
|
|
22
|
+
const [internalOpen, setInternalOpen] = React.useState(defaultOpen ?? false);
|
|
23
|
+
const isControlled = openProp !== undefined;
|
|
24
|
+
const open = isControlled ? openProp : internalOpen;
|
|
25
|
+
const setOpen = (next) => {
|
|
26
|
+
if (!isControlled)
|
|
27
|
+
setInternalOpen(next);
|
|
28
|
+
onOpenChange?.({ open: next });
|
|
29
|
+
};
|
|
30
|
+
return (jsxRuntime.jsxs(react.HoverCard.Root, { positioning: { placement: 'top' }, openDelay: 0, closeDelay: 0, lazyMount: true, open: open, onOpenChange: (e) => setOpen(e.open), ...rest, children: [jsxRuntime.jsx(react.HoverCard.Trigger, { asChild: true, children: jsxRuntime.jsx(IconButton.IconButton, { "aria-label": "Info", opacity: 0.5, transition: "opacity 0.2s", _hover: { opacity: 1, ...iconButtonProps?._hover }, ...iconButtonProps, onClick: (e) => {
|
|
31
|
+
// On non-hover (touch) devices, tapping opens the card.
|
|
32
|
+
if (!hasHover)
|
|
33
|
+
setOpen(true);
|
|
34
|
+
iconButtonProps?.onClick?.(e);
|
|
35
|
+
}, children: jsxRuntime.jsx(index.LuInfo, { color: iconButtonProps?.color ?? 'fg.muted', boxSize: iconButtonProps?.size ?? 'xs' }) }) }), jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.HoverCard.Positioner, { children: jsxRuntime.jsxs(react.HoverCard.Content, { p: 2, ...contentProps, children: [jsxRuntime.jsx(react.HoverCard.Arrow, { children: jsxRuntime.jsx(react.HoverCard.ArrowTip, {}) }), jsxRuntime.jsx(ScaledContext.ScaledContext, { fontSize: baseFontSize, children: children })] }) }) })] }));
|
|
13
36
|
};
|
|
14
37
|
|
|
15
38
|
exports.InfoSprinkle = InfoSprinkle;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfoSprinkle.js","sources":["../../../src/components/InfoSprinkle/InfoSprinkle.tsx"],"sourcesContent":[null],"names":["_jsxs","HoverCard","_jsx","IconButton","LuInfo","Portal","ScaledContext"],"mappings":"
|
|
1
|
+
{"version":3,"file":"InfoSprinkle.js","sources":["../../../src/components/InfoSprinkle/InfoSprinkle.tsx"],"sourcesContent":[null],"names":["useHasHover","useState","_jsxs","HoverCard","_jsx","IconButton","LuInfo","Portal","ScaledContext"],"mappings":";;;;;;;;;;;;AAWO,MAAM,YAAY,GAAG,CAAC,EAC3B,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,YAAY,GAAG,MAAM,EACrB,IAAI,EAAE,QAAQ,EACd,WAAW,EACX,YAAY,EACZ,GAAG,IAAI,EACW,KAAI;;;;;;;;AAQtB,IAAA,MAAM,QAAQ,GAAGA,uBAAW,EAAE;AAC9B,IAAA,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAGC,cAAQ,CAAC,WAAW,IAAI,KAAK,CAAC;AAEtE,IAAA,MAAM,YAAY,GAAG,QAAQ,KAAK,SAAS;IAC3C,MAAM,IAAI,GAAG,YAAY,GAAG,QAAQ,GAAG,YAAY;AAEnD,IAAA,MAAM,OAAO,GAAG,CAAC,IAAa,KAAI;AAChC,QAAA,IAAI,CAAC,YAAY;YAAE,eAAe,CAAC,IAAI,CAAC;QACxC,YAAY,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAChC,IAAA,CAAC;AAED,IAAA,QACEC,eAAA,CAACC,eAAS,CAAC,IAAI,EAAA,EACb,WAAW,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EACjC,SAAS,EAAE,CAAC,EACZ,UAAU,EAAE,CAAC,EACb,SAAS,EAAA,IAAA,EACT,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAA,GAChC,IAAI,EAAA,QAAA,EAAA,CAERC,eAACD,eAAS,CAAC,OAAO,EAAA,EAAC,OAAO,kBACxBC,cAAA,CAACC,qBAAU,EAAA,EAAA,YAAA,EACE,MAAM,EACjB,OAAO,EAAE,GAAG,EACZ,UAAU,EAAC,cAAc,EACzB,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,GAAI,eAAe,EAAE,MAAc,EAAE,EAAA,GACvD,eAAe,EACnB,OAAO,EAAE,CAAC,CAAC,KAAI;;AAEb,wBAAA,IAAI,CAAC,QAAQ;4BAAE,OAAO,CAAC,IAAI,CAAC;AAC5B,wBAAA,eAAe,EAAE,OAAO,GAAG,CAAC,CAAC;AAC/B,oBAAA,CAAC,EAAA,QAAA,EAEDD,cAAA,CAACE,YAAM,EAAA,EACL,KAAK,EAAG,eAAe,EAAE,KAAgB,IAAI,UAAU,EACvD,OAAO,EAAE,eAAe,EAAE,IAAI,IAAI,IAAI,EAAA,CACtC,EAAA,CACS,EAAA,CACK,EACpBF,cAAA,CAACG,YAAM,EAAA,EAAA,QAAA,EACLH,cAAA,CAACD,eAAS,CAAC,UAAU,EAAA,EAAA,QAAA,EACnBD,gBAACC,eAAS,CAAC,OAAO,EAAA,EAAC,CAAC,EAAE,CAAC,EAAA,GAAM,YAAY,EAAA,QAAA,EAAA,CACvCC,cAAA,CAACD,eAAS,CAAC,KAAK,EAAA,EAAA,QAAA,EACdC,cAAA,CAACD,eAAS,CAAC,QAAQ,EAAA,EAAA,CAAG,EAAA,CACN,EAClBC,cAAA,CAACI,2BAAa,EAAA,EAAC,QAAQ,EAAE,YAAY,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAiB,CAAA,EAAA,CAC/C,EAAA,CACC,EAAA,CAChB,CAAA,EAAA,CACM;AAErB;;;;"}
|
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { useState } from 'react';
|
|
3
4
|
import { HoverCard, Portal } from '@chakra-ui/react';
|
|
5
|
+
import { useHasHover } from '../../hooks/useHasHover.mjs';
|
|
4
6
|
import { LuInfo } from '../Icon/index.mjs';
|
|
5
7
|
import { IconButton } from '../IconButton/IconButton.mjs';
|
|
6
8
|
import '../IconButton/IconButton.styles.mjs';
|
|
7
9
|
import { ScaledContext } from '../ScaledContext/ScaledContext.mjs';
|
|
8
10
|
|
|
9
|
-
const InfoSprinkle = ({ children, iconButtonProps, contentProps, baseFontSize = '14px', ...rest }) => {
|
|
10
|
-
|
|
11
|
+
const InfoSprinkle = ({ children, iconButtonProps, contentProps, baseFontSize = '14px', open: openProp, defaultOpen, onOpenChange, ...rest }) => {
|
|
12
|
+
// HoverCard (zag-js) opens on mouse hover and on focus, but its pointer
|
|
13
|
+
// handlers ignore `pointerType: 'touch'`. Browsers that focus the trigger on
|
|
14
|
+
// tap (e.g. Android Chrome) therefore open it for free, but those that don't
|
|
15
|
+
// focus buttons on tap (e.g. iOS Safari) never open it. To cover both, on
|
|
16
|
+
// non-hover devices we open the card on tap. Closing stays with the machine's
|
|
17
|
+
// own dismissal (tap-outside / blur), and opening is idempotent with the
|
|
18
|
+
// focus-open path so it doesn't fight devices that already open on tap.
|
|
19
|
+
const hasHover = useHasHover();
|
|
20
|
+
const [internalOpen, setInternalOpen] = useState(defaultOpen ?? false);
|
|
21
|
+
const isControlled = openProp !== undefined;
|
|
22
|
+
const open = isControlled ? openProp : internalOpen;
|
|
23
|
+
const setOpen = (next) => {
|
|
24
|
+
if (!isControlled)
|
|
25
|
+
setInternalOpen(next);
|
|
26
|
+
onOpenChange?.({ open: next });
|
|
27
|
+
};
|
|
28
|
+
return (jsxs(HoverCard.Root, { positioning: { placement: 'top' }, openDelay: 0, closeDelay: 0, lazyMount: true, open: open, onOpenChange: (e) => setOpen(e.open), ...rest, children: [jsx(HoverCard.Trigger, { asChild: true, children: jsx(IconButton, { "aria-label": "Info", opacity: 0.5, transition: "opacity 0.2s", _hover: { opacity: 1, ...iconButtonProps?._hover }, ...iconButtonProps, onClick: (e) => {
|
|
29
|
+
// On non-hover (touch) devices, tapping opens the card.
|
|
30
|
+
if (!hasHover)
|
|
31
|
+
setOpen(true);
|
|
32
|
+
iconButtonProps?.onClick?.(e);
|
|
33
|
+
}, children: jsx(LuInfo, { color: iconButtonProps?.color ?? 'fg.muted', boxSize: iconButtonProps?.size ?? 'xs' }) }) }), jsx(Portal, { children: jsx(HoverCard.Positioner, { children: jsxs(HoverCard.Content, { p: 2, ...contentProps, children: [jsx(HoverCard.Arrow, { children: jsx(HoverCard.ArrowTip, {}) }), jsx(ScaledContext, { fontSize: baseFontSize, children: children })] }) }) })] }));
|
|
11
34
|
};
|
|
12
35
|
|
|
13
36
|
export { InfoSprinkle };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfoSprinkle.mjs","sources":["../../../src/components/InfoSprinkle/InfoSprinkle.tsx"],"sourcesContent":[null],"names":["_jsxs","_jsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"InfoSprinkle.mjs","sources":["../../../src/components/InfoSprinkle/InfoSprinkle.tsx"],"sourcesContent":[null],"names":["_jsxs","_jsx"],"mappings":";;;;;;;;;;AAWO,MAAM,YAAY,GAAG,CAAC,EAC3B,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,YAAY,GAAG,MAAM,EACrB,IAAI,EAAE,QAAQ,EACd,WAAW,EACX,YAAY,EACZ,GAAG,IAAI,EACW,KAAI;;;;;;;;AAQtB,IAAA,MAAM,QAAQ,GAAG,WAAW,EAAE;AAC9B,IAAA,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,WAAW,IAAI,KAAK,CAAC;AAEtE,IAAA,MAAM,YAAY,GAAG,QAAQ,KAAK,SAAS;IAC3C,MAAM,IAAI,GAAG,YAAY,GAAG,QAAQ,GAAG,YAAY;AAEnD,IAAA,MAAM,OAAO,GAAG,CAAC,IAAa,KAAI;AAChC,QAAA,IAAI,CAAC,YAAY;YAAE,eAAe,CAAC,IAAI,CAAC;QACxC,YAAY,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAChC,IAAA,CAAC;AAED,IAAA,QACEA,IAAA,CAAC,SAAS,CAAC,IAAI,EAAA,EACb,WAAW,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EACjC,SAAS,EAAE,CAAC,EACZ,UAAU,EAAE,CAAC,EACb,SAAS,EAAA,IAAA,EACT,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAA,GAChC,IAAI,EAAA,QAAA,EAAA,CAERC,IAAC,SAAS,CAAC,OAAO,EAAA,EAAC,OAAO,kBACxBA,GAAA,CAAC,UAAU,EAAA,EAAA,YAAA,EACE,MAAM,EACjB,OAAO,EAAE,GAAG,EACZ,UAAU,EAAC,cAAc,EACzB,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,GAAI,eAAe,EAAE,MAAc,EAAE,EAAA,GACvD,eAAe,EACnB,OAAO,EAAE,CAAC,CAAC,KAAI;;AAEb,wBAAA,IAAI,CAAC,QAAQ;4BAAE,OAAO,CAAC,IAAI,CAAC;AAC5B,wBAAA,eAAe,EAAE,OAAO,GAAG,CAAC,CAAC;AAC/B,oBAAA,CAAC,EAAA,QAAA,EAEDA,GAAA,CAAC,MAAM,EAAA,EACL,KAAK,EAAG,eAAe,EAAE,KAAgB,IAAI,UAAU,EACvD,OAAO,EAAE,eAAe,EAAE,IAAI,IAAI,IAAI,EAAA,CACtC,EAAA,CACS,EAAA,CACK,EACpBA,GAAA,CAAC,MAAM,EAAA,EAAA,QAAA,EACLA,GAAA,CAAC,SAAS,CAAC,UAAU,EAAA,EAAA,QAAA,EACnBD,KAAC,SAAS,CAAC,OAAO,EAAA,EAAC,CAAC,EAAE,CAAC,EAAA,GAAM,YAAY,EAAA,QAAA,EAAA,CACvCC,GAAA,CAAC,SAAS,CAAC,KAAK,EAAA,EAAA,QAAA,EACdA,GAAA,CAAC,SAAS,CAAC,QAAQ,EAAA,EAAA,CAAG,EAAA,CACN,EAClBA,GAAA,CAAC,aAAa,EAAA,EAAC,QAAQ,EAAE,YAAY,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAiB,CAAA,EAAA,CAC/C,EAAA,CACC,EAAA,CAChB,CAAA,EAAA,CACM;AAErB;;;;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns whether the primary pointing device is capable of hovering
|
|
3
|
+
* (i.e. a mouse/trackpad rather than a touchscreen).
|
|
4
|
+
*
|
|
5
|
+
* Useful for components that rely on hover interactions on desktop but need a
|
|
6
|
+
* tap/click affordance on touch devices, where hover events never fire.
|
|
7
|
+
*
|
|
8
|
+
* Defaults to `true` so server-rendered markup matches the most common
|
|
9
|
+
* (desktop) case, then resolves to the real value after mount.
|
|
10
|
+
*/
|
|
11
|
+
export declare const useHasHover: () => boolean;
|
|
12
|
+
export default useHasHover;
|
|
13
|
+
//# sourceMappingURL=useHasHover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useHasHover.d.ts","sourceRoot":"","sources":["../../src/hooks/useHasHover.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,eAevB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
6
|
+
var React = require('react');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns whether the primary pointing device is capable of hovering
|
|
10
|
+
* (i.e. a mouse/trackpad rather than a touchscreen).
|
|
11
|
+
*
|
|
12
|
+
* Useful for components that rely on hover interactions on desktop but need a
|
|
13
|
+
* tap/click affordance on touch devices, where hover events never fire.
|
|
14
|
+
*
|
|
15
|
+
* Defaults to `true` so server-rendered markup matches the most common
|
|
16
|
+
* (desktop) case, then resolves to the real value after mount.
|
|
17
|
+
*/
|
|
18
|
+
const useHasHover = () => {
|
|
19
|
+
const [hasHover, setHasHover] = React.useState(true);
|
|
20
|
+
React.useEffect(() => {
|
|
21
|
+
if (typeof window === 'undefined' || !window.matchMedia)
|
|
22
|
+
return;
|
|
23
|
+
const mql = window.matchMedia('(hover: hover)');
|
|
24
|
+
const update = () => setHasHover(mql.matches);
|
|
25
|
+
update();
|
|
26
|
+
mql.addEventListener('change', update);
|
|
27
|
+
return () => mql.removeEventListener('change', update);
|
|
28
|
+
}, []);
|
|
29
|
+
return hasHover;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
exports.default = useHasHover;
|
|
33
|
+
exports.useHasHover = useHasHover;
|
|
34
|
+
//# sourceMappingURL=useHasHover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useHasHover.js","sources":["../../src/hooks/useHasHover.ts"],"sourcesContent":[null],"names":["useState","useEffect"],"mappings":";;;;;;;AAIA;;;;;;;;;AASG;AACI,MAAM,WAAW,GAAG,MAAK;IAC9B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAGA,cAAQ,CAAC,IAAI,CAAC;IAE9CC,eAAS,CAAC,MAAK;QACb,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU;YAAE;QAEzD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC;AAE7C,QAAA,MAAM,EAAE;AACR,QAAA,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC;QACtC,OAAO,MAAM,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC;IACxD,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,OAAO,QAAQ;AACjB;;;;;"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns whether the primary pointing device is capable of hovering
|
|
6
|
+
* (i.e. a mouse/trackpad rather than a touchscreen).
|
|
7
|
+
*
|
|
8
|
+
* Useful for components that rely on hover interactions on desktop but need a
|
|
9
|
+
* tap/click affordance on touch devices, where hover events never fire.
|
|
10
|
+
*
|
|
11
|
+
* Defaults to `true` so server-rendered markup matches the most common
|
|
12
|
+
* (desktop) case, then resolves to the real value after mount.
|
|
13
|
+
*/
|
|
14
|
+
const useHasHover = () => {
|
|
15
|
+
const [hasHover, setHasHover] = useState(true);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (typeof window === 'undefined' || !window.matchMedia)
|
|
18
|
+
return;
|
|
19
|
+
const mql = window.matchMedia('(hover: hover)');
|
|
20
|
+
const update = () => setHasHover(mql.matches);
|
|
21
|
+
update();
|
|
22
|
+
mql.addEventListener('change', update);
|
|
23
|
+
return () => mql.removeEventListener('change', update);
|
|
24
|
+
}, []);
|
|
25
|
+
return hasHover;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export { useHasHover as default, useHasHover };
|
|
29
|
+
//# sourceMappingURL=useHasHover.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useHasHover.mjs","sources":["../../src/hooks/useHasHover.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAIA;;;;;;;;;AASG;AACI,MAAM,WAAW,GAAG,MAAK;IAC9B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC;IAE9C,SAAS,CAAC,MAAK;QACb,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU;YAAE;QAEzD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC;AAE7C,QAAA,MAAM,EAAE;AACR,QAAA,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC;QACtC,OAAO,MAAM,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC;IACxD,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,OAAO,QAAQ;AACjB;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,7 @@ export * from './components/Textarea';
|
|
|
61
61
|
export * from './components/Toast';
|
|
62
62
|
export * from './components/Tooltip';
|
|
63
63
|
export { H1, H2, H3, H4, H5, Link, Subtext, Subtitle, Text, } from './components/Typography';
|
|
64
|
+
export { useHasHover } from './hooks/useHasHover';
|
|
64
65
|
export type { LanguageContextValue } from './hooks/useLanguage';
|
|
65
66
|
export { LanguageContext, useLanguage } from './hooks/useLanguage';
|
|
66
67
|
export { logicianConfig, system, theme } from './theme';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAG5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AAGvC,YAAY,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AACrE,cAAc,yBAAyB,CAAC;AAGxC,YAAY,EACV,WAAW,EACX,SAAS,IAAI,eAAe,GAC7B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAG3E,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AAGxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AAGtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAG5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AAErC,OAAO,EACL,EAAE,EACF,EAAE,EACF,EAAE,EACF,EAAE,EACF,EAAE,EACF,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,IAAI,GACL,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGnE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAG5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AAGvC,YAAY,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AACrE,cAAc,yBAAyB,CAAC;AAGxC,YAAY,EACV,WAAW,EACX,SAAS,IAAI,eAAe,GAC7B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAG3E,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AAGxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AAGtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAG5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AAErC,OAAO,EACL,EAAE,EACF,EAAE,EACF,EAAE,EACF,EAAE,EACF,EAAE,EACF,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,IAAI,GACL,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGnE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -127,6 +127,7 @@ var Link = require('./components/Typography/Link.js');
|
|
|
127
127
|
var Subtext = require('./components/Typography/Subtext.js');
|
|
128
128
|
var Subtitle = require('./components/Typography/Subtitle.js');
|
|
129
129
|
var Text = require('./components/Typography/Text.js');
|
|
130
|
+
var useHasHover = require('./hooks/useHasHover.js');
|
|
130
131
|
var useLanguage = require('./hooks/useLanguage.js');
|
|
131
132
|
var index = require('./theme/index.js');
|
|
132
133
|
|
|
@@ -299,6 +300,7 @@ exports.Link = Link.Link;
|
|
|
299
300
|
exports.Subtext = Subtext.Subtext;
|
|
300
301
|
exports.Subtitle = Subtitle.Subtitle;
|
|
301
302
|
exports.Text = Text.Text;
|
|
303
|
+
exports.useHasHover = useHasHover.useHasHover;
|
|
302
304
|
exports.LanguageContext = useLanguage.LanguageContext;
|
|
303
305
|
exports.useLanguage = useLanguage.useLanguage;
|
|
304
306
|
exports.logicianConfig = index.logicianConfig;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.mjs
CHANGED
|
@@ -125,6 +125,7 @@ export { Link } from './components/Typography/Link.mjs';
|
|
|
125
125
|
export { Subtext } from './components/Typography/Subtext.mjs';
|
|
126
126
|
export { Subtitle } from './components/Typography/Subtitle.mjs';
|
|
127
127
|
export { Text } from './components/Typography/Text.mjs';
|
|
128
|
+
export { useHasHover } from './hooks/useHasHover.mjs';
|
|
128
129
|
export { LanguageContext, useLanguage } from './hooks/useLanguage.mjs';
|
|
129
130
|
export { logicianConfig, system, theme } from './theme/index.mjs';
|
|
130
131
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
1
4
|
import { HoverCard, Portal } from '@chakra-ui/react';
|
|
2
5
|
|
|
6
|
+
import { useHasHover } from '../../hooks/useHasHover';
|
|
3
7
|
import { LuInfo } from '../Icon';
|
|
4
8
|
import { IconButton } from '../IconButton';
|
|
5
9
|
import { ScaledContext } from '../ScaledContext';
|
|
@@ -10,14 +14,37 @@ export const InfoSprinkle = ({
|
|
|
10
14
|
iconButtonProps,
|
|
11
15
|
contentProps,
|
|
12
16
|
baseFontSize = '14px',
|
|
17
|
+
open: openProp,
|
|
18
|
+
defaultOpen,
|
|
19
|
+
onOpenChange,
|
|
13
20
|
...rest
|
|
14
21
|
}: InfoSprinkleProps) => {
|
|
22
|
+
// HoverCard (zag-js) opens on mouse hover and on focus, but its pointer
|
|
23
|
+
// handlers ignore `pointerType: 'touch'`. Browsers that focus the trigger on
|
|
24
|
+
// tap (e.g. Android Chrome) therefore open it for free, but those that don't
|
|
25
|
+
// focus buttons on tap (e.g. iOS Safari) never open it. To cover both, on
|
|
26
|
+
// non-hover devices we open the card on tap. Closing stays with the machine's
|
|
27
|
+
// own dismissal (tap-outside / blur), and opening is idempotent with the
|
|
28
|
+
// focus-open path so it doesn't fight devices that already open on tap.
|
|
29
|
+
const hasHover = useHasHover();
|
|
30
|
+
const [internalOpen, setInternalOpen] = useState(defaultOpen ?? false);
|
|
31
|
+
|
|
32
|
+
const isControlled = openProp !== undefined;
|
|
33
|
+
const open = isControlled ? openProp : internalOpen;
|
|
34
|
+
|
|
35
|
+
const setOpen = (next: boolean) => {
|
|
36
|
+
if (!isControlled) setInternalOpen(next);
|
|
37
|
+
onOpenChange?.({ open: next });
|
|
38
|
+
};
|
|
39
|
+
|
|
15
40
|
return (
|
|
16
41
|
<HoverCard.Root
|
|
17
42
|
positioning={{ placement: 'top' }}
|
|
18
43
|
openDelay={0}
|
|
19
44
|
closeDelay={0}
|
|
20
45
|
lazyMount
|
|
46
|
+
open={open}
|
|
47
|
+
onOpenChange={(e) => setOpen(e.open)}
|
|
21
48
|
{...rest}
|
|
22
49
|
>
|
|
23
50
|
<HoverCard.Trigger asChild>
|
|
@@ -27,6 +54,11 @@ export const InfoSprinkle = ({
|
|
|
27
54
|
transition="opacity 0.2s"
|
|
28
55
|
_hover={{ opacity: 1, ...(iconButtonProps?._hover as any) }}
|
|
29
56
|
{...iconButtonProps}
|
|
57
|
+
onClick={(e) => {
|
|
58
|
+
// On non-hover (touch) devices, tapping opens the card.
|
|
59
|
+
if (!hasHover) setOpen(true);
|
|
60
|
+
iconButtonProps?.onClick?.(e);
|
|
61
|
+
}}
|
|
30
62
|
>
|
|
31
63
|
<LuInfo
|
|
32
64
|
color={(iconButtonProps?.color as string) ?? 'fg.muted'}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns whether the primary pointing device is capable of hovering
|
|
7
|
+
* (i.e. a mouse/trackpad rather than a touchscreen).
|
|
8
|
+
*
|
|
9
|
+
* Useful for components that rely on hover interactions on desktop but need a
|
|
10
|
+
* tap/click affordance on touch devices, where hover events never fire.
|
|
11
|
+
*
|
|
12
|
+
* Defaults to `true` so server-rendered markup matches the most common
|
|
13
|
+
* (desktop) case, then resolves to the real value after mount.
|
|
14
|
+
*/
|
|
15
|
+
export const useHasHover = () => {
|
|
16
|
+
const [hasHover, setHasHover] = useState(true);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (typeof window === 'undefined' || !window.matchMedia) return;
|
|
20
|
+
|
|
21
|
+
const mql = window.matchMedia('(hover: hover)');
|
|
22
|
+
const update = () => setHasHover(mql.matches);
|
|
23
|
+
|
|
24
|
+
update();
|
|
25
|
+
mql.addEventListener('change', update);
|
|
26
|
+
return () => mql.removeEventListener('change', update);
|
|
27
|
+
}, []);
|
|
28
|
+
|
|
29
|
+
return hasHover;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default useHasHover;
|
package/src/index.ts
CHANGED
|
@@ -102,6 +102,7 @@ export {
|
|
|
102
102
|
} from './components/Typography';
|
|
103
103
|
|
|
104
104
|
// Hooks
|
|
105
|
+
export { useHasHover } from './hooks/useHasHover';
|
|
105
106
|
export type { LanguageContextValue } from './hooks/useLanguage';
|
|
106
107
|
export { LanguageContext, useLanguage } from './hooks/useLanguage';
|
|
107
108
|
|