@fluentui/react-tooltip 9.1.1 → 9.1.3

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.json CHANGED
@@ -2,7 +2,81 @@
2
2
  "name": "@fluentui/react-tooltip",
3
3
  "entries": [
4
4
  {
5
- "date": "Fri, 11 Nov 2022 14:53:35 GMT",
5
+ "date": "Mon, 05 Dec 2022 18:25:36 GMT",
6
+ "tag": "@fluentui/react-tooltip_v9.1.3",
7
+ "version": "9.1.3",
8
+ "comments": {
9
+ "patch": [
10
+ {
11
+ "author": "tristan.watanabe@gmail.com",
12
+ "package": "@fluentui/react-tooltip",
13
+ "commit": "3fdfc72488fe30b83f665c7267c5e8cb802682ff",
14
+ "comment": "chore: Migrate to new package structure."
15
+ },
16
+ {
17
+ "author": "beachball",
18
+ "package": "@fluentui/react-tooltip",
19
+ "comment": "Bump @fluentui/react-portal to v9.0.12",
20
+ "commit": "4c29542a51bf068e171690cc8e59c14489883912"
21
+ },
22
+ {
23
+ "author": "beachball",
24
+ "package": "@fluentui/react-tooltip",
25
+ "comment": "Bump @fluentui/react-positioning to v9.3.3",
26
+ "commit": "4c29542a51bf068e171690cc8e59c14489883912"
27
+ },
28
+ {
29
+ "author": "beachball",
30
+ "package": "@fluentui/react-tooltip",
31
+ "comment": "Bump @fluentui/react-shared-contexts to v9.1.2",
32
+ "commit": "4c29542a51bf068e171690cc8e59c14489883912"
33
+ },
34
+ {
35
+ "author": "beachball",
36
+ "package": "@fluentui/react-tooltip",
37
+ "comment": "Bump @fluentui/react-theme to v9.1.3",
38
+ "commit": "4c29542a51bf068e171690cc8e59c14489883912"
39
+ }
40
+ ]
41
+ }
42
+ },
43
+ {
44
+ "date": "Thu, 17 Nov 2022 23:05:30 GMT",
45
+ "tag": "@fluentui/react-tooltip_v9.1.2",
46
+ "version": "9.1.2",
47
+ "comments": {
48
+ "none": [
49
+ {
50
+ "author": "martinhochel@microsoft.com",
51
+ "package": "@fluentui/react-tooltip",
52
+ "commit": "ea768501802d65d63ddc63fff3816fb6b5008ae4",
53
+ "comment": "chore: update package scaffold"
54
+ }
55
+ ],
56
+ "patch": [
57
+ {
58
+ "author": "beachball",
59
+ "package": "@fluentui/react-tooltip",
60
+ "comment": "Bump @fluentui/react-portal to v9.0.11",
61
+ "commit": "94e156be5d3b5790d82dccf08c32672733fb9335"
62
+ },
63
+ {
64
+ "author": "beachball",
65
+ "package": "@fluentui/react-tooltip",
66
+ "comment": "Bump @fluentui/react-positioning to v9.3.2",
67
+ "commit": "94e156be5d3b5790d82dccf08c32672733fb9335"
68
+ },
69
+ {
70
+ "author": "beachball",
71
+ "package": "@fluentui/react-tooltip",
72
+ "comment": "Bump @fluentui/react-utilities to v9.2.2",
73
+ "commit": "94e156be5d3b5790d82dccf08c32672733fb9335"
74
+ }
75
+ ]
76
+ }
77
+ },
78
+ {
79
+ "date": "Fri, 11 Nov 2022 14:57:48 GMT",
6
80
  "tag": "@fluentui/react-tooltip_v9.1.1",
7
81
  "version": "9.1.1",
8
82
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,36 @@
1
1
  # Change Log - @fluentui/react-tooltip
2
2
 
3
- This log was last generated on Fri, 11 Nov 2022 14:53:35 GMT and should not be manually modified.
3
+ This log was last generated on Mon, 05 Dec 2022 18:25:36 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.1.3](https://github.com/microsoft/fluentui/tree/@fluentui/react-tooltip_v9.1.3)
8
+
9
+ Mon, 05 Dec 2022 18:25:36 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-tooltip_v9.1.2..@fluentui/react-tooltip_v9.1.3)
11
+
12
+ ### Patches
13
+
14
+ - chore: Migrate to new package structure. ([PR #25818](https://github.com/microsoft/fluentui/pull/25818) by tristan.watanabe@gmail.com)
15
+ - Bump @fluentui/react-portal to v9.0.12 ([PR #25798](https://github.com/microsoft/fluentui/pull/25798) by beachball)
16
+ - Bump @fluentui/react-positioning to v9.3.3 ([PR #25798](https://github.com/microsoft/fluentui/pull/25798) by beachball)
17
+ - Bump @fluentui/react-shared-contexts to v9.1.2 ([PR #25798](https://github.com/microsoft/fluentui/pull/25798) by beachball)
18
+ - Bump @fluentui/react-theme to v9.1.3 ([PR #25798](https://github.com/microsoft/fluentui/pull/25798) by beachball)
19
+
20
+ ## [9.1.2](https://github.com/microsoft/fluentui/tree/@fluentui/react-tooltip_v9.1.2)
21
+
22
+ Thu, 17 Nov 2022 23:05:30 GMT
23
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-tooltip_v9.1.1..@fluentui/react-tooltip_v9.1.2)
24
+
25
+ ### Patches
26
+
27
+ - Bump @fluentui/react-portal to v9.0.11 ([PR #25683](https://github.com/microsoft/fluentui/pull/25683) by beachball)
28
+ - Bump @fluentui/react-positioning to v9.3.2 ([PR #25683](https://github.com/microsoft/fluentui/pull/25683) by beachball)
29
+ - Bump @fluentui/react-utilities to v9.2.2 ([PR #25683](https://github.com/microsoft/fluentui/pull/25683) by beachball)
30
+
7
31
  ## [9.1.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-tooltip_v9.1.1)
8
32
 
9
- Fri, 11 Nov 2022 14:53:35 GMT
33
+ Fri, 11 Nov 2022 14:57:48 GMT
10
34
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-tooltip_v9.1.0..@fluentui/react-tooltip_v9.1.1)
11
35
 
12
36
  ### Patches
@@ -0,0 +1,6 @@
1
+ define(["require", "exports", "tslib", "./components/Tooltip/index"], function (require, exports, tslib_1, index_1) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ tslib_1.__exportStar(index_1, exports);
5
+ });
6
+ //# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.js","sourceRoot":"","sources":["../../../../../../../packages/react-components/react-tooltip/src/Tooltip.ts"],"names":[],"mappings":";;;IAAA,uCAA2C","sourcesContent":["export * from './components/Tooltip/index';\n"]}
@@ -0,0 +1,18 @@
1
+ define(["require", "exports", "./useTooltip", "./renderTooltip", "./useTooltipStyles"], function (require, exports, useTooltip_1, renderTooltip_1, useTooltipStyles_1) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Tooltip = void 0;
5
+ /**
6
+ * A tooltip provides light weight contextual information on top of its target element.
7
+ */
8
+ var Tooltip = function (props) {
9
+ var state = useTooltip_1.useTooltip_unstable(props);
10
+ useTooltipStyles_1.useTooltipStyles_unstable(state);
11
+ return renderTooltip_1.renderTooltip_unstable(state);
12
+ };
13
+ exports.Tooltip = Tooltip;
14
+ exports.Tooltip.displayName = 'Tooltip';
15
+ // type casting here is required to ensure internal type FluentTriggerComponent is not leaked
16
+ exports.Tooltip.isFluentTriggerComponent = true;
17
+ });
18
+ //# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.js","sourceRoot":"","sources":["../../../../../../../../../packages/react-components/react-tooltip/src/components/Tooltip/Tooltip.tsx"],"names":[],"mappings":";;;;IAOA;;OAEG;IACI,IAAM,OAAO,GAA2B,UAAA,KAAK;QAClD,IAAM,KAAK,GAAG,gCAAmB,CAAC,KAAK,CAAC,CAAC;QAEzC,4CAAyB,CAAC,KAAK,CAAC,CAAC;QACjC,OAAO,sCAAsB,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC,CAAC;IALW,QAAA,OAAO,WAKlB;IAEF,eAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAChC,6FAA6F;IAC5F,eAAkC,CAAC,wBAAwB,GAAG,IAAI,CAAC","sourcesContent":["import * as React from 'react';\nimport { useTooltip_unstable } from './useTooltip';\nimport { renderTooltip_unstable } from './renderTooltip';\nimport { useTooltipStyles_unstable } from './useTooltipStyles';\nimport type { TooltipProps } from './Tooltip.types';\nimport type { FluentTriggerComponent } from '@fluentui/react-utilities';\n\n/**\n * A tooltip provides light weight contextual information on top of its target element.\n */\nexport const Tooltip: React.FC<TooltipProps> = props => {\n const state = useTooltip_unstable(props);\n\n useTooltipStyles_unstable(state);\n return renderTooltip_unstable(state);\n};\n\nTooltip.displayName = 'Tooltip';\n// type casting here is required to ensure internal type FluentTriggerComponent is not leaked\n(Tooltip as FluentTriggerComponent).isFluentTriggerComponent = true;\n"]}
@@ -0,0 +1,5 @@
1
+ define(["require", "exports"], function (require, exports) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ });
5
+ //# sourceMappingURL=Tooltip.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.types.js","sourceRoot":"","sources":["../../../../../../../../../packages/react-components/react-tooltip/src/components/Tooltip/Tooltip.types.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\nimport type { PositioningShorthand } from '@fluentui/react-positioning';\nimport type { ComponentProps, ComponentState, Slot, TriggerProps } from '@fluentui/react-utilities';\nimport type { PortalProps } from '@fluentui/react-portal';\n\n/**\n * Slot properties for Tooltip\n */\nexport type TooltipSlots = {\n /**\n * The text or JSX content of the tooltip.\n */\n content: NonNullable<Slot<'div'>>;\n};\n\n/**\n * The properties that are added to the child of the Tooltip\n */\nexport type TooltipChildProps = {\n ref?: React.Ref<unknown>;\n} & Pick<\n React.HTMLAttributes<HTMLElement>,\n 'aria-describedby' | 'aria-label' | 'aria-labelledby' | 'onBlur' | 'onFocus' | 'onPointerEnter' | 'onPointerLeave'\n>;\n\n/**\n * Data for the Tooltip's onVisibleChange event.\n */\nexport type OnVisibleChangeData = {\n visible: boolean;\n};\n\n/**\n * Properties for Tooltip\n */\nexport type TooltipProps = ComponentProps<TooltipSlots> &\n TriggerProps<TooltipChildProps> &\n Pick<PortalProps, 'mountNode'> & {\n /**\n * The tooltip's visual appearance.\n * * `normal` - Uses the theme's background and text colors.\n * * `inverted` - Higher contrast variant that uses the theme's inverted colors.\n *\n * @default normal\n */\n appearance?: 'normal' | 'inverted';\n /**\n * Delay before the tooltip is hidden, in milliseconds.\n *\n * @default 250\n */\n hideDelay?: number;\n\n /**\n * Notification when the visibility of the tooltip is changing\n */\n onVisibleChange?: (\n event: React.PointerEvent<HTMLElement> | React.FocusEvent<HTMLElement> | undefined,\n data: OnVisibleChangeData,\n ) => void;\n\n /**\n * Configure the positioning of the tooltip\n *\n * @default above\n */\n positioning?: PositioningShorthand;\n\n /**\n * (Required) Specifies whether this tooltip is acting as the description or label of its trigger element.\n *\n * * `label` - The tooltip sets the trigger's aria-label or aria-labelledby attribute. This is useful for buttons\n * displaying only an icon, for example.\n * * `description` - The tooltip sets the trigger's aria-description or aria-describedby attribute.\n * * `inaccessible` - No aria attributes are set on the trigger. This makes the tooltip's content inaccessible to\n * screen readers, and should only be used if the tooltip's text is available by some other means.\n */\n relationship: 'label' | 'description' | 'inaccessible';\n\n /**\n * Delay before the tooltip is shown, in milliseconds.\n *\n * @default 250\n */\n showDelay?: number;\n\n /**\n * Control the tooltip's visibility programatically.\n *\n * This can be used in conjunction with onVisibleChange to modify the tooltip's show and hide behavior.\n *\n * If not provided, the visibility will be controlled by the tooltip itself, based on hover and focus events on the\n * trigger (child) element.\n *\n * @default false\n */\n visible?: boolean;\n\n /**\n * Render an arrow pointing to the target element\n *\n * @default false\n */\n withArrow?: boolean;\n };\n\n/**\n * State used in rendering Tooltip\n */\nexport type TooltipState = ComponentState<TooltipSlots> &\n Pick<TooltipProps, 'mountNode' | 'relationship'> &\n Required<Pick<TooltipProps, 'appearance' | 'hideDelay' | 'positioning' | 'showDelay' | 'visible' | 'withArrow'>> & {\n children?: React.ReactElement | null;\n\n /**\n * Whether the tooltip should be rendered to the DOM.\n */\n shouldRenderTooltip?: boolean;\n\n /**\n * Ref to the arrow element\n */\n arrowRef?: React.Ref<HTMLDivElement>;\n\n /**\n * CSS class for the arrow element\n */\n arrowClassName?: string;\n };\n"]}
@@ -0,0 +1,10 @@
1
+ define(["require", "exports", "tslib", "./Tooltip", "./Tooltip.types", "./renderTooltip", "./useTooltip", "./useTooltipStyles"], function (require, exports, tslib_1, Tooltip_1, Tooltip_types_1, renderTooltip_1, useTooltip_1, useTooltipStyles_1) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ tslib_1.__exportStar(Tooltip_1, exports);
5
+ tslib_1.__exportStar(Tooltip_types_1, exports);
6
+ tslib_1.__exportStar(renderTooltip_1, exports);
7
+ tslib_1.__exportStar(useTooltip_1, exports);
8
+ tslib_1.__exportStar(useTooltipStyles_1, exports);
9
+ });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../../../packages/react-components/react-tooltip/src/components/Tooltip/index.ts"],"names":[],"mappings":";;;IAAA,yCAA0B;IAC1B,+CAAgC;IAChC,+CAAgC;IAChC,4CAA6B;IAC7B,kDAAmC","sourcesContent":["export * from './Tooltip';\nexport * from './Tooltip.types';\nexport * from './renderTooltip';\nexport * from './useTooltip';\nexport * from './useTooltipStyles';\n"]}
@@ -0,0 +1,18 @@
1
+ define(["require", "exports"], function (require, exports) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.tooltipBorderRadius = exports.arrowHeight = void 0;
5
+ /**
6
+ * The height of the tooltip's arrow in pixels.
7
+ */
8
+ exports.arrowHeight = 6;
9
+ /**
10
+ * The default value of the tooltip's border radius (borderRadiusMedium).
11
+ *
12
+ * Unfortunately, Popper requires it to be specified as a variable instead of using CSS.
13
+ * While we could use getComputedStyle, that adds a performance penalty for something that
14
+ * will likely never change.
15
+ */
16
+ exports.tooltipBorderRadius = 4;
17
+ });
18
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../../../../../../../packages/react-components/react-tooltip/src/components/Tooltip/private/constants.ts"],"names":[],"mappings":";;;;IAAA;;OAEG;IACU,QAAA,WAAW,GAAG,CAAC,CAAC;IAE7B;;;;;;OAMG;IACU,QAAA,mBAAmB,GAAG,CAAC,CAAC","sourcesContent":["/**\n * The height of the tooltip's arrow in pixels.\n */\nexport const arrowHeight = 6;\n\n/**\n * The default value of the tooltip's border radius (borderRadiusMedium).\n *\n * Unfortunately, Popper requires it to be specified as a variable instead of using CSS.\n * While we could use getComputedStyle, that adds a performance penalty for something that\n * will likely never change.\n */\nexport const tooltipBorderRadius = 4;\n"]}
@@ -0,0 +1,19 @@
1
+ define(["require", "exports", "tslib", "react", "@fluentui/react-portal", "@fluentui/react-utilities"], function (require, exports, tslib_1, React, react_portal_1, react_utilities_1) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.renderTooltip_unstable = void 0;
5
+ /**
6
+ * Render the final JSX of Tooltip
7
+ */
8
+ var renderTooltip_unstable = function (state) {
9
+ var _a = react_utilities_1.getSlots(state), slots = _a.slots, slotProps = _a.slotProps;
10
+ return (React.createElement(React.Fragment, null,
11
+ state.children,
12
+ state.shouldRenderTooltip && (React.createElement(react_portal_1.Portal, { mountNode: state.mountNode },
13
+ React.createElement(slots.content, tslib_1.__assign({}, slotProps.content),
14
+ state.withArrow && React.createElement("div", { ref: state.arrowRef, className: state.arrowClassName }),
15
+ state.content.children)))));
16
+ };
17
+ exports.renderTooltip_unstable = renderTooltip_unstable;
18
+ });
19
+ //# sourceMappingURL=renderTooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderTooltip.js","sourceRoot":"","sources":["../../../../../../../../../packages/react-components/react-tooltip/src/components/Tooltip/renderTooltip.tsx"],"names":[],"mappings":";;;;IAKA;;OAEG;IACI,IAAM,sBAAsB,GAAG,UAAC,KAAmB;QAClD,IAAA,KAAuB,0BAAQ,CAAe,KAAK,CAAC,EAAlD,KAAK,WAAA,EAAE,SAAS,eAAkC,CAAC;QAE3D,OAAO,CACL;YACG,KAAK,CAAC,QAAQ;YACd,KAAK,CAAC,mBAAmB,IAAI,CAC5B,oBAAC,qBAAM,IAAC,SAAS,EAAE,KAAK,CAAC,SAAS;gBAChC,oBAAC,KAAK,CAAC,OAAO,uBAAK,SAAS,CAAC,OAAO;oBACjC,KAAK,CAAC,SAAS,IAAI,6BAAK,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,cAAc,GAAI;oBAChF,KAAK,CAAC,OAAO,CAAC,QAAQ,CACT,CACT,CACV,CACA,CACJ,CAAC;IACJ,CAAC,CAAC;IAhBW,QAAA,sBAAsB,0BAgBjC","sourcesContent":["import * as React from 'react';\nimport { Portal } from '@fluentui/react-portal';\nimport { getSlots } from '@fluentui/react-utilities';\nimport type { TooltipSlots, TooltipState } from './Tooltip.types';\n\n/**\n * Render the final JSX of Tooltip\n */\nexport const renderTooltip_unstable = (state: TooltipState) => {\n const { slots, slotProps } = getSlots<TooltipSlots>(state);\n\n return (\n <>\n {state.children}\n {state.shouldRenderTooltip && (\n <Portal mountNode={state.mountNode}>\n <slots.content {...slotProps.content}>\n {state.withArrow && <div ref={state.arrowRef} className={state.arrowClassName} />}\n {state.content.children}\n </slots.content>\n </Portal>\n )}\n </>\n );\n};\n"]}
@@ -0,0 +1,158 @@
1
+ define(["require", "exports", "tslib", "react", "@fluentui/react-positioning", "@fluentui/react-shared-contexts", "@fluentui/react-utilities", "./private/constants", "@fluentui/keyboard-keys"], function (require, exports, tslib_1, React, react_positioning_1, react_shared_contexts_1, react_utilities_1, constants_1, keyboard_keys_1) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useTooltip_unstable = void 0;
5
+ /**
6
+ * Create the state required to render Tooltip.
7
+ *
8
+ * The returned state can be modified with hooks such as useTooltipStyles_unstable,
9
+ * before being passed to renderTooltip_unstable.
10
+ *
11
+ * @param props - props from this instance of Tooltip
12
+ */
13
+ var useTooltip_unstable = function (props) {
14
+ var _a, _b, _c, _d;
15
+ var context = react_shared_contexts_1.useTooltipVisibility_unstable();
16
+ var isServerSideRender = react_utilities_1.useIsSSR();
17
+ var targetDocument = react_shared_contexts_1.useFluent_unstable().targetDocument;
18
+ var _e = react_utilities_1.useTimeout(), setDelayTimeout = _e[0], clearDelayTimeout = _e[1];
19
+ var _f = props.appearance, appearance = _f === void 0 ? 'normal' : _f, children = props.children, content = props.content, _g = props.withArrow, withArrow = _g === void 0 ? false : _g, _h = props.positioning, positioning = _h === void 0 ? 'above' : _h, onVisibleChange = props.onVisibleChange, relationship = props.relationship, _j = props.showDelay, showDelay = _j === void 0 ? 250 : _j, _k = props.hideDelay, hideDelay = _k === void 0 ? 250 : _k, mountNode = props.mountNode;
20
+ var _l = react_utilities_1.useControllableState({ state: props.visible, initialState: false }), visible = _l[0], setVisibleInternal = _l[1];
21
+ var setVisible = React.useCallback(function (newVisible, ev) {
22
+ clearDelayTimeout();
23
+ setVisibleInternal(function (oldVisible) {
24
+ if (newVisible !== oldVisible) {
25
+ onVisibleChange === null || onVisibleChange === void 0 ? void 0 : onVisibleChange(ev, { visible: newVisible });
26
+ }
27
+ return newVisible;
28
+ });
29
+ }, [clearDelayTimeout, setVisibleInternal, onVisibleChange]);
30
+ var state = {
31
+ withArrow: withArrow,
32
+ positioning: positioning,
33
+ showDelay: showDelay,
34
+ hideDelay: hideDelay,
35
+ relationship: relationship,
36
+ visible: visible,
37
+ shouldRenderTooltip: visible,
38
+ appearance: appearance,
39
+ mountNode: mountNode,
40
+ // Slots
41
+ components: {
42
+ content: 'div',
43
+ },
44
+ content: react_utilities_1.resolveShorthand(content, {
45
+ defaultProps: {
46
+ role: 'tooltip',
47
+ },
48
+ required: true,
49
+ }),
50
+ };
51
+ state.content.id = react_utilities_1.useId('tooltip-', state.content.id);
52
+ var positioningOptions = tslib_1.__assign({ enabled: state.visible, arrowPadding: 2 * constants_1.tooltipBorderRadius, position: 'above', align: 'center', offset: 4 }, react_positioning_1.resolvePositioningShorthand(state.positioning));
53
+ if (state.withArrow) {
54
+ positioningOptions.offset = react_positioning_1.mergeArrowOffset(positioningOptions.offset, constants_1.arrowHeight);
55
+ }
56
+ var _m = react_positioning_1.usePositioning(positioningOptions), targetRef = _m.targetRef, containerRef = _m.containerRef, arrowRef = _m.arrowRef;
57
+ state.content.ref = react_utilities_1.useMergedRefs(state.content.ref, containerRef);
58
+ state.arrowRef = arrowRef;
59
+ // When this tooltip is visible, hide any other tooltips, and register it
60
+ // as the visibleTooltip with the TooltipContext.
61
+ // Also add a listener on document to hide the tooltip if Escape is pressed
62
+ react_utilities_1.useIsomorphicLayoutEffect(function () {
63
+ var _a;
64
+ if (visible) {
65
+ var thisTooltip_1 = { hide: function () { return setVisible(false); } };
66
+ (_a = context.visibleTooltip) === null || _a === void 0 ? void 0 : _a.hide();
67
+ context.visibleTooltip = thisTooltip_1;
68
+ var onDocumentKeyDown_1 = function (ev) {
69
+ if (ev.key === keyboard_keys_1.Escape) {
70
+ thisTooltip_1.hide();
71
+ // stop propagation to avoid conflicting with other elements that listen for `Escape`
72
+ // e,g: Dialog, Popover, Menu
73
+ ev.stopPropagation();
74
+ }
75
+ };
76
+ targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.addEventListener('keydown', onDocumentKeyDown_1, {
77
+ // As this event is added at targeted document,
78
+ // we need to capture the event to be sure keydown handling from tooltip happens first
79
+ capture: true,
80
+ });
81
+ return function () {
82
+ if (context.visibleTooltip === thisTooltip_1) {
83
+ context.visibleTooltip = undefined;
84
+ }
85
+ targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.removeEventListener('keydown', onDocumentKeyDown_1, { capture: true });
86
+ };
87
+ }
88
+ }, [context, targetDocument, visible, setVisible]);
89
+ // The focused element gets a blur event when the document loses focus
90
+ // (e.g. switching tabs in the browser), but we don't want to show the
91
+ // tooltip again when the document gets focus back. Handle this case by
92
+ // checking if the blurred element is still the document's activeElement.
93
+ // See https://github.com/microsoft/fluentui/issues/13541
94
+ var ignoreNextFocusEventRef = React.useRef(false);
95
+ // Listener for onPointerEnter and onFocus on the trigger element
96
+ var onEnterTrigger = React.useCallback(function (ev) {
97
+ if (ev.type === 'focus' && ignoreNextFocusEventRef.current) {
98
+ ignoreNextFocusEventRef.current = false;
99
+ return;
100
+ }
101
+ // Show immediately if another tooltip is already visible
102
+ var delay = context.visibleTooltip ? 0 : state.showDelay;
103
+ setDelayTimeout(function () {
104
+ setVisible(true, ev);
105
+ }, delay);
106
+ ev.persist(); // Persist the event since the setVisible call will happen asynchronously
107
+ }, [setDelayTimeout, setVisible, state.showDelay, context]);
108
+ // Listener for onPointerLeave and onBlur on the trigger element
109
+ var onLeaveTrigger = React.useCallback(function (ev) {
110
+ var delay = state.hideDelay;
111
+ if (ev.type === 'blur') {
112
+ // Hide immediately when losing focus
113
+ delay = 0;
114
+ ignoreNextFocusEventRef.current = (targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.activeElement) === ev.target;
115
+ }
116
+ setDelayTimeout(function () {
117
+ setVisible(false, ev);
118
+ }, delay);
119
+ ev.persist(); // Persist the event since the setVisible call will happen asynchronously
120
+ }, [setDelayTimeout, setVisible, state.hideDelay, targetDocument]);
121
+ // Cancel the hide timer when the mouse or focus enters the tooltip, and restart it when the mouse or focus leaves.
122
+ // This keeps the tooltip visible when the mouse is moved over it, or it has focus within.
123
+ state.content.onPointerEnter = react_utilities_1.mergeCallbacks(state.content.onPointerEnter, clearDelayTimeout);
124
+ state.content.onPointerLeave = react_utilities_1.mergeCallbacks(state.content.onPointerLeave, onLeaveTrigger);
125
+ state.content.onFocus = react_utilities_1.mergeCallbacks(state.content.onFocus, clearDelayTimeout);
126
+ state.content.onBlur = react_utilities_1.mergeCallbacks(state.content.onBlur, onLeaveTrigger);
127
+ var child = react_utilities_1.getTriggerChild(children);
128
+ var triggerAriaProps = {};
129
+ if (relationship === 'label') {
130
+ // aria-label only works if the content is a string. Otherwise, need to use aria-labelledby.
131
+ if (typeof state.content.children === 'string') {
132
+ triggerAriaProps['aria-label'] = state.content.children;
133
+ }
134
+ else {
135
+ triggerAriaProps['aria-labelledby'] = state.content.id;
136
+ // Always render the tooltip even if hidden, so that aria-labelledby refers to a valid element
137
+ state.shouldRenderTooltip = true;
138
+ }
139
+ }
140
+ else if (relationship === 'description') {
141
+ triggerAriaProps['aria-describedby'] = state.content.id;
142
+ // Always render the tooltip even if hidden, so that aria-describedby refers to a valid element
143
+ state.shouldRenderTooltip = true;
144
+ }
145
+ // Don't render the Tooltip in SSR to avoid hydration errors
146
+ if (isServerSideRender) {
147
+ state.shouldRenderTooltip = false;
148
+ }
149
+ var childTargetRef = react_utilities_1.useMergedRefs(child === null || child === void 0 ? void 0 : child.ref, targetRef);
150
+ // Apply the trigger props to the child, either by calling the render function, or cloning with the new props
151
+ state.children = react_utilities_1.applyTriggerPropsToChildren(children, tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, triggerAriaProps), child === null || child === void 0 ? void 0 : child.props), {
152
+ // If the target prop is not provided, attach targetRef to the trigger element's ref prop
153
+ ref: positioningOptions.target === undefined ? childTargetRef : child === null || child === void 0 ? void 0 : child.ref, onPointerEnter: react_utilities_1.useEventCallback(react_utilities_1.mergeCallbacks((_a = child === null || child === void 0 ? void 0 : child.props) === null || _a === void 0 ? void 0 : _a.onPointerEnter, onEnterTrigger)), onPointerLeave: react_utilities_1.useEventCallback(react_utilities_1.mergeCallbacks((_b = child === null || child === void 0 ? void 0 : child.props) === null || _b === void 0 ? void 0 : _b.onPointerLeave, onLeaveTrigger)), onFocus: react_utilities_1.useEventCallback(react_utilities_1.mergeCallbacks((_c = child === null || child === void 0 ? void 0 : child.props) === null || _c === void 0 ? void 0 : _c.onFocus, onEnterTrigger)), onBlur: react_utilities_1.useEventCallback(react_utilities_1.mergeCallbacks((_d = child === null || child === void 0 ? void 0 : child.props) === null || _d === void 0 ? void 0 : _d.onBlur, onLeaveTrigger)) }));
154
+ return state;
155
+ };
156
+ exports.useTooltip_unstable = useTooltip_unstable;
157
+ });
158
+ //# sourceMappingURL=useTooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTooltip.js","sourceRoot":"","sources":["../../../../../../../../../packages/react-components/react-tooltip/src/components/Tooltip/useTooltip.tsx"],"names":[],"mappings":";;;;IAuBA;;;;;;;OAOG;IACI,IAAM,mBAAmB,GAAG,UAAC,KAAmB;;QACrD,IAAM,OAAO,GAAG,qDAAoB,EAAE,CAAC;QACvC,IAAM,kBAAkB,GAAG,0BAAQ,EAAE,CAAC;QAC9B,IAAA,cAAc,GAAK,0CAAS,EAAE,eAAhB,CAAiB;QACjC,IAAA,KAAuC,4BAAU,EAAE,EAAlD,eAAe,QAAA,EAAE,iBAAiB,QAAgB,CAAC;QAGxD,IAAA,KAUE,KAAK,WAVc,EAArB,UAAU,mBAAG,QAAQ,KAAA,EACrB,QAAQ,GASN,KAAK,SATC,EACR,OAAO,GAQL,KAAK,QARA,EACP,KAOE,KAAK,UAPU,EAAjB,SAAS,mBAAG,KAAK,KAAA,EACjB,KAME,KAAK,YANc,EAArB,WAAW,mBAAG,OAAO,KAAA,EACrB,eAAe,GAKb,KAAK,gBALQ,EACf,YAAY,GAIV,KAAK,aAJK,EACZ,KAGE,KAAK,UAHQ,EAAf,SAAS,mBAAG,GAAG,KAAA,EACf,KAEE,KAAK,UAFQ,EAAf,SAAS,mBAAG,GAAG,KAAA,EACf,SAAS,GACP,KAAK,UADE,CACD;QAEJ,IAAA,KAAgC,sCAAoB,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,EAAlG,OAAO,QAAA,EAAE,kBAAkB,QAAuE,CAAC;QAC1G,IAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAClC,UAAC,UAAmB,EAAE,EAAoE;YACxF,iBAAiB,EAAE,CAAC;YACpB,kBAAkB,CAAC,UAAA,UAAU;gBAC3B,IAAI,UAAU,KAAK,UAAU,EAAE;oBAC7B,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAG,EAAE,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;iBAChD;gBACD,OAAO,UAAU,CAAC;YACpB,CAAC,CAAC,CAAC;QACL,CAAC,EACD,CAAC,iBAAiB,EAAE,kBAAkB,EAAE,eAAe,CAAC,CACzD,CAAC;QAEF,IAAM,KAAK,GAAiB;YAC1B,SAAS,WAAA;YACT,WAAW,aAAA;YACX,SAAS,WAAA;YACT,SAAS,WAAA;YACT,YAAY,cAAA;YACZ,OAAO,SAAA;YACP,mBAAmB,EAAE,OAAO;YAC5B,UAAU,YAAA;YACV,SAAS,WAAA;YACT,QAAQ;YACR,UAAU,EAAE;gBACV,OAAO,EAAE,KAAK;aACf;YACD,OAAO,EAAE,kCAAgB,CAAC,OAAO,EAAE;gBACjC,YAAY,EAAE;oBACZ,IAAI,EAAE,SAAS;iBAChB;gBACD,QAAQ,EAAE,IAAI;aACf,CAAC;SACH,CAAC;QAEF,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,uBAAK,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEvD,IAAM,kBAAkB,sBACtB,OAAO,EAAE,KAAK,CAAC,OAAO,EACtB,YAAY,EAAE,CAAC,GAAG,+BAAmB,EACrC,QAAQ,EAAE,OAAgB,EAC1B,KAAK,EAAE,QAAiB,EACxB,MAAM,EAAE,CAAC,IACN,+CAA2B,CAAC,KAAK,CAAC,WAAW,CAAC,CAClD,CAAC;QAEF,IAAI,KAAK,CAAC,SAAS,EAAE;YACnB,kBAAkB,CAAC,MAAM,GAAG,oCAAgB,CAAC,kBAAkB,CAAC,MAAM,EAAE,uBAAW,CAAC,CAAC;SACtF;QAEK,IAAA,KAQF,kCAAc,CAAC,kBAAkB,CAAC,EAPpC,SAAS,eAAA,EACT,YAAY,kBAAA,EACZ,QAAQ,cAK4B,CAAC;QAEvC,KAAK,CAAC,OAAO,CAAC,GAAG,GAAG,+BAAa,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACnE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAE1B,yEAAyE;QACzE,iDAAiD;QACjD,2EAA2E;QAC3E,2CAAyB,CAAC;;YACxB,IAAI,OAAO,EAAE;gBACX,IAAM,aAAW,GAAG,EAAE,IAAI,EAAE,cAAM,OAAA,UAAU,CAAC,KAAK,CAAC,EAAjB,CAAiB,EAAE,CAAC;gBAEtD,MAAA,OAAO,CAAC,cAAc,0CAAE,IAAI,EAAE,CAAC;gBAC/B,OAAO,CAAC,cAAc,GAAG,aAAW,CAAC;gBAErC,IAAM,mBAAiB,GAAG,UAAC,EAAiB;oBAC1C,IAAI,EAAE,CAAC,GAAG,KAAK,sBAAM,EAAE;wBACrB,aAAW,CAAC,IAAI,EAAE,CAAC;wBACnB,qFAAqF;wBACrF,6BAA6B;wBAC7B,EAAE,CAAC,eAAe,EAAE,CAAC;qBACtB;gBACH,CAAC,CAAC;gBAEF,cAAc,aAAd,cAAc,uBAAd,cAAc,CAAE,gBAAgB,CAAC,SAAS,EAAE,mBAAiB,EAAE;oBAC7D,+CAA+C;oBAC/C,sFAAsF;oBACtF,OAAO,EAAE,IAAI;iBACd,CAAC,CAAC;gBAEH,OAAO;oBACL,IAAI,OAAO,CAAC,cAAc,KAAK,aAAW,EAAE;wBAC1C,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;qBACpC;oBAED,cAAc,aAAd,cAAc,uBAAd,cAAc,CAAE,mBAAmB,CAAC,SAAS,EAAE,mBAAiB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBACvF,CAAC,CAAC;aACH;QACH,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;QAEnD,sEAAsE;QACtE,sEAAsE;QACtE,uEAAuE;QACvE,yEAAyE;QACzE,yDAAyD;QACzD,IAAM,uBAAuB,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEpD,iEAAiE;QACjE,IAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CACtC,UAAC,EAAmE;YAClE,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,IAAI,uBAAuB,CAAC,OAAO,EAAE;gBAC1D,uBAAuB,CAAC,OAAO,GAAG,KAAK,CAAC;gBACxC,OAAO;aACR;YAED,yDAAyD;YACzD,IAAM,KAAK,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;YAE3D,eAAe,CAAC;gBACd,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACvB,CAAC,EAAE,KAAK,CAAC,CAAC;YAEV,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,yEAAyE;QACzF,CAAC,EACD,CAAC,eAAe,EAAE,UAAU,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CACxD,CAAC;QAEF,gEAAgE;QAChE,IAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CACtC,UAAC,EAAmE;YAClE,IAAI,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC;YAE5B,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM,EAAE;gBACtB,qCAAqC;gBACrC,KAAK,GAAG,CAAC,CAAC;gBAEV,uBAAuB,CAAC,OAAO,GAAG,CAAA,cAAc,aAAd,cAAc,uBAAd,cAAc,CAAE,aAAa,MAAK,EAAE,CAAC,MAAM,CAAC;aAC/E;YAED,eAAe,CAAC;gBACd,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACxB,CAAC,EAAE,KAAK,CAAC,CAAC;YAEV,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,yEAAyE;QACzF,CAAC,EACD,CAAC,eAAe,EAAE,UAAU,EAAE,KAAK,CAAC,SAAS,EAAE,cAAc,CAAC,CAC/D,CAAC;QAEF,mHAAmH;QACnH,0FAA0F;QAC1F,KAAK,CAAC,OAAO,CAAC,cAAc,GAAG,gCAAc,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;QAC/F,KAAK,CAAC,OAAO,CAAC,cAAc,GAAG,gCAAc,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;QAC5F,KAAK,CAAC,OAAO,CAAC,OAAO,GAAG,gCAAc,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;QACjF,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,gCAAc,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QAE5E,IAAM,KAAK,GAAG,iCAAe,CAAC,QAAQ,CAAC,CAAC;QAExC,IAAM,gBAAgB,GAAmF,EAAE,CAAC;QAE5G,IAAI,YAAY,KAAK,OAAO,EAAE;YAC5B,4FAA4F;YAC5F,IAAI,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE;gBAC9C,gBAAgB,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;aACzD;iBAAM;gBACL,gBAAgB,CAAC,iBAAiB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACvD,8FAA8F;gBAC9F,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC;aAClC;SACF;aAAM,IAAI,YAAY,KAAK,aAAa,EAAE;YACzC,gBAAgB,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YACxD,+FAA+F;YAC/F,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC;SAClC;QAED,4DAA4D;QAC5D,IAAI,kBAAkB,EAAE;YACtB,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC;SACnC;QAED,IAAM,cAAc,GAAG,+BAAa,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAE5D,6GAA6G;QAC7G,KAAK,CAAC,QAAQ,GAAG,6CAA2B,CAAC,QAAQ,yDAChD,gBAAgB,GAChB,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK;YACf,yFAAyF;YACzF,GAAG,EAAE,kBAAkB,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,GAAG,EAC1E,cAAc,EAAE,kCAAgB,CAAC,gCAAc,CAAC,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK,0CAAE,cAAc,EAAE,cAAc,CAAC,CAAC,EAC9F,cAAc,EAAE,kCAAgB,CAAC,gCAAc,CAAC,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK,0CAAE,cAAc,EAAE,cAAc,CAAC,CAAC,EAC9F,OAAO,EAAE,kCAAgB,CAAC,gCAAc,CAAC,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK,0CAAE,OAAO,EAAE,cAAc,CAAC,CAAC,EAChF,MAAM,EAAE,kCAAgB,CAAC,gCAAc,CAAC,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK,0CAAE,MAAM,EAAE,cAAc,CAAC,CAAC,IAC9E,CAAC;QAEH,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IApNW,QAAA,mBAAmB,uBAoN9B","sourcesContent":["import * as React from 'react';\nimport { mergeArrowOffset, resolvePositioningShorthand, usePositioning } from '@fluentui/react-positioning';\nimport {\n useTooltipVisibility_unstable as useTooltipVisibility,\n useFluent_unstable as useFluent,\n} from '@fluentui/react-shared-contexts';\nimport {\n applyTriggerPropsToChildren,\n resolveShorthand,\n useControllableState,\n useId,\n useIsomorphicLayoutEffect,\n useIsSSR,\n useMergedRefs,\n useTimeout,\n getTriggerChild,\n mergeCallbacks,\n useEventCallback,\n} from '@fluentui/react-utilities';\nimport type { TooltipProps, TooltipState, TooltipChildProps } from './Tooltip.types';\nimport { arrowHeight, tooltipBorderRadius } from './private/constants';\nimport { Escape } from '@fluentui/keyboard-keys';\n\n/**\n * Create the state required to render Tooltip.\n *\n * The returned state can be modified with hooks such as useTooltipStyles_unstable,\n * before being passed to renderTooltip_unstable.\n *\n * @param props - props from this instance of Tooltip\n */\nexport const useTooltip_unstable = (props: TooltipProps): TooltipState => {\n const context = useTooltipVisibility();\n const isServerSideRender = useIsSSR();\n const { targetDocument } = useFluent();\n const [setDelayTimeout, clearDelayTimeout] = useTimeout();\n\n const {\n appearance = 'normal',\n children,\n content,\n withArrow = false,\n positioning = 'above',\n onVisibleChange,\n relationship,\n showDelay = 250,\n hideDelay = 250,\n mountNode,\n } = props;\n\n const [visible, setVisibleInternal] = useControllableState({ state: props.visible, initialState: false });\n const setVisible = React.useCallback(\n (newVisible: boolean, ev?: React.PointerEvent<HTMLElement> | React.FocusEvent<HTMLElement>) => {\n clearDelayTimeout();\n setVisibleInternal(oldVisible => {\n if (newVisible !== oldVisible) {\n onVisibleChange?.(ev, { visible: newVisible });\n }\n return newVisible;\n });\n },\n [clearDelayTimeout, setVisibleInternal, onVisibleChange],\n );\n\n const state: TooltipState = {\n withArrow,\n positioning,\n showDelay,\n hideDelay,\n relationship,\n visible,\n shouldRenderTooltip: visible,\n appearance,\n mountNode,\n // Slots\n components: {\n content: 'div',\n },\n content: resolveShorthand(content, {\n defaultProps: {\n role: 'tooltip',\n },\n required: true,\n }),\n };\n\n state.content.id = useId('tooltip-', state.content.id);\n\n const positioningOptions = {\n enabled: state.visible,\n arrowPadding: 2 * tooltipBorderRadius,\n position: 'above' as const,\n align: 'center' as const,\n offset: 4,\n ...resolvePositioningShorthand(state.positioning),\n };\n\n if (state.withArrow) {\n positioningOptions.offset = mergeArrowOffset(positioningOptions.offset, arrowHeight);\n }\n\n const {\n targetRef,\n containerRef,\n arrowRef,\n }: {\n targetRef: React.MutableRefObject<unknown>;\n containerRef: React.MutableRefObject<HTMLDivElement>;\n arrowRef: React.MutableRefObject<HTMLDivElement>;\n } = usePositioning(positioningOptions);\n\n state.content.ref = useMergedRefs(state.content.ref, containerRef);\n state.arrowRef = arrowRef;\n\n // When this tooltip is visible, hide any other tooltips, and register it\n // as the visibleTooltip with the TooltipContext.\n // Also add a listener on document to hide the tooltip if Escape is pressed\n useIsomorphicLayoutEffect(() => {\n if (visible) {\n const thisTooltip = { hide: () => setVisible(false) };\n\n context.visibleTooltip?.hide();\n context.visibleTooltip = thisTooltip;\n\n const onDocumentKeyDown = (ev: KeyboardEvent) => {\n if (ev.key === Escape) {\n thisTooltip.hide();\n // stop propagation to avoid conflicting with other elements that listen for `Escape`\n // e,g: Dialog, Popover, Menu\n ev.stopPropagation();\n }\n };\n\n targetDocument?.addEventListener('keydown', onDocumentKeyDown, {\n // As this event is added at targeted document,\n // we need to capture the event to be sure keydown handling from tooltip happens first\n capture: true,\n });\n\n return () => {\n if (context.visibleTooltip === thisTooltip) {\n context.visibleTooltip = undefined;\n }\n\n targetDocument?.removeEventListener('keydown', onDocumentKeyDown, { capture: true });\n };\n }\n }, [context, targetDocument, visible, setVisible]);\n\n // The focused element gets a blur event when the document loses focus\n // (e.g. switching tabs in the browser), but we don't want to show the\n // tooltip again when the document gets focus back. Handle this case by\n // checking if the blurred element is still the document's activeElement.\n // See https://github.com/microsoft/fluentui/issues/13541\n const ignoreNextFocusEventRef = React.useRef(false);\n\n // Listener for onPointerEnter and onFocus on the trigger element\n const onEnterTrigger = React.useCallback(\n (ev: React.PointerEvent<HTMLElement> | React.FocusEvent<HTMLElement>) => {\n if (ev.type === 'focus' && ignoreNextFocusEventRef.current) {\n ignoreNextFocusEventRef.current = false;\n return;\n }\n\n // Show immediately if another tooltip is already visible\n const delay = context.visibleTooltip ? 0 : state.showDelay;\n\n setDelayTimeout(() => {\n setVisible(true, ev);\n }, delay);\n\n ev.persist(); // Persist the event since the setVisible call will happen asynchronously\n },\n [setDelayTimeout, setVisible, state.showDelay, context],\n );\n\n // Listener for onPointerLeave and onBlur on the trigger element\n const onLeaveTrigger = React.useCallback(\n (ev: React.PointerEvent<HTMLElement> | React.FocusEvent<HTMLElement>) => {\n let delay = state.hideDelay;\n\n if (ev.type === 'blur') {\n // Hide immediately when losing focus\n delay = 0;\n\n ignoreNextFocusEventRef.current = targetDocument?.activeElement === ev.target;\n }\n\n setDelayTimeout(() => {\n setVisible(false, ev);\n }, delay);\n\n ev.persist(); // Persist the event since the setVisible call will happen asynchronously\n },\n [setDelayTimeout, setVisible, state.hideDelay, targetDocument],\n );\n\n // Cancel the hide timer when the mouse or focus enters the tooltip, and restart it when the mouse or focus leaves.\n // This keeps the tooltip visible when the mouse is moved over it, or it has focus within.\n state.content.onPointerEnter = mergeCallbacks(state.content.onPointerEnter, clearDelayTimeout);\n state.content.onPointerLeave = mergeCallbacks(state.content.onPointerLeave, onLeaveTrigger);\n state.content.onFocus = mergeCallbacks(state.content.onFocus, clearDelayTimeout);\n state.content.onBlur = mergeCallbacks(state.content.onBlur, onLeaveTrigger);\n\n const child = getTriggerChild(children);\n\n const triggerAriaProps: Pick<TooltipChildProps, 'aria-label' | 'aria-labelledby' | 'aria-describedby'> = {};\n\n if (relationship === 'label') {\n // aria-label only works if the content is a string. Otherwise, need to use aria-labelledby.\n if (typeof state.content.children === 'string') {\n triggerAriaProps['aria-label'] = state.content.children;\n } else {\n triggerAriaProps['aria-labelledby'] = state.content.id;\n // Always render the tooltip even if hidden, so that aria-labelledby refers to a valid element\n state.shouldRenderTooltip = true;\n }\n } else if (relationship === 'description') {\n triggerAriaProps['aria-describedby'] = state.content.id;\n // Always render the tooltip even if hidden, so that aria-describedby refers to a valid element\n state.shouldRenderTooltip = true;\n }\n\n // Don't render the Tooltip in SSR to avoid hydration errors\n if (isServerSideRender) {\n state.shouldRenderTooltip = false;\n }\n\n const childTargetRef = useMergedRefs(child?.ref, targetRef);\n\n // Apply the trigger props to the child, either by calling the render function, or cloning with the new props\n state.children = applyTriggerPropsToChildren(children, {\n ...triggerAriaProps,\n ...child?.props,\n // If the target prop is not provided, attach targetRef to the trigger element's ref prop\n ref: positioningOptions.target === undefined ? childTargetRef : child?.ref,\n onPointerEnter: useEventCallback(mergeCallbacks(child?.props?.onPointerEnter, onEnterTrigger)),\n onPointerLeave: useEventCallback(mergeCallbacks(child?.props?.onPointerLeave, onLeaveTrigger)),\n onFocus: useEventCallback(mergeCallbacks(child?.props?.onFocus, onEnterTrigger)),\n onBlur: useEventCallback(mergeCallbacks(child?.props?.onBlur, onLeaveTrigger)),\n });\n\n return state;\n};\n"]}
@@ -0,0 +1,36 @@
1
+ define(["require", "exports", "tslib", "@griffel/react", "@fluentui/react-positioning", "@fluentui/react-theme", "./private/constants"], function (require, exports, tslib_1, react_1, react_positioning_1, react_theme_1, constants_1) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useTooltipStyles_unstable = exports.tooltipClassNames = void 0;
5
+ exports.tooltipClassNames = {
6
+ content: 'fui-Tooltip__content',
7
+ };
8
+ /**
9
+ * Styles for the tooltip
10
+ */
11
+ var useStyles = react_1.makeStyles({
12
+ root: tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({ display: 'none', boxSizing: 'border-box', maxWidth: '240px', cursor: 'default', fontFamily: react_theme_1.tokens.fontFamilyBase, fontSize: react_theme_1.tokens.fontSizeBase200, lineHeight: react_theme_1.tokens.lineHeightBase200 }, react_1.shorthands.borderRadius(react_theme_1.tokens.borderRadiusMedium)), react_1.shorthands.border('1px', 'solid', react_theme_1.tokens.colorTransparentStroke)), react_1.shorthands.padding('4px', '11px', '6px', '11px')), { backgroundColor: react_theme_1.tokens.colorNeutralBackground1, color: react_theme_1.tokens.colorNeutralForeground1,
13
+ // TODO need to add versions of tokens.alias.shadow.shadow8, etc. that work with filter
14
+ filter: "drop-shadow(0 0 2px " + react_theme_1.tokens.colorNeutralShadowAmbient + ") " +
15
+ ("drop-shadow(0 4px 8px " + react_theme_1.tokens.colorNeutralShadowKey + ")") }),
16
+ visible: {
17
+ display: 'block',
18
+ },
19
+ inverted: {
20
+ backgroundColor: react_theme_1.tokens.colorNeutralBackgroundStatic,
21
+ color: react_theme_1.tokens.colorNeutralForegroundStaticInverted,
22
+ },
23
+ arrow: react_positioning_1.createArrowStyles({ arrowHeight: constants_1.arrowHeight }),
24
+ });
25
+ /**
26
+ * Apply styling to the Tooltip slots based on the state
27
+ */
28
+ var useTooltipStyles_unstable = function (state) {
29
+ var styles = useStyles();
30
+ state.content.className = react_1.mergeClasses(exports.tooltipClassNames.content, styles.root, state.appearance === 'inverted' && styles.inverted, state.visible && styles.visible, state.content.className);
31
+ state.arrowClassName = styles.arrow;
32
+ return state;
33
+ };
34
+ exports.useTooltipStyles_unstable = useTooltipStyles_unstable;
35
+ });
36
+ //# sourceMappingURL=useTooltipStyles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTooltipStyles.js","sourceRoot":"","sources":["../../../../../../../../../packages/react-components/react-tooltip/src/components/Tooltip/useTooltipStyles.ts"],"names":[],"mappings":";;;;IAOa,QAAA,iBAAiB,GAAiC;QAC7D,OAAO,EAAE,sBAAsB;KAChC,CAAC;IAEF;;OAEG;IACH,IAAM,SAAS,GAAG,kBAAU,CAAC;QAC3B,IAAI,wEACF,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,YAAY,EACvB,QAAQ,EAAE,OAAO,EACjB,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,oBAAM,CAAC,cAAc,EACjC,QAAQ,EAAE,oBAAM,CAAC,eAAe,EAChC,UAAU,EAAE,oBAAM,CAAC,iBAAiB,IAEjC,kBAAU,CAAC,YAAY,CAAC,oBAAM,CAAC,kBAAkB,CAAC,GAClD,kBAAU,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,oBAAM,CAAC,sBAAsB,CAAC,GAChE,kBAAU,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KACnD,eAAe,EAAE,oBAAM,CAAC,uBAAuB,EAC/C,KAAK,EAAE,oBAAM,CAAC,uBAAuB;YAErC,uFAAuF;YACvF,MAAM,EACJ,yBAAuB,oBAAM,CAAC,yBAAyB,OAAI;iBAC3D,2BAAyB,oBAAM,CAAC,qBAAqB,MAAG,CAAA,GAC3D;QAED,OAAO,EAAE;YACP,OAAO,EAAE,OAAO;SACjB;QAED,QAAQ,EAAE;YACR,eAAe,EAAE,oBAAM,CAAC,4BAA4B;YACpD,KAAK,EAAE,oBAAM,CAAC,oCAAoC;SACnD;QAED,KAAK,EAAE,qCAAiB,CAAC,EAAE,WAAW,yBAAA,EAAE,CAAC;KAC1C,CAAC,CAAC;IAEH;;OAEG;IACI,IAAM,yBAAyB,GAAG,UAAC,KAAmB;QAC3D,IAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAE3B,KAAK,CAAC,OAAO,CAAC,SAAS,GAAG,oBAAY,CACpC,yBAAiB,CAAC,OAAO,EACzB,MAAM,CAAC,IAAI,EACX,KAAK,CAAC,UAAU,KAAK,UAAU,IAAI,MAAM,CAAC,QAAQ,EAClD,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,EAC/B,KAAK,CAAC,OAAO,CAAC,SAAS,CACxB,CAAC;QAEF,KAAK,CAAC,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC;QAEpC,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAdW,QAAA,yBAAyB,6BAcpC","sourcesContent":["import { shorthands, makeStyles, mergeClasses } from '@griffel/react';\nimport { createArrowStyles } from '@fluentui/react-positioning';\nimport { tokens } from '@fluentui/react-theme';\nimport { arrowHeight } from './private/constants';\nimport type { TooltipSlots, TooltipState } from './Tooltip.types';\nimport type { SlotClassNames } from '@fluentui/react-utilities';\n\nexport const tooltipClassNames: SlotClassNames<TooltipSlots> = {\n content: 'fui-Tooltip__content',\n};\n\n/**\n * Styles for the tooltip\n */\nconst useStyles = makeStyles({\n root: {\n display: 'none',\n boxSizing: 'border-box',\n maxWidth: '240px',\n cursor: 'default',\n fontFamily: tokens.fontFamilyBase,\n fontSize: tokens.fontSizeBase200,\n lineHeight: tokens.lineHeightBase200,\n\n ...shorthands.borderRadius(tokens.borderRadiusMedium),\n ...shorthands.border('1px', 'solid', tokens.colorTransparentStroke),\n ...shorthands.padding('4px', '11px', '6px', '11px'), // '5px 12px 7px 12px' minus the border width '1px'\n backgroundColor: tokens.colorNeutralBackground1,\n color: tokens.colorNeutralForeground1,\n\n // TODO need to add versions of tokens.alias.shadow.shadow8, etc. that work with filter\n filter:\n `drop-shadow(0 0 2px ${tokens.colorNeutralShadowAmbient}) ` +\n `drop-shadow(0 4px 8px ${tokens.colorNeutralShadowKey})`,\n },\n\n visible: {\n display: 'block',\n },\n\n inverted: {\n backgroundColor: tokens.colorNeutralBackgroundStatic,\n color: tokens.colorNeutralForegroundStaticInverted,\n },\n\n arrow: createArrowStyles({ arrowHeight }),\n});\n\n/**\n * Apply styling to the Tooltip slots based on the state\n */\nexport const useTooltipStyles_unstable = (state: TooltipState): TooltipState => {\n const styles = useStyles();\n\n state.content.className = mergeClasses(\n tooltipClassNames.content,\n styles.root,\n state.appearance === 'inverted' && styles.inverted,\n state.visible && styles.visible,\n state.content.className,\n );\n\n state.arrowClassName = styles.arrow;\n\n return state;\n};\n"]}
@@ -0,0 +1,11 @@
1
+ define(["require", "exports", "./Tooltip"], function (require, exports, Tooltip_1) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useTooltip_unstable = exports.useTooltipStyles_unstable = exports.tooltipClassNames = exports.renderTooltip_unstable = exports.Tooltip = void 0;
5
+ Object.defineProperty(exports, "Tooltip", { enumerable: true, get: function () { return Tooltip_1.Tooltip; } });
6
+ Object.defineProperty(exports, "renderTooltip_unstable", { enumerable: true, get: function () { return Tooltip_1.renderTooltip_unstable; } });
7
+ Object.defineProperty(exports, "tooltipClassNames", { enumerable: true, get: function () { return Tooltip_1.tooltipClassNames; } });
8
+ Object.defineProperty(exports, "useTooltipStyles_unstable", { enumerable: true, get: function () { return Tooltip_1.useTooltipStyles_unstable; } });
9
+ Object.defineProperty(exports, "useTooltip_unstable", { enumerable: true, get: function () { return Tooltip_1.useTooltip_unstable; } });
10
+ });
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/react-components/react-tooltip/src/index.ts"],"names":[],"mappings":";;;;IACE,kGAAA,OAAO,OAAA;IACP,iHAAA,sBAAsB,OAAA;IACtB,4GAAA,iBAAiB,OAAA;IACjB,oHAAA,yBAAyB,OAAA;IACzB,8GAAA,mBAAmB,OAAA","sourcesContent":["export {\n Tooltip,\n renderTooltip_unstable,\n tooltipClassNames,\n useTooltipStyles_unstable,\n useTooltip_unstable,\n} from './Tooltip';\nexport type {\n OnVisibleChangeData,\n TooltipProps,\n TooltipSlots,\n TooltipState,\n TooltipChildProps as TooltipTriggerProps,\n} from './Tooltip';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui/react-tooltip",
3
- "version": "9.1.1",
3
+ "version": "9.1.3",
4
4
  "description": "React components for building web experiences",
