@udixio/ui-react 2.9.7 → 2.9.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/index.cjs +3 -3
  3. package/dist/index.js +2158 -2042
  4. package/dist/lib/components/Tooltip.d.ts +9 -0
  5. package/dist/lib/components/Tooltip.d.ts.map +1 -0
  6. package/dist/lib/components/index.d.ts +1 -1
  7. package/dist/lib/effects/State.d.ts.map +1 -1
  8. package/dist/lib/hooks/index.d.ts +5 -0
  9. package/dist/lib/hooks/index.d.ts.map +1 -0
  10. package/dist/lib/hooks/useTooltipPosition.d.ts +22 -0
  11. package/dist/lib/hooks/useTooltipPosition.d.ts.map +1 -0
  12. package/dist/lib/hooks/useTooltipTrigger.d.ts +44 -0
  13. package/dist/lib/hooks/useTooltipTrigger.d.ts.map +1 -0
  14. package/dist/lib/index.d.ts +1 -0
  15. package/dist/lib/index.d.ts.map +1 -1
  16. package/dist/lib/interfaces/tooltip.interface.d.ts +24 -2
  17. package/dist/lib/interfaces/tooltip.interface.d.ts.map +1 -1
  18. package/dist/lib/styles/card.style.d.ts.map +1 -1
  19. package/dist/lib/styles/tooltip.style.d.ts +32 -4
  20. package/dist/lib/styles/tooltip.style.d.ts.map +1 -1
  21. package/package.json +3 -3
  22. package/src/lib/components/Fab.tsx +2 -2
  23. package/src/lib/components/IconButton.tsx +3 -3
  24. package/src/lib/components/Tooltip.tsx +172 -0
  25. package/src/lib/components/index.ts +1 -1
  26. package/src/lib/effects/State.tsx +6 -2
  27. package/src/lib/hooks/index.ts +11 -0
  28. package/src/lib/hooks/useTooltipPosition.ts +95 -0
  29. package/src/lib/hooks/useTooltipTrigger.ts +270 -0
  30. package/src/lib/index.ts +1 -0
  31. package/src/lib/interfaces/tooltip.interface.ts +24 -2
  32. package/src/lib/styles/card.style.ts +4 -1
  33. package/src/lib/styles/tooltip.style.ts +1 -0
  34. package/src/stories/communication/tool-tip.stories.tsx +19 -19
  35. package/tsconfig.json +0 -6
  36. package/dist/lib/components/ToolTip.d.ts +0 -9
  37. package/dist/lib/components/ToolTip.d.ts.map +0 -1
  38. package/src/lib/components/ToolTip.tsx +0 -256
@@ -0,0 +1,9 @@
1
+ import { MotionProps } from '../utils';
2
+ import { ToolTipInterface } from '../interfaces';
3
+ /**
4
+ * Tooltips display brief labels or messages
5
+ * @status beta
6
+ * @category Communication
7
+ */
8
+ export declare const Tooltip: ({ variant, buttons, className, children, title, text, content, position: positionProp, targetRef, ref, trigger, transition, openDelay, closeDelay, isOpen: isOpenProp, defaultOpen, onOpenChange, id, ...props }: MotionProps<ToolTipInterface>) => import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=Tooltip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Tooltip.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAMjD;;;;GAIG;AACH,eAAO,MAAM,OAAO,GAAI,kNAoBrB,WAAW,CAAC,gBAAgB,CAAC,4CAyI/B,CAAC"}
@@ -23,5 +23,5 @@ export * from './TabPanel';
23
23
  export * from './TextField';
24
24
  export * from './NavigationRailItem';
25
25
  export * from './NavigationRail';