5
5
  "main": "lib-commonjs/index.js",
6
6
  "module": "lib/index.js",
@@ -32,11 +32,11 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@fluentui/keyboard-keys": "^9.0.1",
35
- "@fluentui/react-portal": "^9.0.10",
36
- "@fluentui/react-positioning": "^9.3.1",
37
- "@fluentui/react-shared-contexts": "^9.1.1",
38
- "@fluentui/react-theme": "^9.1.2",
39
- "@fluentui/react-utilities": "^9.2.1",
35
+ "@fluentui/react-portal": "^9.0.12",
36
+ "@fluentui/react-positioning": "^9.3.3",
37
+ "@fluentui/react-shared-contexts": "^9.1.2",
38
+ "@fluentui/react-theme": "^9.1.3",
39
+ "@fluentui/react-utilities": "^9.2.2",
40
40
  "@griffel/react": "^1.4.2",
41
41
  "tslib": "^2.1.0"
42
42
  },
package/MIGRATION.md DELETED
@@ -1,68 +0,0 @@
1
- # Tooltip Migration
2
-
3
- ## STATUS: WIP 🚧
4
-
5
- This Migration guide is a work in progress and is not yet ready for use.
6
-
7
- ## Migration from v8
8
-
9
- TooltipHost is replaced by Tooltip itself, as the wrapper around the element that should receive a tooltip.
10
-
11
- - `Tooltip`
12
- - `calloutProps`
13
- - `isBeakVisible` => `withArrow`
14
- - `beakWidth` => Not supported.
15
- - `gapSpace` => Not supported.
16
- - `doNotLayer` => Not supported. Tooltips are always layered by rendering in a Portal.
17
- - `setInitialFocus` => Not supported. Tooltips can't be focused, by design.
18
- - `componentRef` => Not supported. Tooltips can be controlled declaratively with props like `visible`, instead of using an imperative API like `componentRef`.
19
- - `delay` => `showDelay`
20
- - `directionalHint` => `positioning`
21
- - `topLeftEdge` => `positioning="above-start"`
22
- - `topCenter` => `positioning="above"`
23
- - `topRightEdge` => `positioning="above-end"`
24
- - `topAutoEdge` => Not supported
25
- - `bottomLeftEdge` => `positioning="below-start"`
26
- - `bottomCenter` => `positioning="below"`
27
- - `bottomRightEdge` => `positioning="below-end"`
28
- - `bottomAutoEdge` => Not supported
29
- - `leftTopEdge` => `positioning="before-top"`
30
- - `leftCenter` => `positioning="before"`
31
- - `leftBottomEdge` => `positioning="before-bottom"`
32
- - `rightTopEdge` => `positioning="after-top"`
33
- - `rightCenter` => `positioning="after"`
34
- - `rightBottomEdge` => `positioning="after-bottom"`
35
- - `directionalHintForRTL` => Automatic based on whether the element is in an RTL context according to `FluentProvider`.
36
- - `maxWidth` => Supported only through CSS styling of the `content` slot.
37
- - `onRenderContent` => Set the `content` slot to a custom render function.
38
- - `TooltipHost` => The tooltip itself is the "host".
39
- - `closeDelay` => `hideDelay`
40
- - `hostClassName` => Not needed because there is no element rendered inline by Tooltip
41
- - `onTooltipToggle` => `onVisibleChange`
42
- - `overflowMode` => Not supported. If this behavior is needed, the tooltip's visibility can be controlled using the `visible` prop and `onVisibleChange` event.
43
-
44
- ## Migration from v0
45
-
46
- The v9 Tooltip swaps the meaning of children between content and trigger. In v0, Tooltip's children is the tooltip content, and its trigger is a prop. In v9, that is swapped: Tooltip's children is the trigger, and its content is a prop.
47
-
48
- - `Tooltip`
49
- - children => `content`
50
- - `trigger` => children
51
- - `defaultOpen` => Not supported. The tooltip's visibility can be controlled using the `visible` prop and `onVisibleChange` event.
52
- - `mountNode` => Not supported
53
- - `open` => `visible`
54
- - `onOpenChange` => `onVisibleChange`
55
- - `pointing` => `withArrow`
56
- - `mouseEnterDelay` => `showDelay`
57
- - `mouseLeaveDelay` => `hideDelay`
58
- - `subtle={true}` = `appearance="normal"` (default)
59
- - `subtle={false}` => `appearance="inverted"`
60
- - Positioning props are now attributes of the `positioning` prop:
61
- - `flipBoundary` => `positioning.flipBoundary`
62
- - `offset` => `positioning.offset`
63
- - `overflowBoundary` => `positioning.overflowBoundary`
64
- - `popperRef` => `positioning.popperRef`
65
- - `position` => `positioning.position`
66
- - `align` => `positioning.align`
67
- - `positionFixed` => `positioning.positionFixed`
68
- - `target` => `positioning.target`
package/Spec.md DELETED
@@ -1,374 +0,0 @@
1
- # Tooltip Spec
2
-
3
- Tooltips provide additional information about an element when hovering or focusing on the element.
4
-
5
- ## Prior Art
6
-
7
- - OpenUI Tooltip resarch: https://open-ui.org/components/tooltip.research
8
- - GitHub Epic issue: [Tooltip Convergence #16735](https://github.com/microsoft/fluentui/issues/16735)
9
-
10
- ### Tooltips in v8/Fabric
11
-
12
- v8 tooltips use a `TooltipHost` wrapped around the target element to provide tooltip functionality. This creates a `div` around the element that listens for mouse and focus events.
13
-
14
- The `Tooltip` component renders as a `Callout`, and supports all `Callout` props.
15
-
16
- ```tsx
17
- <TooltipHost
18
- content="This is the tooltip content"
19
- // This id is used on the tooltip itself, not the host
20
- // (so an element with this id only exists when the tooltip is shown)
21
- id={tooltipId}
22
- calloutProps={calloutProps}
23
- styles={hostStyles}
24
- >
25
- <DefaultButton aria-describedby={tooltipId}>Hover over me</DefaultButton>
26
- </TooltipHost>
27
- ```
28
-
29
- #### Drawbacks
30
-
31
- There are a few drawbacks with this approach to adding tooltips, which are outlined in [☂ Tooltip: open issues to resolve in converged approach #15102](https://github.com/microsoft/fluentui/issues/15102), and summarized below:
32
-
33
- - The wrapper `div` created by `TooltipHost` can cause layout issues for the component. It also doesn't always result in proper positioning for the tooltip.
34
- - The API is overly complex.
35
- - There's no coordination between tooltips on a page. For example, moving the mouse between two elements with tooltips should cause the second tooltip to appear immediately without fading in/out.
36
-
37
- ### Tooltips in v0/Northstar
38
-
39
- v0 tooltips use a `trigger` property to render the tooltip's target component. However, unlike v8 it does not create a wrapper `div` around the target component, but instead adds listeners to the target component's props.
40
-
41
- ```tsx
42
- <Tooltip content="Example tooltip" trigger={<Button content="A button" />} />
43
- ```
44
-
45
- # Sample Code
46
-
47
- Label tooltip for an icon-only button:
48
-
49
- ```tsx
50
- <Tooltip content="Copy" relationship="label">
51
- <Button icon={<CopyRegular />} />
52
- </Tooltip>
53
- ```
54
-
55
- Description tooltip for a link:
56
-
57
- ```tsx
58
- <Tooltip content="This is an example" relationship="description">
59
- <a href="http://example.com">A link</a>
60
- </Tooltip>
61
- ```
62
-
63
- Tooltip with custom JSX content:
64
-
65
- ```tsx
66
- <Tooltip content={<b>The content can be JSX</b>} relationship="label">
67
- <Button />
68
- </Tooltip>
69
- ```
70
-
71
- Custom component as a trigger:
72
-
73
- ```tsx
74
- <Tooltip content="Supports any component that accepts HTML attributes" relationship="label">
75
- <FancyButton />
76
- </Tooltip>
77
- ```
78
-
79
- Render function for the trigger:
80
-
81
- ```tsx
82
- <Tooltip content="The child can be a render function" relationship="description">
83
- {triggerProps => (
84
- <>
85
- <div>
86
- <button {...triggerProps}>The trigger element</button>
87
- </div>
88
- </>
89
- )}
90
- </Tooltip>
91
- ```
92
-
93
- ```tsx
94
- <Tooltip
95
- content="It can target an element other than its trigger"
96
- relationship="description"
97
- positioning={{ target: targetElement }}
98
- >
99
- <button>
100
- Custom target: <div ref={setTargetElement} />
101
- </button>
102
- </Tooltip>
103
- ```
104
-
105
- # Variants
106
-
107
- - The tooltip supports higher contrast colors with `appearance="inverted"`.
108
- - The tooltip supports rendering an arrow pointing to the target element, using `withArrow`.
109
-
110
- # API
111
-
112
- To attach a tooltip to an element, wrap it with a `Tooltip`. There is a `content` slot for the text of the tooltip itself.
113
-
114
- Unlike most components, Tooltip doesn't have a root slot and doesn't allow native DOM props on the Tooltip itself. This is because it doesn't render any nodes inline around its trigger (it does _not_ wrap the element with a `<div>` for example). Instead, it attaches listeners to the child by cloning the JSX object and adding `onPointerEnter`, etc. listeners.
115
-
116
- Tooltip only supports a single child element, which can be either:
117
-
118
- - A native element or component that supports DOM attributes (the child can't be a string, for example).
119
- - A render function that takes the extra props to be added to the trigger element.
120
- - It is allowed to have a tooltip without a child (trigger) element, in which case it _must_ have a target set via the `positioning` prop, and its visibility must be controlled with the `visible` prop.
121
-
122
- _A note about the terminology used for the elements that the tooltip is attached to:_
123
-
124
- - _The **trigger** is the element that causes the tooltip to open._
125
- - _The **target** is the element that the tooltip is anchored to (and the arrow points to)._
126
- - _Almost always, these will both be the same element, but it is possible to specify them separately, so the tooltip can show up adjacent to a different element than the one that triggered it._
127
-
128
- ## Types
129
-
130
- ### `Tooltip`
131
-
132
- From [Tooltip.types.tsx](https://github.com/microsoft/fluentui/blob/master/packages/react-tooltip/src/components/Tooltip/Tooltip.types.tsx) in `@fluentui/react-tooltip`:
133
-
134
- ```ts
135
- /**
136
- * Slot properties for Tooltip
137
- */
138
- export type TooltipSlots = {
139
- /**
140
- * The text or JSX content of the tooltip.
141
- */
142
- content: NonNullable<Slot<'div'>>;
143
- };
144
-
145
- /**
146
- * Properties for Tooltip
147
- */
148
- export type TooltipProps = ComponentProps<TooltipSlots> & {
149
- /**
150
- * (Required) Specifies whether this tooltip is acting as the description or label of its trigger element.
151
- *
152
- * * `label` - The tooltip sets the trigger's aria-label or aria-labelledby attribute. This is useful for buttons
153
- * displaying only an icon, for example.
154
- * * `description` - The tooltip sets the trigger's aria-description or aria-describedby attribute.
155
- * * `inaccessible` - No aria attributes are set on the trigger. This makes the tooltip's content inaccessible to
156
- * screen readers, and should only be used if the tooltip's text is available by some other means.
157
- */
158
- relationship: 'label' | 'description' | 'inaccessible';
159
-
160
- /**
161
- * The tooltip can have a single JSX child, or a render function that accepts TooltipTriggerProps.
162
- *
163
- * If no child is provided, the tooltip's target must be set with the `positioning` prop, and its
164
- * visibility must be controlled with the `visible` prop.
165
- */
166
- children?:
167
- | (React.ReactElement & { ref?: React.Ref<unknown> })
168
- | ((props: TooltipTriggerProps) => React.ReactElement | null)
169
- | null;
170
-
171
- /**
172
- * The tooltip's visual appearance.
173
- * * `normal` - Uses the theme's background and text colors.
174
- * * `inverted` - Higher contrast variant that uses the theme's inverted colors.
175
- *
176
- * @defaultvalue normal
177
- */
178
- appearance?: 'normal' | 'inverted';
179
-
180
- /**
181
- * Render an arrow pointing to the target element
182
- *
183
- * @defaultvalue false
184
- */
185
- withArrow?: boolean;
186
-
187
- /**
188
- * Configure the positioning of the tooltip
189
- *
190
- * @defaultvalue above
191
- */
192
- positioning?: PositioningShorthand;
193
-
194
- /**
195
- * Control the tooltip's visibility programatically.
196
- *
197
- * This can be used in conjunction with onVisibleChange to modify the tooltip's show and hide behavior.
198
- *
199
- * If not provided, the visibility will be controlled by the tooltip itself, based on hover and focus events on the
200
- * trigger (child) element.
201
- */
202
- visible?: boolean;
203
-
204
- /**
205
- * Notification when the visibility of the tooltip is changing
206
- */
207
- onVisibleChange?: (
208
- event: React.PointerEvent<HTMLElement> | React.FocusEvent<HTMLElement> | undefined,
209
- data: OnVisibleChangeData,
210
- ) => void;
211
-
212
- /**
213
- * Delay before the tooltip is shown, in milliseconds.
214
- *
215
- * @defaultvalue 250
216
- */
217
- showDelay?: number;
218
-
219
- /**
220
- * Delay before the tooltip is hidden, in milliseconds.
221
- *
222
- * @defaultvalue 250
223
- */
224
- hideDelay?: number;
225
- };
226
-
227
- /**
228
- * The properties that are added to the trigger of the Tooltip
229
- */
230
- export type TooltipTriggerProps = {
231
- ref?: React.Ref<never>;
232
- } & Pick<
233
- React.HTMLAttributes<HTMLElement>,
234
- 'onPointerEnter' | 'onPointerLeave' | 'onFocus' | 'onBlur' | 'aria-describedby' | 'aria-labelledby' | 'aria-label'
235
- >;
236
-
237
- /**
238
- * Data for the Tooltip's onVisibleChange event.
239
- */
240
- export type OnVisibleChangeData = {
241
- visible: boolean;
242
- };
243
- ```
244
-
245
- ### `TooltipContext`
246
-
247
- The context is included at the app root on `FluentProvider` and is used by `Tooltip` to ensure that only one is visible at once.
248
-
249
- From [TooltipContext.ts](https://github.com/microsoft/fluentui/blob/master/packages/react-shared-contexts/src/TooltipContext/TooltipContext.ts) in `@fluentui/react-shared-contexts`:
250
-
251
- ```ts
252
- /**
253
- * The context provided by TooltipProvider
254
- */
255
- export type TooltipContextType = {
256
- /**
257
- * When a tooltip is shown, it sets itself as the visibleTooltip.
258
- * The next tooltip to become visible can use it to hide the previous tooltip immediately.
259
- */
260
- visibleTooltip?: {
261
- hide: () => void;
262
- };
263
- };
264
-
265
- /**
266
- * Context shared by all of the tooltips in the app
267
- */
268
- export const TooltipContext = React.createContext<TooltipContextType>({});
269
- ```
270
-
271
- # Structure
272
-
273
- ## Tooltip as a label
274
-
275
- ### JSX tree
276
-
277
- ```tsx
278
- <Tooltip content="Example" relationship="label">
279
- <button>
280
- <svg>...</svg>
281
- </button>
282
- </Tooltip>
283
- ```
284
-
285
- ### DOM
286
-
287
- Tooltip with `relationship="label"` is not rendered when it is not visible. Its content is used as the `aria-label` of the control. The Tooltip will be rendered once it is visible; see the next example for what the DOM structure looks like in that case.
288
-
289
- ```html
290
- <body>
291
- <!-- App root -->
292
- <div>
293
- <button aria-label="Example" onPointerEnter="{...}" onPointerLeave="{...}" onFocus="{...}" onBlur="{...}">
294
- <svg>...</svg>
295
- </button>
296
- </div>
297
- </body>
298
- ```
299
-
300
- ## Tooltip as a description
301
-
302
- ### JSX tree
303
-
304
- ```tsx
305
- <Tooltip content="Example description of the button" relationship="description" withArrow>
306
- <button>The Button</button>
307
- </Tooltip>
308
- ```
309
-
310
- ### DOM
311
-
312
- Tooltip with `relationship="description"` is always rendered because it's used as the `aria-describedby` of the control, which always has to point to a valid DOM element even if it's not visible.
313
-
314
- ```html
315
- <body>
316
- <!-- App root -->
317
- <div>
318
- <button aria-describedby="tooltip-2" onPointerEnter="{...}" onPointerLeave="{...}" onFocus="{...}" onBlur="{...}">
319
- The Button
320
- </button>
321
- </div>
322
-
323
- <!-- Portal for Tooltip -->
324
- <div>
325
- <div role="tooltip" id="tooltip-2" class="{tooltip}">
326
- <div class="{arrow}"></div>
327
- Example description of the button
328
- </div>
329
- </div>
330
- </body>
331
- ```
332
-
333
- # Migration
334
-
335
- See [MIGRATION.md](./MIGRATION.md).
336
-
337
- # Behaviors
338
-
339
- ## Visibility
340
-
341
- - The tooltip shows:
342
- - After `showDelay` (250ms default) from when the mouse/pointer enters the trigger.
343
- - After `showDelay` (250ms default) from when the trigger gets keyboard focus.
344
- - _Immediately_ (ignoring `showDelay`) if it is triggered while another tooltip is currently visible.
345
- - The tooltip hides:
346
- - After `hideDelay` (250ms default) from when the mouse/pointer leaves BOTH the trigger AND the tooltip itself.
347
- - _Immediately_ when the trigger loses keyboard focus.
348
- - _Immediately_ when the ESC key is pressed.
349
- - _Immediately_ when another tooltip is shown.
350
-
351
- There is only ever one tooltip visible at once (coordinated using `TooltipContext`). If another tooltip is triggered while there's one currently visible, the previous one hides and the new one shows immediately, without delay.
352
-
353
- ### Placement
354
-
355
- The tooltip is placed relative to its target element based on the `positioning` prop. The placement is handled by the `@fluentui/react-positioning` package, which uses PopperJS.
356
-
357
- ### Focus
358
-
359
- Content within the tooltip is not focusable, and can't be interacted with directly by keyboard or mouse.
360
-
361
- # Accessibility
362
-
363
- - ARIA design pattern: https://www.w3.org/TR/wai-aria-practices-1.2/#tooltip.
364
- - The Tooltip content element has `role="tooltip"`.
365
- - If Tooltip has `relationship="label"` with simple string content:
366
- - The content is set as the trigger's `aria-label`.
367
- - The tooltip is only rendered while it is visible.
368
- - If Tooltip has `relationship="label"` with JSX content, OR `relationship="description"` (string or JSX):
369
- - The tooltip's ID is set as the trigger's `aria-labelledby` or `aria-describedby` (an ID is generated if not provided).
370
- - The tooltip is always rendered, even while hidden.
371
- - While hidden, the tooltip itself is styled with `display: none`.
372
- - The Tooltip itself can never receive focus.
373
- - The Tooltip should never contain focusable elements.
374
- - The trigger for the Tooltip should be focusable.