26
- export * from './ToolTip';
26
+ export * from './Tooltip';
27
27
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"State.d.ts","sourceRoot":"","sources":["../../../src/lib/effects/State.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAGlB,UAAU,EACX,MAAM,UAAU,CAAC;AAGlB,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,CAAC,EACX,MAAM,GACN,oBAAoB,GACpB,aAAa,GACb,aAAa,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;KAC7B,CAAC;IACF,MAAM,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,QAAQ,EAAE,CAAC,YAAY,CAAC,CAAC;CAC1B;AAED,eAAO,MAAM,KAAK,GAAI,kDAKnB,UAAU,CAAC,cAAc,CAAC,4CAqC5B,CAAC;AAYF,eAAO,MAAM,aAAa;cA1DJ,OAAO;;eATd,MAAM;qBAEb,MAAM,GACN,oBAAoB,GACpB,aAAa,GACb,aAAa;gBACL,MAAM;YACV,KAAK,CAAC,aAAa;;;kCA+D9B,CAAC"}
1
+ {"version":3,"file":"State.d.ts","sourceRoot":"","sources":["../../../src/lib/effects/State.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAGlB,UAAU,EACX,MAAM,UAAU,CAAC;AAGlB,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,CAAC,EACX,MAAM,GACN,oBAAoB,GACpB,aAAa,GACb,aAAa,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;KAC7B,CAAC;IACF,MAAM,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,QAAQ,EAAE,CAAC,YAAY,CAAC,CAAC;CAC1B;AAED,eAAO,MAAM,KAAK,GAAI,kDAKnB,UAAU,CAAC,cAAc,CAAC,4CAyC5B,CAAC;AAYF,eAAO,MAAM,aAAa;cA9DJ,OAAO;;eATd,MAAM;qBAEb,MAAM,GACN,oBAAoB,GACpB,aAAa,GACb,aAAa;gBACL,MAAM;YACV,KAAK,CAAC,aAAa;;;kCAmE9B,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { useTooltipTrigger } from './useTooltipTrigger';
2
+ export type { UseTooltipTriggerOptions, UseTooltipTriggerReturn, } from './useTooltipTrigger';
3
+ export { useTooltipPosition } from './useTooltipPosition';
4
+ export type { UseTooltipPositionOptions, UseTooltipPositionReturn, } from './useTooltipPosition';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EACV,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EACV,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { RefObject } from 'react';
2
+ type Position = 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
3
+ type Variant = 'plain' | 'rich';
4
+ export interface UseTooltipPositionOptions {
5
+ targetRef: RefObject<HTMLElement | null>;
6
+ position?: Position;
7
+ variant?: Variant;
8
+ isOpen: boolean;
9
+ }
10
+ export interface UseTooltipPositionReturn {
11
+ resolvedPosition: Position;
12
+ }
13
+ /**
14
+ * Hook to calculate tooltip position using useLayoutEffect.
15
+ * Auto-flips position if not enough viewport space.
16
+ *
17
+ * For plain variant: prefers left/right, falls back to top/bottom
18
+ * For rich variant: uses corner positions (top-left, top-right, bottom-left, bottom-right)
19
+ */
20
+ export declare function useTooltipPosition({ targetRef, position: positionProp, variant, isOpen, }: UseTooltipPositionOptions): UseTooltipPositionReturn;
21
+ export {};
22
+ //# sourceMappingURL=useTooltipPosition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTooltipPosition.d.ts","sourceRoot":"","sources":["../../../src/lib/hooks/useTooltipPosition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA6B,MAAM,OAAO,CAAC;AAE7D,KAAK,QAAQ,GACT,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,CAAC;AAEnB,KAAK,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhC,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,gBAAgB,EAAE,QAAQ,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,QAAQ,EAAE,YAAY,EACtB,OAAiB,EACjB,MAAM,GACP,EAAE,yBAAyB,GAAG,wBAAwB,CAyDtD"}
@@ -0,0 +1,44 @@
1
+ type Trigger = 'hover' | 'click' | 'focus' | null;
2
+ type TooltipState = 'hidden' | 'hovered' | 'focused' | 'clicked';
3
+ export interface UseTooltipTriggerOptions {
4
+ trigger?: Trigger | Trigger[];
5
+ isOpen?: boolean;
6
+ defaultOpen?: boolean;
7
+ onOpenChange?: (open: boolean) => void;
8
+ openDelay?: number;
9
+ closeDelay?: number;
10
+ id?: string;
11
+ }
12
+ export interface UseTooltipTriggerReturn {
13
+ triggerProps: {
14
+ 'aria-describedby': string | undefined;
15
+ onMouseEnter: () => void;
16
+ onMouseLeave: () => void;
17
+ onFocus: () => void;
18
+ onBlur: () => void;
19
+ onClick: () => void;
20
+ onKeyDown: (event: React.KeyboardEvent) => void;
21
+ };
22
+ tooltipProps: {
23
+ id: string;
24
+ role: 'tooltip';
25
+ 'aria-hidden': boolean;
26
+ onMouseEnter: () => void;
27
+ onMouseLeave: () => void;
28
+ };
29
+ isOpen: boolean;
30
+ state: TooltipState;
31
+ }
32
+ /**
33
+ * Hook to manage tooltip trigger state machine, events, and accessibility props.
34
+ *
35
+ * State Machine:
36
+ * - States: hidden | hovered | focused | clicked
37
+ * - Priority: clicked > focused > hovered > hidden
38
+ * - Focus takes priority over hover (don't close on mouse leave if focused)
39
+ * - Escape key closes tooltip from any open state
40
+ * - Click toggles for 'click' trigger
41
+ */
42
+ export declare function useTooltipTrigger({ trigger, isOpen: isOpenProp, defaultOpen, onOpenChange, openDelay, closeDelay, id: idProp, }?: UseTooltipTriggerOptions): UseTooltipTriggerReturn;
43
+ export {};
44
+ //# sourceMappingURL=useTooltipTrigger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTooltipTrigger.d.ts","sourceRoot":"","sources":["../../../src/lib/hooks/useTooltipTrigger.ts"],"names":[],"mappings":"AAEA,KAAK,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;AAElD,KAAK,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE;QACZ,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;QACvC,YAAY,EAAE,MAAM,IAAI,CAAC;QACzB,YAAY,EAAE,MAAM,IAAI,CAAC;QACzB,OAAO,EAAE,MAAM,IAAI,CAAC;QACpB,MAAM,EAAE,MAAM,IAAI,CAAC;QACnB,OAAO,EAAE,MAAM,IAAI,CAAC;QACpB,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;KACjD,CAAC;IACF,YAAY,EAAE;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,SAAS,CAAC;QAChB,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,MAAM,IAAI,CAAC;QACzB,YAAY,EAAE,MAAM,IAAI,CAAC;KAC1B,CAAC;IACF,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAA4B,EAC5B,MAAM,EAAE,UAAU,EAClB,WAAmB,EACnB,YAAY,EACZ,SAAe,EACf,UAAgB,EAChB,EAAE,EAAE,MAAM,GACX,GAAE,wBAA6B,GAAG,uBAAuB,CAsNzD"}
@@ -1,5 +1,6 @@
1
1
  export * from './components';
2
2
  export * from './effects';
3
+ export * from './hooks';
3
4
  export * from './icon';
4
5
  export * from './interfaces';
5
6
  export * from './styles';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
@@ -8,11 +8,26 @@ export type ToolTipInterface<T extends HTMLElement = any> = {
8
8
  props: {
9
9
  variant?: 'plain' | 'rich';
10
10
  title?: string;
11
- text: string;
11
+ /** Supporting text for the tooltip. Optional when using `content` prop. */
12
+ text?: string;
13
+ /** Custom content slot that replaces title/text/buttons when provided */
14
+ content?: ReactNode;
12
15
  buttons?: ReactProps<ButtonInterface> | ReactProps<ButtonInterface>[];
13
16
  position?: 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
14
17
  trigger?: Trigger | Trigger[];
15
18
  transition?: Transition;
19
+ /** Delay in milliseconds before showing the tooltip. Default: 400ms */
20
+ openDelay?: number;
21
+ /** Delay in milliseconds before hiding the tooltip. Default: 150ms */
22
+ closeDelay?: number;
23
+ /** Controlled mode: explicitly control whether the tooltip is open */
24
+ isOpen?: boolean;
25
+ /** Uncontrolled mode: default open state */
26
+ defaultOpen?: boolean;
27
+ /** Callback when the open state changes */
28
+ onOpenChange?: (open: boolean) => void;
29
+ /** Custom ID for accessibility linking. Auto-generated if not provided. */
30
+ id?: string;
16
31
  } & ({
17
32
  children?: never;
18
33
  targetRef: RefObject<T>;
@@ -20,7 +35,14 @@ export type ToolTipInterface<T extends HTMLElement = any> = {
20
35
  children: ReactNode;
21
36
  targetRef?: never;
22
37
  });
23
- elements: ['toolTip', 'container', 'subHead', 'supportingText', 'actions'];
38
+ elements: [
39
+ 'toolTip',
40
+ 'container',
41
+ 'subHead',
42
+ 'supportingText',
43
+ 'actions',
44
+ 'content'
45
+ ];
24
46
  };
25
47
  export {};
26
48
  //# sourceMappingURL=tooltip.interface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/tooltip.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,KAAK,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;AAElD,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,WAAW,GAAG,GAAG,IAAI;IAC1D,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE;QACL,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACtE,QAAQ,CAAC,EACL,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;QAC9B,UAAU,CAAC,EAAE,UAAU,CAAC;KACzB,GAAG,CACA;QACE,QAAQ,CAAC,EAAE,KAAK,CAAC;QACjB,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;KACzB,GACD;QACE,QAAQ,EAAE,SAAS,CAAC;QACpB,SAAS,CAAC,EAAE,KAAK,CAAC;KACnB,CACJ,CAAC;IACF,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,CAAC,CAAC;CAC5E,CAAC"}
1
+ {"version":3,"file":"tooltip.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/tooltip.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,KAAK,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;AAElD,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,WAAW,GAAG,GAAG,IAAI;IAC1D,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE;QACL,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,2EAA2E;QAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,yEAAyE;QACzE,OAAO,CAAC,EAAE,SAAS,CAAC;QACpB,OAAO,CAAC,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACtE,QAAQ,CAAC,EACL,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;QAC9B,UAAU,CAAC,EAAE,UAAU,CAAC;QACxB,uEAAuE;QACvE,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,sEAAsE;QACtE,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,sEAAsE;QACtE,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,4CAA4C;QAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,2CAA2C;QAC3C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QACvC,2EAA2E;QAC3E,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,GAAG,CACA;QACE,QAAQ,CAAC,EAAE,KAAK,CAAC;QACjB,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;KACzB,GACD;QACE,QAAQ,EAAE,SAAS,CAAC;QACpB,SAAS,CAAC,EAAE,KAAK,CAAC;KACnB,CACJ,CAAC;IACF,QAAQ,EAAE;QACR,SAAS;QACT,WAAW;QACX,SAAS;QACT,gBAAgB;QAChB,SAAS;QACT,SAAS;KACV,CAAC;CACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"card.style.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/card.style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,UAAU,CAAC;AAclB,eAAO,MAAM,SAAS;;;;;;;;;;2CAAuD,CAAC;AAE9E,eAAO,MAAM,YAAY;;;;;;2CAGxB,CAAC"}
1
+ {"version":3,"file":"card.style.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/card.style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,UAAU,CAAC;AAiBlB,eAAO,MAAM,SAAS;;;;;;;;;;2CAAuD,CAAC;AAE9E,eAAO,MAAM,YAAY;;;;;;2CAGxB,CAAC"}
@@ -4,30 +4,51 @@ export declare const toolStyle: (states: ({
4
4
  variant: any;
5
5
  title: any;
6
6
  text: any;
7
+ content: any;
7
8
  buttons: any;
8
9
  position: any;
9
10
  trigger: any;
10
11
  transition: any;
12
+ openDelay: any;
13
+ closeDelay: any;
14
+ isOpen: any;
15
+ defaultOpen: any;
16
+ onOpenChange: any;
17
+ id: any;
11
18
  children: any;
12
19
  targetRef: any;
13
20
  } | {
14
21
  variant: any;
15
22
  title: any;
16
23
  text: any;
24
+ content: any;
17
25
  buttons: any;
18
26
  position: any;
19
27
  trigger: any;
20
28
  transition: any;
29
+ openDelay: any;
30
+ closeDelay: any;
31
+ isOpen: any;
32
+ defaultOpen: any;
33
+ onOpenChange: any;
34
+ id: any;
21
35
  children: any;
22
36
  targetRef: any;
23
37
  }) & (({
24
38
  variant?: "plain" | "rich";
25
39
  title?: string;
26
- text: string;
40
+ text?: string;
41
+ content?: import('react').ReactNode;
27
42
  buttons?: import('..').ReactProps<import('..').ButtonInterface> | import('..').ReactProps<import('..').ButtonInterface>[];
28
43
  position?: "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
29
44
  trigger?: ("click" | "focus" | "hover" | null) | ("click" | "focus" | "hover" | null)[];
30
45
  transition?: import('motion').Transition;
46
+ openDelay?: number;
47
+ closeDelay?: number;
48
+ isOpen?: boolean;
49
+ defaultOpen?: boolean;
50
+ onOpenChange?: (open: boolean) => void;
51
+ id?: string;
31
52
  } & ({
32
53
  children: import('react').ReactNode;
33
54
  targetRef?: never;
@@ -36,15 +57,22 @@ export declare const toolStyle: (states: ({
36
57
  targetRef: import('react').RefObject<any>;
37
58
  })) & {
38
59
  className: string | ClassNameComponent<ToolTipInterface> | undefined;
39
- })) => Record<"container" | "actions" | "supportingText" | "toolTip" | "subHead", string>;
60
+ })) => Record<"container" | "content" | "actions" | "supportingText" | "toolTip" | "subHead", string>;
40
61
  export declare const useToolTipStyle: (states: ({
41
62
  variant?: "plain" | "rich";
42
63
  title?: string;
43
- text: string;
64
+ text?: string;
65
+ content?: import('react').ReactNode;
44
66
  buttons?: import('..').ReactProps<import('..').ButtonInterface> | import('..').ReactProps<import('..').ButtonInterface>[];
45
67
  position?: "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
46
68
  trigger?: ("click" | "focus" | "hover" | null) | ("click" | "focus" | "hover" | null)[];
47
69
  transition?: import('motion').Transition;
70
+ openDelay?: number;
71
+ closeDelay?: number;
72
+ isOpen?: boolean;
73
+ defaultOpen?: boolean;
74
+ onOpenChange?: (open: boolean) => void;
75
+ id?: string;
48
76
  } & ({
49
77
  children: import('react').ReactNode;
50
78
  targetRef?: never;
@@ -53,5 +81,5 @@ export declare const useToolTipStyle: (states: ({
53
81
  targetRef: import('react').RefObject<any>;
54
82
  })) & {
55
83
  className?: string | ClassNameComponent<ToolTipInterface> | undefined;
56
- }) => Record<"container" | "actions" | "supportingText" | "toolTip" | "subHead", string>;
84
+ }) => Record<"container" | "content" | "actions" | "supportingText" | "toolTip" | "subHead", string>;
57
85
  //# sourceMappingURL=tooltip.style.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.style.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/tooltip.style.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAgCjD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yFAGrB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;wFAG3B,CAAC"}
1
+ {"version":3,"file":"tooltip.style.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/tooltip.style.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAiCjD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qGAGrB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;oGAG3B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@udixio/ui-react",
3
- "version": "2.9.7",
3
+ "version": "2.9.9",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -37,8 +37,8 @@
37
37
  "devDependencies": {
38
38
  "react": "^19.1.1",
39
39
  "react-dom": "^19.1.1",
40
- "@udixio/theme": "2.1.10",
41
- "@udixio/tailwind": "2.4.8"
40
+ "@udixio/theme": "2.1.11",
41
+ "@udixio/tailwind": "2.4.9"
42
42
  },
43
43
  "repository": {
44
44
  "type": "git",
@@ -5,7 +5,7 @@ import { FabInterface } from '../interfaces/fab.interface';
5
5
  import { useFabStyle } from '../styles/fab.style';
6
6
  import { classNames } from '../utils';
7
7
  import { ReactProps } from '../utils/component';
8
- import { ToolTip } from './ToolTip';
8
+ import { Tooltip } from './Tooltip';
9
9
  import { State } from '../effects';
10
10
 
11
11
  /**
@@ -86,7 +86,7 @@ export const Fab = ({
86
86
  aria-label={extended ? undefined : label}
87
87
  className={styles.fab}
88
88
  >
89
- <ToolTip
89
+ <Tooltip
90
90
  trigger={extended ? null : undefined}
91
91
  text={label}
92
92
  targetRef={resolvedRef}
@@ -6,7 +6,7 @@ import { useIconButtonStyle } from '../styles/icon-button.style';
6
6
  import { ReactProps } from '../utils/component';
7
7
  import { State } from '../effects';
8
8
  import { classNames } from '../utils';
9
- import { ToolTip } from './ToolTip';
9
+ import { Tooltip } from './Tooltip';
10
10
 
11
11
  export type IconButtonVariant = 'standard' | 'filled' | 'tonal' | 'outlined';
12
12
 
@@ -104,11 +104,11 @@ export const IconButton = ({
104
104
  onClick={handleClick}
105
105
  ref={resolvedRef}
106
106
  >
107
- <ToolTip
107
+ <Tooltip
108
108
  targetRef={resolvedRef}
109
109
  trigger={disabled ? null : undefined}
110
110
  text={title}
111
- ></ToolTip>
111
+ ></Tooltip>
112
112
 
113
113
  <div className={styles.touchTarget} />
114
114
  <State
@@ -0,0 +1,172 @@
1
+ import { cloneElement, isValidElement, useRef } from 'react';
2
+ import { MotionProps } from '../utils';
3
+ import { Button } from './Button';
4
+ import { ToolTipInterface } from '../interfaces';
5
+ import { useToolTipStyle } from '../styles';
6
+ import { AnimatePresence, motion } from 'motion/react';
7
+ import { SyncedFixedWrapper } from '../effects';
8
+ import { useTooltipTrigger, useTooltipPosition } from '../hooks';
9
+
10
+ /**
11
+ * Tooltips display brief labels or messages
12
+ * @status beta
13
+ * @category Communication
14
+ */
15
+ export const Tooltip = ({
16
+ variant = 'plain',
17
+ buttons,
18
+ className,
19
+ children,
20
+ title,
21
+ text,
22
+ content,
23
+ position: positionProp,
24
+ targetRef,
25
+ ref,
26
+ trigger = ['hover', 'focus'],
27
+ transition,
28
+ openDelay = 400,
29
+ closeDelay = 150,
30
+ isOpen: isOpenProp,
31
+ defaultOpen = false,
32
+ onOpenChange,
33
+ id,
34
+ ...props
35
+ }: MotionProps<ToolTipInterface>) => {
36
+ transition = { duration: 0.3, ...transition };
37
+
38
+ if (!children && !targetRef) {
39
+ throw new Error('Tooltip must have a child or a targetRef');
40
+ }
41
+
42
+ if (buttons && !Array.isArray(buttons)) {
43
+ buttons = [buttons];
44
+ }
45
+
46
+ const internalRef = useRef<HTMLElement | null>(null);
47
+ const resolvedRef = targetRef || internalRef;
48
+
49
+ // Use the trigger hook for state management and accessibility
50
+ const { triggerProps, tooltipProps, isOpen } = useTooltipTrigger({
51
+ trigger,
52
+ isOpen: isOpenProp,
53
+ defaultOpen,
54
+ onOpenChange,
55
+ openDelay,
56
+ closeDelay,
57
+ id,
58
+ });
59
+
60
+ // Use the position hook for auto-positioning
61
+ const { resolvedPosition } = useTooltipPosition({
62
+ targetRef: resolvedRef,
63
+ position: positionProp,
64
+ variant,
65
+ isOpen,
66
+ });
67
+
68
+ // Apply trigger props to the target element
69
+ const enhancedChildren =
70
+ !targetRef && isValidElement(children)
71
+ ? cloneElement(children, {
72
+ ref: internalRef,
73
+ ...triggerProps,
74
+ // Merge event handlers if the child already has them
75
+ onMouseEnter: (e: React.MouseEvent) => {
76
+ triggerProps.onMouseEnter();
77
+ (children.props as any)?.onMouseEnter?.(e);
78
+ },
79
+ onMouseLeave: (e: React.MouseEvent) => {
80
+ triggerProps.onMouseLeave();
81
+ (children.props as any)?.onMouseLeave?.(e);
82
+ },
83
+ onFocus: (e: React.FocusEvent) => {
84
+ triggerProps.onFocus();
85
+ (children.props as any)?.onFocus?.(e);
86
+ },
87
+ onBlur: (e: React.FocusEvent) => {
88
+ triggerProps.onBlur();
89
+ (children.props as any)?.onBlur?.(e);
90
+ },
91
+ onClick: (e: React.MouseEvent) => {
92
+ triggerProps.onClick();
93
+ (children.props as any)?.onClick?.(e);
94
+ },
95
+ onKeyDown: (e: React.KeyboardEvent) => {
96
+ triggerProps.onKeyDown(e);
97
+ (children.props as any)?.onKeyDown?.(e);
98
+ },
99
+ } as any)
100
+ : children;
101
+
102
+ const styles = useToolTipStyle({
103
+ variant,
104
+ buttons,
105
+ className,
106
+ title,
107
+ text,
108
+ position: resolvedPosition,
109
+ trigger,
110
+ targetRef: targetRef as any,
111
+ children: children as any,
112
+ });
113
+
114
+ const variants = {
115
+ open: {
116
+ opacity: 1,
117
+ height: 'auto',
118
+ },
119
+ close: {
120
+ opacity: 0,
121
+ height: 16,
122
+ },
123
+ };
124
+
125
+ return (
126
+ <>
127
+ {enhancedChildren}
128
+ <AnimatePresence>
129
+ {isOpen && (
130
+ <SyncedFixedWrapper targetRef={resolvedRef}>
131
+ <motion.div
132
+ initial={'close'}
133
+ variants={variants}
134
+ animate={'open'}
135
+ transition={{ duration: transition.duration }}
136
+ exit={'close'}
137
+ className={styles.toolTip}
138
+ {...props}
139
+ {...tooltipProps}
140
+ >
141
+ <div className={styles.container}>
142
+ {content ? (
143
+ <div className={styles.content}>{content}</div>
144
+ ) : (
145
+ <>
146
+ {title && <div className={styles.subHead}>{title}</div>}
147
+ {text && (
148
+ <div className={styles.supportingText}>{text}</div>
149
+ )}
150
+ {buttons && (
151
+ <div className={styles.actions}>
152
+ {Array.isArray(buttons) &&
153
+ buttons.map((buttonArgs, index) => (
154
+ <Button
155
+ key={index}
156
+ size={'small'}
157
+ variant={'text'}
158
+ {...buttonArgs}
159
+ />
160
+ ))}
161
+ </div>
162
+ )}
163
+ </>
164
+ )}
165
+ </div>
166
+ </motion.div>
167
+ </SyncedFixedWrapper>
168
+ )}
169
+ </AnimatePresence>
170
+ </>
171
+ );
172
+ };
@@ -23,4 +23,4 @@ export * from './TabPanel';
23
23
  export * from './TextField';
24
24
  export * from './NavigationRailItem';
25
25
  export * from './NavigationRail';
26
- export * from './ToolTip';
26
+ export * from './Tooltip';
@@ -44,9 +44,13 @@ export const State = ({
44
44
  if (ref.current && stateClassName !== 'state-layer') {
45
45
  const groupName = !stateClassName.includes('[')
46
46
  ? 'group'
47
- : stateClassName.split('[')[1].split(']')[0];
47
+ : 'group/' + stateClassName.split('[')[1].split(']')[0];
48
+
49
+ // On échappe le slash pour le sélecteur CSS
50
+ const safeGroupName = groupName.replace(/\//g, '\\/');
51
+
48
52
  const furthestGroupState = ref.current.closest(
49
- `.${groupName}:not(.${groupName} .${groupName})`,
53
+ `.${safeGroupName}:not(.${safeGroupName} .${safeGroupName})`,
50
54
  );
51
55
  groupStateRef.current = furthestGroupState as HTMLElement | null;
52
56
  }
@@ -0,0 +1,11 @@
1
+ export { useTooltipTrigger } from './useTooltipTrigger';
2
+ export type {
3
+ UseTooltipTriggerOptions,
4
+ UseTooltipTriggerReturn,
5
+ } from './useTooltipTrigger';
6
+
7
+ export { useTooltipPosition } from './useTooltipPosition';
8
+ export type {
9
+ UseTooltipPositionOptions,
10
+ UseTooltipPositionReturn,
11
+ } from './useTooltipPosition';
@@ -0,0 +1,95 @@
1
+ import { RefObject, useLayoutEffect, useState } from 'react';
2
+
3
+ type Position =
4
+ | 'top'
5
+ | 'bottom'
6
+ | 'left'
7
+ | 'right'
8
+ | 'top-left'
9
+ | 'top-right'
10
+ | 'bottom-left'
11
+ | 'bottom-right';
12
+
13
+ type Variant = 'plain' | 'rich';
14
+
15
+ export interface UseTooltipPositionOptions {
16
+ targetRef: RefObject<HTMLElement | null>;
17
+ position?: Position;
18
+ variant?: Variant;
19
+ isOpen: boolean;
20
+ }
21
+
22
+ export interface UseTooltipPositionReturn {
23
+ resolvedPosition: Position;
24
+ }
25
+
26
+ /**
27
+ * Hook to calculate tooltip position using useLayoutEffect.
28
+ * Auto-flips position if not enough viewport space.
29
+ *
30
+ * For plain variant: prefers left/right, falls back to top/bottom
31
+ * For rich variant: uses corner positions (top-left, top-right, bottom-left, bottom-right)
32
+ */
33
+ export function useTooltipPosition({
34
+ targetRef,
35
+ position: positionProp,
36
+ variant = 'plain',
37
+ isOpen,
38
+ }: UseTooltipPositionOptions): UseTooltipPositionReturn {
39
+ const [resolvedPosition, setResolvedPosition] = useState<Position>(
40
+ positionProp ?? 'bottom',
41
+ );
42
+
43
+ useLayoutEffect(() => {
44
+ // If position is explicitly set, use it
45
+ if (positionProp) {
46
+ setResolvedPosition(positionProp);
47
+ return;
48
+ }
49
+
50
+ // Only calculate if open and we have a target
51
+ if (!isOpen || !targetRef.current || typeof window === 'undefined') {
52
+ return;
53
+ }
54
+
55
+ const targetElement = targetRef.current;
56
+ const rect = targetElement.getBoundingClientRect();
57
+
58
+ const viewportWidth = window.innerWidth;
59
+ const viewportHeight = window.innerHeight;
60
+
61
+ // Normalized position (0-1 range)
62
+ const x = rect.left / viewportWidth;
63
+ const y = rect.top / viewportHeight;
64
+
65
+ let newPosition: Position;
66
+
67
+ if (variant === 'plain') {
68
+ // Plain variant: prefer horizontal positioning, fall back to vertical
69
+ if (x < 1 / 3) {
70
+ newPosition = 'right';
71
+ } else if (x > 2 / 3) {
72
+ newPosition = 'left';
73
+ } else {
74
+ newPosition = y > 0.5 ? 'top' : 'bottom';
75
+ }
76
+ } else {
77
+ // Rich variant: use corner positions
78
+ if (x < 0.5 && y < 0.5) {
79
+ newPosition = 'bottom-right';
80
+ } else if (x >= 0.5 && y < 0.5) {
81
+ newPosition = 'bottom-left';
82
+ } else if (x >= 0.5 && y >= 0.5) {
83
+ newPosition = 'top-left';
84
+ } else {
85
+ newPosition = 'top-right';
86
+ }
87
+ }
88
+
89
+ setResolvedPosition(newPosition);
90
+ }, [isOpen, targetRef, positionProp, variant]);
91
+
92
+ return {
93
+ resolvedPosition,
94
+ };
95
+ }